From 20ded69afb17534c240b6468e693b0402406b0f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 13 Sep 2026 19:17:01 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=84=20Sync=202026-09-13=2019:17:01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aw-bpf/Makefile | 79 - aw-bpf/files/aw-bpf.conf | 2 - aw-bpf/files/aw-bpf.init | 325 ---- luci-app-aw-bpf/LICENSE | 674 --------- luci-app-aw-bpf/Makefile | 13 - .../luci-static/resources/view/aw-bpf.css | 570 ------- .../resources/view/aw-bpf/display.js | 787 ---------- .../luci-static/resources/view/aw-bpf/l7.js | 996 ------------- .../resources/view/aw-bpf/settings.js | 28 - luci-app-aw-bpf/po/zh-cn | 1 - luci-app-aw-bpf/po/zh_Hans/aw-bpf.po | 1207 --------------- .../root/etc/uci-defaults/luci-app-aw-bpf.sh | 6 - .../share/luci/menu.d/luci-app-aw-bpf.json | 46 - .../usr/share/rpcd/acl.d/luci-app-aw-bpf.json | 19 - luci-app-openlist2/Makefile | 7 +- .../resources/view/openlist2/basic.js | 561 ++++--- .../resources/view/openlist2/logs.js | 105 +- luci-app-openlist2/po/templates/openlist2.po | 1318 +++++++++-------- luci-app-openlist2/po/zh_Hans/openlist2.po | 628 ++++---- luci-app-openlist2/po/zh_Hant/openlist2.po | 630 ++++---- .../root/etc/uci-defaults/luci-app-openlist2 | 3 + .../share/rpcd/acl.d/luci-app-openlist2.json | 24 +- luci-app-passwall2/Makefile | 2 +- .../luasrc/controller/passwall2.lua | 2 +- .../model/cbi/passwall2/client/global.lua | 4 +- luci-app-passwall2/luasrc/passwall2/api.lua | 16 +- .../luasrc/passwall2/util_sing-box.lua | 57 +- .../luasrc/passwall2/util_xray.lua | 59 +- .../luasrc/view/passwall2/global/footer.htm | 2 +- .../root/usr/share/passwall2/app.sh | 8 +- .../root/usr/share/passwall2/app_acl.lua | 2 +- .../root/usr/share/passwall2/haproxy.lua | 30 +- .../usr/share/passwall2/helper_dnsmasq.lua | 2 +- .../root/usr/share/passwall2/iptables.sh | 8 +- .../root/usr/share/passwall2/nftables.sh | 45 +- .../root/usr/share/passwall2/utils.sh | 21 +- luci-app-ssr-plus/Makefile | 2 +- .../root/etc/init.d/shadowsocksr | 22 +- luci-app-wwand/Makefile | 6 +- .../.dev/src/media/components/_table.css | 2 +- luci-theme-aurora/Makefile | 4 +- .../htdocs/luci-static/aurora/main.css | 2 +- luci-theme-footstrap/Makefile | 2 +- .../htdocs/luci-static/resources/fs-fit.js | 58 +- .../.dev/src/media/components/_form.css | 20 +- .../.dev/src/media/components/_table.css | 99 +- luci-theme-shadcn/Makefile | 4 +- .../htdocs/luci-static/shadcn/main.css | 2 +- openlist2/Makefile | 13 +- openlist2/files/data.db | Bin 24576 -> 24576 bytes openlist2/files/openlist2.common | 252 ++++ openlist2/files/openlist2.config | 11 +- openlist2/files/openlist2.defaults | 4 + openlist2/files/openlist2.helper | 46 + openlist2/files/openlist2.init | 319 ++-- .../patches/100-retire-legacy-polyfill.patch | 16 + wwand/Makefile | 28 +- 57 files changed, 2774 insertions(+), 6425 deletions(-) delete mode 100644 aw-bpf/Makefile delete mode 100644 aw-bpf/files/aw-bpf.conf delete mode 100644 aw-bpf/files/aw-bpf.init delete mode 100644 luci-app-aw-bpf/LICENSE delete mode 100644 luci-app-aw-bpf/Makefile delete mode 100644 luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf.css delete mode 100644 luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/display.js delete mode 100644 luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/l7.js delete mode 100644 luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/settings.js delete mode 120000 luci-app-aw-bpf/po/zh-cn delete mode 100644 luci-app-aw-bpf/po/zh_Hans/aw-bpf.po delete mode 100644 luci-app-aw-bpf/root/etc/uci-defaults/luci-app-aw-bpf.sh delete mode 100644 luci-app-aw-bpf/root/usr/share/luci/menu.d/luci-app-aw-bpf.json delete mode 100644 luci-app-aw-bpf/root/usr/share/rpcd/acl.d/luci-app-aw-bpf.json create mode 100644 openlist2/files/openlist2.common create mode 100755 openlist2/files/openlist2.defaults create mode 100755 openlist2/files/openlist2.helper create mode 100644 openlist2/patches/100-retire-legacy-polyfill.patch diff --git a/aw-bpf/Makefile b/aw-bpf/Makefile deleted file mode 100644 index 2e1eff340..000000000 --- a/aw-bpf/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (C) 2025 Dengfeng Liu -# -# This is free software, licensed under the GNU General Public License v3. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=aw-bpf -PKG_VERSION:=1.08.23 -PKG_RELEASE:=1 - -PKG_SOURCE:=aw-bpf-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://codeload.github.com/liudf0716/$(PKG_NAME)/tar.gz/$(PKG_VERSION)? -PKG_HASH:=skip -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) - -PKG_MAINTAINER:=Dengfeng Liu -PKG_LICENSE:=GPL-2.0-or-later -PKG_LICENSE_FILES:=LICENSE - -PKG_BUILD_DEPENDS:=bpf-headers - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk -include $(INCLUDE_DIR)/bpf.mk -include $(INCLUDE_DIR)/kernel.mk - -define Package/aw-bpf - SECTION:=net - CATEGORY:=Network - TITLE:=ApFree eBPF programs and tools - DEPENDS:=+libbpf +libelf +libjson-c +libmnl +libnftnl +tc-full +bpftool-minimal +ip +kmod-xdpi +kmod-sched-bpf $(BPF_DEPENDS) - URL:=https://github.com/liudf0716/aw-bpf -endef - -define Package/aw-bpf/description - ApFree eBPF provides eBPF programs for session tracking, xDPI, DNS monitoring - and user-space tools: aw-bpfctl (control CLI) and aw-eventd (session / DNS - consumer with independent nftables table inet awbpf). -endef - - -define KernelPackage/xdpi - SECTION:=kernel - SUBMENU:=Network Support - TITLE:=xdpi ebpf module - FILES:=$(PKG_BUILD_DIR)/xdpi_bpf.ko - AUTOLOAD:=$(call AutoProbe,xdpi_bpf) -endef - -# Build cmake userspace first (aw-bpfctl, aw-eventd), then BPF objects and kmod. -define Build/Compile - $(call Build/Compile/Default) - $(call CompileBPF,$(PKG_BUILD_DIR)/aw_bpf.c,$(if $(filter arm aarch64 x86_64 i386,$(ARCH)),-DENABLE_XDPI_FEATURE)) - $(call CompileBPF,$(PKG_BUILD_DIR)/dns_bpf.c,$(if $(filter arm aarch64 x86_64 i386,$(ARCH)),-DENABLE_XDPI_FEATURE)) - $(KERNEL_MAKE) M=$(PKG_BUILD_DIR) modules -endef - -define Package/aw-bpf/conffiles -/etc/config/aw-bpf -endef - -define Package/aw-bpf/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/aw-bpfctl $(1)/usr/bin/aw-bpfctl - $(INSTALL_BIN) $(PKG_BUILD_DIR)/aw-eventd $(1)/usr/bin/aw-eventd - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/aw-bpf.init $(1)/etc/init.d/aw-bpf - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./files/aw-bpf.conf $(1)/etc/config/aw-bpf - $(INSTALL_DIR) $(1)/lib/bpf - $(INSTALL_DATA) $(PKG_BUILD_DIR)/aw_bpf.o $(1)/lib/bpf/aw-bpf.o - $(INSTALL_DATA) $(PKG_BUILD_DIR)/dns_bpf.o $(1)/lib/bpf/dns-bpf.o -endef - -$(eval $(call BuildPackage,aw-bpf)) -$(eval $(call KernelPackage,xdpi)) diff --git a/aw-bpf/files/aw-bpf.conf b/aw-bpf/files/aw-bpf.conf deleted file mode 100644 index bb6d50914..000000000 --- a/aw-bpf/files/aw-bpf.conf +++ /dev/null @@ -1,2 +0,0 @@ -config aw-bpf 'common' - option enable_event_log '0' diff --git a/aw-bpf/files/aw-bpf.init b/aw-bpf/files/aw-bpf.init deleted file mode 100644 index 640d272cc..000000000 --- a/aw-bpf/files/aw-bpf.init +++ /dev/null @@ -1,325 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2025-2026 Dengfeng Liu -# aw-bpf service - manages aw-bpf lifecycle: aw-eventd, xdpi module, BPF maps - -START=90 -STOP=10 -USE_PROCD=1 -NAME=aw-bpf -PROG="/usr/bin/aw-eventd" -CONF_FILE="/var/etc/eventd.conf" -BPF_FS_ROOT="/sys/fs/bpf" -AW_BPF_PIN_DIR="$BPF_FS_ROOT/tc/globals" -AW_BPF_LEGACY_PIN_DIR="$BPF_FS_ROOT/xdp/globals" -AW_BPF_MAPS="ipv4_map ipv6_map mac_map tcp_conn_map udp_conn_map xdpi_l7_map session_events_map prog_array_map dns_ringbuf dns_ringbuf_portal dns_stats_map" -AW_BPF_PROGS="tc_ingress tc_egress" -AW_BPF_LAN_IFACES="" -AW_BPF_WAN_IFACES="" - -resolve_lan_ifaces() { - local lan_device lan_ifname - - AW_BPF_LAN_IFACES="" - - config_load network - config_get lan_device lan device - config_get lan_ifname lan ifname - - if [ -n "$lan_device" ] && [ -e "/sys/class/net/$lan_device" ]; then - AW_BPF_LAN_IFACES="$lan_device" - return 0 - fi - - for iface in $lan_ifname; do - if [ -n "$iface" ] && [ -e "/sys/class/net/$iface" ]; then - AW_BPF_LAN_IFACES="$iface" - return 0 - fi - done -} - -resolve_wan_ifaces() { - local wan_device wan_ifname - - AW_BPF_WAN_IFACES="" - - config_load network - config_get wan_device wan device - config_get wan_ifname wan ifname - - if [ -n "$wan_device" ] && [ -e "/sys/class/net/$wan_device" ]; then - AW_BPF_WAN_IFACES="$wan_device" - return 0 - fi - - for iface in $wan_ifname; do - if [ -n "$iface" ] && [ -e "/sys/class/net/$iface" ]; then - AW_BPF_WAN_IFACES="$iface" - return 0 - fi - done -} - -detach_tc_programs() { - local iface="$1" - - [ -z "$iface" ] && return 0 - [ ! -e "/sys/class/net/$iface" ] && return 0 - - tc filter del dev "$iface" ingress 2>/dev/null || true - tc filter del dev "$iface" egress 2>/dev/null || true - tc qdisc del dev "$iface" clsact 2>/dev/null || true -} - -attach_tc_programs() { - local iface="$1" - local aw_bpf_file="/lib/bpf/aw-bpf.o" - - [ -z "$iface" ] && return 0 - [ ! -e "/sys/class/net/$iface" ] && return 0 - [ ! -f "$aw_bpf_file" ] && { - echo "aw-bpf.o not found at $aw_bpf_file" >&2 - return 1 - } - - tc qdisc del dev "$iface" clsact 2>/dev/null || true - tc qdisc add dev "$iface" clsact 2>/dev/null || true - - if ! tc filter add dev "$iface" ingress prio 1 bpf da obj "$aw_bpf_file" sec tc/ingress 2>/tmp/aw-bpf.ingress.err; then - echo "Failed to attach aw-bpf ingress to $iface: $(cat /tmp/aw-bpf.ingress.err 2>/dev/null)" >&2 - rm -f /tmp/aw-bpf.ingress.err - return 1 - fi - rm -f /tmp/aw-bpf.ingress.err - - if ! tc filter add dev "$iface" egress prio 1 bpf da obj "$aw_bpf_file" sec tc/egress 2>/tmp/aw-bpf.egress.err; then - echo "Failed to attach aw-bpf egress to $iface: $(cat /tmp/aw-bpf.egress.err 2>/dev/null)" >&2 - rm -f /tmp/aw-bpf.egress.err - tc filter del dev "$iface" ingress 2>/dev/null || true - tc qdisc del dev "$iface" clsact 2>/dev/null || true - return 1 - fi - rm -f /tmp/aw-bpf.egress.err - - echo "aw-bpf attached on $iface" >&2 - return 0 -} - -cleanup_aw_bpf_pins() { - local entry - - for entry in $AW_BPF_PROGS $AW_BPF_MAPS; do - [ -e "$BPF_FS_ROOT/$entry" ] && rm -f "$BPF_FS_ROOT/$entry" - [ -e "$AW_BPF_PIN_DIR/$entry" ] && rm -f "$AW_BPF_PIN_DIR/$entry" - [ -e "$AW_BPF_LEGACY_PIN_DIR/$entry" ] && rm -f "$AW_BPF_LEGACY_PIN_DIR/$entry" - done -} - -load_bpf_resources() { - echo "Loading BPF resources..." >&2 - mkdir -p "$AW_BPF_PIN_DIR" 2>/dev/null || true - - cleanup_aw_bpf_pins - resolve_lan_ifaces - - if [ -z "$AW_BPF_LAN_IFACES" ]; then - echo "No valid interfaces found from network.lan" >&2 - return 1 - fi - - for iface in $AW_BPF_LAN_IFACES; do - attach_tc_programs "$iface" || return 1 - done - - load_dns_bpf_program - - return 0 -} - -load_xdpi() { - if lsmod | grep -q xdpi; then - echo "xdpi module already loaded" >&2 - return 0 - fi - - if command -v modprobe >/dev/null 2>&1; then - if modprobe xdpi_bpf 2>/dev/null || modprobe xdpi-bpf 2>/dev/null; then - echo "xdpi module loaded via modprobe" >&2 - return 0 - fi - fi - - for modfile in /lib/modules/$(uname -r)/xdpi_bpf.ko /lib/modules/$(uname -r)/xdpi-bpf.ko /lib/modules/$(uname -r)/extra/xdpi_bpf.ko /lib/modules/$(uname -r)/extra/xdpi-bpf.ko /lib/xdpi_bpf.ko /lib/xdpi-bpf.ko; do - if [ -f "$modfile" ]; then - insmod "$modfile" 2>/dev/null && echo "xdpi module loaded via insmod $modfile" >&2 && return 0 || true - fi - done - - echo "Warning: xdpi module not found or failed to load" >&2 - return 1 -} - -load_dns_bpf_program() { - local dns_bpf_file="/lib/bpf/dns-bpf.o" - local xdp_pin_base="/sys/fs/bpf/aw" - - if [ ! -f "$dns_bpf_file" ]; then - echo "dns-bpf.o not found at $dns_bpf_file" >&2 - return 0 - fi - - mkdir -p "$xdp_pin_base" 2>/dev/null || true - - resolve_wan_ifaces - if [ -z "$AW_BPF_WAN_IFACES" ]; then - echo "No valid WAN interfaces found. Skip loading DNS XDP." >&2 - return 1 - fi - - for iface in $AW_BPF_WAN_IFACES; do - echo "Attaching DNS XDP program to $iface..." >&2 - ip link set dev "$iface" xdp off 2>/dev/null || true - if ! ip link set dev "$iface" xdp obj "$dns_bpf_file" sec xdp 2>/tmp/aw-bpf.xdp.err; then - echo "Failed to attach dns xdp to $iface: $(cat /tmp/aw-bpf.xdp.err 2>/dev/null)" >&2 - rm -f /tmp/aw-bpf.xdp.err - return 1 - fi - rm -f /tmp/aw-bpf.xdp.err - done - - sleep 1 - - local xdp_prog_id=$(bpftool prog show name xdp_dns_monitor 2>/dev/null | head -n1 | cut -d':' -f1) - [ ! -e "$xdp_pin_base/dns_ringbuf" ] && bpftool map pin name dns_ringbuf "$xdp_pin_base/dns_ringbuf" 2>/dev/null - if [ ! -e "$xdp_pin_base/dns_ringbuf_portal" ]; then - bpftool map pin name dns_ringbuf_por "$xdp_pin_base/dns_ringbuf_portal" 2>/dev/null || \ - bpftool map pin name dns_ringbuf_portal "$xdp_pin_base/dns_ringbuf_portal" 2>/dev/null - fi - [ ! -e "$xdp_pin_base/dns_stats_map" ] && bpftool map pin name dns_stats_map "$xdp_pin_base/dns_stats_map" 2>/dev/null - - return 0 -} - -cleanup_bpf_resources() { - echo "Cleaning up global BPF resources..." >&2 - - resolve_lan_ifaces - for iface in $AW_BPF_LAN_IFACES; do - detach_tc_programs "$iface" - done - - resolve_wan_ifaces - for iface in $AW_BPF_WAN_IFACES; do - ip link set dev "$iface" xdp off 2>/dev/null || true - done - - rm -rf /sys/fs/bpf/aw/dns_* 2>/dev/null - cleanup_aw_bpf_pins - - return 0 -} - -unload_xdpi() { - if ! lsmod | grep -q xdpi; then - echo "xdpi module not loaded" >&2 - return 0 - fi - - local rmmod_output - rmmod_output=$(rmmod xdpi_bpf 2>&1 || rmmod xdpi-bpf 2>&1) - local rmmod_status=$? - - if [ $rmmod_status -ne 0 ]; then - echo "Note: Failed to unload xdpi module (may still be in use). Error: $rmmod_output" >&2 - return 0 - fi - - if lsmod | grep -q xdpi; then - echo "Note: Module still loaded after rmmod attempt" >&2 - return 0 - fi - - echo "xdpi module unloaded successfully" >&2 - return 0 -} - -generate_conf() { - local enable_event_log - local location_id ap_device_id ap_mac_address ap_longitude ap_latitude - - config_load "aw-bpf" - config_get enable_event_log "common" enable_event_log "0" - config_get location_id "common" location_id "" - config_get ap_device_id "common" ap_device_id "" - config_get ap_mac_address "common" ap_mac_address "" - config_get ap_longitude "common" ap_longitude "" - config_get ap_latitude "common" ap_latitude "" - - # Inherit location/device audit info from wifidogx if not explicitly set in aw-bpf - if [ -f "/etc/config/wifidogx" ]; then - local w_loc w_dev w_mac w_long w_lat - config_load "wifidogx" - config_get w_loc "common" location_id "" - config_get w_dev "common" ap_device_id "" - config_get w_mac "common" ap_mac_address "" - config_get w_long "common" ap_longitude "" - config_get w_lat "common" ap_latitude "" - - [ -z "$location_id" ] && location_id="$w_loc" - [ -z "$ap_device_id" ] && ap_device_id="$w_dev" - [ -z "$ap_mac_address" ] && ap_mac_address="$w_mac" - [ -z "$ap_longitude" ] && ap_longitude="$w_long" - [ -z "$ap_latitude" ] && ap_latitude="$w_lat" - fi - - [ -z "$location_id" ] && location_id="UNKNOWN" - [ -z "$ap_device_id" ] && ap_device_id="UNKNOWN" - [ -z "$ap_mac_address" ] && ap_mac_address="UNKNOWN" - [ -z "$ap_longitude" ] && ap_longitude="0.000000" - [ -z "$ap_latitude" ] && ap_latitude="0.000000" - - mkdir -p /var/etc - cat > "$CONF_FILE" </dev/null 2>&1; then - echo "aw-eventd binary not found" >&2 - return 1 - fi - - generate_conf - - echo "Starting aw-bpf service (aw-eventd)..." >&2 - procd_open_instance - procd_set_param command "$PROG" -c "$CONF_FILE" - procd_set_param respawn 3600 5 0 - procd_set_param file "$CONF_FILE" - procd_close_instance -} - -stop_service() { - echo "Stopping aw-bpf service..." >&2 - cleanup_bpf_resources - unload_xdpi - echo "aw-bpf cleanup completed" >&2 -} - -service_triggers() { - procd_add_reload_trigger "aw-bpf" -} - -reload_service() { - restart -} diff --git a/luci-app-aw-bpf/LICENSE b/luci-app-aw-bpf/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/luci-app-aw-bpf/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/luci-app-aw-bpf/Makefile b/luci-app-aw-bpf/Makefile deleted file mode 100644 index 46dd8062f..000000000 --- a/luci-app-aw-bpf/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# This is free software, licensed under the Apache License, Version 2.0 - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI Support for aw-bpf traffic control -LUCI_DEPENDS:=+aw-bpf +luci-lib-echarts - -PKG_LICENSE:=Apache-2.0 -PKG_MAINTAINER:=Dengfeng Liu - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf.css b/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf.css deleted file mode 100644 index d08a665c6..000000000 --- a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf.css +++ /dev/null @@ -1,570 +0,0 @@ -/* Theme tokens: follow LuCI bootstrap vars, Argon, or JS-set data-aw-theme */ -.l7-view-container, -.display-view-container { - --aw-card-bg: var(--background-color-medium, var(--background-color, #f9f9f9)); - --aw-card-border: var(--border-color-medium, #e0e0e0); - --aw-chart-bg: var(--background-color-high, #ffffff); - --aw-text: var(--text-color-highest, var(--text-color-high, #333333)); - --aw-text-muted: var(--text-color-medium, #666666); - --aw-accent: var(--primary-color-high, var(--primary, #3771c8)); - --aw-hover: var(--background-color-low, #f0f0f0); - --aw-error-bg: #ffefef; - --aw-error-fg: #c62828; - --aw-dl: #28a745; - --aw-ul: #007bff; - --aw-vol-dl: #17a2b8; - --aw-vol-ul: #6610f2; - --aw-pkt: #6c757d; -} - -@media (prefers-color-scheme: dark) { - .l7-view-container:not([data-aw-theme="light"]), - .display-view-container:not([data-aw-theme="light"]) { - --aw-card-bg: #2a2a2a; - --aw-card-border: #3c3c3c; - --aw-chart-bg: #252526; - --aw-text: #cccccc; - --aw-text-muted: #adb5bd; - --aw-accent: #a5b2ff; - --aw-hover: #333333; - --aw-error-bg: #3a1f1f; - --aw-error-fg: #ff8a80; - --aw-dl: #5dd879; - --aw-ul: #6eb6ff; - --aw-vol-dl: #4ecbd8; - --aw-vol-ul: #b794f6; - --aw-pkt: #adb5bd; - } -} - -[data-darkmode="true"] .l7-view-container, -[data-darkmode="true"] .display-view-container, -.l7-view-container[data-aw-theme="dark"], -.display-view-container[data-aw-theme="dark"] { - --aw-card-bg: #2a2a2a; - --aw-card-border: #3c3c3c; - --aw-chart-bg: #252526; - --aw-text: #cccccc; - --aw-text-muted: #adb5bd; - --aw-accent: #a5b2ff; - --aw-hover: #333333; - --aw-error-bg: #3a1f1f; - --aw-error-fg: #ff8a80; - --aw-dl: #5dd879; - --aw-ul: #6eb6ff; - --aw-vol-dl: #4ecbd8; - --aw-vol-ul: #b794f6; - --aw-pkt: #adb5bd; -} - -[data-darkmode="false"] .l7-view-container, -[data-darkmode="false"] .display-view-container, -.l7-view-container[data-aw-theme="light"], -.display-view-container[data-aw-theme="light"] { - --aw-card-bg: #f9f9f9; - --aw-card-border: #e0e0e0; - --aw-chart-bg: #ffffff; - --aw-text: #333333; - --aw-text-muted: #666666; - --aw-accent: #3771c8; - --aw-hover: #f0f0f0; - --aw-error-bg: #ffefef; - --aw-error-fg: #c62828; - --aw-dl: #28a745; - --aw-ul: #007bff; - --aw-vol-dl: #17a2b8; - --aw-vol-ul: #6610f2; - --aw-pkt: #6c757d; -} - -.aw-inner-tabs { - margin-top: 4px; -} - -.aw-inner-tabs > .cbi-tabmenu { - margin-bottom: 12px; -} - -.pie label { - font-weight: bold; - font-size: 14px; - display: block; - margin-bottom: 10px; - text-align: center; -} - -.kpi ul { - list-style: none; -} - -.kpi li { - margin: 10px; - display: none; -} - -.kpi big { - font-weight: bold; -} - -.head { - text-align: center; - position: relative; - display: flex; - flex-wrap: wrap; - white-space: normal; -} - -.head .pie { - /* min-width: 200px; */ - padding: 5px; - flex: 1 1 30%; -} - -.cbi-tooltip .head .pie { - min-width: 100px; -} - -.head .kpi { - padding: 5px; - font-size: smaller; - text-align: left; - align-self: center; - flex: 1 0 33%; - min-width: 150px; - display: flex; - justify-content: center; -} - -.head .kpi ul { - margin: 0; -} - -.td.double > span { - display: block; -} - -.cbi-tooltip { - box-shadow: 0 0 5px #000; -} - -@media screen and (max-width: 992px) { - .td.hide-xs { - display: none; - } - - .td.double:not(.hide-xs) > span { - white-space: nowrap; - text-align: left; - } - - .td.double:not(.hide-xs) > span:first-child::before { - content: "IPv4: "; - font-weight: bold; - } - - .td.double:not(.hide-xs) > span:last-child::before { - content: "IPv6: "; - font-weight: bold; - } -} - -.form-group { - display: flex; - align-items: center; /* 垂直居中 */ - margin-bottom: 15px; /* 项间距 */ - gap: 10px; /* Label 和 Input 间距 */ -} - -/* 标签固定最小宽度 + 右对齐 */ -.form-label { - flex: 0 0 120px; /* 不伸缩、不收缩、基础宽度120px */ - text-align: right; - font-weight: bold; - color: var(--aw-text, #333); -} - -.th-sort-asc::after { - content: " ▲"; -} - -.th-sort-desc::after { - content: " ▼"; -} - -.table .th { - cursor: pointer; -} - -.table .th:hover { - background-color: var(--aw-hover, #f0f0f0); -} - -/* L7 View Specific Styles */ -.l7-view-container #l7-error-message { color: var(--aw-error-fg, red); background-color: var(--aw-error-bg, #ffefef); border: 1px solid var(--aw-error-fg, red); padding: 10px; margin-bottom: 10px; display: none; } -.l7-view-container .dashboard-container { display: flex; flex-direction: column; gap: 20px; margin-bottom: 20px; } -.l7-view-container .line-chart-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 20px; } -.l7-view-container .kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; } -.l7-view-container .kpi-card { background-color: var(--aw-card-bg, #f9f9f9); border-radius: 8px; padding: 15px; text-align: center; border: 1px solid var(--aw-card-border, #e0e0e0); } -.l7-view-container .kpi-card big { display: block; font-size: 1.8em; font-weight: bold; color: var(--aw-accent, #3771c8); } -.l7-view-container .kpi-card-label { font-size: 0.9em; color: var(--aw-text-muted, #666); } -.l7-view-container .chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; } -.l7-view-container .chart-card { background-color: var(--aw-chart-bg, #ffffff); border-radius: 8px; padding: 20px; border: 1px solid var(--aw-card-border, #e0e0e0); } -.l7-view-container .chart-card h4 { margin-top: 0; margin-bottom: 15px; text-align: center; font-size: 1.1em; color: var(--aw-text, inherit); } -.l7-view-container .l7-controls { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 20px; - padding: 15px 20px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 8px; - box-shadow: 0 4px 6px rgba(0,0,0,0.1); - color: white; -} -.l7-view-container .l7-controls-left, .l7-view-container .l7-controls-right { - display: flex; - align-items: center; - gap: 15px; -} - -/* Display View Specific Styles */ -.display-view-container .dashboard-container { display: flex; flex-direction: column; gap: 20px; margin-bottom: 20px; } -.display-view-container .kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; } -.display-view-container .kpi-card { background-color: var(--aw-card-bg, #f9f9f9); border-radius: 8px; padding: 15px; text-align: center; border: 1px solid var(--aw-card-border, #e0e0e0); } -.display-view-container .kpi-card big { display: block; font-size: 1.8em; font-weight: bold; color: var(--aw-accent, #3771c8); } -.display-view-container .kpi-card-label { font-size: 0.9em; color: var(--aw-text-muted, #666); } -.display-view-container .chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; } -.display-view-container .chart-card { background-color: var(--aw-chart-bg, #ffffff); border-radius: 8px; padding: 20px; border: 1px solid var(--aw-card-border, #e0e0e0); } -.display-view-container .chart-card h4 { margin-top: 0; margin-bottom: 15px; text-align: center; font-size: 1.1em; color: var(--aw-text, inherit); } -.display-view-container .display-controls { - display: flex; - justify-content: space-between; - align-items: center; - padding: 15px 20px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 8px; - box-shadow: 0 4px 6px rgba(0,0,0,0.1); - margin-top: 20px; -} - -/* Control Groups */ -.control-group { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 12px; - background-color: rgba(255, 255, 255, 0.15); - border-radius: 6px; - backdrop-filter: blur(10px); -} - -.control-icon { - font-size: 1.2em; - display: inline-block; -} - -.control-label { - font-weight: 500; - color: white; - margin: 0; - white-space: nowrap; -} - -.control-input { - border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.3); - background-color: rgba(255, 255, 255, 0.9); - padding: 6px 12px; - transition: all 0.3s ease; -} - -.control-input:focus { - background-color: white; - border-color: #667eea; - box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2); - outline: none; -} - -.control-buttons { - display: flex; - align-items: center; - gap: 10px; -} - -.status-group { - background-color: rgba(255, 255, 255, 0.2); -} - -.last-updated-text { - color: rgba(255, 255, 255, 0.95); - font-size: 0.9em; - font-weight: 500; -} - -/* Enhanced Select Styling */ -.cbi-input-select { - padding: 6px 30px 6px 12px; - border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.3); - background-color: rgba(255, 255, 255, 0.9); - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23667eea' d='M6 9L1 4h10z'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: right 8px center; - background-size: 12px; - appearance: none; - cursor: pointer; - transition: all 0.3s ease; - font-weight: 500; -} - -.cbi-input-select:hover { - background-color: white; - border-color: #667eea; -} - -.cbi-input-select:focus { - background-color: white; - border-color: #667eea; - box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2); - outline: none; -} - -/* Button Enhancements for Controls */ -.l7-controls .cbi-button, -.display-controls .cbi-button { - padding: 8px 16px; - border-radius: 6px; - font-weight: 500; - transition: all 0.3s ease; - border: 2px solid transparent; -} - -.cbi-button-action { - background: rgba(255, 193, 7, 0.9); - color: #333; - border-color: rgba(255, 193, 7, 0.3); -} - -.cbi-button-action:hover { - background: #ffc107; - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(255, 193, 7, 0.4); -} - -.cbi-button-positive { - background: rgba(40, 167, 69, 0.9); - color: white; - border-color: rgba(40, 167, 69, 0.3); -} - -.cbi-button-positive:hover { - background: #28a745; - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(40, 167, 69, 0.4); -} - -/* Responsive Controls */ -@media screen and (max-width: 768px) { - .l7-controls, - .display-controls { - flex-direction: column; - gap: 15px; - } - - .l7-controls-left, - .l7-controls-right, - .control-buttons { - width: 100%; - justify-content: center; - } - - .control-group { - justify-content: center; - } -} - -/* Table Cell Icon Styles */ -.activity-indicator { - font-size: 12px; - display: inline-block; - margin-right: 2px; -} - -.icon, .btn-icon, .th-icon { - display: inline-block; - font-style: normal; - margin-right: 4px; -} - -.th-icon { - opacity: 0.7; -} - -/* Cell Specific Styles */ -.sid-cell, .id-cell, .host-cell, .hostname-cell, .protocol-cell { - display: inline-flex; - align-items: center; - gap: 4px; -} - -.speed-cell { - display: inline-flex; - align-items: center; - justify-content: flex-end; - gap: 4px; - font-weight: 500; - min-width: 100px; -} - -.speed-cell.download { - color: var(--aw-dl, #28a745); -} - -.speed-cell.upload { - color: var(--aw-ul, #007bff); -} - -.volume-cell { - display: inline-flex; - align-items: center; - justify-content: flex-end; - gap: 4px; - min-width: 90px; -} - -.volume-cell.download { - color: var(--aw-vol-dl, #17a2b8); -} - -.volume-cell.upload { - color: var(--aw-vol-ul, #6610f2); -} - -.packet-cell { - display: inline-flex; - align-items: center; - justify-content: flex-end; - gap: 4px; - color: var(--aw-pkt, #6c757d); - min-width: 80px; -} - -/* Data value with monospace font for better alignment */ -.data-value { - font-family: 'Courier New', Consolas, monospace; - font-size: 0.95em; - letter-spacing: 0.5px; -} - -/* Table header enhancements */ -.table .th { - font-weight: 600; - padding: 10px 8px; - white-space: nowrap; -} - -.table .td { - padding: 8px; - vertical-align: middle; -} - -.protocol-icon.l7::before { - content: ''; - display: inline-block; - width: 8px; - height: 8px; - border-radius: 50%; - background-color: #5470c6; - margin-right: 4px; -} - -.protocol-icon.domain::before { - content: ''; - display: inline-block; - width: 8px; - height: 8px; - border-radius: 50%; - background-color: #91cc75; - margin-right: 4px; -} - -/* Button Enhancements */ -.cbi-button { - display: inline-flex; - align-items: center; - gap: 4px; - transition: all 0.2s ease; -} - -.cbi-button:hover { - transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0,0,0,0.1); -} - -.cbi-button-edit { - background-color: #ffc107; - border-color: #ffc107; -} - -.cbi-button-edit:hover { - background-color: #e0a800; - border-color: #e0a800; -} - -.cbi-button-remove { - background-color: #dc3545; - border-color: #dc3545; - color: white; -} - -.cbi-button-remove:hover { - background-color: #c82333; - border-color: #bd2130; -} - -.cbi-button-add { - background-color: #28a745; - border-color: #28a745; - color: white; -} - -.cbi-button-add:hover:not(:disabled) { - background-color: #218838; - border-color: #1e7e34; -} - -.cbi-button-add:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -/* Table Row Hover Effects */ -.table .tr:not(.table-titles):not(.placeholder):hover { - background-color: var(--aw-hover, #f8f9fa); - transition: background-color 0.2s ease; -} - -/* Active/Inactive Status Styles */ -.activity-indicator[title*="Active"] { - animation: pulse 2s ease-in-out infinite; -} - -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -/* Responsive Icon Handling */ -@media screen and (max-width: 768px) { - .icon, .btn-icon { - margin-right: 2px; - } - - .btn-icon + span { - display: none; - } - - .th-icon { - margin-right: 0; - } -} diff --git a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/display.js b/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/display.js deleted file mode 100644 index 82adaf4e9..000000000 --- a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/display.js +++ /dev/null @@ -1,787 +0,0 @@ -'use strict'; -'require view'; -'require fs'; -'require ui'; -'require poll'; -'require rpc'; -'require dom'; -'require uci'; - -// Global variables from original display.js -var chartRegistry = {}; -var hostNames = {}; // mac => hostname -var hostInfo = {}; // ip => mac -var hostNameMacSectionId = ""; -var isPaused = false; -var lastUpdated = null; - -// Line chart variables (from l7.js) -var downloadLineChart = {}, uploadLineChart = {}; -var lineCategories = { ipv4: [], ipv6: [], mac: [] }; -var downloadSeriesData = { ipv4: {}, ipv6: {}, mac: {} }; -var uploadSeriesData = { ipv4: {}, ipv6: {}, mac: {} }; - -// Color palette for chart series -var colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']; - -var resizeListenerAdded = false; - -// Pre-fill with 60 empty points for a smooth start -['ipv4', 'ipv6', 'mac'].forEach(function(type) { - for (var i = 0; i < 60; i++) { - lineCategories[type].push(''); - } -}); - -// Helper to convert hex to rgba (from l7.js) -function hexToRgba(hex, opacity) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? - 'rgba(' + parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) + ', ' + opacity + ')' : - null; -}; - -function isDarkMode() { - var attr = document.documentElement.getAttribute('data-darkmode'); - if (attr === 'true') - return true; - if (attr === 'false') - return false; - - var bg = getComputedStyle(document.body).backgroundColor; - var m = bg && bg.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); - if (m) { - var lum = (0.299 * m[1] + 0.587 * m[2] + 0.114 * m[3]) / 255; - return lum < 0.5; - } - - return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; -} - -function getChartColors() { - var dark = isDarkMode(); - return { - background: 'transparent', - text: dark ? '#cccccc' : '#333333', - muted: dark ? '#adb5bd' : '#666666', - axis: dark ? 'rgba(255,255,255,0.28)' : 'rgba(0,0,0,0.25)', - split: dark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)', - pieBorder: dark ? '#252526' : '#ffffff', - tooltipBg: dark ? 'rgba(32,32,32,0.94)' : 'rgba(255,255,255,0.95)', - tooltipBorder: dark ? '#555555' : '#cccccc', - tooltipText: dark ? '#eeeeee' : '#333333' - }; -} - -function applyViewTheme() { - var theme = isDarkMode() ? 'dark' : 'light'; - document.querySelectorAll('.l7-view-container, .display-view-container').forEach(function(el) { - el.setAttribute('data-aw-theme', theme); - }); - return theme; -} - -function observeChartEl(chart, el) { - if (!chart || !el || !window.ResizeObserver || el._awRo) - return; - el._awRo = new ResizeObserver(function() { - chart.resize(); - }); - el._awRo.observe(el); -} - -function chartAxisTheme(colors) { - return { - backgroundColor: colors.background, - textStyle: { color: colors.text }, - legend: { textStyle: { color: colors.text } }, - tooltip: { - backgroundColor: colors.tooltipBg, - borderColor: colors.tooltipBorder, - textStyle: { color: colors.tooltipText } - }, - xAxis: { - axisLine: { lineStyle: { color: colors.axis } }, - axisLabel: { color: colors.muted }, - splitLine: { show: false } - }, - yAxis: { - axisLine: { lineStyle: { color: colors.axis } }, - axisLabel: { color: colors.muted }, - splitLine: { lineStyle: { color: colors.split } } - } - }; -} - -return view.extend({ - // --- Core Data Logic from display.js --- - - loadHostNames: async function() { - try { - await uci.sections('hostnames', "hostname", function (params) { - hostNameMacSectionId = params['.name']; - for (var key in params) { - if (key.startsWith('.')) continue; - var macAddr = key.split('_').join(':'); - hostNames[macAddr] = params[key]; - } - }); - - const dhcpLeases = await fs.exec_direct('/usr/bin/awk', ['-F', ' ', '{print $2, $3, $4}', '/tmp/dhcp.leases'], 'text'); - dhcpLeases.split('\n').forEach(function(line) { - if (line === '') return; - const [mac, ip, hostname] = line.split(' '); - if (!hostNames.hasOwnProperty(mac)) { - hostNames[mac] = hostname; - } - }); - - const arp = await fs.exec_direct('/usr/bin/awk', ['-F', ' ', '{print $1, $4}', '/proc/net/arp'], 'text'); - arp.split('\n').forEach(function(line, i) { - if (i === 0 || line === '') return; - const [ip, mac] = line.split(' '); - hostInfo[ip] = mac; - }); - - } catch (e) { - console.error('Error getting host names:', e); - } - }, - - loadHostSpeedData: async function() { - var self = this; - try { - const results = await Promise.all([ - fs.exec_direct('/usr/bin/aw-bpfctl', ['ipv4', 'json'], 'json'), - fs.exec_direct('/usr/bin/aw-bpfctl', ['ipv6', 'json'], 'json'), - fs.exec_direct('/usr/bin/aw-bpfctl', ['mac', 'json'], 'json') - ]); - - const defaultData = {status: "success", data: []}; - const ipv4Data = results[0] || defaultData; - const ipv6Data = results[1] || defaultData; - const macData = results[2] || defaultData; - - ipv4Data.data.forEach(function(item) { - const mac = hostInfo[item.ip]; - if (mac) { - item.mac = mac; - item.hostname = hostNames[mac]; - } - }); - macData.data.forEach(function(item) { - const mac = item.mac; - if (mac) { - item.hostname = hostNames[mac]; - } - }); - - self.renderHostSpeed(ipv4Data, "ipv4"); - self.renderHostSpeed(ipv6Data, "ipv6"); - self.renderHostSpeed(macData, "mac"); - - lastUpdated = new Date(); - var timestampEl = document.getElementById('display-last-updated'); - if (timestampEl) { - timestampEl.textContent = _('Last updated: %s').format(lastUpdated.toLocaleTimeString()); - } - - } catch (e) { - console.error('Error polling data:', e); - } - }, - - pollData: function() { - poll.add(L.bind(async function() { - if (isPaused) return; - await this.loadHostNames(); - await this.loadHostSpeedData(); - }, this), 5); - }, - - resizeAllCharts: function() { - ['ipv4', 'ipv6', 'mac'].forEach(function(type) { - if (downloadLineChart[type]) - downloadLineChart[type].resize(); - if (uploadLineChart[type]) - uploadLineChart[type].resize(); - }); - Object.keys(chartRegistry).forEach(function(chartId) { - if (chartRegistry[chartId]) - chartRegistry[chartId].resize(); - }); - }, - - bindTabChartResize: function(root) { - var self = this; - if (!root) - return; - var host = root.parentNode || root; - if (host._awTabResizeBound) - return; - host._awTabResizeBound = true; - - var schedule = function() { - setTimeout(function() { self.resizeAllCharts(); }, 80); - }; - - host.addEventListener('click', function(ev) { - if (ev.target.closest && ev.target.closest('ul.cbi-tabmenu')) - schedule(); - }); - root.querySelectorAll('[data-tab]').forEach(function(pane) { - pane.addEventListener('cbi-tab-active', schedule); - }); - }, - - // --- UI Rendering and Interaction (New structure based on l7.js) --- - - pie: function(id, data, valueFormatter) { - var total = data.reduce(function(n, d) { return n + d.value; }, 0); - data.sort(function(a, b) { return b.value - a.value; }); - - if (total === 0) { - data = [{ value: 1, color: '#cccccc', name: _('no traffic') }]; - } - - data.forEach(function(d, i) { - if (!d.color) { - var hue = (i * 137.508) % 360; - d.color = 'hsl(' + hue + ', 75%, 55%)'; - } - }); - - var colors = getChartColors(); - var option = { - backgroundColor: colors.background, - textStyle: { color: colors.text }, - tooltip: { - trigger: 'item', - backgroundColor: colors.tooltipBg, - borderColor: colors.tooltipBorder, - textStyle: { color: colors.tooltipText }, - formatter: function(params) { - if (valueFormatter) { - // 将 ECharts params 对象转换为自定义格式 - return valueFormatter({ - name: params.name, - value: params.value, - percent: params.percent.toFixed(2) - }); - } - return params.name + ': ' + params.value + ' (' + params.percent.toFixed(2) + '%)'; - } - }, - series: [{ - type: 'pie', - radius: ['25%', '80%'], - avoidLabelOverlap: false, - padAngle: 10, - itemStyle: { borderRadius: 10, borderColor: colors.pieBorder, borderWidth: 2 }, - label: { show: false, position: 'center', color: colors.text }, - emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold', color: colors.text } }, - labelLine: { show: false }, - data: data.map(function(d) { - return { value: d.value, name: d.label || d.name, itemStyle: { color: d.color } }; - }) - }] - }; - - var dom = typeof id === 'string' ? document.getElementById(id) : id; - if (!chartRegistry[id]) { - chartRegistry[id] = echarts.init(dom); - observeChartEl(chartRegistry[id], dom); - } - chartRegistry[id].setOption(option, true); - return chartRegistry[id]; - }, - - updateStackedLineCharts: function(type, perHostDownload, perHostUpload) { - var now = new Date().toLocaleTimeString(); - lineCategories[type].push(now); - lineCategories[type].shift(); - - var processChartData = function(seriesData, perHostData) { - var allHosts = Object.keys(seriesData); - Object.keys(perHostData).forEach(function(host) { - if (allHosts.indexOf(host) === -1) { - allHosts.push(host); - } - }); - - allHosts.forEach(function(host) { - if (!seriesData[host]) { - seriesData[host] = Array(59).fill(0); - } - var rate = perHostData[host] || 0; - seriesData[host].push(rate); - seriesData[host].shift(); - }); - - return Object.keys(seriesData).map(function(host, index) { - var color = colorPalette[index % colorPalette.length]; - return { - name: host, - type: 'line', - stack: 'Total', - smooth: true, - lineStyle: { width: 1, color: color }, - showSymbol: false, - itemStyle: { color: color }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: hexToRgba(color, 0.5) }, - { offset: 1, color: hexToRgba(color, 0) } - ]) - }, - data: seriesData[host] - }; - }); - }; - - var downloadChartSeries = processChartData(downloadSeriesData[type], perHostDownload); - var uploadChartSeries = processChartData(uploadSeriesData[type], perHostUpload); - - var legendData = downloadChartSeries.map(function(s) { return s.name; }); - - var colors = getChartColors(); - if (downloadLineChart[type]) { - downloadLineChart[type].setOption({ - legend: { data: legendData, type: 'scroll', top: 0, left: 'center', textStyle: { color: colors.text } }, - series: downloadChartSeries, - xAxis: { data: lineCategories[type] } - }); - } - - if (uploadLineChart[type]) { - uploadLineChart[type].setOption({ - legend: { data: legendData, type: 'scroll', top: 0, left: 'center', textStyle: { color: colors.text } }, - series: uploadChartSeries, - xAxis: { data: lineCategories[type] } - }); - } - }, - - renderHostSpeed: function(data, type) { - if (!data || data.status !== "success" || !Array.isArray(data.data)) return; - - var rows = []; - var txRateData = [], rxRateData = []; - var txVolumeData = [], rxVolumeData = []; - var tx_rate_total = 0, rx_rate_total = 0; - var tx_bytes_total = 0, rx_bytes_total = 0; - var perHostTxRate = {}; - var perHostRxRate = {}; - - data.data.forEach(item => { - if (!item || !item.incoming || !item.outgoing) return; - - var host = item.ip || item.mac || ''; - var hostname = item.hostname || hostNames[item.mac] || ''; - var displayName = hostname || host; - - // 判断连接是否活跃 - var isActive = item.incoming.rate > 0 || item.outgoing.rate > 0; - var activityIcon = isActive ? '🟢' : '⚪'; - - rows.push([ - E('span', { 'class': 'host-cell' }, [ - E('span', { 'class': 'activity-indicator', 'title': isActive ? _('Active') : _('Inactive') }, activityIcon), - E('span', {}, ' ' + host) - ]), - E('span', { 'class': 'hostname-cell' }, [ - E('span', { 'class': 'icon' }, hostname ? '👤' : '❓'), - E('span', {}, ' ' + (hostname || _('Unknown'))) - ]), - E('span', { 'class': 'speed-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mBps'.format(item.incoming.rate)) - ]), - E('span', { 'class': 'volume-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mB'.format(item.incoming.total_bytes)) - ]), - E('span', { 'class': 'packet-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1000.2mP'.format(item.incoming.total_packets)) - ]), - E('span', { 'class': 'speed-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mBps'.format(item.outgoing.rate)) - ]), - E('span', { 'class': 'volume-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mB'.format(item.outgoing.total_bytes)) - ]), - E('span', { 'class': 'packet-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1000.2mP'.format(item.outgoing.total_packets)) - ]), - E('div', { 'class': 'button-container' }, [ - E('button', { - 'class': 'btn cbi-button cbi-button-edit', - 'style': 'margin-right: 5px;', - 'click': ui.createHandlerFn(this, () => this.handleEditSpeed(host, item.mac, hostname, type)) - }, [ - E('span', { 'class': 'btn-icon' }, '✏️'), - E('span', {}, ' ' + _('Edit')) - ]), - E('button', { - 'class': 'btn cbi-button cbi-button-remove', - 'click': ui.createHandlerFn(this, () => this.handleDeleteHost(host, type)) - }, [ - E('span', { 'class': 'btn-icon' }, '🗑️'), - E('span', {}, ' ' + _('Delete')) - ]) - ]) - ]); - rx_rate_total += item.outgoing.rate; - tx_rate_total += item.incoming.rate; - rx_bytes_total += item.outgoing.total_bytes; - tx_bytes_total += item.incoming.total_bytes; - - rxRateData.push({ value: item.outgoing.rate, label: displayName }); - txRateData.push({ value: item.incoming.rate, label: displayName }); - rxVolumeData.push({ value: item.outgoing.total_bytes, label: displayName }); - txVolumeData.push({ value: item.incoming.total_bytes, label: displayName }); - - perHostTxRate[displayName] = (perHostTxRate[displayName] || 0) + item.incoming.rate; - perHostRxRate[displayName] = (perHostRxRate[displayName] || 0) + item.outgoing.rate; - }); - - this.updateStackedLineCharts(type, perHostTxRate, perHostRxRate); - - var table = document.getElementById(type + '-speed-data'); - cbi_update_table(table, rows, E('em', _('No data recorded yet.'))); - - this.pie(type + '-tx-rate-pie', txRateData, (p) => `${p.name}: ${'%1024.2mBps'.format(p.value)} (${p.percent}%)`); - this.pie(type + '-rx-rate-pie', rxRateData, (p) => `${p.name}: ${'%1024.2mBps'.format(p.value)} (${p.percent}%)`); - this.pie(type + '-tx-volume-pie', txVolumeData, (p) => `${p.name}: ${'%1024.2mB'.format(p.value)} (${p.percent}%)`); - this.pie(type + '-rx-volume-pie', rxVolumeData, (p) => `${p.name}: ${'%1024.2mB'.format(p.value)} (${p.percent}%)`); - - var hostEl = document.getElementById(type + '-host-val'); - if (hostEl) hostEl.textContent = data.data.length; - - var txRateEl = document.getElementById(type + '-tx-rate-val'); - if (txRateEl) txRateEl.textContent = '%1024.2mBps'.format(tx_rate_total); - - var rxRateEl = document.getElementById(type + '-rx-rate-val'); - if (rxRateEl) rxRateEl.textContent = '%1024.2mBps'.format(rx_rate_total); - - var txVolEl = document.getElementById(type + '-tx-volume-val'); - if (txVolEl) txVolEl.textContent = '%1024.2mB'.format(tx_bytes_total); - - var rxVolEl = document.getElementById(type + '-rx-volume-val'); - if (rxVolEl) rxVolEl.textContent = '%1024.2mB'.format(rx_bytes_total); - }, - - // --- Interaction Handlers from display.js --- - - handleDeleteHost: function(host, type) { - ui.showModal(_('Delete Host'), [ - E('p', _('Are you sure you want to delete this host?')), - E('div', { 'class': 'right' }, [ - E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Cancel')), - E('button', { 'class': 'btn cbi-button-negative', 'click': ui.createHandlerFn(this, async () => { - try { - await fs.exec_direct('/usr/bin/aw-bpfctl', [type, 'del', host], 'text'); - this.loadHostSpeedData(); - ui.hideModal(); - } catch (e) { - ui.addNotification(null, E('p', _('Error: ') + e.message)); - ui.hideModal(); - } - })}, _('Delete')) - ]) - ]); - }, - - handleEditSpeed: function(host, mac, hostname, type) { - fs.exec_direct('/usr/bin/aw-bpfctl', [type, 'json'], 'json').then(L.bind(res => { - let rate_limit_dl = 0, rate_limit_ul = 0; - if (res && res.status === 'success' && Array.isArray(res.data)) { - const item = res.data.find(d => (d.ip === host || d.mac === host)); - if (item) { - rate_limit_dl = (item.incoming.incoming_rate_limit || 0) / 1024 / 1024; - rate_limit_ul = (item.outgoing.outgoing_rate_limit || 0) / 1024 / 1024; - } - } - this.displaySpeedLimitDialog(host, mac, hostname, type, rate_limit_dl, rate_limit_ul); - }, this)).catch(e => { - console.error('Error getting speed limit:', e); - this.displaySpeedLimitDialog(host, mac, hostname, type, 0, 0); - }); - }, - - displaySpeedLimitDialog: function(host, mac, hostname, type, dl, ul) { - const inputDom = E('input', { type: 'text', id: 'host-name', class: 'cbi-input-text', value: hostname, disabled: !mac }); - - ui.showModal(_('Edit Speed Limit'), [ - E('div', { 'class': 'form-group' }, [ E('label', { 'class': 'form-label' }, _('Host')), E('span',{}, host) ]), - E('div', { 'class': 'form-group' }, [ E('label', { 'class': 'form-label' }, _('Hostname')), inputDom ]), - E('div', { 'class': 'form-group' }, [ - E('label', { 'class': 'form-label' }, _('Download Limit')), - E('input', { type: 'number', id: 'dl-rate', class: 'cbi-input-number', min: '0', value: dl }), - E('span',{}, " Mbps") - ]), - E('div', { 'class': 'form-group' }, [ - E('label', { 'class': 'form-label' }, _('Upload Limit')), - E('input', { type: 'number', id: 'ul-rate', class: 'cbi-input-number', min: '0', value: ul }), - E('span',{}, " Mbps") - ]), - E('div', { 'class': 'cbi-page-actions right' }, [ - E('button', { 'class': 'btn cbi-button cbi-button-neutral', 'click': ui.hideModal }, _('Cancel')), - E('button', { 'class': 'btn cbi-button cbi-button-positive', 'click': ui.createHandlerFn(this, async ev => { - const dl_val = document.getElementById('dl-rate').value; - const ul_val = document.getElementById('ul-rate').value; - const newName = document.getElementById('host-name').value; - try { - if (mac && newName !== hostname) { - hostNames[mac] = newName; - await uci.set('hostnames', hostNameMacSectionId, mac.split(':').join('_'), newName); - await uci.save('hostnames'); - await uci.apply('hostnames'); - } - await fs.exec_direct('/usr/bin/aw-bpfctl', [type, 'update', host, "downrate", dl_val*1024*1024 || '0', "uprate", ul_val*1024*1024 || '0']); - this.loadHostSpeedData(); - ui.addNotification(null, E('p',_('Speed limit updated'))); - ui.hideModal(); - } catch (e) { - ui.addNotification(null, E('p', _('Error: ') + e.message)); - } - })}, _('Save')) - ]) - ]); - }, - - validateData: function(value, type) { - if (typeof value !== 'string') return false; - const ipv4Regex = /^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/; - const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^(([0-9a-fA-F]{1,4}:){0,6}::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$/i; - const macRegex = /^([0-9A-Fa-f]{2}([-:]))([0-9A-Fa-f]{2}\2){4}[0-9A-Fa-f]{2}$|^([0-9A-Fa-f]{12})$/i; - return (type === 'ipv4') ? ipv4Regex.test(value) : (type === 'ipv6') ? ipv6Regex.test(value) : macRegex.test(value); - }, - - createAddControls: function(type, placeholder) { - const input = E('input', { - type: 'text', - class: 'cbi-input-text control-input', - style: (type === 'ipv6') ? 'width:320px' : 'width:180px', - placeholder: _(placeholder) - }); - const addBtn = E('button', { - class: 'btn cbi-button cbi-button-add', - disabled: true - }, [ - E('span', { 'class': 'btn-icon' }, '➕'), - E('span', {}, ' ' + _('Add')) - ]); - const refreshBtn = E('button', { - class: 'btn cbi-button cbi-button-action', - click: () => this.loadHostSpeedData() - }, [ - E('span', { 'class': 'btn-icon' }, '🔄'), - E('span', {}, ' ' + _('Refresh')) - ]); - - input.addEventListener('input', () => { addBtn.disabled = (input.value.trim() === ''); }); - addBtn.addEventListener('click', ui.createHandlerFn(this, async () => { - const value = input.value.trim(); - if (!this.validateData(value, type)) { - return ui.addNotification(null, E('p', _('Data format error'))); - } - try { - await fs.exec_direct('/usr/bin/aw-bpfctl', [type, 'add', value]); - this.loadHostSpeedData(); - ui.addNotification(null, E('p',_('Updated successfully!'))); - input.value = ''; - addBtn.disabled = true; - } catch (e) { - ui.addNotification(null, E('p', _('Error: ') + e.message)); - } - })); - - return E('div', { 'class': 'display-controls' }, [ - E('div', { 'class': 'control-group' }, [ - E('span', { 'class': 'control-icon' }, '🖥️'), - E('label', { 'class': 'control-label' }, _('Add Host:')), - input - ]), - E('div', { 'class': 'control-buttons' }, [ - addBtn, - refreshBtn, - E('div', { 'class': 'control-group status-group' }, [ - E('span', { 'class': 'control-icon' }, '🕐'), - E('span', { 'id': 'display-last-updated', 'class': 'last-updated-text' }, _('Ready')) - ]) - ]) - ]); - }, - - initializeUI: function() { - applyViewTheme(); - if (window.echarts) { - var self = this; - var colors = getChartColors(); - var axisTheme = chartAxisTheme(colors); - ['ipv4', 'ipv6', 'mac'].forEach(function(type) { - var dlChartEl = document.getElementById(type + '-download-speed-line-chart'); - var ulChartEl = document.getElementById(type + '-upload-speed-line-chart'); - if (!dlChartEl || !ulChartEl) return; - - var baseChartOption = { - backgroundColor: axisTheme.backgroundColor, - textStyle: axisTheme.textStyle, - legend: axisTheme.legend, - tooltip: Object.assign({ - trigger: 'axis', - formatter: function (params) { - if (!params || params.length === 0) { - return null; - } - var tooltipContent = params[0].axisValueLabel + '
'; - params.sort(function(a, b) { return b.value - a.value; }); - params.forEach(function(item) { - if (item.value > 0) { - tooltipContent += item.marker + ' ' + item.seriesName + ': ' + '%1024.2mBps'.format(item.value) + '
'; - } - }); - return tooltipContent; - } - }, axisTheme.tooltip), - grid: { left: '3%', right: '4%', bottom: '10%', top: '50px', containLabel: true }, - xAxis: { - type: 'category', - boundaryGap: false, - data: lineCategories[type], - axisLine: axisTheme.xAxis.axisLine, - axisLabel: axisTheme.xAxis.axisLabel, - splitLine: axisTheme.xAxis.splitLine - }, - yAxis: { - type: 'value', - axisLine: axisTheme.yAxis.axisLine, - splitLine: axisTheme.yAxis.splitLine, - axisLabel: { formatter: function(val) { return '%1024.2mBps'.format(val); }, color: colors.muted } - }, - series: [] - }; - - downloadLineChart[type] = echarts.init(dlChartEl); - downloadLineChart[type].setOption(baseChartOption); - observeChartEl(downloadLineChart[type], dlChartEl); - - uploadLineChart[type] = echarts.init(ulChartEl); - uploadLineChart[type].setOption(baseChartOption); - observeChartEl(uploadLineChart[type], ulChartEl); - }); - - // 添加窗口大小变化监听器,使图表能够响应式调整 - if (!resizeListenerAdded) { - var resizeTimer = null; - var resizeHandler = function() { - // 使用防抖,避免频繁触发 resize - if (resizeTimer) { - clearTimeout(resizeTimer); - } - resizeTimer = setTimeout(function() { - self.resizeAllCharts(); - }, 200); - }; - - window.addEventListener('resize', resizeHandler); - resizeListenerAdded = true; - } - - this.pollData(); - } else { - setTimeout(this.initializeUI.bind(this), 50); - } - }, - - // --- Main Render Function (New) --- - - render: function() { - var self = this; - - const createTab = (type, title, placeholder) => { - var innerTabs = E('div', { 'class': 'aw-inner-tabs' }, [ - E('div', { 'class': 'cbi-section', 'data-tab': type + '-trend', 'data-tab-title': _('Speed Trend') }, [ - E('div', { 'class': 'dashboard-container' }, [ - E('div', { 'class': 'kpi-row' }, [ - E('div', { 'class': 'kpi-card' }, [ E('big', { id: type + '-host-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Hosts')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: type + '-tx-rate-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Download Speed')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: type + '-rx-rate-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Upload Speed')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: type + '-tx-volume-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Download Total')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: type + '-rx-volume-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Upload Total')) ]) - ]), - E('div', { 'class': 'line-chart-row' }, [ - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Real-time Download Speed')]), - E('div', { id: type + '-download-speed-line-chart', style: 'width: 100%; height: 350px;' }) - ]), - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Real-time Upload Speed')]), - E('div', { id: type + '-upload-speed-line-chart', style: 'width: 100%; height: 350px;' }) - ]) - ]) - ]) - ]), - E('div', { 'class': 'cbi-section', 'data-tab': type + '-share', 'data-tab-title': _('Traffic Share') }, [ - E('div', { 'class': 'dashboard-container' }, [ - E('div', { 'class': 'chart-grid' }, [ - E('div', { 'class': 'chart-card' }, [ E('h4', [_('Download Speed / Host')]), E('div', { id: type + '-tx-rate-pie', style: 'width:100%; height:300px;' }) ]), - E('div', { 'class': 'chart-card' }, [ E('h4', [_('Upload Speed / Host')]), E('div', { id: type + '-rx-rate-pie', style: 'width:100%; height:300px;' }) ]), - E('div', { 'class': 'chart-card' }, [ E('h4', [_('Download Total')]), E('div', { id: type + '-tx-volume-pie', style: 'width:100%; height:300px;' }) ]), - E('div', { 'class': 'chart-card' }, [ E('h4', [_('Upload Total')]), E('div', { id: type + '-rx-volume-pie', style: 'width:100%; height:300px;' }) ]) - ]) - ]) - ]), - E('div', { 'class': 'cbi-section', 'data-tab': type + '-hosts', 'data-tab-title': _('Host List') }, [ - E('table', { 'class': 'table', 'id': type + '-speed-data' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🖥️'), ' ', _('Host') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '👤'), ' ', _('Hostname') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '⬇️'), ' ', _('Download Speed') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📦'), ' ', _('Download Total') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📨'), ' ', _('Download Packets') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '⬆️'), ' ', _('Upload Speed') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📦'), ' ', _('Upload Total') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📨'), ' ', _('Upload Packets') ]), - E('th', { 'class': 'th center' }, [ E('span', { 'class': 'th-icon' }, '⚙️'), ' ', _('Actions') ]) - ]), - E('tr', { 'class': 'tr placeholder' }, [ E('td', { 'class': 'td', 'colspan': '9' }, [ E('em', { 'class': 'spinning' }, [ _('Collecting data...') ]) ]) ]) - ]), - self.createAddControls(type, placeholder) - ]) - ]); - - return E('div', { 'class': 'cbi-section', 'data-tab': type, 'data-tab-title': _(title) }, [ - innerTabs - ]); - }; - - var tabContainer = E('div', {}, [ - createTab('ipv4', 'IPv4', 'Please enter a valid IPv4 address'), - createTab('ipv6', 'IPv6', 'Please enter a valid IPv6 address'), - createTab('mac', 'MAC', 'Please enter a valid MAC address') - ]); - - var node = E([], [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('view/aw-bpf.css') }), - E('script', { 'type': 'text/javascript', 'src': L.resource('echarts.min.js') }), - E('div', { 'class': 'l7-view-container', 'data-aw-theme': isDarkMode() ? 'dark' : 'light' }, [ - E('h2', [ _('Host Speed Monitor') ]), - tabContainer - ]) - ]); - - tabContainer.querySelectorAll('.aw-inner-tabs').forEach(function(inner) { - ui.tabs.initTabGroup(inner.childNodes); - }); - ui.tabs.initTabGroup(tabContainer.childNodes); - this.bindTabChartResize(tabContainer); - - setTimeout(() => this.initializeUI(), 0); - - return node; - }, - - handleSave: null, - handleSaveApply: null, - handleReset: null -}); diff --git a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/l7.js b/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/l7.js deleted file mode 100644 index 7bc7e09da..000000000 --- a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/l7.js +++ /dev/null @@ -1,996 +0,0 @@ -'use strict'; -'require view'; -'require fs'; -'require ui'; -'require poll'; -'require rpc'; -'require dom'; - -var chartRegistry = {}; -var downloadLineChart, uploadLineChart; - -// Data structures for stacked line charts -var lineCategories = []; -var downloadSeriesData = {}; -var uploadSeriesData = {}; - -// Color palette for chart series -var colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']; - -var currentSortInfo = { - table: null, - column: null, - reverse: false -}; -var sidLookupTable = {}; -var isPaused = false; -var lastUpdated = null; -var pollActive = false; -var lastSIDData = null; -var lastL7ProtoData = null; -var resizeListenerAdded = false; -var resizeTimer = null; - -// Pre-fill with 60 empty points for a smooth start -for (var i = 0; i < 60; i++) { - lineCategories.push(''); -} - -// Helper to convert hex to rgba -function hexToRgba(hex, opacity) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? - 'rgba(' + parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) + ', ' + opacity + ')' : - null; -}; - -function isDarkMode() { - var attr = document.documentElement.getAttribute('data-darkmode'); - if (attr === 'true') - return true; - if (attr === 'false') - return false; - - var bg = getComputedStyle(document.body).backgroundColor; - var m = bg && bg.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); - if (m) { - var lum = (0.299 * m[1] + 0.587 * m[2] + 0.114 * m[3]) / 255; - return lum < 0.5; - } - - return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; -} - -function getChartColors() { - var dark = isDarkMode(); - return { - background: 'transparent', - text: dark ? '#cccccc' : '#333333', - muted: dark ? '#adb5bd' : '#666666', - axis: dark ? 'rgba(255,255,255,0.28)' : 'rgba(0,0,0,0.25)', - split: dark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)', - pieBorder: dark ? '#252526' : '#ffffff', - tooltipBg: dark ? 'rgba(32,32,32,0.94)' : 'rgba(255,255,255,0.95)', - tooltipBorder: dark ? '#555555' : '#cccccc', - tooltipText: dark ? '#eeeeee' : '#333333' - }; -} - -function applyViewTheme() { - var theme = isDarkMode() ? 'dark' : 'light'; - document.querySelectorAll('.l7-view-container, .display-view-container').forEach(function(el) { - el.setAttribute('data-aw-theme', theme); - }); - return theme; -} - -function observeChartEl(chart, el) { - if (!chart || !el || !window.ResizeObserver || el._awRo) - return; - el._awRo = new ResizeObserver(function() { - chart.resize(); - }); - el._awRo.observe(el); -} - -function chartAxisTheme(colors) { - return { - backgroundColor: colors.background, - textStyle: { color: colors.text }, - legend: { textStyle: { color: colors.text } }, - tooltip: { - backgroundColor: colors.tooltipBg, - borderColor: colors.tooltipBorder, - textStyle: { color: colors.tooltipText } - }, - xAxis: { - axisLine: { lineStyle: { color: colors.axis } }, - axisLabel: { color: colors.muted }, - splitLine: { show: false } - }, - yAxis: { - axisLine: { lineStyle: { color: colors.axis } }, - axisLabel: { color: colors.muted }, - splitLine: { lineStyle: { color: colors.split } } - } - }; -} - -return view.extend({ - hasXdns: false, - xdnsDomains: {}, - - load: function() { - return Promise.all([ - this.loadSIDData(), - this.loadL7ProtoData(), - this.checkXdnsStatus() - ]); - }, - - checkXdnsStatus: function() { - var self = this; - return fs.stat('/usr/bin/xdns-ctl').then(function(stat) { - if (stat && stat.type === 'file') { - self.hasXdns = true; - return fs.read_direct('/etc/xdns/whitelist.txt').then(function(content) { - var domains = {}; - if (content) { - content.split('\n').forEach(function(line) { - line = line.trim(); - if (!line || line.charAt(0) === '#') return; - if (line.indexOf('*.') === 0) line = line.substring(2); - if (line.charAt(0) === '.') line = line.substring(1); - domains[line.toLowerCase()] = true; - }); - } - self.xdnsDomains = domains; - return true; - }).catch(function() { - self.xdnsDomains = {}; - return true; - }); - } else { - self.hasXdns = false; - return false; - } - }).catch(function() { - self.hasXdns = false; - return false; - }); - }, - - isDomainProxied: function(dName) { - if (!dName || !this.xdnsDomains) return false; - dName = dName.toLowerCase(); - if (this.xdnsDomains[dName]) return true; - var parts = dName.split('.'); - for (var i = 1; i < parts.length - 1; i++) { - var parent = parts.slice(i).join('.'); - if (this.xdnsDomains[parent]) return true; - } - return false; - }, - - handleAddXdnsDomain: function(domain, btn) { - var self = this; - if (!domain) return; - btn.disabled = true; - var origText = btn.textContent; - btn.textContent = _('添加中...'); - - fs.exec_direct('/usr/bin/xdns-ctl', ['add-domain', domain]).then(function() { - self.xdnsDomains[domain.toLowerCase()] = true; - ui.addNotification(null, E('p', _('域名「%s」已成功加入 xdns-bpf 代理名单并即刻生效!').format(domain)), 'info'); - if (lastL7ProtoData) { - self.renderL7ProtoData(lastL7ProtoData); - } - }).catch(function(err) { - btn.disabled = false; - btn.textContent = origText; - ui.addNotification(null, E('p', _('加入代理名单失败: %s').format(err.message || err)), 'error'); - }); - }, - - showError: function(message) { - var errorEl = document.getElementById('l7-error-message'); - if (errorEl) { - errorEl.textContent = message; - errorEl.style.display = 'block'; - } - }, - - hideError: function() { - var errorEl = document.getElementById('l7-error-message'); - if (errorEl) { - errorEl.style.display = 'none'; - } - }, - - loadSIDData: function() { - var self = this; - return fs.exec_direct('/usr/bin/aw-bpfctl', ['sid', 'json'], 'json').then(function(result) { - self.hideError(); - lastSIDData = result; - return result; - }).catch(function(error) { - console.error('Error loading SID data:', error); - self.showError(_('Error loading SID data: %s').format(error.message)); - return { status: 'error', data: [] }; - }); - }, - - loadL7ProtoData: function() { - var self = this; - return fs.exec_direct('/usr/bin/aw-bpfctl', ['l7', 'json'], 'json').then(function(result) { - self.hideError(); - return result; - }).catch(function(error) { - console.error('Error loading L7 protocol data:', error); - self.showError(_('Error loading L7 protocol data: %s').format(error.message)); - return { status: 'error', data: [] }; - }); - }, - - updateStackedLineCharts: function(perServiceDownload, perServiceUpload) { - var now = new Date().toLocaleTimeString(); - lineCategories.push(now); - lineCategories.shift(); - - var processChartData = function(seriesData, perServiceData) { - var allServices = Object.keys(seriesData); - Object.keys(perServiceData).forEach(function(service) { - if (allServices.indexOf(service) === -1) { - allServices.push(service); - } - }); - - allServices.forEach(function(service) { - if (!seriesData[service]) { - seriesData[service] = Array(59).fill(0); - } - var rate = perServiceData[service] || 0; - seriesData[service].push(rate); - seriesData[service].shift(); - }); - - return Object.keys(seriesData).map(function(service, index) { - var color = colorPalette[index % colorPalette.length]; - return { - name: service, - type: 'line', - stack: 'Total', - smooth: true, - lineStyle: { width: 1, color: color }, - showSymbol: false, - itemStyle: { color: color }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: hexToRgba(color, 0.5) }, - { offset: 1, color: hexToRgba(color, 0) } - ]) - }, - data: seriesData[service] - }; - }); - }; - - var downloadChartSeries = processChartData(downloadSeriesData, perServiceDownload); - var uploadChartSeries = processChartData(uploadSeriesData, perServiceUpload); - - var legendData = downloadChartSeries.map(function(s) { return s.name; }); - var colors = getChartColors(); - - if (downloadLineChart) { - downloadLineChart.setOption({ - legend: { data: legendData, type: 'scroll', top: 0, left: 'center', textStyle: { color: colors.text } }, - series: downloadChartSeries, - xAxis: { data: lineCategories } - }); - } - - if (uploadLineChart) { - uploadLineChart.setOption({ - legend: { data: legendData, type: 'scroll', top: 0, left: 'center', textStyle: { color: colors.text } }, - series: uploadChartSeries, - xAxis: { data: lineCategories } - }); - } - }, - - pie: function(id, data, valueFormatter) { - var total = data.reduce(function(n, d) { return n + d.value; }, 0); - - data.sort(function(a, b) { return b.value - a.value; }); - - if (total === 0) { - data = [{ value: 1, color: '#cccccc', name: _('no traffic') }]; - } - - data.forEach(function(d, i) { - if (!d.color) { - var hue = (i * 137.508) % 360; - d.color = 'hsl(' + hue + ', 75%, 55%)'; - } - }); - - var colors = getChartColors(); - var option = { - backgroundColor: colors.background, - textStyle: { color: colors.text }, - tooltip: { - trigger: 'item', - backgroundColor: colors.tooltipBg, - borderColor: colors.tooltipBorder, - textStyle: { color: colors.tooltipText }, - formatter: function(params) { - if (valueFormatter) { - // 将 ECharts params 对象转换为自定义格式 - return valueFormatter({ - name: params.name, - value: params.value, - percent: params.percent.toFixed(2) - }); - } - return params.name + ': ' + params.value + ' (' + params.percent.toFixed(2) + '%)'; - } - }, - series: [{ - type: 'pie', - radius: ['25%', '80%'], - avoidLabelOverlap: false, - padAngle: 10, - itemStyle: { borderRadius: 10, borderColor: colors.pieBorder, borderWidth: 2 }, - label: { show: false, position: 'center', color: colors.text }, - emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold', color: colors.text } }, - labelLine: { show: false }, - data: data.map(function(d) { - return { value: d.value, name: d.label || d.name, itemStyle: { color: d.color } }; - }) - }] - }; - - var dom = typeof id === 'string' ? document.getElementById(id) : id; - - if (!chartRegistry[id]) { - chartRegistry[id] = echarts.init(dom); - observeChartEl(chartRegistry[id], dom); - } - - chartRegistry[id].setOption(option, true); - - return chartRegistry[id]; - }, - - sortTable: function(table, column) { - var tbody = table.querySelector('tbody'); - if (!tbody) return; - var rows = Array.from(tbody.querySelectorAll('tr:not(.table-titles):not(.placeholder)')); - var reverse = (currentSortInfo.table === table && currentSortInfo.column === column) ? !currentSortInfo.reverse : false; - - table.querySelectorAll('th').forEach(function(th) { - th.classList.remove('th-sort-asc', 'th-sort-desc'); - }); - - var th = table.querySelector('th:nth-child(' + (column + 1) + ')'); - th.classList.add(reverse ? 'th-sort-desc' : 'th-sort-asc'); - - rows.sort(function(row1, row2) { - var a = row1.cells[column].getAttribute('data-value') || row1.cells[column].textContent; - var b = row2.cells[column].getAttribute('data-value') || row2.cells[column].textContent; - - if (!isNaN(a) && !isNaN(b)) { a = Number(a); b = Number(b); } - - if (a < b) return reverse ? 1 : -1; - if (a > b) return reverse ? -1 : 1; - return 0; - }); - - currentSortInfo.table = table; - currentSortInfo.column = column; - currentSortInfo.reverse = reverse; - - rows.forEach(function(row) { tbody.removeChild(row); }); - rows.forEach(function(row) { tbody.appendChild(row); }); - }, - - formatMbps: function(bits) { - if (typeof bits !== 'number') return '0.00 Mbps'; - return (bits / 1024 / 1024).toFixed(2) + ' Mbps'; - }, - - formatMB: function(bytes) { - if (typeof bytes !== 'number') return '0.00 MB'; - return (bytes / 1024 / 1024).toFixed(2) + ' MB'; - }, - - renderSIDData: function(data) { - var rows = []; - var txRateData = [], rxRateData = []; - var txVolumeData = [], rxVolumeData = []; - var tx_rate_total = 0, rx_rate_total = 0; - var tx_bytes_total = 0, rx_bytes_total = 0; - var perServiceTxRate = {}; - var perServiceRxRate = {}; - var self = this; - var allItems = []; - - if (data && data.status === 'success' && Array.isArray(data.data)) { - allItems = data.data; - var listSizeEl = document.getElementById('sid-size-select'); - var listSize = listSizeEl ? parseInt(listSizeEl.value, 10) : 10; - - var activeConnections = allItems.filter(function(item) { return item.incoming.rate > 0 || item.outgoing.rate > 0; }); - var inactiveConnections = allItems.filter(function(item) { return item.incoming.rate === 0 && item.outgoing.rate === 0; }); - - activeConnections.sort(function(a, b) { return (b.incoming.rate + b.outgoing.rate) - (a.incoming.rate + a.outgoing.rate); }); - inactiveConnections.sort(function(a, b) { return b.incoming.total_bytes - a.incoming.total_bytes; }); - - var displayData = activeConnections; - if (displayData.length < listSize) { - displayData = displayData.concat(inactiveConnections.slice(0, listSize - displayData.length)); - } - - if (displayData.length > listSize) { - displayData = displayData.slice(0, listSize); - } - - displayData.forEach(function(item) { - var domainOrL7Proto = 'unknown'; - var lookupInfo = sidLookupTable[item.sid]; - - if (lookupInfo) { - domainOrL7Proto = lookupInfo.name; - } else if (item.sid_type === 'Domain' && item.domain && item.domain !== 'unknown') { - domainOrL7Proto = item.domain; - } else if (item.sid_type === 'L7' && item.l7_proto_desc && item.l7_proto_desc !== 'unknown') { - domainOrL7Proto = item.l7_proto_desc; - } - - // 判断连接是否活跃 - var isActive = item.incoming.rate > 0 || item.outgoing.rate > 0; - var activityIcon = isActive ? '🟢' : '⚪'; - - rows.push([ - E('span', { 'class': 'sid-cell' }, [ - E('span', { 'class': 'activity-indicator', 'title': isActive ? _('Active') : _('Inactive') }, activityIcon), - E('span', {}, ' ' + item.sid) - ]), - E('span', { 'class': 'protocol-cell' }, [ - E('span', { 'class': 'protocol-icon' }, '🌐'), - E('span', {}, ' ' + domainOrL7Proto) - ]), - [ item.incoming.rate, E('span', { 'class': 'speed-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mbps'.format(item.incoming.rate)) - ])], - [ item.incoming.total_bytes, E('span', { 'class': 'volume-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mB'.format(item.incoming.total_bytes)) - ])], - [ item.incoming.total_packets, E('span', { 'class': 'packet-cell download' }, [ - E('span', { 'class': 'data-value' }, '%1000.2mP'.format(item.incoming.total_packets)) - ])], - [ item.outgoing.rate, E('span', { 'class': 'speed-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mbps'.format(item.outgoing.rate)) - ])], - [ item.outgoing.total_bytes, E('span', { 'class': 'volume-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1024.2mB'.format(item.outgoing.total_bytes)) - ])], - [ item.outgoing.total_packets, E('span', { 'class': 'packet-cell upload' }, [ - E('span', { 'class': 'data-value' }, '%1000.2mP'.format(item.outgoing.total_packets)) - ])] - ]); - - txRateData.push({ value: item.incoming.rate, label: domainOrL7Proto }); - rxRateData.push({ value: item.outgoing.rate, label: domainOrL7Proto }); - txVolumeData.push({ value: item.incoming.total_bytes, label: domainOrL7Proto }); - rxVolumeData.push({ value: item.outgoing.total_bytes, label: domainOrL7Proto }); - - perServiceTxRate[domainOrL7Proto] = (perServiceTxRate[domainOrL7Proto] || 0) + item.incoming.rate; - perServiceRxRate[domainOrL7Proto] = (perServiceRxRate[domainOrL7Proto] || 0) + item.outgoing.rate; - }); - - allItems.forEach(function(item) { - tx_rate_total += item.incoming.rate; - rx_rate_total += item.outgoing.rate; - tx_bytes_total += item.incoming.total_bytes; - rx_bytes_total += item.outgoing.total_bytes; - }); - } - - this.updateStackedLineCharts(perServiceTxRate, perServiceRxRate); - - var table = document.getElementById('sid-data'); - cbi_update_table(table, rows, E('em', _('No data recorded yet.'))); - - var headers = table.querySelectorAll('th'); - - if (!table.hasAttribute('data-sort-initialized')) { - headers.forEach(function(header, index) { - header.style.cursor = 'pointer'; - header.addEventListener('click', function() { self.sortTable(table, index); }); - }); - table.setAttribute('data-sort-initialized', 'true'); - } - - table.querySelectorAll('tr:not(.table-titles):not(.placeholder)').forEach(function(row, rowIndex) { - if (!rows[rowIndex]) return; - Array.from(row.cells).forEach(function(cell, cellIndex) { - if (Array.isArray(rows[rowIndex][cellIndex])) { - cell.setAttribute('data-value', rows[rowIndex][cellIndex][0]); - } - }); - }); - - this.pie('sid-tx-rate-pie', txRateData, function(p) { return p.name + ': ' + self.formatMbps(p.value) + ' (' + p.percent + '%)'; }); - this.pie('sid-rx-rate-pie', rxRateData, function(p) { return p.name + ': ' + self.formatMbps(p.value) + ' (' + p.percent + '%)'; }); - this.pie('sid-tx-volume-pie', txVolumeData, function(p) { return p.name + ': ' + self.formatMB(p.value) + ' (' + p.percent + '%)'; }); - this.pie('sid-rx-volume-pie', rxVolumeData, function(p) { return p.name + ': ' + self.formatMB(p.value) + ' (' + p.percent + '%)'; }); - - var sidTotalEl = document.getElementById('sid-total-val'); - if(sidTotalEl) sidTotalEl.textContent = allItems.length; - - var txRateEl = document.getElementById('sid-tx-rate-val'); - if(txRateEl) txRateEl.textContent = '%1024.2mbps'.format(tx_rate_total); - - var rxRateEl = document.getElementById('sid-rx-rate-val'); - if(rxRateEl) rxRateEl.textContent = '%1024.2mbps'.format(rx_rate_total); - - var txVolEl = document.getElementById('sid-tx-volume-val'); - if(txVolEl) txVolEl.textContent = '%1024.2mB'.format(tx_bytes_total); - - var rxVolEl = document.getElementById('sid-rx-volume-val'); - if(rxVolEl) rxVolEl.textContent = '%1024.2mB'.format(rx_bytes_total); - - lastUpdated = new Date(); - var timestampEl = document.getElementById('last-updated'); - if (timestampEl) { - timestampEl.textContent = _('Last updated: %s').format(lastUpdated.toLocaleTimeString()); - } - }, - - fillSortableTable: function(tableId, rows) { - var table = document.getElementById(tableId); - var self = this; - if (!table) - return; - - if (!table.hasAttribute('data-sort-initialized')) { - table.querySelectorAll('th').forEach(function(header, index) { - header.style.cursor = 'pointer'; - header.addEventListener('click', function() { self.sortTable(table, index); }); - }); - table.setAttribute('data-sort-initialized', 'true'); - } - - cbi_update_table(table, rows, E('em', _('No data recorded yet.'))); - - table.querySelectorAll('tr:not(.table-titles):not(.placeholder)').forEach(function(row, rowIndex) { - if (!rows[rowIndex]) - return; - Array.from(row.cells).forEach(function(cell, cellIndex) { - if (Array.isArray(rows[rowIndex][cellIndex])) - cell.setAttribute('data-value', rows[rowIndex][cellIndex][0]); - }); - }); - }, - - renderL7ProtoData: function(data) { - var self = this; - var protoRows = []; - var domainRows = []; - - lastL7ProtoData = data; - sidLookupTable = {}; - - if (data && data.status === 'success' && data.data) { - if (Array.isArray(data.data.protocols)) { - data.data.protocols.forEach(function(item) { - sidLookupTable[item.sid] = { type: 'protocol', name: item.protocol }; - protoRows.push([ - [ item.id, E('span', { 'class': 'id-cell' }, item.id) ], - E('span', { 'class': 'protocol-cell' }, [ - E('span', { 'class': 'protocol-icon l7' }, '🔌'), - E('span', {}, ' ' + item.protocol) - ]), - [ item.sid, E('span', { 'class': 'sid-cell' }, item.sid) ] - ]); - }); - } - - if (Array.isArray(data.data.domains)) { - var domains = data.data.domains.slice().sort(function(a, b) { - var ac = (b.access_count || 0) - (a.access_count || 0); - if (ac !== 0) - return ac; - return (b.last_access || 0) - (a.last_access || 0); - }); - - domains.forEach(function(item) { - sidLookupTable[item.sid] = { type: 'domain', name: item.domain }; - var row = [ - [ item.id, E('span', { 'class': 'id-cell' }, item.id) ], - E('span', { 'class': 'protocol-cell' }, [ - E('span', { 'class': 'protocol-icon domain' }, '🌍'), - E('span', {}, ' ' + item.domain) - ]), - [ item.sid, E('span', { 'class': 'sid-cell' }, item.sid) ], - [ item.access_count || 0, E('span', { 'class': 'data-value' }, item.access_count || 0) ], - item.first_seen_str || '-', - item.last_access_str || '-' - ]; - - if (self.hasXdns) { - var isProxied = self.isDomainProxied(item.domain); - if (isProxied) { - row.push(E('span', { - 'class': 'badge success', - 'style': 'color: #2ecc71; background: rgba(46,204,113,0.12); border: 1px solid rgba(46,204,113,0.3); padding: 2px 8px; border-radius: 4px; font-size: 85%; white-space: nowrap;' - }, [ '✔ ', _('已代理') ])); - } else { - row.push(E('button', { - 'class': 'btn cbi-button cbi-button-action', - 'style': 'padding: 2px 8px; font-size: 85%; white-space: nowrap;', - 'click': function(ev) { - var b = ev.target.closest('button'); - self.handleAddXdnsDomain(item.domain, b); - } - }, [ '➕ ', _('加入代理') ])); - } - } - - domainRows.push(row); - }); - } - } - - this.fillSortableTable('l7-protocol-data', protoRows); - this.fillSortableTable('l7-domain-data', domainRows); - - var protoCountEl = document.getElementById('l7-protocol-count'); - if (protoCountEl) - protoCountEl.textContent = protoRows.length; - var domainCountEl = document.getElementById('l7-domain-count'); - if (domainCountEl) - domainCountEl.textContent = domainRows.length; - }, - - pollL7Data: function() { - if (pollActive) return; - - var self = this; - pollActive = true; - - self.loadL7ProtoData().then(function(l7data) { - self.renderL7ProtoData(l7data); - return self.loadSIDData(); - }).then(function(sidData){ - self.renderSIDData(sidData); - }); - - poll.add(function() { - if (isPaused) return Promise.resolve(); - - return self.loadL7ProtoData().then(function(data) { - self.renderL7ProtoData(data); - }).then(function() { - return self.loadSIDData().then(function(data) { - self.renderSIDData(data); - }); - }); - }, 5); - }, - - initializeUI: function() { - applyViewTheme(); - if (window.echarts) { - var self = this; - var dlChartEl = document.getElementById('download-speed-line-chart'); - var ulChartEl = document.getElementById('upload-speed-line-chart'); - if (!dlChartEl || !ulChartEl) return; - - var colors = getChartColors(); - var axisTheme = chartAxisTheme(colors); - var baseChartOption = { - backgroundColor: axisTheme.backgroundColor, - textStyle: axisTheme.textStyle, - legend: axisTheme.legend, - tooltip: Object.assign({ - trigger: 'axis', - formatter: function (params) { - if (!params || params.length === 0) { - return null; - } - var tooltipContent = params[0].axisValueLabel + '
'; - params.sort(function(a, b) { return b.value - a.value; }); - params.forEach(function(item) { - if (item.value > 0) { - tooltipContent += item.marker + ' ' + item.seriesName + ': ' + '%1024.2mbps'.format(item.value) + '
'; - } - }); - return tooltipContent; - } - }, axisTheme.tooltip), - grid: { left: '3%', right: '4%', bottom: '10%', top: '50px', containLabel: true }, - xAxis: { - type: 'category', - boundaryGap: false, - data: lineCategories, - axisLine: axisTheme.xAxis.axisLine, - axisLabel: axisTheme.xAxis.axisLabel, - splitLine: axisTheme.xAxis.splitLine - }, - yAxis: { - type: 'value', - axisLine: axisTheme.yAxis.axisLine, - splitLine: axisTheme.yAxis.splitLine, - axisLabel: { formatter: function(val) { return '%1024.2mbps'.format(val); }, color: colors.muted } - }, - series: [] - }; - - - downloadLineChart = echarts.init(dlChartEl); - downloadLineChart.setOption(baseChartOption); - observeChartEl(downloadLineChart, dlChartEl); - - uploadLineChart = echarts.init(ulChartEl); - uploadLineChart.setOption(baseChartOption); - observeChartEl(uploadLineChart, ulChartEl); - - // 添加窗口大小变化监听器,使图表能够响应式调整 - if (!resizeListenerAdded) { - var resizeTimer = null; - var resizeHandler = function() { - // 使用防抖,避免频繁触发 resize - if (resizeTimer) { - clearTimeout(resizeTimer); - } - resizeTimer = setTimeout(function() { - self.resizeAllCharts(); - }, 200); - }; - - window.addEventListener('resize', resizeHandler); - resizeListenerAdded = true; - } - - this.pollL7Data(); - } else { - setTimeout(this.initializeUI.bind(this), 50); - } - }, - - resizeAllCharts: function() { - if (downloadLineChart) - downloadLineChart.resize(); - if (uploadLineChart) - uploadLineChart.resize(); - Object.keys(chartRegistry).forEach(function(chartId) { - if (chartRegistry[chartId]) - chartRegistry[chartId].resize(); - }); - }, - - bindTabChartResize: function(root) { - var self = this; - if (!root) - return; - var host = root.parentNode || root; - if (host._awTabResizeBound) - return; - host._awTabResizeBound = true; - - var schedule = function() { - setTimeout(function() { self.resizeAllCharts(); }, 80); - }; - - host.addEventListener('click', function(ev) { - if (ev.target.closest && ev.target.closest('ul.cbi-tabmenu')) - schedule(); - }); - root.querySelectorAll('[data-tab]').forEach(function(pane) { - pane.addEventListener('cbi-tab-active', schedule); - }); - }, - - render: function() { - var self = this; - - var controls = E('div', { 'class': 'l7-controls' }, [ - E('div', { 'class': 'l7-controls-left' }, [ - E('div', { 'class': 'control-group' }, [ - E('span', { 'class': 'control-icon' }, '📊'), - E('label', { 'for': 'sid-size-select', 'class': 'control-label' }, _('Show entries:')), - E('select', { - 'id': 'sid-size-select', - 'class': 'cbi-input-select', - 'change': ui.createHandlerFn(this, function() { - if (lastSIDData) { - self.renderSIDData(lastSIDData); - } - }) - }, [ - E('option', { 'value': '10' }, '10'), - E('option', { 'value': '15' }, '15'), - E('option', { 'value': '20' }, '20'), - E('option', { 'value': '25' }, '25'), - E('option', { 'value': '50' }, '50') - ]) - ]) - ]), - E('div', { 'class': 'l7-controls-right' }, [ - E('div', { 'class': 'control-group' }, [ - E('span', { 'class': 'control-icon' }, '🕐'), - E('span', { 'id': 'last-updated', 'class': 'last-updated-text' }, _('Last updated: never')) - ]), - E('button', { - 'class': 'cbi-button cbi-button-action', - 'id': 'pause-resume-btn', - 'click': function(ev) { - isPaused = !isPaused; - var btn = ev.target; - if (isPaused) { - btn.innerHTML = '▶️ ' + _('Resume'); - btn.classList.remove('cbi-button-action'); - btn.classList.add('cbi-button-positive'); - } else { - btn.innerHTML = '⏸️ ' + _('Pause'); - btn.classList.remove('cbi-button-positive'); - btn.classList.add('cbi-button-action'); - } - } - }, [ - E('span', { 'class': 'btn-icon' }, '⏸️'), - E('span', {}, ' ' + _('Pause')) - ]) - ]) - ]); - - var sidInnerTabs = E('div', { 'class': 'aw-inner-tabs' }, [ - E('div', { 'class': 'cbi-section', 'data-tab': 'sid-trend', 'data-tab-title': _('Speed Trend') }, [ - E('div', { 'class': 'dashboard-container' }, [ - E('div', { 'class': 'kpi-row' }, [ - E('div', { 'class': 'kpi-card' }, [ E('big', { id: 'sid-total-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('L7 Protocol Data')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: 'sid-tx-rate-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Download Speed')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: 'sid-rx-rate-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Upload Speed')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: 'sid-tx-volume-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Download Total')) ]), - E('div', { 'class': 'kpi-card' }, [ E('big', { id: 'sid-rx-volume-val' }, '0'), E('span', { 'class': 'kpi-card-label' }, _('Upload Total')) ]) - ]), - E('div', { 'class': 'line-chart-row' }, [ - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Real-time Download Speed')]), - E('div', { id: 'download-speed-line-chart', style: 'width: 100%; height: 350px;' }) - ]), - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Real-time Upload Speed')]), - E('div', { id: 'upload-speed-line-chart', style: 'width: 100%; height: 350px;' }) - ]) - ]) - ]) - ]), - E('div', { 'class': 'cbi-section', 'data-tab': 'sid-share', 'data-tab-title': _('Traffic Share') }, [ - E('div', { 'class': 'dashboard-container' }, [ - E('div', { 'class': 'chart-grid' }, [ - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Download Speed / SID')]), - E('div', { id: 'sid-tx-rate-pie', style: 'width: 100%; height: 300px;' }) - ]), - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Upload Speed / SID')]), - E('div', { id: 'sid-rx-rate-pie', style: 'width: 100%; height: 300px;' }) - ]), - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Download Total')]), - E('div', { id: 'sid-tx-volume-pie', style: 'width: 100%; height: 300px;' }) - ]), - E('div', { 'class': 'chart-card' }, [ - E('h4', [_('Upload Total')]), - E('div', { id: 'sid-rx-volume-pie', style: 'width: 100%; height: 300px;' }) - ]) - ]) - ]) - ]), - E('div', { 'class': 'cbi-section', 'data-tab': 'sid-list', 'data-tab-title': _('SID List') }, [ - E('table', { 'class': 'table', 'id': 'sid-data' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🆔'), ' ', _('SID') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🌐'), ' ', _('Domain&L7Protocol') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '⬇️'), ' ', _('Download Speed (Bit/s)') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📦'), ' ', _('Download (Bytes)') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📨'), ' ', _('Download (Packets)') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '⬆️'), ' ', _('Upload Speed (Bit/s)') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📦'), ' ', _('Upload (Bytes)') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📨'), ' ', _('Upload (Packets)') ]) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td', 'colspan': '8' }, [ - E('em', { 'class': 'spinning' }, [ _('Collecting data...') ]) - ]) - ]) - ]), - controls - ]) - ]); - - var tabContainer = E('div', {}, [ - E('div', { 'class': 'cbi-section', 'data-tab': 'sid', 'data-tab-title': _('L7 SID Data') }, [ - sidInnerTabs - ]), - E('div', { 'class': 'cbi-section', 'data-tab': 'l7proto', 'data-tab-title': _('L7 Protocol Data') }, [ - E('div', { 'class': 'aw-inner-tabs' }, [ - E('div', { 'class': 'cbi-section', 'data-tab': 'l7-protocols', 'data-tab-title': _('Protocol Library') }, [ - E('p', { 'class': 'cbi-section-descr' }, [ - _('Built-in L7 protocol signatures from aw-bpf.'), - ' ', - _('Entries:'), - ' ', - E('strong', { 'id': 'l7-protocol-count' }, '0') - ]), - E('table', { 'class': 'table', 'id': 'l7-protocol-data' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '#️⃣'), ' ', _('ID') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🔌'), ' ', _('Protocol') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '🔑'), ' ', _('SID') ]) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td', 'colspan': '3' }, [ - E('em', { 'class': 'spinning' }, [ _('Collecting data...') ]) - ]) - ]) - ]) - ]), - E('div', { 'class': 'cbi-section', 'data-tab': 'l7-domains', 'data-tab-title': _('常用域名') }, [ - E('p', { 'class': 'cbi-section-descr' }, [ - _('Frequently accessed domains discovered by xDPI, sorted by access count.'), - ' ', - _('Entries:'), - ' ', - E('strong', { 'id': 'l7-domain-count' }, '0') - ]), - E('table', { 'class': 'table', 'id': 'l7-domain-data' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '#️⃣'), ' ', _('ID') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🌍'), ' ', _('Domain') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '🔑'), ' ', _('SID') ]), - E('th', { 'class': 'th right' }, [ E('span', { 'class': 'th-icon' }, '📊'), ' ', _('Access Count') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🕒'), ' ', _('First Seen') ]), - E('th', { 'class': 'th left' }, [ E('span', { 'class': 'th-icon' }, '🕒'), ' ', _('Last Access') ]), - this.hasXdns ? E('th', { 'class': 'th center' }, [ E('span', { 'class': 'th-icon' }, '⚡'), ' ', _('xdns代理') ]) : null - ].filter(Boolean)), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td', 'colspan': this.hasXdns ? '7' : '6' }, [ - E('em', { 'class': 'spinning' }, [ _('Collecting data...') ]) - ]) - ]) - ]) - ]) - ]) - ]) - ]); - - var node = E([], [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('view/aw-bpf.css') }), - E('script', { 'type': 'text/javascript', 'src': L.resource('echarts.min.js') }), - - E('div', { 'class': 'l7-view-container', 'data-aw-theme': isDarkMode() ? 'dark' : 'light' }, [ - E('h2', [ _('L7 Data Monitor') ]), - E('div', { 'id': 'l7-error-message' }), - tabContainer - ]) - ]); - - tabContainer.querySelectorAll('.aw-inner-tabs').forEach(function(inner) { - ui.tabs.initTabGroup(inner.childNodes); - }); - ui.tabs.initTabGroup(tabContainer.childNodes); - this.bindTabChartResize(tabContainer); - - setTimeout(this.initializeUI.bind(this), 0); - - return node; - }, - - handleSave: null, - handleSaveApply: null, - handleReset: null -}); \ No newline at end of file diff --git a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/settings.js b/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/settings.js deleted file mode 100644 index 3aa37de38..000000000 --- a/luci-app-aw-bpf/htdocs/luci-static/resources/view/aw-bpf/settings.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require uci'; - -return view.extend({ - load: function() { - return uci.load('aw-bpf'); - }, - - render: function() { - var m, s, o; - - m = new form.Map('aw-bpf', _('eBPF Traffic Control & DPI'), - _('eBPF kernel-level bandwidth control, session audit logging and xDPI L7 application/domain recognition.')); - - s = m.section(form.TypedSection, 'aw-bpf', _('General Settings')); - s.anonymous = true; - s.addremove = false; - - o = s.option(form.Flag, 'enable_event_log', _('Enable Session Event Logging'), - _('Record TCP/UDP session connection events as structured JSON to system log / syslog. (DNS learning and xDPI protocol recognition are always active in background).')); - o.rmempty = false; - o.default = '0'; - - return m.render(); - } -}); diff --git a/luci-app-aw-bpf/po/zh-cn b/luci-app-aw-bpf/po/zh-cn deleted file mode 120000 index 8d69574dd..000000000 --- a/luci-app-aw-bpf/po/zh-cn +++ /dev/null @@ -1 +0,0 @@ -zh_Hans \ No newline at end of file diff --git a/luci-app-aw-bpf/po/zh_Hans/aw-bpf.po b/luci-app-aw-bpf/po/zh_Hans/aw-bpf.po deleted file mode 100644 index 2ed0f2de6..000000000 --- a/luci-app-aw-bpf/po/zh_Hans/aw-bpf.po +++ /dev/null @@ -1,1207 +0,0 @@ -# Translations for LuCI -# Copyright (C) 2022 Jo-Philipp Wich -# This file is distributed under the Apache License, Version 2.0. -# -msgid "" -msgstr "" -"Project-Id-Version: luci-app-aw-bpf 1.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-16 00:00+0000\n" -"PO-Revision-Date: 2025-03-16 00:00+0000\n" -"Last-Translator: \n" -"Language-Team: Chinese (Simplified)\n" -"Language: zh_Hans\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "apfree-wifidog" -msgstr "门户认证" - -msgid "ApFree-WiFiDog" -msgstr "门户认证" - -msgid "apfree-wifidog offers a stable and secure captive portal solution." -msgstr "apfree-wifidog 提供了一个稳定安全的门户认证解决方案" - -msgid "Enable apfree-wifidog service." -msgstr "启用apfree-wifidog门户认证服务" - -msgid "Log Level" -msgstr "日志级别" - -msgid "The log level of the apfree-wifidog." -msgstr "apfree-wifidog的日志级别" - -msgid "Debug" -msgstr "调试" - -msgid "Info" -msgstr "信息" - -msgid "Notice" -msgstr "通知" - -msgid "Warning" -msgstr "警告" - -msgid "Error" -msgstr "错误" - -msgid "Critical" -msgstr "严重" - -msgid "Alert" -msgstr "警报" - -msgid "Emergency" -msgstr "紧急" - -msgid "None" -msgstr "无" - -msgid "Enable" -msgstr "启用" - -msgid "Auth Enabled" -msgstr "启用认证" - -msgid "Enable the authentication of the gateway." -msgstr "启用网关的认证功能" - -msgid "Gateway Name" -msgstr "网关名称" - -msgid "The name of the gateway." -msgstr "开启认证的网关所属网络区域" - -msgid "Gateway Channel" -msgstr "网关通道" - -msgid "The channel of the gateway." -msgstr "网关的通道" - -msgid "Gateway Subnetv4" -msgstr "网关IPv4子网" - -msgid "The ipv4 subnet of the gateway." -msgstr "网关的IPv4子网" - -msgid "Gateway ID" -msgstr "网关 ID" - -msgid "The ID of the gateway." -msgstr "网关的ID(一般为设备的MAC地址)" - -msgid "Channel Path" -msgstr "用户渠道" - -msgid "The channel path of the gateway." -msgstr "网关的用户渠道" - -msgid "Auth Server Hostname" -msgstr "认证服务器主机名" - -msgid "The domain or IP address of the authentication server." -msgstr "认证服务器的域名或 IP 地址" - -msgid "Auth Server Port" -msgstr "认证服务器端口" - -msgid "The port of the authentication server." -msgstr "认证服务器的端口" - -msgid "Auth Server URI path" -msgstr "认证服务器URI路径" - -msgid "The URI path of the authentication server." -msgstr "认证服务器的URI路径" - -msgid "Trusted Domains" -msgstr "信任的域名" - -msgid "The trusted domains of the gateway" -msgstr "网关的信任域名" - -msgid "The trusted domains of the gateway, for example: \"www.baidu.com,www.qq.com,...\"." -msgstr "域名白名单(多域名用逗号分隔),例如:\"www.baidu.com,www.qq.com,...\"" - -msgid "Trusted MACs" -msgstr "信任的MAC地址" - -msgid "The trusted MAC addresses of the gateway" -msgstr "网关的 MAC 地址白名单" - -msgid "The trusted MAC addresses of the gateway, for example: \"00:11:22:33:44:55,66:77:88:99:00:11,...\"." -msgstr "MAC 地址白名单(多 MAC 地址用逗号分隔),例如:\"00:11:22:33:44:55,66:77:88:99:00:11,...\"" - -msgid "running..." -msgstr "运行中" - -msgid "not running..." -msgstr "未运行" - -msgid "Value" -msgstr "值" - -msgid "Internet Connectivity" -msgstr "互联网连接" - -msgid "Auth server reachable" -msgstr "认证服务器可达" - -msgid "Authentication servers" -msgstr "认证服务器" - -msgid "Enable Wildcard Domain" -msgstr "启用通配符域名" - -msgid "Enable wildcard domain support." -msgstr "启用通配符域名支持" - -msgid "Trusted Wildcard Domains" -msgstr "信任的通配符域名" - -msgid "The trusted wildcard domains of the gateway." -msgstr "网关的信任通配符域名" - -msgid "App White List" -msgstr "应用白名单" - -msgid "The app white list of the gateway." -msgstr "网关的应用白名单" - -msgid "MAC White List" -msgstr "MAC白名单" - -msgid "The MAC white list of the gateway." -msgstr "网关的MAC白名单" - -msgid "Wildcard White List" -msgstr "通配符白名单" - -msgid "The wildcard domain white list of the gateway." -msgstr "网关的通配符域名白名单" - -msgid "Check Interval" -msgstr "检查间隔" - -msgid "The interval of the check(s)." -msgstr "检查的时间间隔(秒)" - -msgid "Check Timeout" -msgstr "检查超时" - -msgid "Client Timeout" -msgstr "客户端超时" - -msgid "The timeout of the client." -msgstr "客户端的超时时间" - -msgid "Wired Passed" -msgstr "有线免认证" - -msgid "Wired users do not need to authenticate to access the internet." -msgstr "有线用户无需认证即可访问互联网" - -msgid "Apple CNA" -msgstr "苹果CNA" - -msgid "Enable Apple Captive Network Assistant." -msgstr "启用苹果强制网络门户助手" - -msgid "JS Filter" -msgstr "JS过滤" - -msgid "Enable JS redirect." -msgstr "启用JS重定向" - -msgid "Enable WebSocket" -msgstr "启用 Websocket" - -msgid "Enable websocket support." -msgstr "启用 Websocket 支持, 用于实现认证服务器端放行功能" - -msgid "Enable Anti NAT" -msgstr "启用防NAT" - -msgid "Enable Anti NAT devices." -msgstr "启用防NAT设备" - -msgid "TTL Value" -msgstr "TTL值" - -msgid "The TTL value of the gateway support." -msgstr "网关支持的TTL值" - -msgid "Bypass Auth" -msgstr "旁认证" - -msgid "Anti NAT Permit MAC" -msgstr "防NAT允许的MAC" - -msgid "The MAC address of the Anti NAT permit." -msgstr "防NAT允许的MAC地址" - -msgid "Enable Global QoS" -msgstr "启用全局QoS" - -msgid "Enable Global QoS." -msgstr "启用全局QoS" - -msgid "Global QoS Up" -msgstr "全局QoS上行" - -msgid "The global QoS up value(Mbps)." -msgstr "全局QoS上行速度(Mbps)" - -msgid "Global QoS Down" -msgstr "全局QoS下行" - -msgid "The global QoS down value(Mbps)." -msgstr "全局QoS下行速度(Mbps)" - -msgid "WebSocket Hostname" -msgstr "WebSocket主机名" - -msgid "The hostname of the websocket, if the field is left empty, automatically use the same hostname as the auth server." -msgstr "WebSocket的主机名,如果此字段为空,自动使用与认证服务器相同的主机名" - -msgid "WebSocket Port" -msgstr "WebSocket端口" - -msgid "The port of the websocket, if the field is left empty, automatically use the same port as the auth server." -msgstr "WebSocket的端口,如果此字段为空,自动使用与认证服务器相同的端口" - -msgid "WebSocket URI path" -msgstr "WebSocket URI路径" - -msgid "The URI path of the websocket." -msgstr "WebSocket的URI路径" - -msgid "MQTT Port" -msgstr "MQTT端口" - -msgid "The port of the mqtt." -msgstr "MQTT的端口" - -msgid "MQTT Username" -msgstr "MQTT用户名" - -msgid "The username of the mqtt." -msgstr "MQTT的用户名" - -msgid "MQTT Password" -msgstr "MQTT密码" - -msgid "The password of the mqtt." -msgstr "MQTT的密码" - -msgid "Device ID" -msgstr "设备ID" - -msgid "The ID of the device." -msgstr "设备的ID" - -msgid "Local Portal" -msgstr "本地门户" - -msgid "The local portal url." -msgstr "本地门户网址" - -msgid "External Interface" -msgstr "外部接口" - -msgid "The external interface of the device, if bypass mode, do not choose." -msgstr "设备的外部接口,如果是旁路模式,请不要选择" - -msgid "Disable Portal Authentication" -msgstr "禁用Portal认证" - -msgid "When enabled, users can access the internet without portal authentication. Firewall redirect rules will not be created. Use this mode for pure traffic statistics without captive portal." -msgstr "启用后,用户无需Portal认证即可上网。不会创建防火墙重定向规则。适用于纯流量统计场景,不需要强制Portal认证页面。" - -msgid "Configuration" -msgstr "配置" - -msgid "Basic Settings" -msgstr "基本设置" - -msgid "Gateway Settings" -msgstr "网关设置" - -msgid "Advanced Settings" -msgstr "高级设置" - -msgid "Long Connection Settings" -msgstr "长连接设置" - -msgid "Auth Server Settings" -msgstr "认证服务器设置" - -msgid "Rule Settings" -msgstr "规则设置" - -msgid "QoS Settings" -msgstr "QoS设置" - -msgid "Authentication Location Settings" -msgstr "认证位置设置" - -msgid "Group Define" -msgstr "组定义" - -msgid "Group Type" -msgstr "组类型" - -msgid "The type of the group." -msgstr "组的类型" - -msgid "Domain Group" -msgstr "域名组" - -msgid "MAC Group" -msgstr "MAC地址组" - -msgid "Wildcard Domain Group" -msgstr "通配符域名组" - -msgid "Domain Name" -msgstr "域名" - -msgid "The domain name of the group." -msgstr "组的域名" - -msgid "MAC Address" -msgstr "MAC地址" - -msgid "The MAC address of the group." -msgstr "组的MAC地址" - -msgid "Wildcard Domain" -msgstr "通配符域名" - -msgid "The wildcard domain of the group." -msgstr "组的通配符域名" - -msgid "Group Description" -msgstr "组描述" - -msgid "The description of the group." -msgstr "组的描述" - -msgid "The group is used by " -msgstr "该组正被 " - -msgid " please remove it from " -msgstr " 使用,请先从 " - -msgid " first." -msgstr " 中移除。" - -# Client status UI additions -msgid "Download Rate" -msgstr "下载速率" - -msgid "Upload Rate" -msgstr "上传速率" - -#~ msgid "Down. (Bytes / Pkts.)" -#~ msgstr "下载(字节 / 数据包)" - -#~ msgid "Download (Bytes / Packets)" -#~ msgstr "下载(字节 / 数据包)" - -#~ msgid "Up. (Bytes / Pkts.)" -#~ msgstr "上传(字节 / 数据包)" - -#~ msgid "Upload (Bytes / Packets)" -#~ msgstr "上传(字节 / 数据包)" - -msgid "Speed Distribution" -msgstr "速率分布" - -msgid "Download Speed (Bit/s)" -msgstr "下载速率 (比特/秒)" - -msgid "Upload Speed (Bit/s)" -msgstr "上传速率 (比特/秒)" - -msgid "Upload Speed / Host" -msgstr "上传速率 / 主机" - -msgid "Download Speed / Host" -msgstr "下载速率 / 主机" - -msgid "Traffic History" -msgstr "流量统计" - -msgid "Network Speed Monitor" -msgstr "网络速度监控" - -msgid "Auth User Speed Monitor" -msgstr "认证用户速率监控" - -msgid "Host Speed Monitor" -msgstr "主机速率监控" - -msgid "Speed Trend" -msgstr "实时趋势" - -msgid "Traffic Share" -msgstr "流量分布" - -msgid "Host List" -msgstr "主机列表" - -msgid "SID List" -msgstr "SID 列表" - -msgid "Protocol Library" -msgstr "协议库" - -msgid "常用域名" -msgstr "常用域名" - -msgid "Access Count" -msgstr "访问次数" - -msgid "First Seen" -msgstr "首次发现" - -msgid "Last Access" -msgstr "最近访问" - -msgid "Entries:" -msgstr "条目:" - -msgid "Built-in L7 protocol signatures from aw-bpf." -msgstr "aw-bpf 内置的 L7 协议特征库。" - -msgid "Domains discovered by xDPI DNS inspection." -msgstr "xDPI 通过 DNS 发现的域名。" - -msgid "Frequently accessed domains discovered by xDPI, sorted by access count." -msgstr "xDPI 发现的常用域名,按访问次数排序。" - -msgid "aw-bpf QoS" -msgstr "aw-bpf 流控" - -msgid "Hosts" -msgstr "主机" - -msgid "0 hosts" -msgstr "主机:0" - -msgid "0 download speed" -msgstr "总下载速度:0" - -msgid "0 upload speed" -msgstr "总上传速度:0" - -msgid "0 hosts" -msgstr "主机:0" - -msgid "0 download speed" -msgstr "总下载速度:0" - -msgid "0 upload speed" -msgstr "总上传速度:0" - -msgid "0 hosts" -msgstr "主机:0" - -msgid "0 download speed" -msgstr "总下载速度:0" - -msgid "0 upload speed" -msgstr "总上传速度:0" - -msgid "0 cause the most download" -msgstr "下载量最大的协议:0" - -msgid "0 cause the most upload" -msgstr "上传量最大的协议:0" - -msgid "0 different application protocols" -msgstr "应用层协议计数:0" - -msgid "L7 Protocol Support" -msgstr "应用层协议支持" - -msgid "Initial traffic" -msgstr "初始流量" - -msgid "apfree-wifidog Status" -msgstr "apfree-wifidog 状态" - -msgid "Upload (Bytes)" -msgstr "上传 (字节)" - -msgid "Upload (Packets)" -msgstr "上传 (数据包)" - -msgid "Download (Bytes)" -msgstr "下载 (字节)" - -msgid "Download (Packets)" -msgstr "下载 (数据包)" - -msgid "download speed" -msgstr "下载速度" - -msgid "upload speed" -msgstr "上传速度" - -msgid "Display" -msgstr "主机流速显示" - -msgid "Auth User" -msgstr "认证用户" - -msgid "No data recorded yet." -msgstr "暂无数据记录" - -msgid "Edit Speed Limit" -msgstr "带宽控制" - -msgid "Download Limit" -msgstr "限制下载速度" - -msgid "Upload Limit" -msgstr "限制上传速度" - -msgid "Speed limit updated" -msgstr "限速配置已更新" - -msgid "Data format error" -msgstr "数据格式错误" - -msgid "Please enter a valid IPv4 address" -msgstr "请输入有效的 IPv4 地址" - -msgid "Please enter a valid IPv6 address" -msgstr "请输入有效的 IPv6 地址" - -msgid "Please enter a valid MAC address" -msgstr "请输入有效的 MAC 地址" - -msgid "Updated successfully!" -msgstr "更新成功!" - -msgid "L7 SID Data" -msgstr "L7 应用数据" - -msgid "L7 Protocol Data" -msgstr "L7 协议数据" - -msgid "Download / SID" -msgstr "下载 / SID" - -msgid "Upload / SID" -msgstr "上传 / SID" - -msgid "Download / Protocol" -msgstr "下载 / 协议" - -msgid "Upload / Protocol" -msgstr "上传 / 协议" - -msgid "SID" -msgstr "应用" - -msgid "Name" -msgstr "名称" - -msgid "Incoming" -msgstr "接收" - -msgid "Outgoing" -msgstr "发送" - -msgid "ID" -msgstr "ID" - -msgid "Description" -msgstr "描述" - -msgid "Bytes" -msgstr "字节" - -msgid "Collecting data..." -msgstr "正在收集数据..." - -msgid "different SIDs" -msgstr "个不同的应用" - -msgid "total download" -msgstr "总下载" - -msgid "total upload" -msgstr "总上传" - -msgid "different protocols" -msgstr "个不同的协议" - -msgid "no traffic" -msgstr "无流量" - -msgid "QoS" -msgstr "流控" - -msgid "L7 application" -msgstr "L7应用" - -msgid "L7 Data Monitor" -msgstr "L7 数据监控" - -msgid "Upload Speed / SID" -msgstr "上传速率 / 应用" - -msgid "Download Speed / SID" -msgstr "下载速率 / 应用" - -msgid "0 different SIDs" -msgstr "应用计数:0" - -msgid "0 download speed" -msgstr "总下载速度:0" - -msgid "0 upload speed" -msgstr "总上传速度:0" - -msgid "Actions" -msgstr "操作" - -msgid "Edit" -msgstr "编辑" - -msgid "Add" -msgstr "添加" - -msgid "Refreshing" -msgstr "刷新" - -msgid "Error: " -msgstr "错误:" - -msgid "Delete Host" -msgstr "删除主机" - -msgid "Are you sure you want to delete this host?" -msgstr "您确定要删除这个主机吗?" - -msgid "Enable Internet Access Log" -msgstr "开启上网记录功能" - -msgid "Enable logging of internet access events and user activities." -msgstr "启用互联网访问事件和用户活动的日志记录功能。" - -msgid "Client Status" -msgstr "客户端状态" - -msgid "Authentication Server Status" -msgstr "认证服务器状态" - -msgid "Internet Connected" -msgstr "互联网连接" - -msgid "Auth Server Connected" -msgstr "认证服务器连接" - -msgid "MQTT Connected" -msgstr "MQTT 连接" - -msgid "WebSocket Connected" -msgstr "WebSocket 连接" - -msgid "Auth Server Mode" -msgstr "认证服务器模式" - -msgid "Online Clients" -msgstr "在线客户端" - -msgid "Active Clients" -msgstr "活跃客户端" - -msgid "Connected Clients" -msgstr "已连接客户端" - -msgid "IP Address" -msgstr "IP地址" - -msgid "Status" -msgstr "状态" - -msgid "Online Time" -msgstr "在线时间" - -msgid "Connection Type" -msgstr "连接类型" - -msgid "Online" -msgstr "在线" - -msgid "Offline" -msgstr "离线" - -msgid "Wired" -msgstr "有线" - -msgid "Wireless" -msgstr "无线" - -msgid "Auth Server Online" -msgstr "认证服务器在线" - -msgid "Failed to get wifidogx status" -msgstr "获取wifidogx状态失败" - -msgid "Failed to get client status" -msgstr "获取客户端状态失败" - -msgid "Failed to get auth server status" -msgstr "获取认证服务器状态失败" - -msgid "Error getting status information: " -msgstr "获取状态信息错误:" - -msgid "Cloud Auth" -msgstr "云认证" - -msgid "Local Auth" -msgstr "本地认证" - -msgid "Unknown" -msgstr "未知" - -msgid "d" -msgstr "天" - -msgid "h" -msgstr "小时" - -msgid "m" -msgstr "分钟" - -msgid "s" -msgstr "秒" - -msgid "Authentication Server" -msgstr "认证服务器" - -msgid "Select the authentication server to use for cloud authentication." -msgstr "选择用于云认证的认证服务器" - -msgid "Please create an authentication server first" -msgstr "请先创建认证服务器" - -msgid "Domain&L7Protocol" -msgstr "域名&L7协议" - -msgid "Protocol" -msgstr "协议" - -msgid "Domain" -msgstr "域名" - -msgid "Download Total" -msgstr "下载总量" - -msgid "Upload Total" -msgstr "上传总量" - -msgid "Download Speed" -msgstr "下载速度" - -msgid "Upload Speed" -msgstr "上传速度" - -msgid "Showing top %d by %s" -msgstr "按%s显示前%d项" - -msgid "Download Traffic / SID" -msgstr "下载流量 / 应用" - -msgid "Upload Traffic / SID" -msgstr "上传流量 / 应用" - -msgid "Show entries: " -msgstr "显示条目: " - -msgid "Pause" -msgstr "暂停" - -msgid "Resume" -msgstr "恢复" - -msgid "Last updated: %s" -msgstr "上次更新:%s" - -msgid "Error loading SID data: %s" -msgstr "加载 SID 数据错误:%s" - -msgid "Error loading L7 protocol data: %s" -msgstr "加载 L7 协议数据错误:%s" - -msgid "Last updated: never" -msgstr "上次更新:从未" - -msgid "Real-time Download Speed" -msgstr "实时下载速度" - -msgid "Real-time Upload Speed" -msgstr "实时上传速度" - -msgid "AP Device ID" -msgstr "AP设备ID" - -msgid "AP Device ID must be exactly 21 characters long" -msgstr "AP设备ID必须是21个字符长" - -msgid "AP Device ID must contain only uppercase letters and digits" -msgstr "AP设备ID只能包含大写字母和数字" - -msgid "AP MAC Address" -msgstr "AP MAC地址" - -msgid "Auto Fill" -msgstr "自动填充" - -msgid "Auto Fill All Fields" -msgstr "自动填充所有字段" - -msgid "Auto fill completed successfully! All fields have been filled." -msgstr "自动填充成功!所有字段已填写。" - -msgid "Auto fill failed. No fields could be filled. Please check your network connection and try again." -msgstr "自动填充失败。无法填写任何字段。请检查您的网络连接并重试。" - -msgid "Auto fill partially completed." -msgstr "自动填充部分完成。" - -msgid "Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude" -msgstr "自动填充 AP MAC地址、设备ID、位置ID、经度和纬度" - -msgid "Device ID: " -msgstr "设备ID: " - -msgid "First 6 digits must be valid administrative division code (GB/T 2260)" -msgstr "前6位必须是有效的行政区划代码 (GB/T 2260)" - -msgid "Generating Device ID..." -msgstr "生成设备ID..." - -msgid "Generating Location ID..." -msgstr "生成位置ID..." - -msgid "Getting WAN MAC address..." -msgstr "正在获取 WAN MAC 地址..." - -msgid "Getting device information and location data, please wait..." -msgstr "正在获取设备信息和位置数据,请稍候..." - -msgid "Getting location coordinates..." -msgstr "正在获取位置坐标..." - -msgid "Last 12 characters must be a valid MAC address in uppercase hexadecimal format (e.g., 00E04C3B7D2F)" -msgstr "最后12个字符必须是大写十六进制格式的有效MAC地址(例如:00E04C3B7D2F)" - -msgid "Last 5 digits must be sequence number (00000-99999)" -msgstr "最后5位必须是序列号 (00000-99999)" - -msgid "Latitude must be a valid number" -msgstr "纬度必须是一个有效的数字" - -msgid "Latitude must be between -90.000000 and 90.000000" -msgstr "纬度必须在 -90.000000 到 90.000000 之间" - -msgid "Latitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 39.900000 or -33.000000). Suggested format: " -msgstr "纬度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:39.900000 或 -33.000000)。建议格式:" - -msgid "Latitude: " -msgstr "纬度: " - -msgid "Location ID" -msgstr "位置ID" - -msgid "Location ID is required" -msgstr "必须填写位置ID" - -msgid "Location ID must be exactly 14 digits long" -msgstr "位置ID必须是14位数字" - -msgid "Location ID must contain only digits (0-9)" -msgstr "位置ID只能包含数字 (0-9)" - -msgid "Location ID: " -msgstr "位置ID: " - -msgid "Longitude must be a valid number" -msgstr "经度必须是一个有效的数字" - -msgid "Longitude must be between -180.000000 and 180.000000" -msgstr "经度必须在 -180.000000 到 180.000000 之间" - -msgid "Longitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 123.230000 or -133.000000). Suggested format: " -msgstr "经度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:123.230000 或 -133.000000)。建议格式:" - -msgid "Longitude: " -msgstr "经度: " - -msgid "MAC Address: " -msgstr "MAC地址: " - -msgid "MAC address must be exactly 17 characters long" -msgstr "MAC地址必须是17个字符长" - -msgid "MAC address must be in format XX-XX-XX-XX-XX-XX (uppercase hexadecimal separated by hyphens)" -msgstr "MAC地址格式必须为 XX-XX-XX-XX-XX-XX(大写十六进制,由连字符分隔)" - -msgid "MAC address should match the MAC address part (last 12 characters) in AP Device ID" -msgstr "MAC地址应与 AP设备ID 中的 MAC地址部分(最后12个字符)匹配" - -msgid "MQTT Connection Mode" -msgstr "MQTT连接模式" - -msgid "MQTT Secure Connection Mode" -msgstr "MQTT安全连接模式" - -msgid "MQTT Hostname" -msgstr "MQTT主机名" - -msgid "Mobile AP Latitude" -msgstr "移动AP纬度" - -msgid "Mobile AP Longitude" -msgstr "移动AP经度" - -msgid "Persistent Connection Mode" -msgstr "持久连接模式" - -msgid "RPC failed, trying direct method..." -msgstr "RPC失败,正在尝试直接方法..." - -msgid "RPC failed, trying fallback..." -msgstr "RPC失败,正在尝试备用方法..." - -msgid "Service type code (7-9 digits) must be \"100\" for commercial internet service locations, \"2XX\" for non-commercial locations, or \"3XX\" for WiFi wireless collection terminals" -msgstr "服务类型代码(第7-9位)必须是:商业上网场所为\"100\",非商业场所为\"2XX\",或WiFi无线采集终端为\"3XX\"" - -msgid "The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens)." -msgstr "AP设备的MAC地址。必须为17个字符,格式为 XX-XX-XX-XX-XX-XX(大写,由连字符分隔)。" - -msgid "The hostname of the mqtt." -msgstr "MQTT的主机名。" - -msgid "The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South." -msgstr "纬度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。北纬为正,南纬为负。" - -msgid "The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West." -msgstr "经度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。东经为正,西经为负。" - -msgid "The mode of the authentication server." -msgstr "认证服务器的模式。" - -msgid "The persistent connection mode of the device to auth server." -msgstr "设备到认证服务器的持久连接模式。" - -msgid "The trusted wildcard domains of the gateway" -msgstr "网关信任的通配符域名" - -msgid "The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase)." -msgstr "AP设备的唯一标识符。必须是21个字符:9位厂商代码 + 12位MAC地址(大写)。" - -msgid "The unique identifier of the internet service location." -msgstr "上网服务场所的唯一标识符。" - -msgid "WebSocket Connection Mode" -msgstr "WebSocket连接模式" - -msgid "WebSocket Secure Connection Mode" -msgstr "WebSocket加密连接模式" - -msgid "fields filled successfully." -msgstr "个字段已填充。" - -msgid "✓ Device ID generated: " -msgstr "✓ 设备ID已生成: " - -msgid "✓ Location ID generated: " -msgstr "✓ 位置ID已生成: " - -msgid "✓ Location obtained (fallback): " -msgstr "✓ 已获取位置(备用方法): " - -msgid "✓ Location obtained: " -msgstr "✓ 已获取位置: " - -msgid "✓ WAN MAC address obtained (fallback): " -msgstr "✓ 已获取 WAN MAC 地址(备用方法): " - -msgid "✓ WAN MAC address obtained: " -msgstr "✓ 已获取 WAN MAC 地址: " - -msgid "✗ Cannot generate Device ID due to MAC error" -msgstr "✗ 由于 MAC 错误,无法生成设备 ID" - -msgid "✗ Cannot generate Device ID without MAC address" -msgstr "✗ 没有 MAC 地址,无法生成设备 ID" - -msgid "✗ Error getting WAN MAC address: " -msgstr "✗ 获取 WAN MAC 地址错误: " - -msgid "✗ Error getting location: " -msgstr "✗ 获取位置错误: " - -msgid "✗ Failed to get WAN MAC address: " -msgstr "✗ 获取 WAN MAC 地址失败: " - -msgid "✗ Failed to get location data" -msgstr "✗ 获取位置数据失败" - -msgid "✗ Failed to get location: " -msgstr "✗ 获取位置失败: " - -msgid "✗ Failed to parse location data" -msgstr "✗ 解析位置数据失败" - -msgid "✗ No valid coordinates found" -msgstr "✗ 未找到有效的坐标" - -msgid "✗ RPC call failed, trying fallback..." -msgstr "✗ RPC 调用失败,正在尝试备用方法..." - -msgid " (interface: " -msgstr " (接口: " - -msgid ")" -msgstr ")" - -msgid "Unknown error" -msgstr "未知错误" - -msgid "Unknown" -msgstr "未知" - -msgid "Long Connection Profile" -msgstr "长连接配置" - -msgid "Select which long connection configuration to use. This option is always available regardless of authentication mode." -msgstr "选择使用的长连接配置。该选项在所有认证模式下都可用。" - -msgid "Please create a long connection profile first" -msgstr "请先创建一个长连接配置" - -msgid "Persistent Connection Profiles" -msgstr "持久连接配置" - -msgid "Create one or more long connection profiles for cloud authentication and OpenClaw intelligent control channels." -msgstr "创建长连接配置用于云认证和OpenClaw(龙虾)智能管控通道" - -msgid "Connection Mode" -msgstr "连接模式" - -msgid "The type of persistent connection to the remote management server." -msgstr "到远程管理服务器的持久连接类型。" - -msgid "WebSocket (ws://)" -msgstr "WebSocket (ws://)" - -msgid "WebSocket Secure (wss://)" -msgstr "WebSocket加密 (wss://)" - -msgid "MQTT Secure" -msgstr "MQTT安全" - -msgid "The hostname or IP address of the WebSocket server." -msgstr "WebSocket服务器的主机名或IP地址。" - -msgid "The port of the WebSocket server." -msgstr "WebSocket服务器的端口。" - -msgid "WebSocket Path" -msgstr "WebSocket路径" - -msgid "The URI path for the WebSocket connection." -msgstr "WebSocket连接的URI路径。" - -msgid "MQTT Hostname" -msgstr "MQTT主机名" - -msgid "The hostname or IP address of the MQTT broker." -msgstr "MQTT代理的主机名或IP地址。" - -msgid "The port of the MQTT broker." -msgstr "MQTT代理的端口。" - -msgid "The username for MQTT authentication." -msgstr "MQTT认证的用户名。" - -msgid "The password for MQTT authentication." -msgstr "MQTT认证的密码。" - -msgid "Add Authentication Server" -msgstr "添加认证服务器" - -msgid "Enter a unique name for this authentication server profile." -msgstr "请输入认证服务器配置文件的唯一名称。" - -msgid "Add Long Connection Profile" -msgstr "添加长连接配置" - -msgid "Enter a unique name for this long connection profile." -msgstr "请输入长连接配置文件的唯一名称。" - -msgid "Rename Authentication Server" -msgstr "重命名认证服务器" - -msgid "Enter a new unique name for this authentication server profile." -msgstr "请输入认证服务器配置文件的新名称。" - -msgid "Rename Long Connection Profile" -msgstr "重命名长连接配置" - -msgid "Enter a new unique name for this long connection profile." -msgstr "请输入长连接配置文件的新名称。" - -msgid "Please enter a name." -msgstr "请输入名称。" - -msgid "The name \"%s\" already exists in Auth Server profiles. Please choose a different name." -msgstr "名称\"%s\"已存在于认证服务器配置中,请选择其他名称。" - -msgid "The name \"%s\" already exists in Long Connection profiles. Please choose a different name." -msgstr "名称\"%s\"已存在于长连接配置中,请选择其他名称。" - -msgid "Created new authentication server profile \"%s\"." -msgstr "已创建新的认证服务器配置\"%s\"。" - -msgid "Created new long connection profile \"%s\"." -msgstr "已创建新的长连接配置\"%s\"。" - -msgid "Renamed authentication server profile from \"%s\" to \"%s\"." -msgstr "已将认证服务器配置从\"%s\"重命名为\"%s\"。" - -msgid "Renamed long connection profile from \"%s\" to \"%s\"." -msgstr "已将长连接配置从\"%s\"重命名为\"%s\"。" - -msgid "eBPF Traffic Control & DPI" -msgstr "eBPF 流控与 xDPI" - -msgid "eBPF kernel-level bandwidth control, session audit logging and xDPI L7 application/domain recognition." -msgstr "基于内核级 eBPF 的网络带宽控制、连接会话审计日志与 xDPI 七层应用/域名识别。" - -msgid "General Settings" -msgstr "常规设置" - -msgid "Enable Session Event Logging" -msgstr "启用会话事件日志" - -msgid "Record TCP/UDP session connection events as structured JSON to system log / syslog. (DNS learning and xDPI protocol recognition are always active in background)." -msgstr "将 TCP/UDP 连接建立与销毁等会话事件以结构化 JSON 格式输出至系统日志(DNS 域名学习与 xDPI 协议识别始终在后台常驻运行)。" - -msgid "Settings" -msgstr "设置" - - diff --git a/luci-app-aw-bpf/root/etc/uci-defaults/luci-app-aw-bpf.sh b/luci-app-aw-bpf/root/etc/uci-defaults/luci-app-aw-bpf.sh deleted file mode 100644 index cf3a7cbdd..000000000 --- a/luci-app-aw-bpf/root/etc/uci-defaults/luci-app-aw-bpf.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -[ -f "/etc/config/hostnames" ] || { - echo 'config hostname' > /etc/config/hostnames -} - -exit 0 diff --git a/luci-app-aw-bpf/root/usr/share/luci/menu.d/luci-app-aw-bpf.json b/luci-app-aw-bpf/root/usr/share/luci/menu.d/luci-app-aw-bpf.json deleted file mode 100644 index 3716b9b2a..000000000 --- a/luci-app-aw-bpf/root/usr/share/luci/menu.d/luci-app-aw-bpf.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "admin/qos": { - "title": "QoS", - "order": 60, - "action": { - "type": "firstchild", - "recurse": true - }, - "depends": { - "acl": [ "luci-app-aw-bpf" ] - } - }, - "admin/qos/hosts": { - "title": "Hosts", - "order": 10, - "action": { - "type": "view", - "path": "aw-bpf/display" - }, - "depends": { - "acl": [ "luci-app-aw-bpf" ] - } - }, - "admin/qos/l7": { - "title": "L7 application", - "order": 20, - "action": { - "type": "view", - "path": "aw-bpf/l7" - }, - "depends": { - "acl": [ "luci-app-aw-bpf" ] - } - }, - "admin/qos/settings": { - "title": "Settings", - "order": 30, - "action": { - "type": "view", - "path": "aw-bpf/settings" - }, - "depends": { - "acl": [ "luci-app-aw-bpf" ] - } - } -} diff --git a/luci-app-aw-bpf/root/usr/share/rpcd/acl.d/luci-app-aw-bpf.json b/luci-app-aw-bpf/root/usr/share/rpcd/acl.d/luci-app-aw-bpf.json deleted file mode 100644 index 3df9e8713..000000000 --- a/luci-app-aw-bpf/root/usr/share/rpcd/acl.d/luci-app-aw-bpf.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "luci-app-aw-bpf": { - "description": "Grant access to LuCI app aw-bpf", - "read": { - "file": { - "/usr/bin/aw-bpfctl": [ "exec" ], - "/usr/bin/xdns-ctl": [ "exec" ], - "/usr/bin/awk": [ "exec" ], - "/tmp/dhcp.leases": [ "read" ], - "/proc/net/arp": [ "read" ], - "/etc/xdns/whitelist.txt": [ "read" ] - }, - "uci": [ "hostnames", "network", "aw-bpf" ] - }, - "write": { - "uci": [ "hostnames", "aw-bpf" ] - } - } -} diff --git a/luci-app-openlist2/Makefile b/luci-app-openlist2/Makefile index bf3c17342..357db008a 100644 --- a/luci-app-openlist2/Makefile +++ b/luci-app-openlist2/Makefile @@ -6,11 +6,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-openlist2 -PKG_VERSION:=1.0.3 -PKG_RELEASE:=5 +PKG_VERSION:=1.0.4 +PKG_RELEASE:=6 LUCI_TITLE:=LuCI support for openlist -LUCI_DEPENDS:=+openlist2 +# The virtual provide forces installation of a core package with the helper. +LUCI_DEPENDS:=+openlist2 +openlist2-helper include $(TOPDIR)/feeds/luci/luci.mk diff --git a/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js b/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js index e2954924f..b3fe25006 100644 --- a/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js +++ b/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js @@ -5,8 +5,11 @@ 'require poll'; 'require rpc'; 'require uci'; +'require ui'; 'require view'; +const HELPER = '/usr/libexec/openlist2-helper'; + const callServiceList = rpc.declare({ object: 'service', method: 'list', @@ -25,25 +28,25 @@ const getServiceStatus = () => { }; const getWebInterfaceUrl = (protocol, webport, site_url) => { - const fallbackUrl = `${protocol}//${window.location.hostname}:${webport}/`; const configuredUrl = (site_url || '').trim(); if (configuredUrl) { try { - const url = new URL(configuredUrl, fallbackUrl); + const url = new URL(configuredUrl); if (url.protocol === 'http:' || url.protocol === 'https:') return url.href; } catch (e) { } } - - return fallbackUrl; + return webport ? protocol + '//' + window.location.hostname + ':' + webport + '/' : null; }; const renderStatus = (isRunning, protocol, webport, site_url) => { const status = E('em', {}, E('span', { 'style': `color:${isRunning ? 'green' : 'red'}` }, E('strong', {}, ['OpenList ', isRunning ? _('RUNNING') : _('NOT RUNNING')]))); - if (isRunning && webport) { + if (isRunning && (webport || site_url)) { const buttonUrl = getWebInterfaceUrl(protocol, webport, site_url); + if (!buttonUrl) + return status; const button = E('input', { 'class': 'cbi-button-reload', 'type': 'button', @@ -58,32 +61,24 @@ const renderStatus = (isRunning, protocol, webport, site_url) => { return status; }; -const isSafeLogPath = value => /^\/var\/log\/openlist2(?:[._-][A-Za-z0-9._-]+)?$/.test(value || ''); +const isSafeLogPath = value => !/[\r\n]/.test(value || '') && + /^\/var\/log\/openlist2(?:[._-][A-Za-z0-9._-]+)?$/.test(value || ''); -const isEnabledPort = value => { - const port = (value || '').trim(); - return port !== '' && port !== '-1'; -}; - -const HTTPS_ENABLED_PORT = /^[1-9][0-9]*$/; +const isEnabledPort = value => /^\d+$/.test(String(value || '').trim()) && Number(value) >= 1 && Number(value) <= 65535; const getListenPortValue = (section_id, option, fallback) => { const value = uci.get('openlist2', section_id, option); - return value == null || String(value).trim() === '' ? fallback : value; -}; - -const getHttpsPortValue = (section_id, httpsPortOption) => { - const value = httpsPortOption.formvalue(section_id); - return value == null || String(value).trim() === '' - ? getListenPortValue(section_id, 'listen_https_port', '-1') - : value; -}; - -const validateHttpsRequiredFile = (section_id, httpsPortOption, value, message) => { - if (!HTTPS_ENABLED_PORT.test(String(getHttpsPortValue(section_id, httpsPortOption)).trim())) - return true; - - return (value || '').trim() ? true : message; + if (value != null && String(value).trim() !== '') + return value; + const legacyPort = uci.get('openlist2', section_id, 'port'); + const legacySsl = uci.get('openlist2', section_id, 'ssl'); + if (legacyPort != null || legacySsl != null) { + const tls = ['1', 'true', 'on', 'yes', 'enabled'].includes(legacySsl); + return option === 'listen_https_port' + ? (tls ? legacyPort || '5244' : '-1') + : (tls ? '-1' : legacyPort || '5244'); + } + return fallback; }; const validateListenPort = value => { @@ -136,49 +131,143 @@ const validateCorsOrigins = value => { }; const getEffectiveWebEndpoint = config => { - const httpPort = uci.get(config, '@openlist2[0]', 'listen_http_port') || '5244'; - const httpsPort = uci.get(config, '@openlist2[0]', 'listen_https_port') || '-1'; + const httpPort = getListenPortValue('@openlist2[0]', 'listen_http_port', '5244'); + const httpsPort = getListenPortValue('@openlist2[0]', 'listen_https_port', '-1'); if (isEnabledPort(httpsPort)) - return { protocol: 'https:', port: httpsPort }; + return { protocol: 'https:', port: String(Number(httpsPort)) }; if (isEnabledPort(httpPort)) - return { protocol: 'http:', port: httpPort }; + return { protocol: 'http:', port: String(Number(httpPort)) }; return { protocol: 'http:', port: '' }; }; + +const normalizePath = value => String(value || '').replace(/\/+/g, '/').replace(/\/$/, '') || '/'; +const containsPath = (parent, child) => child === parent || child.startsWith(parent + '/'); +const broadDirectories = new Set(['/', '/bin', '/boot', '/dev', '/etc', '/home', '/lib', '/lib64', '/media', '/mnt', '/opt', '/overlay', '/proc', '/root', '/rom', '/run', '/sbin', '/srv', '/sys', '/tmp', '/usr', '/var', '/www', '/tmp/log', '/tmp/run']); +const isBroadDirectory = path => broadDirectories.has(path) || + /^\/(?:usr|bin|sbin|lib|lib64|dev|proc|sys|rom|overlay|www)\//.test(path) || + /^\/(?:etc\/(?:config|dropbear|ssl)|tmp\/log)(?:\/|$)/.test(path); + +const validateAbsolutePath = (value, required) => { + const path = String(value || ''); + if (!path && !required) + return true; + if (!path.startsWith('/') || /[\x00-\x1f\x7f]/.test(path) || /\/\.{1,2}(?:\/|$)/.test(path)) + return _('Use an absolute path without control characters or dot segments.'); + return true; +}; + +const passiveRanges = value => (Array.isArray(value) ? value : [value || '']) + .flatMap(item => String(item).split(/[,\s]+/)).filter(Boolean); + +const validatePassivePorts = value => { + for (const range of passiveRanges(value)) { + if (!/^\d+(?:-\d+)?$/.test(range)) + return _('Use passive ports or ranges from 1024 to 65535.'); + const [first, last = first] = range.split('-').map(Number); + if (first < 1024 || last > 65535 || first > last) + return _('Use passive ports or ranges from 1024 to 65535.'); + } + return true; +}; + +const backendUrl = route => { + const endpoint = getEffectiveWebEndpoint('openlist2'); + const base = getWebInterfaceUrl(endpoint.protocol, endpoint.port, + uci.get('openlist2', '@openlist2[0]', 'site_url')); + if (!base) + return null; + const url = new URL(base); + url.pathname = url.pathname.replace(/\/$/, '') + '/' + route.replace(/^\//, ''); + url.search = ''; + url.hash = ''; + return url.href; +}; + +const pollServiceStatus = () => getServiceStatus().then(running => { + const node = document.getElementById('service_status'); + const endpoint = L.hasViewPermission() ? getEffectiveWebEndpoint('openlist2') : { protocol: 'http:', port: '' }; + const site = L.hasViewPermission() ? uci.get('openlist2', '@openlist2[0]', 'site_url') : ''; + if (node) + dom.content(node, renderStatus(running, endpoint.protocol, endpoint.port, site)); +}); + +const renderServiceSection = () => { + poll.add(pollServiceStatus); + return E('div', { 'class': 'cbi-section', 'id': 'status_bar' }, + E('p', { 'id': 'service_status' }, _('Collecting data...'))); +}; + +const copyPassword = async value => { + if (typeof navigator !== 'undefined' && navigator.clipboard) { + try { + await navigator.clipboard.writeText(value); + return true; + } catch (e) { } + } + const field = E('textarea', { 'style': 'position:fixed;left:-10000px' }, value); + document.body.appendChild(field); + try { + field.select(); + return document.execCommand('copy') === true; + } catch (e) { + return false; + } finally { + document.body.removeChild(field); + } +}; + return view.extend({ load() { - return Promise.all([ - uci.load('openlist2') - ]); + // UCI contains credentials; readers may view status and bounded logs only. + return L.hasViewPermission() ? uci.load('openlist2') : Promise.resolve(); }, - async handleResetPassword(data) { - const data_dir = uci.get(data[0], '@openlist2[0]', 'data_dir') || '/etc/openlist2'; + async handleResetPassword() { + if (!L.hasViewPermission()) + return; try { - const newpassword = await fs.exec('/usr/bin/openlist2', ['admin', 'random', '--data', data_dir]); - const new_password = newpassword.stdout.match(/password:\s*(\S+)/)[1]; + const result = await fs.exec(HELPER, ['password-reset']); + const output = (result.stdout || '').replace(/\u001b\[[0-9;]*m/g, ''); + const username = output.match(/^username:\s*(.+)$/m); + const password = output.match(/^password:\s*(\S+)\s*$/m); + if (result.code !== 0 || !username || !password) + throw new Error((result.stderr || _('The password reset did not return a username and password.')).trim()); - const textArea = document.createElement('textarea'); - textArea.value = new_password; - document.body.appendChild(textArea); - textArea.select(); - document.execCommand('copy'); - document.body.removeChild(textArea); - alert(`${_('Username:')}admin\n${_('New Password:')}${new_password}\n\n${_('New password has been copied to clipboard.')}`); + const newPassword = password[1]; + const message = E('p', { 'role': 'status' }, _('Copy the new password before closing this dialog.')); + const copy = async () => { + message.textContent = await copyPassword(newPassword) + ? _('New password has been copied to clipboard.') + : _('Automatic copy failed. Select and copy the password manually.'); + }; + ui.showModal(_('Password reset'), [ + E('p', {}, _('Username:') + ' ' + username[1].trim()), + E('label', {}, _('New Password:')), + E('input', { 'type': 'text', 'readonly': 'readonly', 'value': newPassword, 'style': 'width:100%' }), + message, + E('div', { 'class': 'right' }, [ + E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, copy) }, _('Copy password')), + ' ', + E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Close')) + ]) + ]); + await copy(); } catch (error) { - console.error('Failed to reset password: ', error); + ui.addNotification(null, E('p', _('Unable to reset the password: %s').format(error.message))); } }, - render(data) { - let m, s, o, httpsPortOption; - const endpoint = getEffectiveWebEndpoint(data[0]); - const webport = endpoint.port; - const protocol = endpoint.protocol; - const site_url = uci.get(data[0], '@openlist2[0]', 'site_url') || ''; + render() { + if (!L.hasViewPermission()) + return E('div', {}, [ + renderServiceSection(), + E('p', {}, _('Configuration contains credentials and is available only to users with write access.')) + ]); + let m, s, o; m = new form.Map('openlist2', _('OpenList'), _('A file list program that supports multiple storage.') + '
' + @@ -188,21 +277,28 @@ return view.extend({ s.anonymous = true; s.addremove = false; - s.render = () => { - poll.add(() => { - return L.resolveDefault(getServiceStatus()).then(res => { - const view = document.getElementById('service_status'); - if (view) - dom.content(view, renderStatus(res, protocol, webport, site_url)); - }); - }); - - return E('div', { class: 'cbi-section', id: 'status_bar' }, [ - E('p', { id: 'service_status' }, _('Collecting data...')) - ]); - }; + s.render = renderServiceSection; s = m.section(form.NamedSection, '@openlist2[0]', 'openlist2'); + const fields = {}; + const addOption = (tab, type, name, ...args) => { + const option = s.taboption(tab, type, name, ...args); + fields[name] = option; + return option; + }; + const fieldValue = (section_id, name, fallback = '') => { + const value = fields[name] && fields[name].formvalue(section_id); + return value == null ? uci.get('openlist2', section_id, name) ?? fields[name]?.default ?? fallback : value; + }; + const addBackendLink = (tab, name, route, label, description) => { + const option = addOption(tab, form.DummyValue, name, label, description); + option.renderWidget = () => { + const url = backendUrl(route); + return url ? E('a', { 'href': url, 'target': '_blank', 'rel': 'noopener noreferrer' }, label) + : E('span', {}, _('Configure a web port or Site URL to open the management page.')); + }; + return option; + }; s.tab('basic', _('Basic Settings')); s.tab('global', _('Global Settings')); @@ -210,7 +306,8 @@ return view.extend({ s.tab('database', _('Database')); s.tab('search', _('Search')); s.tab('scheme', _('Web Protocol')); - s.tab('tasks', _('Task threads')); + s.tab('tasks', _('Task threads'), + _('Worker counts below only initialize missing settings. After the first start, change worker counts and speed limits in OpenList Management > Settings > Traffic. Upload and decompression-upload tasks do not support persistence.')); s.tab('cors', _('CORS Settings')); s.tab('s3', _('Object Storage')); s.tab('ftp', _('FTP')); @@ -218,103 +315,108 @@ return view.extend({ s.tab('mcp', _('MCP')); // init - o = s.taboption('basic', form.Flag, 'enabled', _('Enabled')); + o = addOption('basic', form.Flag, 'enabled', _('Enabled')); o.default = o.disabled; o.rmempty = false; - o = s.taboption('basic', form.Flag, 'debug', _('Debug logging'), + o = addOption('basic', form.Flag, 'debug', _('Debug logging'), _('Pass --debug to OpenList and send stderr to procd logs.')); o.rmempty = false; - o = s.taboption('basic', form.Value, 'delayed_start', _('Delayed Start (seconds)')); + o = addOption('basic', form.Value, 'delayed_start', _('Delayed Start (seconds)')); o.datatype = 'uinteger'; o.default = '0'; o.rmempty = false; - o = s.taboption('basic', form.Flag, 'allow_wan', _('Open firewall port')); + o = addOption('basic', form.Flag, 'allow_wan', _('Open firewall port')); o.rmempty = false; - o = s.taboption('basic', form.Value, 'data_dir', _('Data directory')); + o = addOption('basic', form.Value, 'data_dir', _('Data directory'), + _('Changing this path does not move data. Stop OpenList, back up and move the complete data directory, then apply the new path.')); o.default = '/etc/openlist2'; + o.rmempty = false; - o = s.taboption('basic', form.Value, 'temp_dir', _('Cache directory')); + o = addOption('basic', form.Value, 'temp_dir', _('Cache directory'), + _('OpenList clears this directory on startup. Use a dedicated empty subdirectory. Never select a disk mount root or a directory containing files you want to keep.')); o.default = '/tmp/openlist2'; o.rmempty = false; - o = s.taboption('basic', form.Button, '_newpassword', _('Reset Password'), - _('Generate a new random password.')); + o = addOption('basic', form.Button, '_newpassword', _('Reset Password'), + _('Generate a new random password using the saved and applied data directory. Start OpenList once before using this action.')); o.inputtitle = _('Reset Password'); o.inputstyle = 'apply'; - o.onclick = L.bind(this.handleResetPassword, this, data); + o.onclick = ui.createHandlerFn(this, 'handleResetPassword'); // global - o = s.taboption('global', form.Flag, 'force', _('Force read config'), + o = addOption('global', form.Flag, 'force', _('Force read config'), _('Setting this to true will force the program to read the configuration file, ignoring environment variables.')); - o.default = true; + o.default = '1'; o.rmempty = false; - o = s.taboption('global', form.Value, 'site_url', _('Site URL'), + o = addOption('global', form.Value, 'site_url', _('Site URL'), _('When the web is reverse proxied to a subdirectory, this option must be filled out to ensure proper functioning of the web. Do not include \'/\' at the end of the URL')); o.validate = function(section_id, value) { return validateSiteUrl(value); }; - o = s.taboption('global', form.Value, 'cdn', _('CDN URL')); + o = addOption('global', form.Value, 'cdn', _('CDN URL')); o.default = ''; - o = s.taboption('global', form.Value, 'jwt_secret', _('JWT Key')); + o = addOption('global', form.Value, 'jwt_secret', _('JWT Key')); + o.password = true; o.default = ''; - o = s.taboption('global', form.Value, 'token_expires_in', _('Login Validity Period (hours)')); + o = addOption('global', form.Value, 'token_expires_in', _('Login Validity Period (hours)')); o.datatype = 'uinteger'; o.default = '48'; o.rmempty = false; - o = s.taboption('global', form.Value, 'proxy_address', _('Proxy address'), + o = addOption('global', form.Value, 'proxy_address', _('Proxy address'), _('HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList outbound requests.')); + o.password = true; o.default = ''; - o = s.taboption('global', form.Value, 'auto_memory_limit', _('Auto memory limit (MB)'), + o = addOption('global', form.Value, 'auto_memory_limit', _('Auto memory limit (MB)'), _('0 disables the automatic memory limit. The upstream default is 4 MB.')); o.default = '4'; o.datatype = 'uinteger'; o.rmempty = false; - o = s.taboption('global', form.Value, 'min_free_memory', _('Minimum free memory (MB)'), + o = addOption('global', form.Value, 'min_free_memory', _('Minimum free memory (MB)'), _('Values below 16 let OpenList calculate a default; negative values disable memory cache.')); o.default = '0'; o.datatype = 'integer'; o.rmempty = false; - o = s.taboption('global', form.Value, 'max_block_limit', _('Maximum block size (MB)'), + o = addOption('global', form.Value, 'max_block_limit', _('Maximum block size (MB)'), _('Values below 4 let OpenList calculate a default.')); o.default = '0'; o.datatype = 'uinteger'; o.rmempty = false; - o = s.taboption('global', form.Value, 'max_connections', _('Max Connections'), + o = addOption('global', form.Value, 'max_connections', _('Max Connections'), _('0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device')); o.default = '0'; o.datatype = 'uinteger'; o.rmempty = false; - o = s.taboption('global', form.Value, 'max_concurrency', _('Max concurrency of local proxies'), + o = addOption('global', form.Value, 'max_concurrency', _('Max concurrency of local proxies'), _('0 is unlimited, Limit the maximum concurrency of local agents. The default value is 64')); o.default = '64'; o.datatype = 'uinteger'; o.rmempty = false; - o = s.taboption('global', form.Flag, 'tls_insecure_skip_verify', _('Disable TLS Verify'), + o = addOption('global', form.Flag, 'tls_insecure_skip_verify', _('Disable TLS Verify'), _('Skip remote TLS certificate verification (not recommended).')); - o.default = false; + o.default = '0'; o.rmempty = false; // Logs - o = s.taboption('log', form.Flag, 'log', _('Enable Logs')); - o.default = 1; + o = addOption('log', form.Flag, 'log', _('Enable Logs')); + o.default = '1'; o.rmempty = false; - o = s.taboption('log', form.Value, 'log_path', _('Log path')); + o = addOption('log', form.Value, 'log_path', _('Log path')); o.default = '/var/log/openlist2.log'; o.rmempty = false; o.depends('log', '1'); @@ -325,104 +427,114 @@ return view.extend({ return _('Log path must be /var/log/openlist2* without subdirectories.'); }; - o = s.taboption('log', form.Value, 'log_max_size', _('Max Size (MB)')); + o = addOption('log', form.Value, 'log_max_size', _('Max Size (MB)')); o.datatype = 'uinteger'; - o.default = '50'; + o.default = '1'; o.rmempty = false; o.depends('log', '1'); - o = s.taboption('log', form.Value, 'log_max_backups', _('Max backups')); + o = addOption('log', form.Value, 'log_max_backups', _('Max backups')); o.datatype = 'uinteger'; - o.default = '30'; + o.default = '3'; o.rmempty = false; o.depends('log', '1'); - o = s.taboption('log', form.Value, 'log_max_age', _('Max age')); + o = addOption('log', form.Value, 'log_max_age', _('Max age')); o.datatype = 'uinteger'; o.default = '28'; o.rmempty = false; o.depends('log', '1'); - o = s.taboption('log', form.Flag, 'log_compress', _('Log Compress')); - o.default = 'false'; + o = addOption('log', form.Flag, 'log_compress', _('Log Compress')); + o.default = '0'; o.rmempty = false; o.depends('log', '1'); - o = s.taboption('log', form.Flag, 'log_filter', _('Enable common log filters'), + o = addOption('log', form.Flag, 'log_filter', _('Enable common log filters'), _('Filter noisy access logs such as health checks, HEAD requests and WebDAV PROPFIND.')); o.rmempty = false; o.depends('log', '1'); - o = s.taboption('log', form.Value, 'log_filter_cidr', _('Custom log filter CIDR')); + o = addOption('log', form.Value, 'log_filter_cidr', _('Custom log filter CIDR')); o.depends('log_filter', '1'); - o = s.taboption('log', form.Value, 'log_filter_path', _('Custom log filter path')); + o = addOption('log', form.Value, 'log_filter_path', _('Custom log filter path')); o.depends('log_filter', '1'); - o = s.taboption('log', form.Value, 'log_filter_method', _('Custom log filter method')); + o = addOption('log', form.Value, 'log_filter_method', _('Custom log filter method')); o.depends('log_filter', '1'); // database - o = s.taboption('database', form.ListValue, 'database_type', _('Database Type')); + o = addOption('database', form.ListValue, 'database_type', _('Database Type')); o.default = 'sqlite3'; o.value('sqlite3', _('SQLite')); o.value('mysql', _('MySQL')); o.value('postgres', _('PostgreSQL')); - o = s.taboption('database', form.Value, 'mysql_host', _('Database Host')); + o = addOption('database', form.Value, 'mysql_host', _('Database Host')); o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_port', _('Database Port'), + o = addOption('database', form.Value, 'mysql_port', _('Database Port'), _('Use 0 to apply the usual default for the selected database: 3306 for MySQL, 5432 for PostgreSQL.')); o.datatype = 'port'; o.default = '0'; o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_username', _('Database Username')); + o = addOption('database', form.Value, 'mysql_username', _('Database Username')); o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_password', _('Database Password')); + o = addOption('database', form.Value, 'mysql_password', _('Database Password')); + o.password = true; o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_database', _('Database Name')); + o = addOption('database', form.Value, 'mysql_database', _('Database Name')); o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_table_prefix', _('Database Table Prefix')); + o = addOption('database', form.Value, 'mysql_table_prefix', _('Database Table Prefix')); o.default = 'x_'; o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_ssl_mode', _('Database SSL Mode')); + o = addOption('database', form.Value, 'mysql_ssl_mode', _('Database SSL Mode')); o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('database', form.Value, 'mysql_dsn', _('Database DSN')); + o = addOption('database', form.Value, 'mysql_dsn', _('Database DSN')); + o.password = true; o.depends('database_type', 'mysql'); o.depends('database_type', 'postgres'); - o = s.taboption('search', form.Value, 'meilisearch_host', _('Meilisearch Host')); + o = addOption('search', form.Value, 'meilisearch_host', _('Meilisearch Host')); o.default = 'http://localhost:7700'; o.rmempty = false; - o = s.taboption('search', form.Value, 'meilisearch_api_key', _('Meilisearch API Key')); + o = addOption('search', form.Value, 'meilisearch_api_key', _('Meilisearch API Key')); o.password = true; - o = s.taboption('search', form.Value, 'meilisearch_index', _('Meilisearch Index')); + o = addOption('search', form.Value, 'meilisearch_index', _('Meilisearch Index')); o.default = 'openlist'; o.rmempty = false; + o = addOption('search', form.Value, 'bleve_dir', _('Bleve index directory'), + _('Empty uses the bleve subdirectory of the data directory. Keep the index separate from cache and frontend files.')); + o.default = ''; + + o = addOption('global', form.Value, 'dist_dir', _('External frontend directory'), + _('Optional directory containing index.html from a matching OpenList frontend. Empty uses the bundled frontend. Restart OpenList after changing it.')); + o.default = ''; + // scheme - o = s.taboption('scheme', form.Value, 'listen_addr', _('Listen address')); + o = addOption('scheme', form.Value, 'listen_addr', _('Listen address')); o.default = '0.0.0.0'; o.datatype = 'ipaddr'; o.rmempty = false; - o = s.taboption('scheme', form.Value, 'listen_http_port', _('HTTP listen port'), + o = addOption('scheme', form.Value, 'listen_http_port', _('HTTP listen port'), _('The upstream default is 5244. Set to -1 to disable HTTP.')); o.datatype = 'integer'; o.default = '5244'; @@ -432,7 +544,7 @@ return view.extend({ return validateListenPort(value); }; - httpsPortOption = o = s.taboption('scheme', form.Value, 'listen_https_port', _('HTTPS listen port'), + o = addOption('scheme', form.Value, 'listen_https_port', _('HTTPS listen port'), _('The upstream default is -1 (disabled). Set a valid port number to enable HTTPS.')); o.datatype = 'integer'; o.default = '-1'; @@ -442,132 +554,122 @@ return view.extend({ return validateListenPort(value); }; - o = s.taboption('scheme', form.Flag, 'force_https', _('Force HTTPS')); + o = addOption('scheme', form.Flag, 'force_https', _('Force HTTPS')); o.rmempty = false; - o = s.taboption('scheme', form.Value, 'ssl_cert', _('SSL cert'), + o = addOption('scheme', form.Value, 'ssl_cert', _('SSL cert'), _('SSL certificate file path')); - o.validate = function(section_id, value) { - return validateHttpsRequiredFile(section_id, httpsPortOption, value, - _('SSL certificate file path is required when HTTPS is enabled.')); - }; - o = s.taboption('scheme', form.Value, 'ssl_key', _('SSL key'), + o = addOption('scheme', form.Value, 'ssl_key', _('SSL key'), _('SSL key file path')); - o.validate = function(section_id, value) { - return validateHttpsRequiredFile(section_id, httpsPortOption, value, - _('SSL key file path is required when HTTPS is enabled.')); - }; - o = s.taboption('scheme', form.Value, 'listen_unix_file', _('Unix socket file')); + o = addOption('scheme', form.Value, 'listen_unix_file', _('Unix socket file')); - o = s.taboption('scheme', form.Value, 'listen_unix_file_perm', _('Unix socket permission')); + o = addOption('scheme', form.Value, 'listen_unix_file_perm', _('Unix socket permission')); - o = s.taboption('scheme', form.Flag, 'listen_enable_h2c', _('Enable H2C'), + o = addOption('scheme', form.Flag, 'listen_enable_h2c', _('Enable H2C'), _('Enable cleartext HTTP/2 for reverse proxies that use grpc_pass.')); o.rmempty = false; - o = s.taboption('scheme', form.Flag, 'listen_enable_h3', _('Enable HTTP/3/QUIC'), + o = addOption('scheme', form.Flag, 'listen_enable_h3', _('Enable HTTP/3/QUIC'), _('Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and certificate files must be configured.')); o.rmempty = false; // tasks - o = s.taboption('tasks', form.Value, 'download_workers', _('Download Workers')); + addBackendLink('tasks', '_traffic', '@manage/settings/traffic', _('Open traffic settings'), + _('Use the OpenList backend to change the effective worker counts and transfer speed limits.')); + o = addOption('tasks', form.Value, 'download_workers', _('Download Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'download_max_retry', _('Download Max Retry')); + o = addOption('tasks', form.Value, 'download_max_retry', _('Download Max Retry')); o.datatype = 'uinteger'; o.default = '1'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'download_task_persistant', _('Download Task Persistence')); + o = addOption('tasks', form.Flag, 'download_task_persistant', _('Download Task Persistence')); o.rmempty = false; - o = s.taboption('tasks', form.Value, 'transfer_workers', _('Transfer Workers')); + o = addOption('tasks', form.Value, 'transfer_workers', _('Transfer Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'transfer_max_retry', _('Transfer Max Retry')); + o = addOption('tasks', form.Value, 'transfer_max_retry', _('Transfer Max Retry')); o.datatype = 'uinteger'; o.default = '2'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'transfer_task_persistant', _('Transfer Task Persistence')); + o = addOption('tasks', form.Flag, 'transfer_task_persistant', _('Transfer Task Persistence')); o.rmempty = false; - o = s.taboption('tasks', form.Value, 'upload_workers', _('Upload Workers')); + o = addOption('tasks', form.Value, 'upload_workers', _('Upload Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'upload_max_retry', _('Upload Max Retry')); + o = addOption('tasks', form.Value, 'upload_max_retry', _('Upload Max Retry')); o.datatype = 'uinteger'; o.default = '0'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'upload_task_persistant', _('Upload Task Persistence')); - o.rmempty = false; - o = s.taboption('tasks', form.Value, 'copy_workers', _('Copy Workers')); + o = addOption('tasks', form.Value, 'copy_workers', _('Copy Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'copy_max_retry', _('Copy Max Retry')); + o = addOption('tasks', form.Value, 'copy_max_retry', _('Copy Max Retry')); o.datatype = 'uinteger'; o.default = '2'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'copy_task_persistant', _('Copy Task Persistence')); + o = addOption('tasks', form.Flag, 'copy_task_persistant', _('Copy Task Persistence')); o.rmempty = false; - o = s.taboption('tasks', form.Value, 'move_workers', _('Move Workers')); + o = addOption('tasks', form.Value, 'move_workers', _('Move Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'move_max_retry', _('Move Max Retry')); + o = addOption('tasks', form.Value, 'move_max_retry', _('Move Max Retry')); o.datatype = 'uinteger'; o.default = '2'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'move_task_persistant', _('Move Task Persistence')); + o = addOption('tasks', form.Flag, 'move_task_persistant', _('Move Task Persistence')); o.rmempty = false; - o = s.taboption('tasks', form.Value, 'decompress_workers', _('Decompress Workers')); + o = addOption('tasks', form.Value, 'decompress_workers', _('Decompress Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'decompress_max_retry', _('Decompress Max Retry')); + o = addOption('tasks', form.Value, 'decompress_max_retry', _('Decompress Max Retry')); o.datatype = 'uinteger'; o.default = '2'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'decompress_task_persistant', _('Decompress Task Persistence')); + o = addOption('tasks', form.Flag, 'decompress_task_persistant', _('Decompress Task Persistence')); o.rmempty = false; - o = s.taboption('tasks', form.Value, 'decompress_upload_workers', _('Decompress Upload Workers')); + o = addOption('tasks', form.Value, 'decompress_upload_workers', _('Decompress Upload Workers (initial)')); o.datatype = 'uinteger'; o.default = '5'; o.rmempty = false; - o = s.taboption('tasks', form.Value, 'decompress_upload_max_retry', _('Decompress Upload Max Retry')); + o = addOption('tasks', form.Value, 'decompress_upload_max_retry', _('Decompress Upload Max Retry')); o.datatype = 'uinteger'; o.default = '2'; o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'decompress_upload_task_persistant', _('Decompress Upload Task Persistence')); - o.rmempty = false; - o = s.taboption('tasks', form.Flag, 'allow_retry_canceled', _('Allow retry canceled tasks')); + o = addOption('tasks', form.Flag, 'allow_retry_canceled', _('Allow retry canceled tasks')); o.rmempty = false; // cors - o = s.taboption('cors', form.Value, 'cors_allow_origins', _('Allow Origins'), + o = addOption('cors', form.Value, 'cors_allow_origins', _('Allow Origins'), _('Comma-separated list. Use * to allow any value.')); o.default = '*'; o.rmempty = false; @@ -575,83 +677,190 @@ return view.extend({ return validateCorsOrigins(value); }; - o = s.taboption('cors', form.Value, 'cors_allow_methods', _('Allow Methods'), + o = addOption('cors', form.Value, 'cors_allow_methods', _('Allow Methods'), _('Comma-separated list. Use * to allow any value.')); o.default = '*'; o.rmempty = false; - o = s.taboption('cors', form.Value, 'cors_allow_headers', _('Allow Headers'), + o = addOption('cors', form.Value, 'cors_allow_headers', _('Allow Headers'), _('Comma-separated list. Use * to allow any value.')); o.default = '*'; o.rmempty = false; // s3 - o = s.taboption('s3', form.Flag, 's3', _('Enabled S3')); + addBackendLink('s3', '_s3_settings', '@manage/settings/s3', _('Open S3 management'), + _('Generate the S3 access key and secret in OpenList settings, then configure bucket mappings. Restart OpenList after changing credentials.')); + o = addOption('s3', form.Flag, 's3', _('Enabled S3')); o.rmempty = false; - o = s.taboption('s3', form.Value, 's3_port', _('Port')); + o = addOption('s3', form.Value, 's3_port', _('Port')); o.datatype = 'and(port,min(1))'; o.default = 5246; o.rmempty = false; - o = s.taboption('s3', form.Flag, 's3_ssl', _('Enable SSL')); + o = addOption('s3', form.Flag, 's3_ssl', _('Enable SSL')); o.rmempty = false; // ftp - o = s.taboption('ftp', form.Flag, 'ftp', _('Enabled FTP')); + addBackendLink('ftp', '_ftp_settings', '@manage/settings/ftp', _('Open FTP settings'), + _('Configure the public host and passive port mapping in OpenList. Restart the service after changing FTP settings.')); + o = addOption('ftp', form.DynamicList, 'ftp_pasv_ports', _('FTP passive firewall ports'), + _('Ports or ranges to allow from WAN, for example 50000-50100. They must match the listening ports in OpenList passive port mapping. Empty means passive ports must be allowed manually.')); + o.placeholder = '50000-50100'; + o.depends({ ftp: '1', allow_wan: '1' }); + o = addOption('ftp', form.Flag, 'ftp', _('Enabled FTP')); o.rmempty = false; - o = s.taboption('ftp', form.Value, 'ftp_port', _('FTP Port')); + o = addOption('ftp', form.Value, 'ftp_port', _('FTP Port')); o.datatype = 'and(port,min(1))'; o.default = 5221; o.rmempty = false; - o = s.taboption('ftp', form.Value, 'find_pasv_port_attempts', _('Max retries on port conflict during passive transfer')); + o = addOption('ftp', form.Value, 'find_pasv_port_attempts', _('Max retries on port conflict during passive transfer')); o.datatype = 'uinteger'; o.default = '50'; o.rmempty = false; - o = s.taboption('ftp', form.Flag, 'active_transfer_port_non_20', _('Enable non-20 port for active transfer')); + o = addOption('ftp', form.Flag, 'active_transfer_port_non_20', _('Enable non-20 port for active transfer')); o.rmempty = false; - o = s.taboption('ftp', form.Value, 'idle_timeout', _('Client idle timeout (seconds)')); + o = addOption('ftp', form.Value, 'idle_timeout', _('Client idle timeout (seconds)')); o.datatype = 'uinteger'; o.default = '900'; o.rmempty = false; - o = s.taboption('ftp', form.Value, 'connection_timeout', _('Connection timeout (seconds)')); + o = addOption('ftp', form.Value, 'connection_timeout', _('Connection timeout (seconds)')); o.datatype = 'uinteger'; o.default = '30'; o.rmempty = false; - o = s.taboption('ftp', form.Flag, 'disable_active_mode', _('Disable active transfer mode')); + o = addOption('ftp', form.Flag, 'disable_active_mode', _('Disable active transfer mode')); o.rmempty = false; - o = s.taboption('ftp', form.Flag, 'default_transfer_binary', _('Enable binary transfer mode')); + o = addOption('ftp', form.Flag, 'default_transfer_binary', _('Enable binary transfer mode')); o.rmempty = false; - o = s.taboption('ftp', form.Flag, 'enable_active_conn_ip_check', _('Client IP check in active transfer mode')); + o = addOption('ftp', form.Flag, 'enable_active_conn_ip_check', _('Client IP check in active transfer mode')); o.default = '1'; o.rmempty = false; - o = s.taboption('ftp', form.Flag, 'enable_pasv_conn_ip_check', _('Client IP check in passive transfer mode')); + o = addOption('ftp', form.Flag, 'enable_pasv_conn_ip_check', _('Client IP check in passive transfer mode')); o.default = '1'; o.rmempty = false; // sftp - o = s.taboption('sftp', form.Flag, 'sftp', _('Enabled SFTP')); + o = addOption('sftp', form.Flag, 'sftp', _('Enabled SFTP')); o.rmempty = false; - o = s.taboption('sftp', form.Value, 'sftp_port', _('SFTP Port')); + o = addOption('sftp', form.Value, 'sftp_port', _('SFTP Port')); o.datatype = 'and(port,min(1))'; o.default = 5222; o.rmempty = false; // mcp - o = s.taboption('mcp', form.Flag, 'mcp', _('Enabled MCP'), + o = addOption('mcp', form.Flag, 'mcp', _('Enabled MCP'), _('Enable MCP (Model Context Protocol) server.')); o.rmempty = false; + + o = addOption('mcp', form.DummyValue, '_mcp_endpoint', _('MCP endpoint'), + _('Use Streamable HTTP with Authorization: TOKEN, without a Bearer prefix. Use an OpenList user login token; retain MCP-Session-Id for subsequent requests.')); + o.depends('mcp', '1'); + o.renderWidget = () => E('div', {}, [ + E('code', {}, backendUrl('mcp') || _('Configure a web port or Site URL.')), + E('p', {}, E('a', { 'href': 'https://doc.oplist.org/guide/advanced/mcp', 'target': '_blank', 'rel': 'noopener noreferrer' }, _('MCP documentation'))) + ]); + + const validateDirectories = (section_id, changed, value) => { + const required = changed === 'data_dir' || changed === 'temp_dir'; + const valid = validateAbsolutePath(value, required); + if (valid !== true) + return valid; + const get = (name, fallback) => normalizePath(name === changed ? value || fallback : fieldValue(section_id, name, fallback) || fallback); + const data = get('data_dir', '/etc/openlist2'); + const cache = get('temp_dir', '/tmp/openlist2'); + const index = get('bleve_dir', data + '/bleve'); + const distValue = changed === 'dist_dir' ? value : fieldValue(section_id, 'dist_dir'); + const dist = distValue ? normalizePath(distValue) : ''; + for (const path of [data, cache, index, dist].filter(Boolean)) + if (isBroadDirectory(path)) + return _('Use a dedicated subdirectory, not a system directory or disk mount root.'); + if (/^\/(?:mnt|media)\/[^/]+$/.test(cache)) + return _('Use a cache subdirectory below the disk mount.'); + if (containsPath(cache, data) || containsPath(index, data) || + containsPath(cache, index) || containsPath(index, cache)) + return _('Cache and index directories must be separate and must not contain the data directory.'); + if (dist && (containsPath(dist, data) || containsPath(dist, cache) || + containsPath(cache, dist) || containsPath(dist, index) || containsPath(index, dist))) + return _('Frontend files must be separate from private data, cache and index files.'); + return true; + }; + for (const name of ['data_dir', 'temp_dir', 'bleve_dir', 'dist_dir']) + fields[name].validate = (section_id, value) => validateDirectories(section_id, name, value); + + const tlsRequired = section_id => isEnabledPort(fieldValue(section_id, 'listen_https_port', '-1')) || + (fieldValue(section_id, 's3') === '1' && fieldValue(section_id, 's3_ssl') === '1'); + for (const name of ['ssl_cert', 'ssl_key']) { + fields[name].validate = (section_id, value) => { + if (tlsRequired(section_id) && !String(value || '').trim()) + return _('Certificate and key paths are required for HTTPS or S3 SSL.'); + return validateAbsolutePath(value, false); + }; + } + for (const name of ['force_https', 'listen_enable_h3']) + fields[name].validate = (section_id, value) => value !== '1' || isEnabledPort(fieldValue(section_id, 'listen_https_port', '-1')) + ? true : _('Force HTTPS and HTTP/3 require an enabled HTTPS port.'); + fields.s3_ssl.validate = (section_id, value) => value !== '1' || fieldValue(section_id, 's3') !== '1' || + (fieldValue(section_id, 'ssl_cert').trim() && fieldValue(section_id, 'ssl_key').trim()) + ? true : _('Certificate and key paths are required for HTTPS or S3 SSL.'); + fields.listen_unix_file.validate = (section_id, value) => validateAbsolutePath(value, false); + fields.listen_unix_file_perm.validate = (section_id, value) => !value || /^[0-7]{3,4}$/.test(value) + ? true : _('Use 3 or 4 octal digits, for example 660 or 0660.'); + fields.log_max_size.datatype = 'and(uinteger,min(1))'; + + const validatePorts = (section_id, changed, value) => { + const get = name => name === changed ? value : fieldValue(section_id, name, + name === 'listen_http_port' ? '5244' : name === 'listen_https_port' ? '-1' : ''); + const names = ['listen_http_port', 'listen_https_port']; + if (fieldValue(section_id, 's3') === '1') names.push('s3_port'); + if (fieldValue(section_id, 'ftp') === '1') names.push('ftp_port'); + if (fieldValue(section_id, 'sftp') === '1') names.push('sftp_port'); + const seen = new Set(); + const usePassive = changed === 'ftp_pasv_ports' || + (fieldValue(section_id, 'ftp') === '1' && fieldValue(section_id, 'allow_wan') === '1'); + const passive = usePassive ? passiveRanges(changed === 'ftp_pasv_ports' ? value : fieldValue(section_id, 'ftp_pasv_ports')) : []; + const passiveValid = validatePassivePorts(passive); + if (passiveValid !== true) + return passiveValid; + for (const name of names) { + const candidate = String(get(name)).trim(); + const valid = validateListenPort(candidate); + if (valid !== true) + return valid; + if (candidate === '-1') + continue; + const port = Number(candidate); + if (seen.has(port)) + return _('Enabled services cannot share TCP port %s.').format(port); + seen.add(port); + if (fieldValue(section_id, 'ftp') === '1') + for (const range of passive) { + const [first, last = first] = range.split('-').map(Number); + if (port >= first && port <= last) + return _('FTP passive ports must not overlap service port %s.').format(port); + } + } + if (!isEnabledPort(get('listen_https_port')) && + (fieldValue(section_id, 'force_https') === '1' || fieldValue(section_id, 'listen_enable_h3') === '1')) + return _('Force HTTPS and HTTP/3 require an enabled HTTPS port.'); + return true; + }; + for (const name of ['listen_http_port', 'listen_https_port', 's3_port', 'ftp_port', 'sftp_port', 'ftp_pasv_ports']) + fields[name].validate = (section_id, value) => validatePorts(section_id, name, value); + for (const name of ['ftp_pasv_ports', 'log_path', 'log_max_size', 'log_max_backups', 'log_max_age', + 'log_compress', 'log_filter', 'log_filter_cidr', 'log_filter_path', 'log_filter_method']) + fields[name].retain = true; + return m.render(); } }); diff --git a/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js b/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js index 3ba0b5d3d..ad1b4260b 100644 --- a/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js +++ b/luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js @@ -1,91 +1,72 @@ 'use strict'; 'require fs'; 'require poll'; -'require uci'; 'require ui'; 'require view'; -const DEFAULT_LOG_PATH = '/var/log/openlist2.log'; +const HELPER = '/usr/libexec/openlist2-helper'; +let logTextarea, errorMessage; -let scrollPosition = 0; -let userScrolled = false; -let logTextarea; -let log_path = DEFAULT_LOG_PATH; - -const isSafeLogPath = value => /^\/var\/log\/openlist2(?:[._-][A-Za-z0-9._-]+)?$/.test(value || ''); - -const formatLog = res => { - const log = (res || '').trim().replace(/\u001b\[[0-9;]*m/g, ''); - - return log || _('No log data.'); -}; +const formatLog = text => (text || '').replace(/\u001b\[[0-9;]*m/g, '').trim() || _('No log data.'); const pollLog = () => { if (!logTextarea) return Promise.resolve(); - return fs.read_direct(log_path, 'text') - .then(formatLog) - .catch(() => _('No log data.')) - .then(log => { - logTextarea.value = log; + return fs.exec(HELPER, ['log-read']).then(result => { + if (result.code !== 0) + throw new Error((result.stderr || _('Unable to read the log.')).trim()); - if (!userScrolled) { - logTextarea.scrollTop = logTextarea.scrollHeight; - } else { - logTextarea.scrollTop = scrollPosition; - } - }); + // Decide before replacing text, so programmatic scrolling is not + // mistaken for the user scrolling away from the bottom. + const atBottom = logTextarea.scrollTop + logTextarea.clientHeight >= logTextarea.scrollHeight - 10; + const position = logTextarea.scrollTop; + logTextarea.value = formatLog(result.stdout); + logTextarea.scrollTop = atBottom ? logTextarea.scrollHeight : position; + errorMessage.textContent = ''; + errorMessage.hidden = true; + }).catch(error => { + errorMessage.textContent = _('Unable to read the log: %s').format(error.message); + errorMessage.hidden = false; + }); }; return view.extend({ - load() { - return uci.load('openlist2'); - }, - handleCleanLogs() { - return fs.write(log_path, '') - .then(pollLog) - .catch(e => { - ui.addNotification(null, E('p', e.message)); - }); + if (!L.hasViewPermission()) + return Promise.resolve(); + return fs.exec(HELPER, ['log-clear']).then(result => { + if (result.code !== 0) + throw new Error((result.stderr || _('Unable to clear the log.')).trim()); + return pollLog(); + }).catch(error => ui.addNotification(null, E('p', error.message))); }, render() { - const configuredLogPath = uci.get('openlist2', '@openlist2[0]', 'log_path'); - log_path = isSafeLogPath(configuredLogPath) ? configuredLogPath : DEFAULT_LOG_PATH; - logTextarea = E('textarea', { 'id': 'log_content', 'class': 'cbi-input-textarea', 'wrap': 'off', 'readonly': 'readonly', - 'style': 'width: calc(100% - 20px);height: 535px;margin: 10px;overflow-y: scroll;', - }); + 'style': 'width:100%;height:535px;overflow:auto;' + }, _('Collecting data...')); + errorMessage = E('p', { 'class': 'alert-message warning', 'role': 'status', 'hidden': true }); + const clearButton = E('button', { + 'class': 'btn cbi-button-action', + 'type': 'button', + 'disabled': !L.hasViewPermission(), + 'click': ui.createHandlerFn(this, 'handleCleanLogs') + }, _('Clear current log')); - logTextarea.addEventListener('scroll', () => { - userScrolled = true; - scrollPosition = logTextarea.scrollTop; - }); - - const log_textarea_wrapper = E('div', { 'id': 'log_textarea' }, logTextarea); - - setTimeout(() => { - poll.add(pollLog); - }, 100); - - const clear_logs_button = E('input', { 'class': 'btn cbi-button-action', 'type': 'button', 'style': 'margin-left: 10px; margin-top: 10px;', 'value': _('Clear logs') }); - clear_logs_button.addEventListener('click', L.bind(this.handleCleanLogs, this)); - - return E([ - E('div', { 'class': 'cbi-map' }, [ - E('div', { 'class': 'cbi-section' }, [ - clear_logs_button, - log_textarea_wrapper, - E('div', { 'style': 'text-align:right' }, - E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval)) - ) - ]) + poll.add(pollLog); + return E('div', { 'class': 'cbi-map' }, [ + E('div', { 'class': 'cbi-section' }, [ + E('p', {}, _('Showing up to the last 200 lines and 16 KiB. Older entries remain in the log files.')), + clearButton, + errorMessage, + logTextarea, + E('p', { 'style': 'text-align:right' }, + _('Refresh every %s seconds.').format(L.env.pollinterval)) ]) ]); }, diff --git a/luci-app-openlist2/po/templates/openlist2.po b/luci-app-openlist2/po/templates/openlist2.po index c08ea1f23..4f5d961b9 100644 --- a/luci-app-openlist2/po/templates/openlist2.po +++ b/luci-app-openlist2/po/templates/openlist2.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: luci-app-openlist2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-27 09:57+0800\n" -"PO-Revision-Date: 2026-06-26 00:00+0800\n" +"POT-Creation-Date: 2026-09-13 09:36+0800\n" +"PO-Revision-Date: 2026-09-13 09:36+0800\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: en\n" @@ -11,625 +11,765 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "RUNNING" msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "NOT RUNNING" msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:51 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:54 msgid "Open Web Interface" msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:100 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:95 msgid "Port must be -1 or a valid port number from 1 to 65535." msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:120 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:115 msgid "Site URL must start with http:// or https:// and must not end with /." msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:132 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:127 msgid "CORS origins must be * or include http:// or https://." msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "Username:" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:159 +msgid "Use an absolute path without control characters or dot segments." msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New Password:" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New password has been copied to clipboard." -msgstr "" - -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:183 -msgid "OpenList" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:184 -msgid "A file list program that supports multiple storage." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:185 -#, javascript-format -msgid "" -"Initial login username is \"%s\" and password is \"%s\". Change it " -"immediately after first login." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:169 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:172 +msgid "Use passive ports or ranges from 1024 to 65535." msgstr "" #: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:201 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:52 msgid "Collecting data..." msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:207 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:238 +msgid "The password reset did not return a username and password." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:241 +msgid "Copy the new password before closing this dialog." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 +msgid "New password has been copied to clipboard." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 +msgid "Automatic copy failed. Select and copy the password manually." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:247 +msgid "Password reset" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:248 +msgid "Username:" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:249 +msgid "New Password:" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:253 +msgid "Copy password" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 +msgid "Close" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:260 +#, javascript-format +msgid "Unable to reset the password: %s" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:268 +msgid "Configuration contains credentials and is available only to users with write access." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 +msgid "OpenList" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 +msgid "A file list program that supports multiple storage." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:274 +#, javascript-format +msgid "Initial login username is \"%s\" and password is \"%s\". Change it immediately after first login." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:298 +msgid "Configure a web port or Site URL to open the management page." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:303 msgid "Basic Settings" msgstr "" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:208 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:304 msgid "Global Settings" msgstr "" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:305 +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:21 +msgid "Logs" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 +msgid "Database" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 +msgid "Search" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:308 +msgid "Web Protocol" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:309 +msgid "Task threads" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:310 +msgid "Worker counts below only initialize missing settings. After the first start, change worker counts and speed limits in OpenList Management > Settings > Traffic. Upload and decompression-upload tasks do not support persistence." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:311 +msgid "CORS Settings" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 +msgid "Object Storage" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:313 +msgid "FTP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:314 +msgid "SFTP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:315 +msgid "MCP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:318 +msgid "Enabled" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:322 +msgid "Debug logging" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:323 +msgid "Pass --debug to OpenList and send stderr to procd logs." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:326 +msgid "Delayed Start (seconds)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:331 +msgid "Open firewall port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:334 +msgid "Data directory" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:335 +msgid "Changing this path does not move data. Stop OpenList, back up and move the complete data directory, then apply the new path." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 +msgid "Cache directory" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:340 +msgid "OpenList clears this directory on startup. Use a dedicated empty subdirectory. Never select a disk mount root or a directory containing files you want to keep." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:344 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:346 +msgid "Reset Password" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 +msgid "Generate a new random password using the saved and applied data directory. Start OpenList once before using this action." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 +msgid "Force read config" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:352 +msgid "Setting this to true will force the program to read the configuration file, ignoring environment variables." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:356 +msgid "Site URL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:357 +msgid "When the web is reverse proxied to a subdirectory, this option must be filled out to ensure proper functioning of the web. Do not include '/' at the end of the URL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:362 +msgid "CDN URL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 +msgid "JWT Key" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 +msgid "Login Validity Period (hours)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:374 +msgid "Proxy address" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 +msgid "HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList outbound requests." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:379 +msgid "Auto memory limit (MB)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:380 +msgid "0 disables the automatic memory limit. The upstream default is 4 MB." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:385 +msgid "Minimum free memory (MB)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 +msgid "Values below 16 let OpenList calculate a default; negative values disable memory cache." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:391 +msgid "Maximum block size (MB)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:392 +msgid "Values below 4 let OpenList calculate a default." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:397 +msgid "Max Connections" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:398 +msgid "0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 +msgid "Max concurrency of local proxies" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:404 +msgid "0 is unlimited, Limit the maximum concurrency of local agents. The default value is 64" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:409 +msgid "Disable TLS Verify" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:410 +msgid "Skip remote TLS certificate verification (not recommended)." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:415 +msgid "Enable Logs" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 +msgid "Log path" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:427 +msgid "Log path must be /var/log/openlist2* without subdirectories." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:430 +msgid "Max Size (MB)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:436 +msgid "Max backups" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:442 +msgid "Max age" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 +msgid "Log Compress" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:453 +msgid "Enable common log filters" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 +msgid "Filter noisy access logs such as health checks, HEAD requests and WebDAV PROPFIND." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 +msgid "Custom log filter CIDR" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 +msgid "Custom log filter path" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:464 +msgid "Custom log filter method" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:468 +msgid "Database Type" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 +msgid "SQLite" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:471 +msgid "MySQL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:472 +msgid "PostgreSQL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 +msgid "Database Host" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:478 +msgid "Database Port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 +msgid "Use 0 to apply the usual default for the selected database: 3306 for MySQL, 5432 for PostgreSQL." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:485 +msgid "Database Username" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:489 +msgid "Database Password" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:494 +msgid "Database Name" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:498 +msgid "Database Table Prefix" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:503 +msgid "Database SSL Mode" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:507 +msgid "Database DSN" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:512 +msgid "Meilisearch Host" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:516 +msgid "Meilisearch API Key" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:519 +msgid "Meilisearch Index" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 +msgid "Bleve index directory" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:524 +msgid "Empty uses the bleve subdirectory of the data directory. Keep the index separate from cache and frontend files." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:527 +msgid "External frontend directory" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:528 +msgid "Optional directory containing index.html from a matching OpenList frontend. Empty uses the bundled frontend. Restart OpenList after changing it." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:532 +msgid "Listen address" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:537 +msgid "HTTP listen port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:538 +msgid "The upstream default is 5244. Set to -1 to disable HTTP." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:547 +msgid "HTTPS listen port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:548 +msgid "The upstream default is -1 (disabled). Set a valid port number to enable HTTPS." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 +msgid "Force HTTPS" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:560 +msgid "SSL cert" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:561 +msgid "SSL certificate file path" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:563 +msgid "SSL key" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:564 +msgid "SSL key file path" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:566 +msgid "Unix socket file" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:568 +msgid "Unix socket permission" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 +msgid "Enable H2C" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:571 +msgid "Enable cleartext HTTP/2 for reverse proxies that use grpc_pass." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:574 +msgid "Enable HTTP/3/QUIC" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:575 +msgid "Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and certificate files must be configured." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:579 +msgid "Open traffic settings" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:580 +msgid "Use the OpenList backend to change the effective worker counts and transfer speed limits." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:581 +msgid "Download Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:586 +msgid "Download Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 +msgid "Download Task Persistence" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:594 +msgid "Transfer Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:599 +msgid "Transfer Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:604 +msgid "Transfer Task Persistence" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:607 +msgid "Upload Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:612 +msgid "Upload Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:618 +msgid "Copy Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:623 +msgid "Copy Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:628 +msgid "Copy Task Persistence" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:631 +msgid "Move Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 +msgid "Move Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 +msgid "Move Task Persistence" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 +msgid "Decompress Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:649 +msgid "Decompress Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:654 +msgid "Decompress Task Persistence" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:657 +msgid "Decompress Upload Workers (initial)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:662 +msgid "Decompress Upload Max Retry" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:668 +msgid "Allow retry canceled tasks" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:672 +msgid "Allow Origins" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:673 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:681 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:686 +msgid "Comma-separated list. Use * to allow any value." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:680 +msgid "Allow Methods" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:685 +msgid "Allow Headers" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:691 +msgid "Open S3 management" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:692 +msgid "Generate the S3 access key and secret in OpenList settings, then configure bucket mappings. Restart OpenList after changing credentials." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:693 +msgid "Enabled S3" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:696 +msgid "Port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:701 +msgid "Enable SSL" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:705 +msgid "Open FTP settings" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:706 +msgid "Configure the public host and passive port mapping in OpenList. Restart the service after changing FTP settings." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:707 +msgid "FTP passive firewall ports" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:708 +msgid "Ports or ranges to allow from WAN, for example 50000-50100. They must match the listening ports in OpenList passive port mapping. Empty means passive ports must be allowed manually." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:711 +msgid "Enabled FTP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:714 +msgid "FTP Port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:719 +msgid "Max retries on port conflict during passive transfer" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:724 +msgid "Enable non-20 port for active transfer" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:727 +msgid "Client idle timeout (seconds)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:732 +msgid "Connection timeout (seconds)" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:737 +msgid "Disable active transfer mode" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:740 +msgid "Enable binary transfer mode" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:743 +msgid "Client IP check in active transfer mode" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:747 +msgid "Client IP check in passive transfer mode" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:752 +msgid "Enabled SFTP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:755 +msgid "SFTP Port" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:761 +msgid "Enabled MCP" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:762 +msgid "Enable MCP (Model Context Protocol) server." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:766 +msgid "MCP endpoint" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:767 +msgid "Use Streamable HTTP with Authorization: TOKEN, without a Bearer prefix. Use an OpenList user login token; retain MCP-Session-Id for subsequent requests." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:770 +msgid "Configure a web port or Site URL." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:771 +msgid "MCP documentation" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:787 +msgid "Use a dedicated subdirectory, not a system directory or disk mount root." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:789 +msgid "Use a cache subdirectory below the disk mount." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:792 +msgid "Cache and index directories must be separate and must not contain the data directory." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:795 +msgid "Frontend files must be separate from private data, cache and index files." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:806 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:815 +msgid "Certificate and key paths are required for HTTPS or S3 SSL." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:812 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:855 +msgid "Force HTTPS and HTTP/3 require an enabled HTTPS port." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:818 +msgid "Use 3 or 4 octal digits, for example 660 or 0660." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:844 +#, javascript-format +msgid "Enabled services cannot share TCP port %s." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:850 +#, javascript-format +msgid "FTP passive ports must not overlap service port %s." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:10 +msgid "No log data." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:18 +msgid "Unable to read the log." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 +#, javascript-format +msgid "Unable to read the log: %s" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:40 +msgid "Unable to clear the log." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:59 +msgid "Clear current log" +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:64 +msgid "Showing up to the last 200 lines and 16 KiB. Older entries remain in the log files." +msgstr "" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:69 +#, javascript-format +msgid "Refresh every %s seconds." +msgstr "" + #: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:13 msgid "Setting" msgstr "" - -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:21 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:209 -msgid "Logs" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:210 -msgid "Database" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:211 -msgid "Search" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:212 -msgid "Web Protocol" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:213 -msgid "Task threads" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:214 -msgid "CORS Settings" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:215 -msgid "Object Storage" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:216 -msgid "FTP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:217 -msgid "SFTP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:218 -msgid "MCP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:220 -msgid "Enabled" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:224 -msgid "Debug logging" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:225 -msgid "Pass --debug to OpenList and send stderr to procd logs." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:228 -msgid "Delayed Start (seconds)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:233 -msgid "Open firewall port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:236 -msgid "Data directory" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:239 -msgid "Cache directory" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:243 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 -msgid "Reset Password" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 -msgid "Generate a new random password." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:250 -msgid "Force read config" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:251 -msgid "" -"Setting this to true will force the program to read the configuration file, " -"ignoring environment variables." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 -msgid "Site URL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:256 -msgid "" -"When the web is reverse proxied to a subdirectory, this option must be " -"filled out to ensure proper functioning of the web. Do not include '/' at " -"the end of the URL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:261 -msgid "CDN URL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:264 -msgid "JWT Key" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:267 -msgid "Login Validity Period (hours)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 -msgid "Proxy address" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 -msgid "" -"HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList " -"outbound requests." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:276 -msgid "Auto memory limit (MB)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:277 -msgid "0 disables the automatic memory limit. The upstream default is 4 MB." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:282 -msgid "Minimum free memory (MB)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:283 -msgid "" -"Values below 16 let OpenList calculate a default; negative values disable " -"memory cache." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:288 -msgid "Maximum block size (MB)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:289 -msgid "Values below 4 let OpenList calculate a default." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:294 -msgid "Max Connections" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:295 -msgid "" -"0 is unlimited, It is recommend to set a low number of concurrency (10-20) " -"for poor performance device" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:300 -msgid "Max concurrency of local proxies" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:301 -msgid "" -"0 is unlimited, Limit the maximum concurrency of local agents. The default " -"value is 64" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 -msgid "Disable TLS Verify" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 -msgid "Skip remote TLS certificate verification (not recommended)." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 -msgid "Enable Logs" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:316 -msgid "Log path" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:324 -msgid "Log path must be /var/log/openlist2* without subdirectories." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:327 -msgid "Max Size (MB)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:333 -msgid "Max backups" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 -msgid "Max age" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 -msgid "Log Compress" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:350 -msgid "Enable common log filters" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 -msgid "" -"Filter noisy access logs such as health checks, HEAD requests and WebDAV " -"PROPFIND." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:355 -msgid "Custom log filter CIDR" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:358 -msgid "Custom log filter path" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:361 -msgid "Custom log filter method" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 -msgid "Database Type" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:367 -msgid "SQLite" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:368 -msgid "MySQL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 -msgid "PostgreSQL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:371 -msgid "Database Host" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 -msgid "Database Port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:376 -msgid "" -"Use 0 to apply the usual default for the selected database: 3306 for MySQL, " -"5432 for PostgreSQL." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:382 -msgid "Database Username" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 -msgid "Database Password" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:390 -msgid "Database Name" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:394 -msgid "Database Table Prefix" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:399 -msgid "Database SSL Mode" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 -msgid "Database DSN" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:407 -msgid "Meilisearch Host" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:411 -msgid "Meilisearch API Key" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:414 -msgid "Meilisearch Index" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 -msgid "Listen address" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:424 -msgid "HTTP listen port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:425 -msgid "The upstream default is 5244. Set to -1 to disable HTTP." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:434 -msgid "HTTPS listen port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:435 -msgid "" -"The upstream default is -1 (disabled). Set a valid port number to enable " -"HTTPS." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:444 -msgid "Force HTTPS" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:447 -msgid "SSL cert" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 -msgid "SSL certificate file path" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:451 -msgid "SSL certificate file path is required when HTTPS is enabled." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 -msgid "SSL key" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:455 -msgid "SSL key file path" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 -msgid "SSL key file path is required when HTTPS is enabled." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 -msgid "Unix socket file" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:463 -msgid "Unix socket permission" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:465 -msgid "Enable H2C" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:466 -msgid "Enable cleartext HTTP/2 for reverse proxies that use grpc_pass." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:469 -msgid "Enable HTTP/3/QUIC" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 -msgid "" -"Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and " -"certificate files must be configured." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 -msgid "Download Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 -msgid "Download Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:484 -msgid "Download Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:487 -msgid "Transfer Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:492 -msgid "Transfer Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:497 -msgid "Transfer Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:500 -msgid "Upload Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:505 -msgid "Upload Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:510 -msgid "Upload Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:513 -msgid "Copy Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:518 -msgid "Copy Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 -msgid "Copy Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:526 -msgid "Move Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:531 -msgid "Move Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:536 -msgid "Move Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:539 -msgid "Decompress Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:544 -msgid "Decompress Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:549 -msgid "Decompress Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:552 -msgid "Decompress Upload Workers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 -msgid "Decompress Upload Max Retry" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:562 -msgid "Decompress Upload Task Persistence" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:565 -msgid "Allow retry canceled tasks" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:569 -msgid "Allow Origins" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:578 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:583 -msgid "Comma-separated list. Use * to allow any value." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:577 -msgid "Allow Methods" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:582 -msgid "Allow Headers" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:588 -msgid "Enabled S3" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 -msgid "Port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:596 -msgid "Enable SSL" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:600 -msgid "Enabled FTP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:603 -msgid "FTP Port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:608 -msgid "Max retries on port conflict during passive transfer" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:613 -msgid "Enable non-20 port for active transfer" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:616 -msgid "Client idle timeout (seconds)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:621 -msgid "Connection timeout (seconds)" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:626 -msgid "Disable active transfer mode" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:629 -msgid "Enable binary transfer mode" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:632 -msgid "Client IP check in active transfer mode" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 -msgid "Client IP check in passive transfer mode" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 -msgid "Enabled SFTP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 -msgid "SFTP Port" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:651 -msgid "Enabled MCP" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:652 -msgid "Enable MCP (Model Context Protocol) server." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:20 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 -msgid "No log data." -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:77 -msgid "Clear logs" -msgstr "" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:86 -#, javascript-format -msgid "Refresh every %s seconds." -msgstr "" diff --git a/luci-app-openlist2/po/zh_Hans/openlist2.po b/luci-app-openlist2/po/zh_Hans/openlist2.po index 37b4b5962..84a970cec 100644 --- a/luci-app-openlist2/po/zh_Hans/openlist2.po +++ b/luci-app-openlist2/po/zh_Hans/openlist2.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: luci-app-openlist2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-27 09:57+0800\n" -"PO-Revision-Date: 2026-06-25 00:00+0800\n" +"POT-Creation-Date: 2026-09-13 09:36+0800\n" +"PO-Revision-Date: 2026-09-13 09:36+0800\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: zh_Hans\n" @@ -12,633 +12,765 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "RUNNING" msgstr "运行中" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "NOT RUNNING" msgstr "未运行" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:51 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:54 msgid "Open Web Interface" msgstr "打开 Web 界面" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:100 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:95 msgid "Port must be -1 or a valid port number from 1 to 65535." msgstr "端口必须为 -1,或 1 到 65535 之间的有效端口号。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:120 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:115 msgid "Site URL must start with http:// or https:// and must not end with /." msgstr "站点 URL 必须以 http:// 或 https:// 开头,且末尾不能带 /。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:132 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:127 msgid "CORS origins must be * or include http:// or https://." msgstr "CORS 来源必须为 *,或包含 http:// / https://。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "Username:" -msgstr "用户名:" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:159 +msgid "Use an absolute path without control characters or dot segments." +msgstr "使用绝对路径,路径中不能包含控制字符、. 或 .. 路径段。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New Password:" -msgstr "新密码:" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New password has been copied to clipboard." -msgstr "新密码已复制到剪贴板。" - -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:183 -msgid "OpenList" -msgstr "OpenList" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:184 -msgid "A file list program that supports multiple storage." -msgstr "一款支持多种存储的目录文件列表程序。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:185 -#, javascript-format -msgid "" -"Initial login username is \"%s\" and password is \"%s\". Change it " -"immediately after first login." -msgstr "初始登录用户名为「%s」,密码为「%s」。首次登录后请立即修改。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:169 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:172 +msgid "Use passive ports or ranges from 1024 to 65535." +msgstr "请填写 1024 到 65535 之间的被动端口或端口范围。" #: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:201 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:52 msgid "Collecting data..." msgstr "收集数据..." -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:207 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:238 +msgid "The password reset did not return a username and password." +msgstr "密码重置未返回用户名和密码。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:241 +msgid "Copy the new password before closing this dialog." +msgstr "关闭此对话框前请复制新密码。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 +msgid "New password has been copied to clipboard." +msgstr "新密码已复制到剪贴板。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 +msgid "Automatic copy failed. Select and copy the password manually." +msgstr "自动复制失败,请手动选中并复制密码。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:247 +msgid "Password reset" +msgstr "密码已重置" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:248 +msgid "Username:" +msgstr "用户名:" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:249 +msgid "New Password:" +msgstr "新密码:" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:253 +msgid "Copy password" +msgstr "复制密码" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 +msgid "Close" +msgstr "关闭" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:260 +#, javascript-format +msgid "Unable to reset the password: %s" +msgstr "无法重置密码:%s" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:268 +msgid "Configuration contains credentials and is available only to users with write access." +msgstr "配置包含凭据,仅有编辑权限的用户可以查看。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 +msgid "OpenList" +msgstr "OpenList" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 +msgid "A file list program that supports multiple storage." +msgstr "一款支持多种存储的目录文件列表程序。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:274 +#, javascript-format +msgid "Initial login username is \"%s\" and password is \"%s\". Change it immediately after first login." +msgstr "初始登录用户名为「%s」,密码为「%s」。首次登录后请立即修改。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:298 +msgid "Configure a web port or Site URL to open the management page." +msgstr "请配置 Web 端口或站点地址,以打开管理页面。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:303 msgid "Basic Settings" msgstr "基本设置" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:208 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:304 msgid "Global Settings" msgstr "全局设置" -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:13 -msgid "Setting" -msgstr "设置" - +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:305 #: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:21 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:209 msgid "Logs" msgstr "日志" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:210 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 msgid "Database" msgstr "数据库" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:211 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 msgid "Search" msgstr "搜索" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:212 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:308 msgid "Web Protocol" msgstr "Web 协议" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:213 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:309 msgid "Task threads" msgstr "任务线程" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:214 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:310 +msgid "Worker counts below only initialize missing settings. After the first start, change worker counts and speed limits in OpenList Management > Settings > Traffic. Upload and decompression-upload tasks do not support persistence." +msgstr "下方线程数仅用于初始化缺失的设置。首次启动后,请在 OpenList 管理后台 → 设置 → 传输中调整线程数和限速。普通上传和解压上传任务不支持持久化。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:311 msgid "CORS Settings" msgstr "跨域设置" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:215 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 msgid "Object Storage" msgstr "对象存储" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:216 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:313 msgid "FTP" msgstr "FTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:217 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:314 msgid "SFTP" msgstr "SFTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:218 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:315 msgid "MCP" msgstr "MCP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:220 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:318 msgid "Enabled" msgstr "启用" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:224 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:322 msgid "Debug logging" msgstr "调试日志" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:225 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:323 msgid "Pass --debug to OpenList and send stderr to procd logs." msgstr "向 OpenList 传递 --debug,并将 stderr 发送到 procd 日志。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:228 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:326 msgid "Delayed Start (seconds)" msgstr "开机延时启动(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:233 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:331 msgid "Open firewall port" msgstr "打开防火墙端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:236 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:334 msgid "Data directory" msgstr "数据目录" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:239 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:335 +msgid "Changing this path does not move data. Stop OpenList, back up and move the complete data directory, then apply the new path." +msgstr "修改路径不会搬迁数据。请先停止 OpenList,备份并搬迁完整数据目录,再应用新路径。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 msgid "Cache directory" msgstr "缓存目录" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:243 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:340 +msgid "OpenList clears this directory on startup. Use a dedicated empty subdirectory. Never select a disk mount root or a directory containing files you want to keep." +msgstr "OpenList 启动时会清空此目录。请使用专用的空子目录,切勿选择磁盘挂载根目录或包含需要保留文件的目录。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:344 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:346 msgid "Reset Password" msgstr "重置密码" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 -msgid "Generate a new random password." -msgstr "随机生成一个新密码。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 +msgid "Generate a new random password using the saved and applied data directory. Start OpenList once before using this action." +msgstr "按已保存并已应用的数据目录随机生成新密码。请先启动一次 OpenList。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:250 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 msgid "Force read config" msgstr "强制读取配置" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:251 -msgid "" -"Setting this to true will force the program to read the configuration file, " -"ignoring environment variables." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:352 +msgid "Setting this to true will force the program to read the configuration file, ignoring environment variables." msgstr "将此设置为 true 可以强制程序读取配置文件,而忽略环境变量" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:356 msgid "Site URL" msgstr "站点地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:256 -msgid "" -"When the web is reverse proxied to a subdirectory, this option must be " -"filled out to ensure proper functioning of the web. Do not include '/' at " -"the end of the URL" -msgstr "" -"Web 被反向代理到二级目录时,必须填写该选项以确保 Web 正常工作。URL 结尾请勿携" -"带 '/'" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:357 +msgid "When the web is reverse proxied to a subdirectory, this option must be filled out to ensure proper functioning of the web. Do not include '/' at the end of the URL" +msgstr "Web 被反向代理到二级目录时,必须填写该选项以确保 Web 正常工作。URL 结尾请勿携带 '/'" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:261 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:362 msgid "CDN URL" msgstr "CDN 地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:264 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 msgid "JWT Key" msgstr "JWT 密钥" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:267 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 msgid "Login Validity Period (hours)" msgstr "登录有效期(小时)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:374 msgid "Proxy address" msgstr "代理地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 -msgid "" -"HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList " -"outbound requests." -msgstr "" -"OpenList 出站请求使用的 HTTP、HTTPS、SOCKS4、SOCKS5 或 SOCKS5HOSTNAME 代理。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 +msgid "HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList outbound requests." +msgstr "OpenList 出站请求使用的 HTTP、HTTPS、SOCKS4、SOCKS5 或 SOCKS5HOSTNAME 代理。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:276 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:379 msgid "Auto memory limit (MB)" msgstr "自动内存限制(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:277 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:380 msgid "0 disables the automatic memory limit. The upstream default is 4 MB." msgstr "0 表示禁用自动内存限制。上游默认值为 4 MB。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:282 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:385 msgid "Minimum free memory (MB)" msgstr "最小可用内存(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:283 -msgid "" -"Values below 16 let OpenList calculate a default; negative values disable " -"memory cache." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 +msgid "Values below 16 let OpenList calculate a default; negative values disable memory cache." msgstr "低于 16 时由 OpenList 自动计算默认值;负数表示禁用内存缓存。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:288 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:391 msgid "Maximum block size (MB)" msgstr "最大块大小(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:289 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:392 msgid "Values below 4 let OpenList calculate a default." msgstr "低于 4 时由 OpenList 自动计算默认值。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:294 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:397 msgid "Max Connections" msgstr "最大并发连接数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:295 -msgid "" -"0 is unlimited, It is recommend to set a low number of concurrency (10-20) " -"for poor performance device" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:398 +msgid "0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device" msgstr "默认 0 不限制,低性能设备建议设置较低的并发数(10-20)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:300 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 msgid "Max concurrency of local proxies" msgstr "本地代理最大并发数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:301 -msgid "" -"0 is unlimited, Limit the maximum concurrency of local agents. The default " -"value is 64" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:404 +msgid "0 is unlimited, Limit the maximum concurrency of local agents. The default value is 64" msgstr "限制本地代理最大并发数,值为 0 表示不限制,默认值 64" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:409 msgid "Disable TLS Verify" msgstr "禁用 TLS 验证" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:410 msgid "Skip remote TLS certificate verification (not recommended)." msgstr "跳过远程 TLS 证书校验(不推荐)。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:415 msgid "Enable Logs" msgstr "启用日志" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:316 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 msgid "Log path" msgstr "日志文件路径" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:324 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:427 msgid "Log path must be /var/log/openlist2* without subdirectories." msgstr "日志路径必须为 /var/log/openlist2*,且不得包含子目录。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:327 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:430 msgid "Max Size (MB)" msgstr "日志文件大小(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:333 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:436 msgid "Max backups" msgstr "日志备份数量" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:442 msgid "Max age" msgstr "日志保存天数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 msgid "Log Compress" msgstr "日志压缩" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:350 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:453 msgid "Enable common log filters" msgstr "启用常用日志过滤" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 -msgid "" -"Filter noisy access logs such as health checks, HEAD requests and WebDAV " -"PROPFIND." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 +msgid "Filter noisy access logs such as health checks, HEAD requests and WebDAV PROPFIND." msgstr "过滤健康检查、HEAD 请求和 WebDAV PROPFIND 等噪声访问日志。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:355 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 msgid "Custom log filter CIDR" msgstr "自定义日志过滤 CIDR" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:358 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 msgid "Custom log filter path" msgstr "自定义日志过滤路径" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:361 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:464 msgid "Custom log filter method" msgstr "自定义日志过滤方法" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:468 msgid "Database Type" msgstr "数据库类型" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:367 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 msgid "SQLite" msgstr "SQLite" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:368 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:471 msgid "MySQL" msgstr "MySQL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:472 msgid "PostgreSQL" msgstr "PostgreSQL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:371 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 msgid "Database Host" msgstr "主机" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:478 msgid "Database Port" msgstr "端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:376 -msgid "" -"Use 0 to apply the usual default for the selected database: 3306 for MySQL, " -"5432 for PostgreSQL." -msgstr "" -"使用 0 时会按所选数据库使用常见默认端口:MySQL 为 3306,PostgreSQL 为 5432。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 +msgid "Use 0 to apply the usual default for the selected database: 3306 for MySQL, 5432 for PostgreSQL." +msgstr "使用 0 时会按所选数据库使用常见默认端口:MySQL 为 3306,PostgreSQL 为 5432。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:382 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:485 msgid "Database Username" msgstr "用户名" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:489 msgid "Database Password" msgstr "密码" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:390 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:494 msgid "Database Name" msgstr "数据库名" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:394 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:498 msgid "Database Table Prefix" msgstr "数据库表前缀" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:399 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:503 msgid "Database SSL Mode" msgstr "SSL模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:507 msgid "Database DSN" msgstr "DSN" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:407 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:512 msgid "Meilisearch Host" msgstr "Meilisearch 主机" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:411 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:516 msgid "Meilisearch API Key" msgstr "Meilisearch API 密钥" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:414 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:519 msgid "Meilisearch Index" msgstr "Meilisearch 索引" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 +msgid "Bleve index directory" +msgstr "Bleve 索引目录" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:524 +msgid "Empty uses the bleve subdirectory of the data directory. Keep the index separate from cache and frontend files." +msgstr "留空时使用数据目录下的 bleve 子目录。索引应与缓存、前端文件分开。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:527 +msgid "External frontend directory" +msgstr "外部前端目录" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:528 +msgid "Optional directory containing index.html from a matching OpenList frontend. Empty uses the bundled frontend. Restart OpenList after changing it." +msgstr "可选,填写包含匹配版本 OpenList 前端 index.html 的目录。留空时使用内置前端,修改后需重启 OpenList。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:532 msgid "Listen address" msgstr "监听地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:424 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:537 msgid "HTTP listen port" msgstr "HTTP 监听端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:425 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:538 msgid "The upstream default is 5244. Set to -1 to disable HTTP." msgstr "上游默认值为 5244。设为 -1 可禁用 HTTP。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:434 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:547 msgid "HTTPS listen port" msgstr "HTTPS 监听端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:435 -msgid "" -"The upstream default is -1 (disabled). Set a valid port number to enable " -"HTTPS." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:548 +msgid "The upstream default is -1 (disabled). Set a valid port number to enable HTTPS." msgstr "上游默认值为 -1(禁用)。设为有效端口号可启用 HTTPS。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:444 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 msgid "Force HTTPS" msgstr "强制 HTTPS" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:447 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:560 msgid "SSL cert" msgstr "SSL 证书" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:561 msgid "SSL certificate file path" msgstr "SSL 证书文件路径" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:451 -msgid "SSL certificate file path is required when HTTPS is enabled." -msgstr "启用 HTTPS 时必须填写 SSL 证书文件路径。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:563 msgid "SSL key" msgstr "SSL 密钥" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:455 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:564 msgid "SSL key file path" msgstr "SSL 密钥文件路径" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 -msgid "SSL key file path is required when HTTPS is enabled." -msgstr "启用 HTTPS 时必须填写 SSL 密钥文件路径。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:566 msgid "Unix socket file" msgstr "Unix Socket 文件" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:463 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:568 msgid "Unix socket permission" msgstr "Unix Socket 权限" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:465 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 msgid "Enable H2C" msgstr "启用 H2C" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:466 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:571 msgid "Enable cleartext HTTP/2 for reverse proxies that use grpc_pass." msgstr "为使用 grpc_pass 的反向代理启用明文 HTTP/2。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:469 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:574 msgid "Enable HTTP/3/QUIC" msgstr "启用 HTTP/3/QUIC" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 -msgid "" -"Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and " -"certificate files must be configured." -msgstr "" -"在 HTTPS 监听端口上启用基于 QUIC 的 HTTP/3。必须先启用 HTTPS 并配置证书文件。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:575 +msgid "Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and certificate files must be configured." +msgstr "在 HTTPS 监听端口上启用基于 QUIC 的 HTTP/3。必须先启用 HTTPS 并配置证书文件。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 -msgid "Download Workers" -msgstr "下载任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:579 +msgid "Open traffic settings" +msgstr "打开传输设置" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:580 +msgid "Use the OpenList backend to change the effective worker counts and transfer speed limits." +msgstr "在 OpenList 后台调整实际生效的线程数和传输限速。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:581 +msgid "Download Workers (initial)" +msgstr "下载任务初始线程数" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:586 msgid "Download Max Retry" msgstr "下载任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:484 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 msgid "Download Task Persistence" msgstr "下载任务持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:487 -msgid "Transfer Workers" -msgstr "中转任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:594 +msgid "Transfer Workers (initial)" +msgstr "中转任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:492 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:599 msgid "Transfer Max Retry" msgstr "中转任务下载重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:497 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:604 msgid "Transfer Task Persistence" msgstr "中转任务持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:500 -msgid "Upload Workers" -msgstr "上传任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:607 +msgid "Upload Workers (initial)" +msgstr "上传任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:505 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:612 msgid "Upload Max Retry" msgstr "上传任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:510 -msgid "Upload Task Persistence" -msgstr "上传任务持久化" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:618 +msgid "Copy Workers (initial)" +msgstr "复制任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:513 -msgid "Copy Workers" -msgstr "复制任务线程数" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:518 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:623 msgid "Copy Max Retry" msgstr "复制任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:628 msgid "Copy Task Persistence" msgstr "复制任务持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:526 -msgid "Move Workers" -msgstr "移动任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:631 +msgid "Move Workers (initial)" +msgstr "移动任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:531 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 msgid "Move Max Retry" msgstr "移动任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:536 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 msgid "Move Task Persistence" msgstr "移动任务持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:539 -msgid "Decompress Workers" -msgstr "解压任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 +msgid "Decompress Workers (initial)" +msgstr "解压任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:544 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:649 msgid "Decompress Max Retry" msgstr "解压任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:549 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:654 msgid "Decompress Task Persistence" msgstr "解压任务持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:552 -msgid "Decompress Upload Workers" -msgstr "解压上传任务线程数" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:657 +msgid "Decompress Upload Workers (initial)" +msgstr "解压上传任务初始线程数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:662 msgid "Decompress Upload Max Retry" msgstr "解压上传任务重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:562 -msgid "Decompress Upload Task Persistence" -msgstr "解压上传任务持久化" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:565 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:668 msgid "Allow retry canceled tasks" msgstr "允许重试已取消的任务" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:569 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:672 msgid "Allow Origins" msgstr "允许来源(Origins)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:578 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:583 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:673 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:681 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:686 msgid "Comma-separated list. Use * to allow any value." msgstr "使用英文逗号分隔。使用 * 表示允许任意值。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:577 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:680 msgid "Allow Methods" msgstr "允许方法(Methods)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:582 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:685 msgid "Allow Headers" msgstr "允许标头(Headers)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:588 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:691 +msgid "Open S3 management" +msgstr "打开 S3 管理" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:692 +msgid "Generate the S3 access key and secret in OpenList settings, then configure bucket mappings. Restart OpenList after changing credentials." +msgstr "先在 OpenList 设置中生成 S3 访问密钥,再配置存储桶映射。更改凭据后需重启 OpenList。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:693 msgid "Enabled S3" msgstr "启用 S3" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:696 msgid "Port" msgstr "端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:596 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:701 msgid "Enable SSL" msgstr "启用 SSL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:600 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:705 +msgid "Open FTP settings" +msgstr "打开 FTP 设置" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:706 +msgid "Configure the public host and passive port mapping in OpenList. Restart the service after changing FTP settings." +msgstr "在 OpenList 中配置公网地址和被动端口映射,修改 FTP 设置后需重启服务。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:707 +msgid "FTP passive firewall ports" +msgstr "FTP 被动端口放行" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:708 +msgid "Ports or ranges to allow from WAN, for example 50000-50100. They must match the listening ports in OpenList passive port mapping. Empty means passive ports must be allowed manually." +msgstr "允许从 WAN 访问的端口或范围,例如 50000-50100,必须与 OpenList 被动端口映射中的监听端口一致。留空表示需要自行放行被动端口。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:711 msgid "Enabled FTP" msgstr "启用 FTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:603 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:714 msgid "FTP Port" msgstr "FTP 端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:608 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:719 msgid "Max retries on port conflict during passive transfer" msgstr "被动传输端口冲突时最大重试次数" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:613 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:724 msgid "Enable non-20 port for active transfer" msgstr "启用非 20 端口进行主动传输" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:616 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:727 msgid "Client idle timeout (seconds)" msgstr "客户端空闲超时(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:621 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:732 msgid "Connection timeout (seconds)" msgstr "连接超时(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:626 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:737 msgid "Disable active transfer mode" msgstr "禁用主动传输模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:629 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:740 msgid "Enable binary transfer mode" msgstr "启用二进制传输模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:632 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:743 msgid "Client IP check in active transfer mode" msgstr "主动传输模式下对客户端进行 IP 检查" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:747 msgid "Client IP check in passive transfer mode" msgstr "被动传输模式下对客户端进行 IP 检查" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:752 msgid "Enabled SFTP" msgstr "启用 SFTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:755 msgid "SFTP Port" msgstr "SFTP 端口" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:651 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:761 msgid "Enabled MCP" msgstr "启用 MCP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:652 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:762 msgid "Enable MCP (Model Context Protocol) server." msgstr "启用 MCP(模型上下文协议)服务器。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:20 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:766 +msgid "MCP endpoint" +msgstr "MCP 端点" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:767 +msgid "Use Streamable HTTP with Authorization: TOKEN, without a Bearer prefix. Use an OpenList user login token; retain MCP-Session-Id for subsequent requests." +msgstr "使用 Streamable HTTP,认证头为 Authorization: TOKEN,不添加 Bearer 前缀。TOKEN 为 OpenList 用户登录令牌,后续请求需保留 MCP-Session-Id。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:770 +msgid "Configure a web port or Site URL." +msgstr "请配置 Web 端口或站点地址。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:771 +msgid "MCP documentation" +msgstr "MCP 文档" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:787 +msgid "Use a dedicated subdirectory, not a system directory or disk mount root." +msgstr "请使用专用子目录,不能使用系统目录或磁盘挂载根目录。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:789 +msgid "Use a cache subdirectory below the disk mount." +msgstr "请使用磁盘挂载目录下的缓存子目录。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:792 +msgid "Cache and index directories must be separate and must not contain the data directory." +msgstr "缓存和索引目录必须分开,且不能包含数据目录。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:795 +msgid "Frontend files must be separate from private data, cache and index files." +msgstr "前端文件必须与私有数据、缓存和索引分开。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:806 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:815 +msgid "Certificate and key paths are required for HTTPS or S3 SSL." +msgstr "启用 HTTPS 或 S3 SSL 时必须填写证书和私钥路径。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:812 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:855 +msgid "Force HTTPS and HTTP/3 require an enabled HTTPS port." +msgstr "强制 HTTPS 和 HTTP/3 需要先启用 HTTPS 端口。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:818 +msgid "Use 3 or 4 octal digits, for example 660 or 0660." +msgstr "请使用 3 或 4 位八进制数字,例如 660 或 0660。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:844 +#, javascript-format +msgid "Enabled services cannot share TCP port %s." +msgstr "启用的服务不能共用 TCP 端口 %s。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:850 +#, javascript-format +msgid "FTP passive ports must not overlap service port %s." +msgstr "FTP 被动端口不能与服务端口 %s 重叠。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:10 msgid "No log data." msgstr "无日志数据。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:77 -msgid "Clear logs" -msgstr "清空日志" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:18 +msgid "Unable to read the log." +msgstr "无法读取日志。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:86 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 +#, javascript-format +msgid "Unable to read the log: %s" +msgstr "无法读取日志:%s" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:40 +msgid "Unable to clear the log." +msgstr "无法清空日志。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:59 +msgid "Clear current log" +msgstr "清空当前日志" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:64 +msgid "Showing up to the last 200 lines and 16 KiB. Older entries remain in the log files." +msgstr "最多显示末尾 200 行、16 KiB。更早的记录仍保存在日志文件中。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:69 #, javascript-format msgid "Refresh every %s seconds." msgstr "每 %s 秒刷新。" -#~ msgid "Grant UCI access for luci-app-openlist2" -#~ msgstr "授予 luci-app-openlist2 的 UCI 访问权限" +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:13 +msgid "Setting" +msgstr "设置" diff --git a/luci-app-openlist2/po/zh_Hant/openlist2.po b/luci-app-openlist2/po/zh_Hant/openlist2.po index ce365be7d..ee8efc758 100644 --- a/luci-app-openlist2/po/zh_Hant/openlist2.po +++ b/luci-app-openlist2/po/zh_Hant/openlist2.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: luci-app-openlist2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-27 09:57+0800\n" -"PO-Revision-Date: 2026-06-25 00:00+0800\n" +"POT-Creation-Date: 2026-09-13 09:36+0800\n" +"PO-Revision-Date: 2026-09-13 09:36+0800\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: zh_Hant\n" @@ -12,635 +12,765 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "RUNNING" msgstr "執行中" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:43 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:44 msgid "NOT RUNNING" msgstr "未執行" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:51 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:54 msgid "Open Web Interface" msgstr "開啟 Web 介面" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:100 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:95 msgid "Port must be -1 or a valid port number from 1 to 65535." msgstr "埠必須為 -1,或 1 到 65535 之間的有效埠號。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:120 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:115 msgid "Site URL must start with http:// or https:// and must not end with /." msgstr "站點 URL 必須以 http:// 或 https:// 開頭,且末尾不能帶 /。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:132 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:127 msgid "CORS origins must be * or include http:// or https://." msgstr "CORS 來源必須為 *,或包含 http:// / https://。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "Username:" -msgstr "使用者名稱:" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:159 +msgid "Use an absolute path without control characters or dot segments." +msgstr "使用絕對路徑,路徑中不得包含控制字元、. 或 .. 路徑段。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New Password:" -msgstr "新密碼:" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:170 -msgid "New password has been copied to clipboard." -msgstr "新密碼已複製到剪貼簿。" - -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:183 -msgid "OpenList" -msgstr "OpenList" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:184 -msgid "A file list program that supports multiple storage." -msgstr "一款支援多種儲存的目錄檔案列表程式。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:185 -#, javascript-format -msgid "" -"Initial login username is \"%s\" and password is \"%s\". Change it " -"immediately after first login." -msgstr "初始登入使用者名稱為「%s」,密碼為「%s」。首次登入後請立即修改。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:169 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:172 +msgid "Use passive ports or ranges from 1024 to 65535." +msgstr "請填寫 1024 到 65535 之間的被動連接埠或範圍。" #: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:201 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:52 msgid "Collecting data..." msgstr "收集資料..." -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:207 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:238 +msgid "The password reset did not return a username and password." +msgstr "密碼重設未傳回使用者名稱和密碼。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:241 +msgid "Copy the new password before closing this dialog." +msgstr "關閉此對話框前請複製新密碼。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 +msgid "New password has been copied to clipboard." +msgstr "新密碼已複製到剪貼簿。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 +msgid "Automatic copy failed. Select and copy the password manually." +msgstr "自動複製失敗,請手動選取並複製密碼。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:247 +msgid "Password reset" +msgstr "密碼已重設" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:248 +msgid "Username:" +msgstr "使用者名稱:" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:249 +msgid "New Password:" +msgstr "新密碼:" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:253 +msgid "Copy password" +msgstr "複製密碼" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 +msgid "Close" +msgstr "關閉" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:260 +#, javascript-format +msgid "Unable to reset the password: %s" +msgstr "無法重設密碼:%s" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:268 +msgid "Configuration contains credentials and is available only to users with write access." +msgstr "設定包含憑證資訊,僅有編輯權限的使用者可以檢視。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:3 +msgid "OpenList" +msgstr "OpenList" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 +msgid "A file list program that supports multiple storage." +msgstr "一款支援多種儲存的目錄檔案列表程式。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:274 +#, javascript-format +msgid "Initial login username is \"%s\" and password is \"%s\". Change it immediately after first login." +msgstr "初始登入使用者名稱為「%s」,密碼為「%s」。首次登入後請立即修改。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:298 +msgid "Configure a web port or Site URL to open the management page." +msgstr "請設定 Web 連接埠或站點網址,以開啟管理頁面。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:303 msgid "Basic Settings" msgstr "基本設定" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:208 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:304 msgid "Global Settings" msgstr "全域性設定" -#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:13 -msgid "Setting" -msgstr "設定" - +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:305 #: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:21 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:209 msgid "Logs" msgstr "日誌" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:210 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 msgid "Database" msgstr "資料庫" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:211 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 msgid "Search" msgstr "搜尋" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:212 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:308 msgid "Web Protocol" msgstr "Web 協議" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:213 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:309 msgid "Task threads" msgstr "任務執行緒" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:214 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:310 +msgid "Worker counts below only initialize missing settings. After the first start, change worker counts and speed limits in OpenList Management > Settings > Traffic. Upload and decompression-upload tasks do not support persistence." +msgstr "下方執行緒數僅用於初始化缺少的設定。首次啟動後,請在 OpenList 管理後台 → 設定 → 傳輸中調整執行緒數與限速。一般上傳及解壓縮上傳任務不支援持久化。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:311 msgid "CORS Settings" msgstr "跨域設定" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:215 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 msgid "Object Storage" msgstr "物件儲存" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:216 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:313 msgid "FTP" msgstr "FTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:217 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:314 msgid "SFTP" msgstr "SFTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:218 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:315 msgid "MCP" msgstr "MCP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:220 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:318 msgid "Enabled" msgstr "啟用" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:224 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:322 msgid "Debug logging" msgstr "偵錯日誌" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:225 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:323 msgid "Pass --debug to OpenList and send stderr to procd logs." msgstr "向 OpenList 傳遞 --debug,並將 stderr 傳送到 procd 日誌。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:228 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:326 msgid "Delayed Start (seconds)" msgstr "開機延時啟動(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:233 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:331 msgid "Open firewall port" msgstr "開啟防火牆埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:236 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:334 msgid "Data directory" msgstr "資料目錄" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:239 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:335 +msgid "Changing this path does not move data. Stop OpenList, back up and move the complete data directory, then apply the new path." +msgstr "修改路徑不會搬移資料。請先停止 OpenList,備份並搬移完整資料目錄,再套用新路徑。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 msgid "Cache directory" msgstr "快取目錄" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:243 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:245 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:340 +msgid "OpenList clears this directory on startup. Use a dedicated empty subdirectory. Never select a disk mount root or a directory containing files you want to keep." +msgstr "OpenList 啟動時會清空此目錄。請使用專用的空子目錄,切勿選擇磁碟掛載根目錄或含有需要保留檔案的目錄。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:344 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:346 msgid "Reset Password" msgstr "重置密碼" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:244 -msgid "Generate a new random password." -msgstr "隨機生成一個新密碼。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 +msgid "Generate a new random password using the saved and applied data directory. Start OpenList once before using this action." +msgstr "依已儲存並已套用的資料目錄隨機產生新密碼。請先啟動一次 OpenList。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:250 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 msgid "Force read config" msgstr "強制讀取配置" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:251 -msgid "" -"Setting this to true will force the program to read the configuration file, " -"ignoring environment variables." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:352 +msgid "Setting this to true will force the program to read the configuration file, ignoring environment variables." msgstr "將此設定為 true 可以強制程式讀取配置檔案,而忽略環境變數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:255 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:356 msgid "Site URL" msgstr "站點地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:256 -msgid "" -"When the web is reverse proxied to a subdirectory, this option must be " -"filled out to ensure proper functioning of the web. Do not include '/' at " -"the end of the URL" -msgstr "" -"Web 被反向代理到二級目錄時,必須填寫該選項以確保 Web 正常工作。URL 結尾請勿攜" -"帶 '/'" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:357 +msgid "When the web is reverse proxied to a subdirectory, this option must be filled out to ensure proper functioning of the web. Do not include '/' at the end of the URL" +msgstr "Web 被反向代理到二級目錄時,必須填寫該選項以確保 Web 正常工作。URL 結尾請勿攜帶 '/'" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:261 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:362 msgid "CDN URL" msgstr "CDN 地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:264 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 msgid "JWT Key" msgstr "JWT 金鑰" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:267 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 msgid "Login Validity Period (hours)" msgstr "登入有效期(小時)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:272 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:374 msgid "Proxy address" msgstr "代理地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:273 -msgid "" -"HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList " -"outbound requests." -msgstr "" -"OpenList 出站請求使用的 HTTP、HTTPS、SOCKS4、SOCKS5 或 SOCKS5HOSTNAME 代理。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 +msgid "HTTP, HTTPS, SOCKS4, SOCKS5 or SOCKS5HOSTNAME proxy used by OpenList outbound requests." +msgstr "OpenList 出站請求使用的 HTTP、HTTPS、SOCKS4、SOCKS5 或 SOCKS5HOSTNAME 代理。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:276 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:379 msgid "Auto memory limit (MB)" msgstr "自動記憶體限制(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:277 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:380 msgid "0 disables the automatic memory limit. The upstream default is 4 MB." msgstr "0 表示停用自動記憶體限制。上游預設值為 4 MB。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:282 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:385 msgid "Minimum free memory (MB)" msgstr "最小可用記憶體(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:283 -msgid "" -"Values below 16 let OpenList calculate a default; negative values disable " -"memory cache." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 +msgid "Values below 16 let OpenList calculate a default; negative values disable memory cache." msgstr "低於 16 時由 OpenList 自動計算預設值;負數表示停用記憶體快取。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:288 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:391 msgid "Maximum block size (MB)" msgstr "最大區塊大小(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:289 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:392 msgid "Values below 4 let OpenList calculate a default." msgstr "低於 4 時由 OpenList 自動計算預設值。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:294 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:397 msgid "Max Connections" msgstr "最大併發連線數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:295 -msgid "" -"0 is unlimited, It is recommend to set a low number of concurrency (10-20) " -"for poor performance device" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:398 +msgid "0 is unlimited, It is recommend to set a low number of concurrency (10-20) for poor performance device" msgstr "預設 0 不限制,低效能裝置建議設定較低的併發數(10-20)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:300 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 msgid "Max concurrency of local proxies" msgstr "本地代理最大併發數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:301 -msgid "" -"0 is unlimited, Limit the maximum concurrency of local agents. The default " -"value is 64" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:404 +msgid "0 is unlimited, Limit the maximum concurrency of local agents. The default value is 64" msgstr "限制本地代理最大併發數,值為 0 表示不限制,預設值 64" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:306 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:409 msgid "Disable TLS Verify" msgstr "停用 TLS 驗證" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:307 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:410 msgid "Skip remote TLS certificate verification (not recommended)." msgstr "跳過遠端 TLS 憑證驗證(不建議)。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:312 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:415 msgid "Enable Logs" msgstr "啟用日誌" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:316 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 msgid "Log path" msgstr "日誌檔案路徑" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:324 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:427 msgid "Log path must be /var/log/openlist2* without subdirectories." msgstr "日誌路徑必須為 /var/log/openlist2*,且不得包含子目錄。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:327 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:430 msgid "Max Size (MB)" msgstr "日誌檔案大小(MB)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:333 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:436 msgid "Max backups" msgstr "日誌備份數量" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:339 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:442 msgid "Max age" msgstr "日誌儲存天數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:345 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 msgid "Log Compress" msgstr "日誌壓縮" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:350 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:453 msgid "Enable common log filters" msgstr "啟用常用日誌過濾" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:351 -msgid "" -"Filter noisy access logs such as health checks, HEAD requests and WebDAV " -"PROPFIND." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 +msgid "Filter noisy access logs such as health checks, HEAD requests and WebDAV PROPFIND." msgstr "過濾健康檢查、HEAD 請求和 WebDAV PROPFIND 等噪聲存取日誌。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:355 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 msgid "Custom log filter CIDR" msgstr "自訂日誌過濾 CIDR" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:358 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 msgid "Custom log filter path" msgstr "自訂日誌過濾路徑" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:361 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:464 msgid "Custom log filter method" msgstr "自訂日誌過濾方法" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:365 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:468 msgid "Database Type" msgstr "資料庫型別" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:367 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 msgid "SQLite" msgstr "SQLite" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:368 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:471 msgid "MySQL" msgstr "MySQL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:369 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:472 msgid "PostgreSQL" msgstr "PostgreSQL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:371 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 msgid "Database Host" msgstr "主機" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:375 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:478 msgid "Database Port" msgstr "埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:376 -msgid "" -"Use 0 to apply the usual default for the selected database: 3306 for MySQL, " -"5432 for PostgreSQL." -msgstr "" -"使用 0 時會依所選資料庫使用常見預設連接埠:MySQL 為 3306,PostgreSQL 為 " -"5432。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 +msgid "Use 0 to apply the usual default for the selected database: 3306 for MySQL, 5432 for PostgreSQL." +msgstr "使用 0 時會依所選資料庫使用常見預設連接埠:MySQL 為 3306,PostgreSQL 為 5432。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:382 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:485 msgid "Database Username" msgstr "使用者名稱" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:386 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:489 msgid "Database Password" msgstr "密碼" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:390 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:494 msgid "Database Name" msgstr "資料庫名" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:394 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:498 msgid "Database Table Prefix" msgstr "資料庫表字首" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:399 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:503 msgid "Database SSL Mode" msgstr "SSL模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:403 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:507 msgid "Database DSN" msgstr "DSN" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:407 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:512 msgid "Meilisearch Host" msgstr "Meilisearch 主機" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:411 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:516 msgid "Meilisearch API Key" msgstr "Meilisearch API 金鑰" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:414 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:519 msgid "Meilisearch Index" msgstr "Meilisearch 索引" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:419 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 +msgid "Bleve index directory" +msgstr "Bleve 索引目錄" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:524 +msgid "Empty uses the bleve subdirectory of the data directory. Keep the index separate from cache and frontend files." +msgstr "留空時使用資料目錄下的 bleve 子目錄。索引應與快取、前端檔案分開。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:527 +msgid "External frontend directory" +msgstr "外部前端目錄" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:528 +msgid "Optional directory containing index.html from a matching OpenList frontend. Empty uses the bundled frontend. Restart OpenList after changing it." +msgstr "選填,填寫含有相容版本 OpenList 前端 index.html 的目錄。留空時使用內建前端,修改後須重新啟動 OpenList。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:532 msgid "Listen address" msgstr "監聽地址" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:424 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:537 msgid "HTTP listen port" msgstr "HTTP 監聽埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:425 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:538 msgid "The upstream default is 5244. Set to -1 to disable HTTP." msgstr "上游預設值為 5244。設為 -1 可停用 HTTP。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:434 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:547 msgid "HTTPS listen port" msgstr "HTTPS 監聽埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:435 -msgid "" -"The upstream default is -1 (disabled). Set a valid port number to enable " -"HTTPS." +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:548 +msgid "The upstream default is -1 (disabled). Set a valid port number to enable HTTPS." msgstr "上游預設值為 -1(停用)。設為有效埠號可啟用 HTTPS。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:444 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 msgid "Force HTTPS" msgstr "強制 HTTPS" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:447 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:560 msgid "SSL cert" msgstr "SSL 證書" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:448 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:561 msgid "SSL certificate file path" msgstr "SSL 證書檔案路徑" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:451 -msgid "SSL certificate file path is required when HTTPS is enabled." -msgstr "啟用 HTTPS 時必須填寫 SSL 證書檔案路徑。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:454 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:563 msgid "SSL key" msgstr "SSL 金鑰" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:455 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:564 msgid "SSL key file path" msgstr "SSL 金鑰檔案路徑" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:458 -msgid "SSL key file path is required when HTTPS is enabled." -msgstr "啟用 HTTPS 時必須填寫 SSL 金鑰檔案路徑。" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:461 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:566 msgid "Unix socket file" msgstr "Unix Socket 檔案" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:463 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:568 msgid "Unix socket permission" msgstr "Unix Socket 權限" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:465 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 msgid "Enable H2C" msgstr "啟用 H2C" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:466 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:571 msgid "Enable cleartext HTTP/2 for reverse proxies that use grpc_pass." msgstr "為使用 grpc_pass 的反向代理啟用明文 HTTP/2。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:469 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:574 msgid "Enable HTTP/3/QUIC" msgstr "啟用 HTTP/3/QUIC" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:470 -msgid "" -"Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and " -"certificate files must be configured." -msgstr "" -"在 HTTPS 監聽連接埠上啟用基於 QUIC 的 HTTP/3。必須先啟用 HTTPS 並配置憑證檔" -"案。" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:575 +msgid "Enable HTTP/3 over QUIC on the HTTPS listen port. HTTPS must be enabled and certificate files must be configured." +msgstr "在 HTTPS 監聽連接埠上啟用基於 QUIC 的 HTTP/3。必須先啟用 HTTPS 並配置憑證檔案。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:474 -msgid "Download Workers" -msgstr "下載任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:579 +msgid "Open traffic settings" +msgstr "開啟傳輸設定" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:479 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:580 +msgid "Use the OpenList backend to change the effective worker counts and transfer speed limits." +msgstr "在 OpenList 後台調整實際生效的執行緒數與傳輸限速。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:581 +msgid "Download Workers (initial)" +msgstr "下載任務初始執行緒數" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:586 msgid "Download Max Retry" msgstr "下載任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:484 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 msgid "Download Task Persistence" msgstr "下載任務持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:487 -msgid "Transfer Workers" -msgstr "中轉任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:594 +msgid "Transfer Workers (initial)" +msgstr "中轉任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:492 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:599 msgid "Transfer Max Retry" msgstr "中轉任務下載重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:497 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:604 msgid "Transfer Task Persistence" msgstr "中轉任務持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:500 -msgid "Upload Workers" -msgstr "上傳任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:607 +msgid "Upload Workers (initial)" +msgstr "上傳任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:505 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:612 msgid "Upload Max Retry" msgstr "上傳任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:510 -msgid "Upload Task Persistence" -msgstr "上傳任務持久化" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:618 +msgid "Copy Workers (initial)" +msgstr "複製任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:513 -msgid "Copy Workers" -msgstr "複製任務執行緒數" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:518 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:623 msgid "Copy Max Retry" msgstr "複製任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:523 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:628 msgid "Copy Task Persistence" msgstr "複製任務持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:526 -msgid "Move Workers" -msgstr "移動任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:631 +msgid "Move Workers (initial)" +msgstr "移動任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:531 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 msgid "Move Max Retry" msgstr "移動任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:536 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 msgid "Move Task Persistence" msgstr "移動任務持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:539 -msgid "Decompress Workers" -msgstr "解壓縮任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 +msgid "Decompress Workers (initial)" +msgstr "解壓縮任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:544 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:649 msgid "Decompress Max Retry" msgstr "解壓縮任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:549 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:654 msgid "Decompress Task Persistence" msgstr "解壓縮任務持久化" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:552 -msgid "Decompress Upload Workers" -msgstr "解壓縮上傳任務執行緒數" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:657 +msgid "Decompress Upload Workers (initial)" +msgstr "解壓縮上傳任務初始執行緒數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:557 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:662 msgid "Decompress Upload Max Retry" msgstr "解壓縮上傳任務重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:562 -msgid "Decompress Upload Task Persistence" -msgstr "解壓縮上傳任務持久化" - -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:565 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:668 msgid "Allow retry canceled tasks" msgstr "允許重試已取消的任務" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:569 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:672 msgid "Allow Origins" msgstr "允許來源(Origins)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:570 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:578 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:583 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:673 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:681 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:686 msgid "Comma-separated list. Use * to allow any value." msgstr "使用英文逗號分隔。使用 * 表示允許任意值。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:577 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:680 msgid "Allow Methods" msgstr "允許方法(Methods)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:582 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:685 msgid "Allow Headers" msgstr "允許標頭(Headers)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:588 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:691 +msgid "Open S3 management" +msgstr "開啟 S3 管理" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:692 +msgid "Generate the S3 access key and secret in OpenList settings, then configure bucket mappings. Restart OpenList after changing credentials." +msgstr "先在 OpenList 設定中產生 S3 存取金鑰,再設定儲存桶映射。變更憑證資訊後須重新啟動 OpenList。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:693 msgid "Enabled S3" msgstr "啟用 S3" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:591 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:696 msgid "Port" msgstr "埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:596 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:701 msgid "Enable SSL" msgstr "啟用 SSL" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:600 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:705 +msgid "Open FTP settings" +msgstr "開啟 FTP 設定" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:706 +msgid "Configure the public host and passive port mapping in OpenList. Restart the service after changing FTP settings." +msgstr "在 OpenList 中設定公網位址與被動連接埠映射,修改 FTP 設定後須重新啟動服務。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:707 +msgid "FTP passive firewall ports" +msgstr "FTP 被動連接埠放行" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:708 +msgid "Ports or ranges to allow from WAN, for example 50000-50100. They must match the listening ports in OpenList passive port mapping. Empty means passive ports must be allowed manually." +msgstr "允許從 WAN 存取的連接埠或範圍,例如 50000-50100,必須與 OpenList 被動連接埠映射中的監聽埠一致。留空表示需要自行放行被動連接埠。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:711 msgid "Enabled FTP" msgstr "啟用 FTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:603 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:714 msgid "FTP Port" msgstr "FTP 埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:608 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:719 msgid "Max retries on port conflict during passive transfer" msgstr "被動傳輸埠衝突時最大重試次數" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:613 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:724 msgid "Enable non-20 port for active transfer" msgstr "啟用非 20 埠進行主動傳輸" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:616 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:727 msgid "Client idle timeout (seconds)" msgstr "客戶端空閒超時(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:621 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:732 msgid "Connection timeout (seconds)" msgstr "連線超時(秒)" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:626 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:737 msgid "Disable active transfer mode" msgstr "停用主動傳輸模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:629 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:740 msgid "Enable binary transfer mode" msgstr "啟用二進位制傳輸模式" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:632 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:743 msgid "Client IP check in active transfer mode" msgstr "主動傳輸模式下對客戶端進行 IP 檢查" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:636 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:747 msgid "Client IP check in passive transfer mode" msgstr "被動傳輸模式下對客戶端進行 IP 檢查" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:641 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:752 msgid "Enabled SFTP" msgstr "啟用 SFTP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:644 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:755 msgid "SFTP Port" msgstr "SFTP 埠" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:651 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:761 msgid "Enabled MCP" msgstr "啟用 MCP" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:652 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:762 msgid "Enable MCP (Model Context Protocol) server." msgstr "啟用 MCP(模型上下文協定)伺服器。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:20 -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:766 +msgid "MCP endpoint" +msgstr "MCP 端點" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:767 +msgid "Use Streamable HTTP with Authorization: TOKEN, without a Bearer prefix. Use an OpenList user login token; retain MCP-Session-Id for subsequent requests." +msgstr "使用 Streamable HTTP,認證標頭為 Authorization: TOKEN,不加 Bearer 前綴。TOKEN 為 OpenList 使用者登入權杖,後續請求須保留 MCP-Session-Id。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:770 +msgid "Configure a web port or Site URL." +msgstr "請設定 Web 連接埠或站點網址。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:771 +msgid "MCP documentation" +msgstr "MCP 文件" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:787 +msgid "Use a dedicated subdirectory, not a system directory or disk mount root." +msgstr "請使用專用子目錄,不得使用系統目錄或磁碟掛載根目錄。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:789 +msgid "Use a cache subdirectory below the disk mount." +msgstr "請使用磁碟掛載目錄下的快取子目錄。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:792 +msgid "Cache and index directories must be separate and must not contain the data directory." +msgstr "快取與索引目錄必須分開,且不得包含資料目錄。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:795 +msgid "Frontend files must be separate from private data, cache and index files." +msgstr "前端檔案必須與私人資料、快取及索引分開。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:806 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:815 +msgid "Certificate and key paths are required for HTTPS or S3 SSL." +msgstr "啟用 HTTPS 或 S3 SSL 時必須填寫憑證及私密金鑰路徑。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:812 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:855 +msgid "Force HTTPS and HTTP/3 require an enabled HTTPS port." +msgstr "強制 HTTPS 和 HTTP/3 需要先啟用 HTTPS 連接埠。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:818 +msgid "Use 3 or 4 octal digits, for example 660 or 0660." +msgstr "請使用 3 或 4 位八進位數字,例如 660 或 0660。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:844 +#, javascript-format +msgid "Enabled services cannot share TCP port %s." +msgstr "啟用的服務不能共用 TCP 連接埠 %s。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/basic.js:850 +#, javascript-format +msgid "FTP passive ports must not overlap service port %s." +msgstr "FTP 被動連接埠不得與服務埠 %s 重疊。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:10 msgid "No log data." msgstr "無日誌資料。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:77 -msgid "Clear logs" -msgstr "清空日誌" +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:18 +msgid "Unable to read the log." +msgstr "無法讀取日誌。" -#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:86 +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:29 +#, javascript-format +msgid "Unable to read the log: %s" +msgstr "無法讀取日誌:%s" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:40 +msgid "Unable to clear the log." +msgstr "無法清空日誌。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:59 +msgid "Clear current log" +msgstr "清空目前日誌" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:64 +msgid "Showing up to the last 200 lines and 16 KiB. Older entries remain in the log files." +msgstr "最多顯示末尾 200 行、16 KiB。較早的記錄仍保留在日誌檔案中。" + +#: luci-app-openlist2/htdocs/luci-static/resources/view/openlist2/logs.js:69 #, javascript-format msgid "Refresh every %s seconds." msgstr "每 %s 秒重新整理。" -#~ msgid "Grant UCI access for luci-app-openlist2" -#~ msgstr "授予 luci-app-openlist2 的 UCI 訪問許可權" +#: luci-app-openlist2/root/usr/share/luci/menu.d/luci-app-openlist2.json:13 +msgid "Setting" +msgstr "設定" diff --git a/luci-app-openlist2/root/etc/uci-defaults/luci-app-openlist2 b/luci-app-openlist2/root/etc/uci-defaults/luci-app-openlist2 index df2e32445..16eb07444 100644 --- a/luci-app-openlist2/root/etc/uci-defaults/luci-app-openlist2 +++ b/luci-app-openlist2/root/etc/uci-defaults/luci-app-openlist2 @@ -8,6 +8,9 @@ EEOF } +. /usr/share/openlist2/functions.sh +openlist2_migrate_config || exit 1 + [ -f "/etc/config/ucitrack" ] && { uci -q batch <<-EOF >/dev/null delete ucitrack.@openlist2[-1] diff --git a/luci-app-openlist2/root/usr/share/rpcd/acl.d/luci-app-openlist2.json b/luci-app-openlist2/root/usr/share/rpcd/acl.d/luci-app-openlist2.json index cc92f5e4a..a0f0af75b 100644 --- a/luci-app-openlist2/root/usr/share/rpcd/acl.d/luci-app-openlist2.json +++ b/luci-app-openlist2/root/usr/share/rpcd/acl.d/luci-app-openlist2.json @@ -1,23 +1,27 @@ { "luci-app-openlist2": { - "description": "Grant UCI access for luci-app-openlist2", + "description": "Read OpenList status and bounded logs; grant configuration and reset actions only to editors", "read": { "file": { - "/usr/bin/openlist2": [ "exec" ], - "/var/log/openlist2.log": [ "read" ], - "/var/log/openlist2*": [ "read" ] + "/usr/libexec/openlist2-helper log-read": [ "exec" ] }, "ubus": { - "service": [ "list" ] - }, - "uci": [ "openlist2" ] + "service": [ "list" ], + "file": [ "exec" ] + } }, "write": { "file": { - "/var/log/openlist2.log": [ "write" ], - "/var/log/openlist2*": [ "write" ] + "/usr/libexec/openlist2-helper log-clear": [ "exec" ], + "/usr/libexec/openlist2-helper password-reset": [ "exec" ] }, - "uci": [ "openlist2" ] + "ubus": { + "file": [ "exec" ], + "uci": [ "get", "set", "add", "delete", "changes", "apply", "confirm", "revert", "order" ] + }, + "uci": { + "openlist2": [ "read", "write" ] + } } } } diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 7338ef6e2..0a5035be0 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.9.12 -PKG_RELEASE:=120 +PKG_RELEASE:=121 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index a08e030fd..89ea0b541 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -336,7 +336,7 @@ end function index_status() local e = {} - e["global_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep '/acl/default' >/dev/null" % api.TMP_PATH) == 0 + e["global_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep '/acl_default\\.json' >/dev/null" % api.TMP_PATH) == 0 http_write_json(e) end diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index c2fd0babc..2f39c4004 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -311,8 +311,8 @@ loglevel:value("error") o = s:taboption("log", DummyValue, "_log", translate("Log File")) o.rawhtml = true o.cfgvalue = function(t, n) - local log_path = api.TMP_PATH .. "/acl/default.log" - local log_url = api.url("get_redir_log") .. "?id=default" + local log_path = api.TMP_PATH .. "/acl/acl_default.log" + local log_url = api.url("get_redir_log") .. "?id=acl_default" return string.format( '%s  ', log_path, diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index 8828ec022..e7a64a600 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -192,12 +192,16 @@ function sh_uci_commit(config) exec_call(string.format("uci -q commit %s", config)) end +function del_cache_var(key) + sys.call(string.format('. /usr/share/passwall2/utils.sh ; del_cache_var "%s"', key)) +end + function set_cache_var(key, val) - sys.call(string.format('. /usr/share/passwall2/utils.sh ; set_cache_var %s "%s"', key, val)) + sys.call(string.format('. /usr/share/passwall2/utils.sh ; set_cache_var "%s" "%s"', key, val)) end function get_cache_var(key) - local val = sys.exec(string.format('. /usr/share/passwall2/utils.sh ; echo -n $(get_cache_var %s)', key)) + local val = sys.exec(string.format('. /usr/share/passwall2/utils.sh ; echo -n $(get_cache_var "%s")', key)) if val == "" then val = nil end return val end @@ -2054,3 +2058,11 @@ function parseDNS(dns) end return dns, 53 end + +function get_socks_port_by_cache(node_id) + return get_cache_var("node_%s_socks_port" % { node_id }) +end + +function set_socks_port_to_cache(node_id, v) + set_cache_var("node_%s_socks_port" % { node_id }, v) +end diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 7a8f47f9c..91cb5bae4 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -123,31 +123,46 @@ function gen_outbound(flag, node, tag, proxy_table) end if node.type ~= "sing-box" then - local relay_port = node.port - local new_port = api.get_new_port() - local config_file = string.format("%s_%s_%s.json", flag, tag, new_port) - if tag and node_id and not tag:find(node_id) then - config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port) - end + local new_port if run_socks_instance then - sys.call(string.format('/usr/share/passwall2/app.sh run_socks "%s"> /dev/null', - string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", - new_port, --flag - node_id, --node - "127.0.0.1", --bind - new_port, --socks port - config_file, --config file - (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + local relay_port = (proxy_tag and node.port) and tostring(node.port) or "" + if relay_port == "" then + local cache = api.get_socks_port_by_cache(node_id) + if cache then + new_port = cache + run_socks_instance = nil + end + end + if run_socks_instance then + new_port = api.get_new_port() + local config_file = string.format("nodesocks_%s_%s.json", node_id, new_port) + if tag and node_id and not tag:find(node_id) then + config_file = string.format("nodesocks_%s_%s_%s.json", tag, node_id, new_port) + end + sys.call(string.format('/usr/share/passwall2/app.sh run_socks "%s"> /dev/null', + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", + new_port, --flag + node_id, --node + "127.0.0.1", --bind + new_port, --socks port + config_file, --config file + relay_port --relay port + ) ) ) - ) + if relay_port == "" then + api.set_socks_port_to_cache(node_id, new_port) + end + end + end + if new_port then + node = { + protocol = "socks", + address = "127.0.0.1", + port = new_port + } + proxy_tag = "socks <- " .. node_id end - node = { - protocol = "socks", - address = "127.0.0.1", - port = new_port - } - proxy_tag = "socks <- " .. node_id else if proxy_tag then node.detour = proxy_tag diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index b90256824..01fa69b68 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -71,32 +71,47 @@ function gen_outbound(flag, node, tag, proxy_table) end if node.type ~= "Xray" then - local relay_port = node.port - local new_port = api.get_new_port() - local config_file = string.format("%s_%s_%s.json", flag, tag, new_port) - if tag and node_id and not tag:find(node_id) then - config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port) - end + local new_port if run_socks_instance then - sys.call(string.format('/usr/share/passwall2/app.sh run_socks "%s"> /dev/null', - string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", - new_port, --flag - node_id, --node - "127.0.0.1", --bind - new_port, --socks port - config_file, --config file - (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + local relay_port = (proxy_tag and node.port) and tostring(node.port) or "" + if relay_port == "" then + local cache = api.get_socks_port_by_cache(node_id) + if cache then + new_port = cache + run_socks_instance = nil + end + end + if run_socks_instance then + new_port = api.get_new_port() + local config_file = string.format("nodesocks_%s_%s.json", node_id, new_port) + if tag and node_id and not tag:find(node_id) then + config_file = string.format("nodesocks_%s_%s_%s.json", tag, node_id, new_port) + end + sys.call(string.format('/usr/share/passwall2/app.sh run_socks "%s"> /dev/null', + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", + new_port, --flag + node_id, --node + "127.0.0.1", --bind + new_port, --socks port + config_file, --config file + relay_port --relay port + ) ) ) - ) + if relay_port == "" then + api.set_socks_port_to_cache(node_id, new_port) + end + end + end + if new_port then + node = {} + node.protocol = "socks" + node.transport = "tcp" + node.address = "127.0.0.1" + node.port = new_port + node.stream_security = "none" + proxy_tag = "socks <- " .. node_id end - node = {} - node.protocol = "socks" - node.transport = "tcp" - node.address = "127.0.0.1" - node.port = new_port - node.stream_security = "none" - proxy_tag = "socks <- " .. node_id else dialer_proxy_tag = proxy_tag end diff --git a/luci-app-passwall2/luasrc/view/passwall2/global/footer.htm b/luci-app-passwall2/luasrc/view/passwall2/global/footer.htm index 6027f5afd..0696f3aab 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/global/footer.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/global/footer.htm @@ -127,7 +127,7 @@ local sid = "@global[0]" const m = cbid.match(/\.node$/); if (m) { - html += '?id=default' + '\', \'_blank\')"><%:Log%>'; + html += '?id=acl_default' + '\', \'_blank\')"><%:Log%>'; } html = '
' + html + '
' diff --git a/luci-app-passwall2/root/usr/share/passwall2/app.sh b/luci-app-passwall2/root/usr/share/passwall2/app.sh index 7ee542356..a8ee0d4ea 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/app.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/app.sh @@ -855,7 +855,7 @@ acl_node() { local DNSMASQ_DEFAULT_DNS="${AUTO_DNS}" local DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}" [ -n "${DIRECT_DNS_DNSMASQ_SERVER}" ] && DNSMASQ_LOCAL_DNS="${DIRECT_DNS_DNSMASQ_SERVER}" - if [ "${flag}" = "default" ]; then + if [ "${flag}" = "acl_default" ]; then set_cache_var "GLOBAL_SOCKS_server" "127.0.0.1:$socks_port" set_cache_var "ACL_GLOBAL_node" "$node" run_new_dnsmasq=$(config_n_get @global[0] dns_redirect 1) @@ -864,7 +864,7 @@ acl_node() { #Modify the default dnsmasq service lua $APP_PATH/helper_dnsmasq.lua stretch json_init - json_add_string "FLAG" "default" + json_add_string "FLAG" "${flag}" json_add_string "TMP_DNSMASQ_PATH" "${GLOBAL_DNSMASQ_CONF_PATH}" json_add_string "DNSMASQ_CONF_FILE" "${GLOBAL_DNSMASQ_CONF}" json_add_string "DEFAULT_DNS" "${DNSMASQ_DEFAULT_DNS}" @@ -912,7 +912,7 @@ start() { check_run_environment [ -n "$USE_TABLES" ] && { ACL_JSON=$(lua $APP_PATH/app_acl.lua) - [ ! -f ${TMP_ACL_PATH}/acl_node_default ] && ENABLED_DEFAULT_ACL=0 + [ ! -f ${TMP_ACL_PATH}/acl_node_acl_default ] && ENABLED_DEFAULT_ACL=0 local acl_node_num=$(jsonfilter -s "${ACL_JSON}" -e '$.node_order[*]' | wc -l) if [ "${acl_node_num}" == 0 ]; then @@ -1062,7 +1062,7 @@ get_config() { fi fi set_cache_var GLOBAL_DNSMASQ_CONF ${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf - set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${TMP_ACL_PATH}/default_dnsmasq.d + set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${TMP_ACL_PATH}/acl_default_dnsmasq.d QUEUE_RUN=1 } diff --git a/luci-app-passwall2/root/usr/share/passwall2/app_acl.lua b/luci-app-passwall2/root/usr/share/passwall2/app_acl.lua index a4acbe96c..e4ece480c 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/app_acl.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/app_acl.lua @@ -24,7 +24,7 @@ end function init_acl() if true then -- Get Default AC - D.flag = "default" + D.flag = "acl_default" D.remarks = api.i18n.translatef("Default") D.tcp_no_redir_ports = uci_get("@global_forwarding[0]", "tcp_no_redir_ports") D.udp_no_redir_ports = uci_get("@global_forwarding[0]", "udp_no_redir_ports") diff --git a/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua b/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua index 5167adb37..47276ce10 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua @@ -109,20 +109,26 @@ api.uci_foreach_c("haproxy_config", function(t) t.origin_port = server_port if health_check_type == "script_logic" then if server_node.type ~= "Socks" then - local relay_port = server_node.port - local new_port = api.get_new_port() - local config_file = string.format("%s_%s.json", t[".name"], new_port) - sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', - appname, - string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s", - new_port, --flag - server_node[".name"], --node - "127.0.0.1", --bind - new_port, --socks port - config_file --config file + local new_port + local cache = api.get_socks_port_by_cache(server_node[".name"]) + if cache then + new_port = cache + else + new_port = api.get_new_port() + local config_file = string.format("%s_%s.json", t[".name"], new_port) + sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', + appname, + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s", + new_port, --flag + server_node[".name"], --node + "127.0.0.1", --bind + new_port, --socks port + config_file --config file + ) ) ) - ) + api.set_socks_port_to_cache(server_node[".name"], new_port) + end server_address = "127.0.0.1" server_port = new_port end diff --git a/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua b/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua index 17ec2f3e9..5118f6146 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua @@ -329,7 +329,7 @@ function add_rule(var) tinsert(conf_lines, "no-poll") tinsert(conf_lines, "no-resolv") - if FLAG == "default" then + if FLAG == "acl_default" then api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS) end end diff --git a/luci-app-passwall2/root/usr/share/passwall2/iptables.sh b/luci-app-passwall2/root/usr/share/passwall2/iptables.sh index 0befd38bf..4176e3839 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/iptables.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/iptables.sh @@ -755,8 +755,8 @@ add_firewall_rule() { $ipt_m -N PSW2 # Socket Only TCP, UDP Invalid. - $ipt_m -A PSW2 -p tcp -m socket -j MARK --set-mark ${FWMARK} - $ipt_m -A PSW2 -p tcp -m socket -j ACCEPT + $ipt_m -A PSW2 -p tcp -m socket --transparent -j MARK --set-mark ${FWMARK} + $ipt_m -A PSW2 -p tcp -m socket --transparent -j ACCEPT $ipt_m -A PSW2 $(dst $IPSET_VPS) -j RETURN $ipt_m -A PSW2 $(comment "WAN_IP_RETURN") $(dst $IPSET_WAN) -j RETURN $ipt_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN @@ -798,8 +798,8 @@ add_firewall_rule() { $ip6t_m -N PSW2 # Socket Only TCP, UDP Invalid. - $ip6t_m -A PSW2 -p tcp -m socket -j MARK --set-mark ${FWMARK} - $ip6t_m -A PSW2 -p tcp -m socket -j ACCEPT + $ip6t_m -A PSW2 -p tcp -m socket --transparent -j MARK --set-mark ${FWMARK} + $ip6t_m -A PSW2 -p tcp -m socket --transparent -j ACCEPT $ip6t_m -A PSW2 $(dst $IPSET_VPS6) -j RETURN $ip6t_m -A PSW2 $(comment "WAN6_IP_RETURN") $(dst $IPSET_WAN6) -j RETURN $ip6t_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN diff --git a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh index 733abab8e..7cb1960c4 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh @@ -331,12 +331,15 @@ load_acl() { [ -n "$dns_redirect_port" ] && { #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp udp dport 53 counter accept" #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol tcp tcp dport 53 counter accept" - #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp udp dport 53 counter accept" - #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME nat_output ip protocol udp oif lo udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" - nft "add rule $NFTABLE_NAME nat_output ip protocol tcp oif lo tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" - nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" - nft "add rule $NFTABLE_NAME nat_output meta l4proto tcp oif lo tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" + if [ "$PROXY_IPV6" == "1" ]; then + #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp udp dport 53 counter accept" + #nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept" + nft "add rule $NFTABLE_NAME nat_output oif lo meta l4proto udp udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" + nft "add rule $NFTABLE_NAME nat_output oif lo meta l4proto tcp tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" + else + nft "add rule $NFTABLE_NAME nat_output oif lo ip protocol udp udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" + nft "add rule $NFTABLE_NAME nat_output oif lo ip protocol tcp tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\"" + fi log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")" } fi @@ -501,20 +504,26 @@ load_acl() { } if ([ -z "$no_tcp_proxy" ] || [ -z "$no_udp_proxy" ]) && [ -n "$dns_redirect_port" ]; then - nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" + if [ "$PROXY_IPV6" == "1" ]; then + nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter accept" + nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter accept" + nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" + else + nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter accept" + nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter accept" + nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" + fi log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")" else - nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + if [ "$PROXY_IPV6" == "1" ]; then + nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + else + nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + fi fi [ -z "$no_tcp_proxy" ] && [ -n "$redir_port" ] && { diff --git a/luci-app-passwall2/root/usr/share/passwall2/utils.sh b/luci-app-passwall2/root/usr/share/passwall2/utils.sh index 68db5cd69..fc5f08902 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/utils.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/utils.sh @@ -60,15 +60,24 @@ get_cache_var() { } } +del_cache_var() { + local key="${1}" + [ -n "${key}" ] && [ -f "${TMP_PATH}/var" ] && { + sed -i "/${key}=/d" $TMP_PATH/var >/dev/null 2>&1 + } +} + set_cache_var() { local key="${1}" shift 1 - local val="$@" - [ -n "${key}" ] && [ -n "${val}" ] && { - [ ! -d $TMP_PATH ] && mkdir -p $TMP_PATH - sed -i "/${key}=/d" $TMP_PATH/var >/dev/null 2>&1 - echo "${key}=\"${val}\"" >> $TMP_PATH/var - eval ${key}=\"${val}\" + [ -n "${key}" ] && { + del_cache_var ${key} + local val="$@" + [ -n "${val}" ] && { + [ ! -d $TMP_PATH ] && mkdir -p $TMP_PATH + echo "${key}=\"${val}\"" >> $TMP_PATH/var + eval ${key}=\"${val}\" + } } } diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index fdb54d2c7..edb32bd59 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=196 -PKG_RELEASE:=70 +PKG_RELEASE:=71 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 240408992..e037f97cf 100755 --- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -628,16 +628,6 @@ prepare_clash_runtime_config() { client_policy_stats="" client_rules=0 enable_fake_ip="$(uci_get_by_type server_subscribe enable_fake_ip "")" - socks5_auth="$(uci_get_by_type socks5_proxy socks5_auth noauth)" - socks5_user="$(uci_get_by_type socks5_proxy socks5_user "")" - socks5_pass="$(uci_get_by_type socks5_proxy socks5_pass "")" - - if [ "$socks5_auth" = "password" ]; then - if [ -z "$socks5_user" ] || [ -z "$socks5_pass" ]; then - echolog "警告:SOCKS5 代理未完整配置用户名或密码,已自动降级为无认证模式 (noauth)。" - socks5_auth="noauth" - fi - fi [ -s "$cache_file" ] || return 1 @@ -684,6 +674,18 @@ prepare_clash_runtime_config() { if [ -n "$socks_port" ] && [ "$socks_port" != "0" ]; then echo "socks-port: $socks_port" >>"$overlay_file" + + socks5_auth="$(uci_get_by_type socks5_proxy socks5_auth noauth)" + socks5_user="$(uci_get_by_type socks5_proxy socks5_user "")" + socks5_pass="$(uci_get_by_type socks5_proxy socks5_pass "")" + + if [ "$socks5_auth" = "password" ]; then + if [ -z "$socks5_user" ] || [ -z "$socks5_pass" ]; then + echolog "警告:SOCKS5 代理未完整配置用户名或密码,已自动降级为无认证模式 (noauth)。" + socks5_auth="noauth" + fi + fi + if [ "$socks5_auth" = "password" ]; then cat >>"$overlay_file" <<-EOF authentication: diff --git a/luci-app-wwand/Makefile b/luci-app-wwand/Makefile index 4777d9dc8..289bf965f 100644 --- a/luci-app-wwand/Makefile +++ b/luci-app-wwand/Makefile @@ -17,12 +17,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-wwand -PKG_VERSION:=1.6.6_p7 -PKG_RELEASE:=19 +PKG_VERSION:=1.6.6_p9 +PKG_RELEASE:=20 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/ddimension/luci-app-wwand.git -PKG_SOURCE_VERSION:=ef4b59a891229d189ad5167def96eab22a5ceb03 +PKG_SOURCE_VERSION:=630dd7b09fdbd12d9ddb23540968694d898a6d7c PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL-2.0-only diff --git a/luci-theme-aurora/.dev/src/media/components/_table.css b/luci-theme-aurora/.dev/src/media/components/_table.css index b5e0fdc67..5c5b0a4f2 100644 --- a/luci-theme-aurora/.dev/src/media/components/_table.css +++ b/luci-theme-aurora/.dev/src/media/components/_table.css @@ -175,7 +175,7 @@ table.table, /* Mobile cards (bootstrap-style): value fields stack one per row — the row title and long match-rule cells get the full width — while display-only widgets below pair up two per row. */ - @apply break-all max-md:mb-1 max-md:basis-full max-md:self-start max-md:text-left; + @apply wrap-anywhere md:max-w-prose max-md:mb-1 max-md:basis-full max-md:self-start max-md:text-left; &[data-widget="CBI.DummyValue"], &[data-widget="CBI.Button"], diff --git a/luci-theme-aurora/Makefile b/luci-theme-aurora/Makefile index 54e1d055e..56c55055a 100644 --- a/luci-theme-aurora/Makefile +++ b/luci-theme-aurora/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CSS) LUCI_DEPENDS:=+luci-base -PKG_VERSION:=1.3.1 -PKG_RELEASE:=78 +PKG_VERSION:=1.3.2 +PKG_RELEASE:=79 PKG_LICENSE:=Apache-2.0 LUCI_MINIFY_CSS:= diff --git a/luci-theme-aurora/htdocs/luci-static/aurora/main.css b/luci-theme-aurora/htdocs/luci-static/aurora/main.css index ebf7b0ea8..7558c6113 100644 --- a/luci-theme-aurora/htdocs/luci-static/aurora/main.css +++ b/luci-theme-aurora/htdocs/luci-static/aurora/main.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-content:"";--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-border-style:solid;--tw-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components,utilities;:root{--bg:#f7fafc;--surface:#fff;--text:#121a22;--brand:#0085b7;--on-brand:#fff;--link:#0085b7;--info:#0e5794;--warning:#643e00;--success:#004f3e;--danger:#8d1925;--text-muted:#5f666d;--text-subtle:#7f858b;--surface-sunken:#f4f7fa;--surface-overlay:#fff;--hairline:#121a2221;--hover-faint:#ebeff2;--brand-hover:#0073a3;--brand-subtle:#ddecf5;--brand-subtle-hover:#d0dfe8;--focus-ring:#0085b799;--progress-start:#64aed5;--progress-end:#0085b7;--info-surface:#deefff;--warning-surface:#ffedd6;--success-surface:#d3f8eb;--danger-surface:#ffe8e6;--danger-surface-hover:#f9d9d7;--control-bg:#fff;--scrim:#0009;--mega-menu-bg:#f1f7fa;--mega-menu-scrim:#0d1c2a61;--app-shadow-sm:0 1px 3px #0000000f, 0 1px 2px #0000000a;--app-shadow-md:0 4px 16px #00000014, 0 1px 3px #0000000a;--app-shadow-lg:0 12px 32px #0000001f;--app-opacity-disabled:.4;--font-sans:"Lato", ui-sans-serif, system-ui, sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;--spacing:.25rem;--content-width-centered:80rem;--radius-base:.5rem}@supports (color:lab(0% 0 0)){:root{--bg:lab(98.1553% -.760227 -1.25223);--surface:lab(100% 0 0);--text:lab(8.89727% -1.68239 -6.93074);--brand:lab(51.3503% -19.237 -40.2116);--on-brand:lab(100% 0 0);--link:lab(51.3503% -19.237 -40.2116);--info:lab(35.5745% -2.86636 -40.2468);--warning:lab(30.2236% 14.0359 42.8654);--success:lab(29.3859% -35.8952 5.0677);--danger:lab(31.1495% 47.9256 25.8661);--text-muted:lab(42.8254% -1.57365 -4.8763);--text-subtle:lab(55.3248% -1.4126 -4.053);--surface-sunken:lab(97.114% -.949115 -1.56456);--surface-overlay:lab(100.011% -.760317 -1.25225);--hairline:lab(8.89727% -1.68239 -6.93074/.13);--hover-faint:lab(94.2168% -1.13726 -1.87657);--brand-hover:lab(44.3401% -18.0233 -40.0589);--brand-subtle:lab(92.5794% -3.9458 -6.17858);--brand-subtle-hover:lab(87.9391% -3.94133 -6.17628);--focus-ring:lab(51.3503% -19.237 -40.2116/.6);--progress-start:lab(67.4852% -15.7175 -27.197);--progress-end:lab(51.3503% -19.237 -40.2116);--info-surface:lab(93.5628% -4.16487 -14.7881);--warning-surface:lab(94.8007% 4.75499 15.6111);--success-surface:lab(94.7525% -14.2308 2.09508);--danger-surface:lab(93.849% 11.2841 5.29771);--danger-surface-hover:lab(89.2089% 11.2856 5.30034);--control-bg:lab(100.011% -.760317 -1.25225);--scrim:lab(0% 0 0/.6);--mega-menu-bg:lab(96.7742% -1.51286 -2.50006);--mega-menu-scrim:lab(9.40633% -2.1807 -11.9349/.38);--app-shadow-sm:0 1px 3px lab(0% 0 0/.06), 0 1px 2px lab(0% 0 0/.04);--app-shadow-md:0 4px 16px lab(0% 0 0/.08), 0 1px 3px lab(0% 0 0/.04);--app-shadow-lg:0 12px 32px lab(0% 0 0/.12)}}[data-darkmode=true]{--bg:#05070e;--surface:#141822;--text:#f9fafb;--brand:#00958e;--on-brand:#fff;--link:#00958e;--info:#90c1ff;--warning:#f0ba59;--success:#51bd85;--danger:#f17070;--text-muted:#909297;--text-subtle:#5d6067;--surface-sunken:#0a0e17;--surface-overlay:#181d27;--hairline:#f9fafb1a;--hover-faint:#f9fafb0d;--brand-hover:#00837d;--brand-subtle:#061a20;--brand-subtle-hover:#0f242a;--focus-ring:#00958e99;--progress-start:#006261;--progress-end:#00958e;--info-surface:#21344c;--warning-surface:#45310b;--success-surface:#153524;--danger-surface:#541f20;--danger-surface-hover:#602a2a;--control-bg:#0a0e17;--scrim:#0009;--mega-menu-bg:#0a0e17;--mega-menu-scrim:#00000080;--app-shadow-sm:0 4px 12px #0000004d;--app-shadow-md:0 10px 28px #0000006b;--app-shadow-lg:0 20px 48px #0000008c;--app-opacity-disabled:.3}@supports (color:lab(0% 0 0)){[data-darkmode=true]{--bg:lab(1.93894% .0855997 -3.22397);--surface:lab(8.24713% -.0405461 -7.31381);--text:lab(98.252% -.0618994 -.756907);--brand:lab(55.0978% -44.5567 -7.62978);--on-brand:lab(100% 0 0);--link:lab(55.0978% -44.5567 -7.62978);--info:lab(76.3382% -4.43128 -38.7);--warning:lab(79.1996% 12.6808 55.9505);--success:lab(69.2339% -42.392 18.6731);--danger:lab(63.5705% 50.8105 25.3639);--text-muted:lab(60.5379% -.225931 -3.05105);--text-subtle:lab(40.6865% -.278354 -4.23647);--surface-sunken:lab(3.9802% .0812709 -5.64623);--surface-overlay:lab(10.5702% -.0939444 -7.33123);--hairline:lab(98.252% -.0618994 -.756907/.1);--hover-faint:lab(98.252% -.0618994 -.756907/.05);--brand-hover:lab(49.2976% -44.6964 -7.56882);--brand-subtle:lab(7.95734% -6.34954 -6.72844);--brand-subtle-hover:lab(12.602% -6.92477 -6.76408);--focus-ring:lab(55.0986% -44.5682 -7.59286/.6);--progress-start:lab(36.8833% -28.7182 -7.50749);--progress-end:lab(55.0978% -44.5567 -7.62978);--info-surface:lab(20.893% -1.69295 -17.5199);--warning-surface:lab(22.2973% 6.18184 26.7927);--success-surface:lab(19.4608% -16.2551 7.16286);--danger-surface:lab(20.3014% 25.4342 12.827);--danger-surface-hover:lab(24.9464% 25.3964 12.6412);--control-bg:lab(3.9802% .0812709 -5.64623);--scrim:lab(0% 0 0/.6);--mega-menu-bg:lab(3.9802% .0812709 -5.64623);--mega-menu-scrim:lab(0% 0 0/.5);--app-shadow-sm:0 4px 12px lab(0% 0 0/.3);--app-shadow-md:0 10px 28px lab(0% 0 0/.42);--app-shadow-lg:0 20px 48px lab(0% 0 0/.55)}}:root{--icon-activity:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012h4l3%208l4%20-16l3%208h4'%20/%3e%3c/svg%3e");--icon-adjustments:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%2010a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M6%204v4'%20/%3e%3cpath%20d='M6%2012v8'%20/%3e%3cpath%20d='M10%2016a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M12%204v10'%20/%3e%3cpath%20d='M12%2018v2'%20/%3e%3cpath%20d='M16%207a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M18%204v1'%20/%3e%3cpath%20d='M18%209v11'%20/%3e%3c/svg%3e");--icon-apps:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%205a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M4%2015a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M14%2015a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M14%207l6%200'%20/%3e%3cpath%20d='M17%204l0%206'%20/%3e%3c/svg%3e");--icon-arrow-down:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M5.22%208.22a.75.75%200%200%201%201.06%200L10%2011.94l3.72-3.72a.75.75%200%201%201%201.06%201.06l-4.25%204.25a.75.75%200%200%201-1.06%200L5.22%209.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-arrow-down-dark:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23ffffff'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M5.22%208.22a.75.75%200%200%201%201.06%200L10%2011.94l3.72-3.72a.75.75%200%201%201%201.06%201.06l-4.25%204.25a.75.75%200%200%201-1.06%200L5.22%209.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-arrow-right:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M8.22%205.22a.75.75%200%200%201%201.06%200l4.25%204.25a.75.75%200%200%201%200%201.06l-4.25%204.25a.75.75%200%200%201-1.06-1.06L11.94%2010L8.22%206.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-box:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203l8%204.5l0%209l-8%204.5l-8%20-4.5l0%20-9l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l0%209'%20/%3e%3cpath%20d='M12%2012l-8%20-4.5'%20/%3e%3c/svg%3e");--icon-category:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%204h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M14%204h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M4%2014h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M14%2017a3%203%200%201%200%206%200a3%203%200%201%200%20-6%200'%20/%3e%3c/svg%3e");--icon-chart-bar:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2013a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v6a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-6'%20/%3e%3cpath%20d='M15%209a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v10a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-10'%20/%3e%3cpath%20d='M9%205a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v14a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-14'%20/%3e%3cpath%20d='M4%2020h14'%20/%3e%3c/svg%3e");--icon-check:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20d='M918.8%2083.7c-43.5-30.3-104-19.5-134.6%2024.1l-425.8%20606-127-135.7c-36.4-38.9-98.1-41.1-137-4.8-39%2036.2-41.1%2097.7-4.7%20136.6l206.5%20220.7c4.7%205%209.8%209.4%2015.1%2013.1.7.5%201.4%201%202.2%201.5%2043.5%2030.3%20104%2019.5%20134.6-24.1l494-703.2c30.7-43.5%2020.1-103.9-23.3-134.2z'/%3e%3c/svg%3e");--icon-cpu:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M5%206a1%201%200%200%201%201%20-1h12a1%201%200%200%201%201%201v12a1%201%200%200%201%20-1%201h-12a1%201%200%200%201%20-1%20-1l0%20-12'%20/%3e%3cpath%20d='M9%209h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M3%2010h2'%20/%3e%3cpath%20d='M3%2014h2'%20/%3e%3cpath%20d='M10%203v2'%20/%3e%3cpath%20d='M14%203v2'%20/%3e%3cpath%20d='M21%2010h-2'%20/%3e%3cpath%20d='M21%2014h-2'%20/%3e%3cpath%20d='M14%2021v-2'%20/%3e%3cpath%20d='M10%2021v-2'%20/%3e%3c/svg%3e");--icon-error:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%209v4'%20/%3e%3cpath%20d='M10.363%203.591l-8.106%2013.534a1.914%201.914%200%200%200%201.636%202.871h16.214a1.914%201.914%200%200%200%201.636%20-2.87l-8.106%20-13.536a1.914%201.914%200%200%200%20-3.274%200'%20/%3e%3cpath%20d='M12%2016h.01'%20/%3e%3c/svg%3e");--icon-gauge:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%201%200%2018%200a9%209%200%201%200%20-18%200'%20/%3e%3cpath%20d='M11%2012a1%201%200%201%200%202%200a1%201%200%201%200%20-2%200'%20/%3e%3cpath%20d='M13.41%2010.59l2.59%20-2.59'%20/%3e%3cpath%20d='M7%2012a5%205%200%200%201%205%20-5'%20/%3e%3c/svg%3e");--icon-info:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M15%208A7%207%200%201%201%201%208a7%207%200%200%201%2014%200M9%205a1%201%200%201%201-2%200a1%201%200%200%201%202%200M6.75%208a.75.75%200%200%200%200%201.5h.75v1.75a.75.75%200%200%200%201.5%200v-2.5A.75.75%200%200%200%208.25%208z'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-package:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203l8%204.5l0%209l-8%204.5l-8%20-4.5l0%20-9l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l0%209'%20/%3e%3cpath%20d='M12%2012l-8%20-4.5'%20/%3e%3cpath%20d='M16%205.25l-8%204.5'%20/%3e%3c/svg%3e");--icon-phone:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M5%204h4l2%205l-2.5%201.5a11%2011%200%200%200%205%205l1.5%20-2.5l5%202v4a2%202%200%200%201%20-2%202a16%2016%200%200%201%20-15%20-15a2%202%200%200%201%202%20-2'%20/%3e%3c/svg%3e");--icon-radio:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e");--icon-refresh:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%2011a8.1%208.1%200%200%200%20-15.5%20-2m-.5%20-4v4h4'%20/%3e%3cpath%20d='M4%2013a8.1%208.1%200%200%200%2015.5%202m.5%204v-4h-4'%20/%3e%3c/svg%3e");--icon-refresh-off:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%2011a8.1%208.1%200%200%200%20-11.271%20-6.305m-2.41%201.624a8.083%208.083%200%200%200%20-1.819%202.681m-.5%20-4v4h4'%20/%3e%3cpath%20d='M4%2013a8.1%208.1%200%200%200%2013.671%204.691m2.329%20-1.691v-1h-1'%20/%3e%3cpath%20d='M3%203l18%2018'%20/%3e%3c/svg%3e");--icon-router:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2015a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4a2%202%200%200%201%20-2%202h-14a2%202%200%200%201%20-2%20-2l0%20-4'%20/%3e%3cpath%20d='M17%2017l0%20.01'%20/%3e%3cpath%20d='M13%2017l0%20.01'%20/%3e%3cpath%20d='M15%2013l0%20-2'%20/%3e%3cpath%20d='M11.75%208.75a4%204%200%200%201%206.5%200'%20/%3e%3cpath%20d='M8.5%206.5a8%208%200%200%201%2013%200'%20/%3e%3c/svg%3e");--icon-search:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20/%3e%3cpath%20d='M21%2021l-6%20-6'%20/%3e%3c/svg%3e");--icon-server:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%207a3%203%200%200%201%203%20-3h12a3%203%200%200%201%203%203v2a3%203%200%200%201%20-3%203h-12a3%203%200%200%201%20-3%20-3v-2'%20/%3e%3cpath%20d='M3%2015a3%203%200%200%201%203%20-3h12a3%203%200%200%201%203%203v2a3%203%200%200%201%20-3%203h-12a3%203%200%200%201%20-3%20-3l0%20-2'%20/%3e%3cpath%20d='M7%208l0%20.01'%20/%3e%3cpath%20d='M7%2016l0%20.01'%20/%3e%3cpath%20d='M11%208h6'%20/%3e%3cpath%20d='M11%2016h6'%20/%3e%3c/svg%3e");--icon-settings:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M10.325%204.317c.426%20-1.756%202.924%20-1.756%203.35%200a1.724%201.724%200%200%200%202.573%201.066c1.543%20-.94%203.31%20.826%202.37%202.37a1.724%201.724%200%200%200%201.065%202.572c1.756%20.426%201.756%202.924%200%203.35a1.724%201.724%200%200%200%20-1.066%202.573c.94%201.543%20-.826%203.31%20-2.37%202.37a1.724%201.724%200%200%200%20-2.572%201.065c-.426%201.756%20-2.924%201.756%20-3.35%200a1.724%201.724%200%200%200%20-2.573%20-1.066c-1.543%20.94%20-3.31%20-.826%20-2.37%20-2.37a1.724%201.724%200%200%200%20-1.065%20-2.572c-1.756%20-.426%20-1.756%20-2.924%200%20-3.35a1.724%201.724%200%200%200%201.066%20-2.573c-.94%20-1.543%20.826%20-3.31%202.37%20-2.37c1%20.608%202.296%20.07%202.572%20-1.065'%20/%3e%3cpath%20d='M9%2012a3%203%200%201%200%206%200a3%203%200%200%200%20-6%200'%20/%3e%3c/svg%3e");--icon-shield:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203a12%2012%200%200%200%208.5%203a12%2012%200%200%201%20-8.5%2015a12%2012%200%200%201%20-8.5%20-15a12%2012%200%200%200%208.5%20-3'%20/%3e%3c/svg%3e");--icon-spinning:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20opacity='.05'%20d='M512%2085.333c235.648%200%20426.667%20191.019%20426.667%20426.667S747.648%20938.667%20512%20938.667%2085.333%20747.648%2085.333%20512%20276.352%2085.333%20512%2085.333zm0%20128a298.667%20298.667%200%201%200%200%20597.334%20298.667%20298.667%200%200%200%200-597.334z'/%3e%3cpath%20d='M813.696%20813.696c166.613-166.613%20166.613-436.779%200-603.392s-436.779-166.613-603.392%200a64%2064%200%200%200%2090.496%2090.496%20298.667%20298.667%200%201%201%20422.4%20422.4%2064%2064%200%200%200%2090.496%2090.496z'/%3e%3c/svg%3e");--icon-tag:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M6.5%207.5a1%201%200%201%200%202%200a1%201%200%201%200%20-2%200'%20/%3e%3cpath%20d='M3%206v5.172a2%202%200%200%200%20.586%201.414l7.71%207.71a2.41%202.41%200%200%200%203.408%200l5.592%20-5.592a2.41%202.41%200%200%200%200%20-3.408l-7.71%20-7.71a2%202%200%200%200%20-1.414%20-.586h-5.172a3%203%200%200%200%20-3%203'%20/%3e%3c/svg%3e");--icon-world:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%201%200%2018%200a9%209%200%200%200%20-18%200'%20/%3e%3cpath%20d='M3.6%209h16.8'%20/%3e%3cpath%20d='M3.6%2015h16.8'%20/%3e%3cpath%20d='M11.5%203a17%2017%200%200%200%200%2018'%20/%3e%3cpath%20d='M12.5%203a17%2017%200%200%201%200%2018'%20/%3e%3c/svg%3e");--icon-x:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M18%206l-12%2012'%20/%3e%3cpath%20d='M6%206l12%2012'%20/%3e%3c/svg%3e")}html{background-color:var(--bg);min-height:100dvh;font-family:var(--font-sans);--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-darkmode=true]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html body{background-color:var(--bg);min-height:100dvh}.page-bg{pointer-events:none;background-image:var(--page-bg-lqip,var(--page-bg));background-position:50%;background-repeat:no-repeat;background-size:cover;position:fixed;inset:0;transform:translateZ(0)}.page-bg:after{pointer-events:none;background-image:var(--page-bg);opacity:0;--tw-content:"";content:var(--tw-content);background-position:50%;background-repeat:no-repeat;background-size:cover;transition:opacity .5s;position:absolute;inset:0}.page-bg.full-loaded:after{opacity:1}:not(html){scrollbar-width:thin;scrollbar-color:var(--text-muted) transparent}html{scrollbar-width:thin;scrollbar-color:var(--text-muted) var(--surface)}html body{min-height:100dvh;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);flex-direction:column;display:flex;position:relative}html body.modal-overlay-active{height:100vh;overflow:hidden}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text)}h1{margin-bottom:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 6);font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}@media not all and (min-width:48rem){h1{padding-left:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}}h2{margin-bottom:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}@media not all and (min-width:48rem){h2{margin-bottom:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 4);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}}h3{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}@media not all and (min-width:48rem){h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}@media not all and (min-width:48rem){h4{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}h5{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}@media not all and (min-width:48rem){h5{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}h6{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}@media not all and (min-width:48rem){h6{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}hr{margin-block:calc(var(--spacing) * 6);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline)}@media not all and (min-width:48rem){hr{margin-block:calc(var(--spacing) * 4)}}strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}abbr{cursor:help}p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text)}pre{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-wrap:break-word;white-space:pre-wrap;color:var(--text-muted);display:block}code{border-radius:calc(var(--radius-base) * .5);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-muted)}a{color:var(--link);text-decoration-line:none}@media (hover:hover){a:hover{text-decoration-line:underline}}var{font-family:var(--font-mono);color:var(--link)}small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text)}em{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);font-style:italic}header{z-index:40;margin-bottom:calc(var(--spacing) * 2);background-color:var(--bg);position:sticky;top:0}header .header-content{z-index:10;height:calc(var(--spacing) * 14);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex;position:relative}@media not all and (min-width:48rem){header .header-content{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2)}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container{pointer-events:none;visibility:hidden;z-index:0;height:calc(var(--mega-menu-height,0px) + 3.5rem + 3rem);inset-inline:0;width:100%;position:absolute;top:0;overflow:clip}@media not all and (min-width:48rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active,[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{visibility:visible}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active{pointer-events:auto}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.22s;--tw-ease:cubic-bezier(.4,0,.6,1);transition-duration:.22s;transition-timing-function:cubic-bezier(.4,0,.6,1)}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet{height:calc(var(--mega-menu-height,0px) + 3.5rem);--tw-translate-y:-100%;translate:var(--tw-translate-x) var(--tw-translate-y);background-color:var(--mega-menu-bg);transition-property:translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-ease:cubic-bezier(.4,0,.6,1);inset-inline:0;transition-timing-function:cubic-bezier(.4,0,.6,1);position:absolute;top:0;overflow:hidden}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet:after{content:var(--tw-content);pointer-events:none;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);border-bottom-style:var(--tw-border-style);content:var(--tw-content);border-bottom-width:1px;border-color:var(--hairline);content:var(--tw-content);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-content:"";content:var(--tw-content);position:absolute;inset:0}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet:after{content:var(--tw-content);transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-canvas{--tw-translate-y:100%;translate:var(--tw-translate-x) var(--tw-translate-y);transition-property:translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-ease:cubic-bezier(.4,0,.6,1);transition-timing-function:cubic-bezier(.4,0,.6,1);position:absolute;inset:0}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-canvas{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active .desktop-menu-sheet,[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active .desktop-menu-canvas{--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y)}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing .desktop-menu-sheet:after{content:var(--tw-content);opacity:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container>.desktop-menu-board{display:none}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav{pointer-events:none;inset-inline:0;top:calc(var(--spacing) * 14);--tw-translate-y:calc(var(--spacing) * 1.5);max-width:72rem;max-height:calc(100dvh - 3.5rem);translate:var(--tw-translate-x) var(--tw-translate-y);column-gap:calc(var(--spacing) * 8);overscroll-behavior:contain;padding-inline:calc(var(--spacing) * 10);padding-top:calc(var(--spacing) * 13);padding-bottom:calc(var(--spacing) * 8);opacity:0;transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);grid-template-columns:12rem minmax(0,1fr) 13rem;margin-inline:auto;display:grid;position:absolute;overflow-y:auto}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav{max-width:44rem;padding-inline:calc(var(--spacing) * 8);grid-template-columns:repeat(1,minmax(0,1fr))}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav.active{pointer-events:auto;--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y);opacity:1}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor{align-self:flex-start}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor .desktop-nav-title{align-items:center;gap:calc(var(--spacing) * 2.5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);display:flex}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor .desktop-nav-title:before{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;background-color:currentColor;flex-shrink:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list{grid-auto-flow:column;grid-template-rows:repeat(var(--menu-rows,6),auto);place-content:flex-start;column-gap:calc(var(--spacing) * 8);row-gap:var(--spacing);display:grid}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li{margin:0;list-style-type:none}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a{border-radius:calc(var(--radius-base) * 1.5);width:fit-content;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));white-space:nowrap;color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a:hover{background-color:var(--hover-faint)}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board{gap:calc(var(--spacing) * 2);border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--hairline);padding-left:calc(var(--spacing) * 7);flex-direction:column;align-self:flex-start;display:flex}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-label{margin-bottom:calc(var(--spacing) * .5);--tw-font-weight:var(--font-weight-medium);font-size:11px;font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--text-subtle);text-transform:uppercase}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line{align-items:flex-start;gap:calc(var(--spacing) * 2.5);max-width:100%;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);display:flex}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);--tw-content:"";content:var(--tw-content);background-color:currentColor;flex-shrink:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line .board-text{--tw-leading:calc(var(--spacing) * 4);min-width:0;line-height:calc(var(--spacing) * 4);overflow-wrap:anywhere}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-host:before{-webkit-mask:var(--icon-router) center/contain no-repeat;-webkit-mask:var(--icon-router) center/contain no-repeat;-webkit-mask:var(--icon-router) center/contain no-repeat;mask:var(--icon-router) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-model:before{-webkit-mask:var(--icon-cpu) center/contain no-repeat;-webkit-mask:var(--icon-cpu) center/contain no-repeat;-webkit-mask:var(--icon-cpu) center/contain no-repeat;mask:var(--icon-cpu) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-firmware:before{-webkit-mask:var(--icon-package) center/contain no-repeat;-webkit-mask:var(--icon-package) center/contain no-repeat;-webkit-mask:var(--icon-package) center/contain no-repeat;mask:var(--icon-package) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-kernel:before{-webkit-mask:var(--icon-tag) center/contain no-repeat;-webkit-mask:var(--icon-tag) center/contain no-repeat;-webkit-mask:var(--icon-tag) center/contain no-repeat;mask:var(--icon-tag) center/contain no-repeat}[data-nav-type=mega-menu] :is(header):has(.desktop-menu-container:is(.active,.closing)){z-index:70}header .brand{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:color,transform;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex-shrink:0;text-decoration-line:none;transition-duration:.15s;display:inline-block}@media (hover:hover){header .brand:hover{--tw-translate-y:calc(var(--spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y);color:var(--brand)}}@media not all and (min-width:48rem){header .brand{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));flex:1}}@media (min-width:48rem){[data-nav-type=sidebar] :is(header .brand){display:none}[data-nav-type=sidebar].sidebar-collapsed :is(header .brand){transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:inline-block}@starting-style{[data-nav-type=sidebar].sidebar-collapsed :is(header .brand){opacity:0}}}header .nav{z-index:60;--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);align-items:center;gap:var(--spacing);margin:0;padding:0;list-style-type:none;display:flex;position:absolute;left:50%}@media not all and (min-width:48rem){header .nav{display:none}}header .nav>li{position:relative}header .nav>li .menu{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){header .nav>li .menu:hover{background-color:var(--hover-faint)}}header .nav>li .menu.menu-active{background-color:var(--brand-subtle);color:var(--brand)}header .nav>li .desktop-nav{pointer-events:none;z-index:40;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;padding-inline:0;padding-top:0;transition-duration:.15s;left:0}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav){margin-top:calc(var(--spacing) * 2);min-width:calc(var(--spacing) * 48);position:absolute;top:100%}header .nav>li .desktop-nav.active{pointer-events:auto;opacity:1}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list){row-gap:var(--spacing);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding-block:calc(var(--spacing) * 2);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);flex-direction:column;display:flex}header .nav>li .desktop-nav .desktop-nav-list>li{margin:0;list-style-type:none}header .nav>li .desktop-nav .desktop-nav-list>li>a{white-space:nowrap;color:var(--text);text-decoration-line:none;display:block}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list>li>a){margin-inline:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list>li>a):hover{background-color:var(--hover-faint)}}header .nav>li .desktop-nav .desktop-nav-list>li>a.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}header .navigation-controls{margin-right:calc(var(--spacing) * 3);flex-shrink:0;align-items:center;display:flex}@media (min-width:48rem){header .navigation-controls{display:none}[data-nav-type=sidebar] :is(header .navigation-controls){display:flex}[data-nav-type=sidebar]:not(.sidebar-collapsed) :is(header .navigation-controls) .navigation-toggle-line-bottom{stroke-dasharray:15 15}}header .navigation-controls .navigation-toggle{cursor:pointer;border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;border-radius:0;padding:0;transition-duration:.15s}@media (hover:hover){header .navigation-controls .navigation-toggle:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}header .navigation-controls .navigation-toggle:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}header .navigation-controls .navigation-toggle svg{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);color:var(--text)}header .navigation-controls .navigation-toggle .navigation-toggle-line{transform-box:fill-box;transform-origin:50%;transition-property:transform,opacity,stroke-dasharray;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-in-out);transition-duration:.15s;transition-timing-function:var(--ease-in-out)}@media (min-width:48rem){[data-nav-type=sidebar] :is(header .navigation-controls .navigation-toggle .navigation-toggle-line){--tw-duration:.25s;transition-duration:.25s}}header .navigation-controls .navigation-toggle .navigation-toggle-line-bottom{stroke-dasharray:7.5 15}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-top{transform:translateY(5px)rotate(45deg)}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-middle{opacity:0;transform:scaleX(.35)}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-bottom{stroke-dasharray:15 15;transform:translateY(-5px)rotate(-45deg)}header #indicators{gap:calc(var(--spacing) * 5);flex-direction:row-reverse;flex-shrink:0;display:flex}@media (min-width:48rem){header #indicators{gap:calc(var(--spacing) * 8)}}header #indicators span[data-indicator]{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;font-size:0;transition-duration:.15s}header #indicators span[data-indicator]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);content:var(--tw-content);color:var(--text);background-color:currentColor;position:absolute}@media (hover:hover){header #indicators span[data-indicator]:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}header #indicators span[data-indicator]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}header #indicators span[data-indicator][data-indicator=media_error]:before{content:var(--tw-content);-webkit-mask:var(--icon-error) center/cover no-repeat;-webkit-mask:var(--icon-error) center/cover no-repeat;-webkit-mask:var(--icon-error) center/cover no-repeat;mask:var(--icon-error) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask:var(--icon-refresh) center/cover no-repeat;-webkit-mask:var(--icon-refresh) center/cover no-repeat;-webkit-mask:var(--icon-refresh) center/cover no-repeat;mask:var(--icon-refresh) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;mask:var(--icon-refresh-off) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=uci-changes]{position:relative}header #indicators span[data-indicator][data-indicator=uci-changes]:before{content:var(--tw-content);-webkit-mask:var(--icon-settings) center/cover no-repeat;-webkit-mask:var(--icon-settings) center/cover no-repeat;-webkit-mask:var(--icon-settings) center/cover no-repeat;mask:var(--icon-settings) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=uci-changes][data-count]:not([data-count="0"]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -.5);content:var(--tw-content);z-index:10;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 3);content:var(--tw-content);min-width:calc(var(--spacing) * 3);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--danger);content:var(--tw-content);padding-inline:calc(var(--spacing) * .5);content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);--tw-font-weight:var(--font-weight-bold);font-size:8px;line-height:1;font-weight:var(--font-weight-bold);content:var(--tw-content);color:var(--on-brand);content:var(--tw-content);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-content:attr(data-count);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:flex;position:absolute}body[data-nav-type=sidebar]{--sidebar-w-full:17rem;--sidebar-w:var(--sidebar-w-full)}@media (min-width:48rem){body[data-nav-type=sidebar]{grid-template-columns:var(--sidebar-w) minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);display:grid;overflow-x:clip}body[data-nav-type=sidebar].sidebar-collapsed{--sidebar-w:0rem}body[data-nav-type=sidebar]>header{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);grid-row-start:1;grid-column-start:2;margin-bottom:0}body[data-nav-type=sidebar]>.sidebar-panel{grid-row:1/span 2;grid-column-start:1}body[data-nav-type=sidebar]>#maincontent{min-width:0;padding-top:calc(var(--spacing) * 2);width:100%;max-width:none;padding-inline:calc(var(--spacing) * 8);grid-row-start:2;grid-column-start:2}}body[data-nav-type=sidebar] .header-crumb{align-items:center;gap:calc(var(--spacing) * 2);min-width:0;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-muted);margin-block:0;margin-left:0;margin-right:auto;padding:0;list-style-type:none;display:none;overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar] .header-crumb{display:flex}}body[data-nav-type=sidebar] .header-crumb li{white-space:nowrap;margin:0;list-style-type:none}body[data-nav-type=sidebar] .header-crumb .crumb-sep{opacity:.5}body[data-nav-type=sidebar] .header-crumb .current{text-overflow:ellipsis;white-space:nowrap;--tw-font-weight:var(--font-weight-medium);min-width:0;font-weight:var(--font-weight-medium);color:var(--text);overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar].sidebar-collapsed .header-crumb{margin-left:calc(var(--spacing) * 6)}}body[data-nav-type=sidebar] .sidebar-panel{border-radius:0;width:100%;height:100dvh;display:none;position:sticky;top:0;overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar] .sidebar-panel{display:block}}body[data-nav-type=sidebar].sidebar-collapsed .sidebar-panel{visibility:hidden}body[data-nav-type=sidebar] .sidebar-panel-inner{height:100%;width:var(--sidebar-w-full);border-right-style:var(--tw-border-style);border-right-width:1px;border-color:var(--hairline);background-color:var(--bg);flex-direction:column;display:flex;overflow:hidden}body[data-nav-type=sidebar].sidebar-collapsed .sidebar-panel-inner{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}@media (min-width:48rem){body[data-nav-type=sidebar].sidebar-anim-open>header,body[data-nav-type=sidebar].sidebar-anim-open>#maincontent,body[data-nav-type=sidebar].sidebar-anim-open .sidebar-panel-inner{animation:sidebar-run-in .25s var(--ease-in-out) both}body[data-nav-type=sidebar].sidebar-anim-close>header,body[data-nav-type=sidebar].sidebar-anim-close>#maincontent{animation:sidebar-run-back .25s var(--ease-in-out) both}body[data-nav-type=sidebar].sidebar-anim-close .sidebar-panel{visibility:visible;width:var(--sidebar-w-full);position:fixed;top:0;left:0}body[data-nav-type=sidebar].sidebar-anim-close .sidebar-panel-inner{animation:sidebar-run-out .25s var(--ease-in-out) both}}body[data-nav-type=sidebar] .sidebar-head{box-sizing:content-box;height:calc(var(--spacing) * 14);align-items:center;gap:calc(var(--spacing) * 2.5);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 4);flex-shrink:0;display:flex}body[data-nav-type=sidebar] .sidebar-head .sidebar-logo{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * .75);flex-shrink:0}body[data-nav-type=sidebar] .sidebar-head .sidebar-brand{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex:1;text-decoration-line:none;transition-duration:.15s;overflow:hidden}@media (hover:hover){body[data-nav-type=sidebar] .sidebar-head .sidebar-brand:hover{color:var(--brand)}}body[data-nav-type=sidebar] .sidebar-list{flex:1;margin:0;list-style-type:none}:where(body[data-nav-type=sidebar] .sidebar-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}body[data-nav-type=sidebar] .sidebar-list{padding:calc(var(--spacing) * 3);overflow-y:auto}body[data-nav-type=sidebar] .sidebar-list li{margin:0;list-style-type:none}body[data-nav-type=sidebar] .sidebar-list .nav-row{gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}body[data-nav-type=sidebar] .sidebar-list .nav-icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}body[data-nav-type=sidebar] .sidebar-submenu{min-height:0;margin:0;list-style-type:none}:where(body[data-nav-type=sidebar] .sidebar-submenu>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}body[data-nav-type=sidebar] .sidebar-submenu{padding:0;padding-left:calc(var(--spacing) * 6.5);overflow:hidden}body[data-nav-type=sidebar] .sidebar-submenu .navigation-sublink{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}body[data-nav-type=sidebar] .sidebar-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 3);flex-shrink:0}body[data-nav-type=sidebar] .sidebar-footer .nav-link{color:var(--text-muted)}@media (hover:hover){body[data-nav-type=sidebar] .sidebar-footer .nav-link:hover{color:var(--text)}}@keyframes sidebar-run-in{0%{translate:calc(-1 * var(--sidebar-w-full)) 0}}@keyframes sidebar-run-back{0%{translate:var(--sidebar-w-full) 0}}@keyframes sidebar-run-out{to{translate:calc(-1 * var(--sidebar-w-full)) 0}}#luci-nav-progress{pointer-events:none;z-index:80;height:calc(var(--spacing) * .5);--tw-gradient-position:to right;width:0;position:fixed;top:0;left:0}@supports (background-image:linear-gradient(in lab, red, red)){#luci-nav-progress{--tw-gradient-position:to right in oklab}}#luci-nav-progress{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-start);--tw-gradient-to:var(--progress-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;--tw-ease:var(--ease-out);transition-duration:.3s;transition-timing-function:var(--ease-out)}#luci-nav-progress[data-state=done]{opacity:0;transition:width .3s ease-out,opacity .15s ease-in .15s}#luci-nav-status{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}#maincontent{width:95.8333%;min-height:calc(100vh - 4rem);max-width:var(--content-width-centered);padding-inline:calc(var(--spacing) * 4);--tw-outline-style:none;outline-style:none;margin-inline:auto}@media not all and (min-width:48rem){#maincontent{width:100%;padding-inline:calc(var(--spacing) * 3)}}#maincontent .view-staging{visibility:hidden;height:0;overflow:hidden}#maincontent #view{--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;margin-inline:0;padding:0}#maincontent #view:empty{display:none}@media (min-width:48rem){#maincontent #view{padding:0}}#maincontent #view.view-leaving{cursor:progress;opacity:.6;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}#maincontent #view .cbi-title-section{margin-bottom:calc(var(--spacing) * 6);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}@media not all and (min-width:48rem){#maincontent #view .cbi-title-section{margin-inline:calc(var(--spacing) * 2);margin-bottom:calc(var(--spacing) * 3)}}#maincontent #view .controls{margin:calc(var(--spacing) * 2);align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent #view .controls{margin:var(--spacing);gap:calc(var(--spacing) * 2)}}#maincontent #view .controls label input[type=radio],#maincontent #view .controls label input[type=checkbox]{margin-right:var(--spacing);vertical-align:middle}#maincontent #view div[style]>svg:where([data-darkmode=true],[data-darkmode=true] *){background-color:var(--surface)!important}#maincontent #view div[style]>svg line[style]:where([data-darkmode=true],[data-darkmode=true] *){stroke:var(--text)!important}#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-bottom:calc(var(--spacing) * 6);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text-muted)}@media not all and (min-width:48rem){#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-inline:calc(var(--spacing) * 2);margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}#maincontent .cbi-page-actions{margin-top:calc(var(--spacing) * 6);justify-content:flex-end;align-items:center;gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-top:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent .cbi-page-actions{margin-inline:calc(var(--spacing) * 2);margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 2);padding-top:calc(var(--spacing) * 3)}}#maincontent .zone-forwards{align-items:stretch;gap:calc(var(--spacing) * 2);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);flex-wrap:nowrap;display:flex}#maincontent .zone-forwards>span{flex-shrink:0;flex-basis:calc(var(--spacing) * 8);color:var(--text-muted);justify-content:center;align-self:center;align-items:center;display:flex}#maincontent .zone-forwards .zone-src,#maincontent .zone-forwards .zone-dest{gap:calc(var(--spacing) * 1.5);flex-direction:column;flex:1;display:flex}footer{margin-top:calc(var(--spacing) * 2);min-height:calc(var(--spacing) * 16);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);flex-wrap:wrap;justify-content:space-between;align-items:center;display:flex}footer a{color:var(--brand)}footer span{text-align:center;display:inline-block}footer .breadcrumb{align-items:center;gap:var(--spacing);background-color:var(--surface-overlay);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;transition-duration:.15s;display:flex}@media (hover:hover){footer .breadcrumb:hover{background-color:var(--surface)}}footer .breadcrumb li{list-style-type:none}footer .breadcrumb li.active a{color:var(--text)}.control-group{margin-top:var(--spacing)}.control-group,.cbi-page-actions>div,.cbi-section-actions>div{align-items:center;gap:calc(var(--spacing) * 2);flex-flow:row;display:flex}@media not all and (min-width:48rem){.control-group,.cbi-page-actions>div,.cbi-section-actions>div{gap:var(--spacing);flex-wrap:wrap}}.nav-row{cursor:pointer;appearance:none;border-style:var(--tw-border-style);text-align:left;--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-user-select:none;user-select:none;background-color:#0000;border-width:0;align-items:center;text-decoration-line:none;transition-duration:.15s;display:flex}@media (hover:hover){.nav-row:hover{text-decoration-line:none}}.nav-row:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.nav-link{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){.nav-link:hover{background-color:var(--hover-faint);text-decoration-line:none}}.navigation-direct{color:var(--text)}@media (hover:hover){.navigation-direct:hover{color:var(--text)}}.navigation-direct.is-active-page{background-color:var(--brand-subtle);color:var(--brand)}@media (hover:hover){.navigation-direct.is-active-page:hover{color:var(--brand)}}:where(.sidebar-list) .nav-row{color:var(--text-muted)}@media (hover:hover){:where(.sidebar-list) .nav-row:hover{color:var(--text)}:where(.sidebar-list) .navigation-direct:hover{background-color:var(--hover-faint)}}.navigation-group-toggle:after{content:var(--tw-content);width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);opacity:.55;content:var(--tw-content);transition-property:transform,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.25s;--tw-content:"";content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;background-color:currentColor;flex-shrink:0;transition-duration:.25s}@media (hover:hover){.navigation-group-toggle:hover:after{content:var(--tw-content);opacity:1}}.navigation-group.is-expanded>.navigation-group-toggle{color:var(--brand)}.navigation-group.is-expanded>.navigation-group-toggle:after{content:var(--tw-content);rotate:90deg}.navigation-group.is-active-group>.navigation-group-toggle{color:var(--brand)}.nav-icon{opacity:.55;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;background-color:currentColor;flex-shrink:0;transition-duration:.15s}.nav-label,.nav-category-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.navigation-direct:hover .nav-icon,.navigation-group-toggle:hover .nav-icon,.navigation-direct.is-active-page .nav-icon,.navigation-group.is-expanded>.navigation-group-toggle .nav-icon,.navigation-group.is-active-group>.navigation-group-toggle .nav-icon{opacity:1}.navigation-group-region{opacity:0;transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);grid-template-rows:0fr;display:grid}.navigation-group.is-expanded>.navigation-group-region{opacity:1;grid-template-rows:1fr}.navigation-submenu-list{min-height:0;list-style-type:none;overflow:hidden}.navigation-sublink{border-radius:calc(var(--radius-base) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:flex;position:relative}@media (hover:hover){.navigation-sublink:hover{background-color:var(--hover-faint);color:var(--text)}}.navigation-sublink.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand)}@media (hover:hover){.navigation-sublink.is-active-page:hover{color:var(--brand)}}.nav-category-preview{text-overflow:ellipsis;white-space:nowrap;padding-bottom:var(--spacing);color:var(--text-subtle);overflow:hidden}.nav-category-preview .nav-preview-current{color:var(--brand)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=status]{--menu-icon:var(--icon-activity)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=statistics]{--menu-icon:var(--icon-chart-bar)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=nlbw]{--menu-icon:var(--icon-gauge)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=system]{--menu-icon:var(--icon-settings)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=services]{--menu-icon:var(--icon-apps)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=nas]{--menu-icon:var(--icon-server)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=control]{--menu-icon:var(--icon-adjustments)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=network]{--menu-icon:var(--icon-world)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=vpn]{--menu-icon:var(--icon-shield)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=docker]{--menu-icon:var(--icon-box)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=asterisk]{--menu-icon:var(--icon-phone)}.theme-switcher{background-color:var(--surface-sunken);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;align-items:center;gap:0;transition-duration:.15s;display:inline-flex;position:relative}@media not all and (min-width:48rem){.theme-switcher{padding-block:calc(var(--spacing) * .5)}}.theme-switcher{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}.theme-switcher:before{content:var(--tw-content);content:var(--tw-content);top:var(--spacing);content:var(--tw-content);left:var(--spacing);content:var(--tw-content);z-index:0;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--surface-overlay);content:var(--tw-content);--tw-shadow:var(--app-shadow-md);width:calc(33.333% - .5rem);height:calc(100% - .5rem);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.25s;border-radius:3.40282e38px;transition-duration:.25s;position:absolute}@media not all and (min-width:48rem){footer .theme-switcher{display:none}}.theme-switcher .theme-option{z-index:10;cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;transition-duration:.15s;display:flex;position:relative}@media (hover:hover){.theme-switcher .theme-option:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.theme-switcher .theme-option:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.theme-switcher .theme-option input[type=radio]{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.theme-switcher .theme-option .theme-icon{color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;justify-content:center;align-items:center;transition-duration:.15s;display:flex}.theme-switcher .theme-option .theme-icon svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}.theme-switcher .theme-option .theme-label{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:none}.theme-switcher .theme-option.active .theme-icon{color:var(--text)}.theme-switcher .theme-option.active .theme-icon svg{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.theme-switcher .theme-option.active .theme-label,.theme-switcher .theme-option:hover:not(.active) .theme-icon,.theme-switcher .theme-option:hover:not(.active) .theme-label{color:var(--text)}.theme-switcher:has(.theme-option[data-theme=device].active):before{content:var(--tw-content);--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.theme-switcher:has(.theme-option[data-theme=light].active):before{content:var(--tw-content);--tw-translate-x:calc(100% + .5rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.theme-switcher:has(.theme-option[data-theme=dark].active):before{content:var(--tw-content);--tw-translate-x:calc(200% + 1rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.floating-toolbar{pointer-events:none;right:calc(var(--spacing) * 4);bottom:calc(var(--spacing) * 4);z-index:40;flex-direction:column;align-items:center;display:flex;position:fixed}@media not all and (min-width:48rem){.floating-toolbar{right:calc(var(--spacing) * 3);bottom:calc(var(--spacing) * 3)}}.floating-toolbar .toolbar-list{margin-bottom:calc(var(--spacing) * 2.5);align-items:center;gap:calc(var(--spacing) * 2.5);flex-direction:column;display:flex}@media not all and (min-width:48rem){.floating-toolbar .toolbar-list{margin-bottom:calc(var(--spacing) * 2);gap:calc(var(--spacing) * 2)}}.floating-toolbar .toolbar-btn{pointer-events:auto;width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11);cursor:pointer;background-color:var(--surface-overlay);color:var(--text-muted);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-radius:3.40282e38px;place-items:center;display:grid}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}}.floating-toolbar .toolbar-btn{transition:translate .32s cubic-bezier(.34,1.25,.5,1),scale .32s cubic-bezier(.34,1.25,.5,1),opacity .22s,visibility .32s,background-color .15s,color .15s;transition-delay:var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),0s,0s}.floating-toolbar .toolbar-btn:hover{background-color:var(--hover-faint);color:var(--text)}.floating-toolbar .toolbar-btn:active{scale:.92}.floating-toolbar .toolbar-btn:not(.toggle){--fab-d:calc((var(--fab-n,1) - 1 - var(--fab-i,0)) * 60ms);text-decoration-line:none}.floating-toolbar .toolbar-btn:not(.toggle):active{--fab-d:0s}.floating-toolbar .toolbar-btn:not(.toggle) .icon{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);-webkit-mask:var(--fab-icon) center/contain no-repeat;-webkit-mask:var(--fab-icon) center/contain no-repeat;-webkit-mask:var(--fab-icon) center/contain no-repeat;mask:var(--fab-icon) center/contain no-repeat;background-color:currentColor;flex-shrink:0}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn:not(.toggle) .icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}}.floating-toolbar .toolbar-btn.toggle{border-style:var(--tw-border-style);color:var(--text-subtle);border-width:0}@media (hover:hover){.floating-toolbar .toolbar-btn.toggle:hover{color:var(--text)}}.floating-toolbar .toolbar-btn.toggle .icon{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);transition-property:rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);place-items:center;display:grid}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn.toggle .icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}}.floating-toolbar .toolbar-btn.toggle .icon svg{width:100%;height:100%}.floating-toolbar.collapsed .toolbar-btn:not(.toggle){pointer-events:none;visibility:hidden;opacity:0;--tw-translate-y:calc((var(--fab-n,1) - var(--fab-i,0)) * 3.375rem);scale:.35;translate:var(--tw-translate-x) var(--tw-translate-y);--fab-d:calc(var(--fab-i,0) * 60ms)}@media not all and (min-width:48rem){.floating-toolbar.collapsed .toolbar-btn:not(.toggle){--tw-translate-y:calc((var(--fab-n,1) - var(--fab-i,0)) * 3rem);translate:var(--tw-translate-x) var(--tw-translate-y)}}.floating-toolbar.collapsed .toolbar-btn.toggle .icon{rotate:45deg}button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transition-property:background-color,border-color,transform;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-width:1px;transition-duration:.15s;display:inline-flex}@media not all and (min-width:48rem){button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}}:is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button)[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){white-space:nowrap;flex:none;width:auto;display:inline-flex}@media not all and (min-width:48rem){.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){min-height:calc(var(--spacing) * 9);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down{border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text)}@media (hover:hover){:is(.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down):hover{background-color:var(--hover-faint)}}.drag-handle{border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text-muted)}@media (hover:hover){.drag-handle:hover{background-color:var(--hover-faint)}}.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit{border-color:var(--brand);background-color:var(--brand);color:var(--on-brand)}@media (hover:hover){:is(.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit):hover{background-color:var(--brand-hover)}}.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save{background-color:var(--brand-subtle);color:var(--brand);border-color:#0000}@media (hover:hover){:is(.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save):hover{background-color:var(--brand-subtle-hover)}}.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove{background-color:var(--danger-surface);color:var(--danger);border-color:#0000}@media (hover:hover){:is(.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove):hover{background-color:var(--danger-surface-hover)}}input:disabled{cursor:not-allowed;opacity:var(--app-opacity-disabled)}input[type=text],input[type=password],.cbi-input-text,.cbi-input{width:calc(var(--spacing) * 52.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);max-width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);position:relative}:is(input[type=text],input[type=password],.cbi-input-text,.cbi-input)::placeholder{color:var(--text-muted)}input[type=text],input[type=password],.cbi-input-text,.cbi-input{--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}:is(input[type=text],input[type=password],.cbi-input-text,.cbi-input):focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.table.cbi-section-table :is(input[type=text],input[type=password],.cbi-input-text,.cbi-input){width:100%}.cbi-input-text{min-width:calc(var(--spacing) * 20)}@media not all and (min-width:48rem){.cbi-input-text{min-width:calc(var(--spacing) * 14)}}#localtime{min-width:calc(var(--spacing) * 70)}input[type=radio],input[type=checkbox]{margin-right:calc(var(--spacing) * 3);height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);cursor:pointer;appearance:none;vertical-align:middle;display:inline-block;position:relative}:is(input[type=radio],input[type=checkbox]):before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);height:calc(var(--spacing) * 4);content:var(--tw-content);width:calc(var(--spacing) * 4);content:var(--tw-content);border-style:var(--tw-border-style);content:var(--tw-content);border-width:1px;border-color:var(--hairline);content:var(--tw-content);background-color:var(--control-bg);content:var(--tw-content);transition-property:background-color,border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;transition-duration:.15s;position:absolute;top:0;left:0}:is(input[type=radio],input[type=checkbox]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * .5);content:var(--tw-content);left:calc(var(--spacing) * .5);content:var(--tw-content);height:calc(var(--spacing) * 3);content:var(--tw-content);width:calc(var(--spacing) * 3);content:var(--tw-content);background-color:var(--on-brand);content:var(--tw-content);opacity:0;content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;transition-duration:.15s;position:absolute}:is(input[type=radio],input[type=checkbox]):checked:before{content:var(--tw-content);border-color:var(--brand);content:var(--tw-content);background-color:var(--brand)}:is(input[type=radio],input[type=checkbox]):checked:after{content:var(--tw-content);opacity:1}@media (hover:hover){:is(input[type=radio],input[type=checkbox]):hover:before{content:var(--tw-content);border-color:var(--hairline)}}:is(input[type=radio],input[type=checkbox]):focus:before{content:var(--tw-content);border-color:var(--brand);content:var(--tw-content);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);--tw-ring-color:var(--focus-ring);content:var(--tw-content);--tw-outline-style:none;outline-style:none}:is(input[type=radio],input[type=checkbox]):disabled{cursor:not-allowed}input[type=radio]:before{content:var(--tw-content);border-radius:3.40282e38px}input[type=radio]:after{content:var(--tw-content);-webkit-mask:var(--icon-radio) center/cover no-repeat;-webkit-mask:var(--icon-radio) center/cover no-repeat;-webkit-mask:var(--icon-radio) center/cover no-repeat;mask:var(--icon-radio) center/cover no-repeat}input[type=checkbox]:before{content:var(--tw-content);border-radius:calc(var(--radius-base) * .5)}input[type=checkbox]:after{content:var(--tw-content);-webkit-mask:var(--icon-check) center/cover no-repeat;-webkit-mask:var(--icon-check) center/cover no-repeat;-webkit-mask:var(--icon-check) center/cover no-repeat;mask:var(--icon-check) center/cover no-repeat}.cbi-checkbox{vertical-align:middle;align-items:center;display:inline-flex;position:relative}textarea{min-height:calc(var(--spacing) * 24);resize:vertical;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text)}textarea::placeholder{color:var(--text-muted)}textarea{--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}textarea:focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}textarea[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}select{max-width:100%;min-width:calc(var(--spacing) * 52.5);appearance:none;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 10);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}select:focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}@media (min-width:48rem){select{max-width:calc(var(--spacing) * 100)}}select{background-image:var(--icon-arrow-down);background-position:right .75rem center;background-repeat:no-repeat;background-size:16px}select:where([data-darkmode=true],[data-darkmode=true] *){background-image:var(--icon-arrow-down-dark)}select[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}.cbi-dropdown{white-space:nowrap;--tw-shadow:var(--app-shadow-sm);min-width:fit-content;max-width:100%;height:fit-content;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;align-items:center;padding:0;display:inline-flex}.cbi-dropdown[disabled]{pointer-events:none;opacity:var(--app-opacity-disabled)}.cbi-dropdown:not(.btn):not(.cbi-button){max-width:100%;min-width:calc(var(--spacing) * 52.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface)}@media (min-width:48rem){.cbi-dropdown:not(.btn):not(.cbi-button){max-width:calc(var(--spacing) * 100)}}.cbi-dropdown:not(.btn):not(.cbi-button)>ul>li[placeholder]{display:none}.cbi-dropdown>ul{align-items:center;gap:calc(var(--spacing) * .5);flex-wrap:nowrap;flex:1;margin:0;list-style-type:none;display:flex;overflow:hidden}@media not all and (min-width:48rem){.cbi-dropdown>ul{flex-wrap:wrap}}.cbi-dropdown>ul>li{align-items:center;gap:var(--spacing);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);margin:0;list-style-type:none;display:none;overflow:hidden}.cbi-dropdown>ul>li[display]{display:flex!important}.cbi-dropdown>ul>li .hide-open{display:block}.cbi-dropdown>ul>li .hide-close{display:none}.cbi-dropdown>ul>li>form{pointer-events:none;display:none}.cbi-dropdown>ul>li>label{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.cbi-dropdown>ul>li img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);vertical-align:middle;flex:none}.cbi-dropdown>ul>li span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.cbi-dropdown>ul.dropdown{z-index:50;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);--tw-shadow:var(--app-shadow-lg);width:fit-content;min-width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);position:absolute;left:0;overflow-y:auto}.cbi-dropdown>ul.dropdown>li{min-height:calc(var(--spacing) * 9);cursor:pointer;width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted)}@media (hover:hover){.cbi-dropdown>ul.dropdown>li:hover{background-color:var(--brand-subtle)}}.cbi-dropdown>ul.preview{display:none}.cbi-dropdown[empty]>ul{max-width:1px;max-height:1px}.cbi-dropdown[empty]>ul>li,.cbi-dropdown[optional][open]>ul.dropdown>li[placeholder]{display:block}.cbi-dropdown[open]{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);position:relative}.cbi-dropdown[open]>ul.dropdown{width:auto;max-width:none;display:block}.cbi-dropdown[open]>ul.dropdown>li{display:flex}.cbi-dropdown[open]>ul.dropdown>li[selected]{background-color:var(--brand-subtle);color:var(--brand)}.cbi-dropdown[open]>ul.dropdown>li[unselectable]{opacity:var(--app-opacity-disabled)}.cbi-dropdown[open]>ul.dropdown>li .hide-open{display:none}.cbi-dropdown[open]>ul.dropdown>li .hide-close{display:block}.cbi-dropdown[open]>ul.preview{display:flex}:is(.cbi-dropdown[multiple][more],.cbi-dropdown[multiple][empty])>.more{padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);flex:none;display:flex}.cbi-dropdown[multiple][empty]>.more{flex:1}.cbi-dropdown[multiple][open]>ul.dropdown>li>form{align-items:center;display:flex}.cbi-dropdown[multiple]>ul>li>label{display:flex}.cbi-dropdown>.open{cursor:pointer;border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:currentColor;flex:none;justify-content:center;align-items:center;display:flex}.cbi-dropdown>.more{display:none}.cbi-tooltip{z-index:110;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--text);opacity:0;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:absolute;inset-inline-start:-10000px}.cbi-tooltip.error{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}.cbi-tooltip.success{border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}.cbi-tooltip.info{border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}.cbi-tooltip.notice{border-color:var(--hairline);background-color:var(--warning-surface);color:var(--warning)}.cbi-tooltip-container,[data-tooltip]{cursor:help;white-space:nowrap;text-underline-offset:2px;text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;display:inline-block;position:relative}:is(.cbi-tooltip-container,[data-tooltip]) .cbi-tooltip{visibility:hidden;--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:0;transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out)}:is(.cbi-tooltip-container,[data-tooltip]):hover .cbi-tooltip{visibility:visible;--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;inset-inline-start:auto}[data-tip]:not([data-tip=""]){position:relative}[data-tip]:not([data-tip=""]):after{content:attr(data-tip);pointer-events:none;z-index:110;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:var(--radius-base);background-color:var(--text);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--bg);opacity:0;transition-property:opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:absolute}[data-tip]:not([data-tip=""]):not([data-tip-pos]):after,[data-tip]:not([data-tip=""])[data-tip-pos=top]:after{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);bottom:calc(100% + .5rem);left:50%}[data-tip]:not([data-tip=""])[data-tip-pos=bottom]:after{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:calc(100% + .5rem);left:50%}[data-tip]:not([data-tip=""])[data-tip-pos=left]:after{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:50%;right:calc(100% + .625rem)}[data-tip]:not([data-tip=""])[data-tip-pos=right]:after{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:50%;left:calc(100% + .625rem)}[data-tip]:not([data-tip=""]):focus-visible:after{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;transition-delay:.3s}@media (hover:hover){[data-tip]:not([data-tip=""]):hover:after{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;transition-delay:.3s}}.alert-message{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text)}@media not all and (min-width:48rem){.alert-message{margin-inline:0;margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 4)}}.modal .alert-message{margin-bottom:0}.login-shell .alert-message{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2.5);text-align:center;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));margin-bottom:0}@media not all and (min-width:48rem){.login-shell .alert-message{padding-inline:calc(var(--spacing) * .5)}}.alert-message.success{border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}.alert-message.info{border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}.alert-message.warning,.alert-message.notice{border-color:var(--hairline);background-color:var(--warning-surface);color:var(--warning)}.alert-message.error,.alert-message.danger{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}.alert-message h4,.alert-message h5,.alert-message pre,.alert-message ul,.alert-message li,.alert-message p{border-style:var(--tw-border-style);color:inherit;background-color:#0000;border-width:0}.alert-message h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}@media not all and (min-width:48rem){.alert-message h4{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}@media not all and (min-width:48rem){.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.alert-message .right{margin-top:calc(var(--spacing) * 4)}@media not all and (min-width:48rem){.alert-message .right{margin-top:calc(var(--spacing) * 3)}}.cbi-progressbar{height:calc(var(--spacing) * 3.5);cursor:help;background-color:var(--surface-sunken);border-radius:3.40282e38px;width:100%;position:relative;overflow:hidden}.cbi-progressbar:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);border-radius:calc(var(--radius-base) * 2);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);white-space:nowrap;content:var(--tw-content);color:var(--text);--tw-content:attr(title);content:var(--tw-content);position:absolute;top:50%;left:50%}@media not all and (min-width:48rem){.cbi-progressbar{height:calc(var(--spacing) * 4)}.cbi-progressbar:before{content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}}@media not all and (min-width:40rem){[data-page=admin-system-package-manager] .cbi-progressbar:before{content:var(--tw-content);font-size:10px}}.cbi-progressbar>div{--tw-gradient-position:to right;height:100%}@supports (background-image:linear-gradient(in lab, red, red)){.cbi-progressbar>div{--tw-gradient-position:to right in oklab}}.cbi-progressbar>div{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-start);--tw-gradient-to:var(--progress-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.label{background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);color:var(--text);text-transform:uppercase;border-radius:3.40282e38px}.label.important{background-color:var(--info-surface);color:var(--info)}.label.warning{background-color:var(--danger-surface);color:var(--danger)}.label.success{background-color:var(--success-surface);color:var(--success)}.label.notice{background-color:var(--warning-surface);color:var(--warning)}.zonebadge{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text);display:inline-flex;overflow:visible}@media not all and (min-width:48rem){.zonebadge{gap:var(--spacing);padding-inline:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.zonebadge[style*=--zone-color-rgb]{border-color:#0000;background-color:rgb(var(--zone-color-rgb),.7)!important}.zonebadge[style*=--zone-color-rgb] em{color:var(--text)}.zonebadge.zonebadge-empty{--tw-border-style:dashed;--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text-muted);background-color:#0000;border-style:dashed;font-style:italic}.ifacebadge>.zonebadge{padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);border-radius:3.40282e38px}.cbi-dropdown .zonebadge{padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.ifacebadge{cursor:default;align-items:center;gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:box-shadow,border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex-wrap:nowrap;transition-duration:.15s;display:inline-flex}@media (hover:hover){.ifacebadge:hover{border-color:var(--hairline);background-color:var(--surface-sunken);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media not all and (min-width:48rem){.ifacebadge{gap:calc(var(--spacing) * 1.5);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.zonebadge>.ifacebadge{border-radius:calc(var(--radius-base) * 2);padding-inline:calc(var(--spacing) * 1.5);padding-block:0}.zonebadge>.ifacebadge img{margin-right:var(--spacing);width:calc(var(--spacing) * 4)}.cbi-dropdown .ifacebadge{gap:var(--spacing);border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){.cbi-dropdown .ifacebadge:hover{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.cbi-dropdown .ifacebadge img{margin-right:var(--spacing);width:calc(var(--spacing) * 4)}.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}@media not all and (min-width:48rem){.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 4)}}.ifacebadge>span>.nowrap{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}@media not all and (min-width:48rem){.ifacebadge>span>.nowrap{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.ifacebadge.ifacebadge-active{border-color:var(--brand);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.ifacebadge.large{min-width:200px;padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex:1}@media not all and (min-width:48rem){.ifacebadge.large{min-width:180px;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5)}}.cbi-section{margin-bottom:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 2);padding:calc(var(--spacing) * 5);overflow:visible}@media not all and (min-width:48rem){.cbi-section{padding:calc(var(--spacing) * 3)}}.cbi-section[data-tab-title]{margin:0;padding:0}.cbi-section[data-tab-active=true]{margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 5)}@media not all and (min-width:48rem){.cbi-section[data-tab-active=true]{padding:calc(var(--spacing) * 3)}}#maincontent .cbi-section{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-section>.cbi-title{justify-content:space-between;align-items:flex-start;display:flex}.cbi-section>.cbi-title>h3{flex:1}.cbi-section>.cbi-title>h3 .label[data-clickable]{background-color:var(--surface-sunken);color:var(--text);width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7);cursor:pointer;justify-content:center;align-items:center;padding:0;display:inline-flex}.cbi-section>.cbi-title>h3 .label[data-clickable]:before{content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;background-color:currentColor;transition-duration:.15s}@media (hover:hover){.cbi-section>.cbi-title>h3 .label[data-clickable]:hover{--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.cbi-section>.cbi-title>h3 .label[data-clickable]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}@media not all and (min-width:48rem){.cbi-section>.cbi-title>h3 .label[data-clickable]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;font-size:0;position:relative}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;content:var(--tw-content);--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);background-color:currentColor;position:absolute}@media (hover:hover){.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:hover:before{content:var(--tw-content);--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:active:before{content:var(--tw-content);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;rotate:0deg}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;rotate:90deg}.cbi-section legend{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.cbi-section h3{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-bottom:calc(var(--spacing) * 4);color:var(--text)}@media not all and (min-width:48rem){.cbi-section h3{padding-bottom:calc(var(--spacing) * 2);margin-inline:0}.cbi-section div[style*=display\:grid]{gap:calc(var(--spacing) * 3);grid-template-columns:repeat(2,minmax(0,1fr))!important}}.cbi-section div[style*=display\:grid]:has(>.ifacebox){place-items:center}.cbi-section .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:nowrap;display:flex}@media not all and (min-width:48rem){.cbi-section .network-status-table{flex-direction:column}}.cbi-section .cbi-section-create{margin-top:calc(var(--spacing) * 6);align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){.cbi-section .cbi-section-create{margin-inline:0;margin-top:calc(var(--spacing) * 5);align-items:stretch;gap:calc(var(--spacing) * 3);flex-direction:column}}.cbi-section .cbi-section-create>div{flex:none}@media not all and (min-width:48rem){.cbi-section .cbi-section-create>div{flex:1;width:100%}}.ifacebox{min-width:calc(var(--spacing) * 28);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);text-align:center;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;align-items:stretch;display:inline-flex;position:relative;overflow:visible}@media (hover:hover){.ifacebox:hover{border-color:var(--hairline);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media not all and (min-width:48rem){.ifacebox{min-width:calc(var(--spacing) * 30);border-radius:calc(var(--radius-base) * 3);border-color:var(--hairline);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex:1}#cbi-network-interface .ifacebox{flex-direction:row}}@media (min-width:48rem){#cbi-network-interface .ifacebox{min-width:calc(var(--spacing) * 38)}}.ifacebox .ifacebox-head{border-top-left-radius:calc(var(--radius-base) * 2);border-top-right-radius:calc(var(--radius-base) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);width:100%;padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);text-align:center;--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:background-color,border-color,color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media not all and (min-width:48rem){.ifacebox .ifacebox-head{border-top-left-radius:calc(var(--radius-base) * 3);border-top-right-radius:calc(var(--radius-base) * 3);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}}.ifacebox .ifacebox-head[style*=--zone-color-rgb]{background-color:rgb(var(--zone-color-rgb),.75)!important}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-head){border-top-left-radius:calc(var(--radius-base) * 3);border-bottom-left-radius:calc(var(--radius-base) * 3);border-right-style:var(--tw-border-style);border-right-width:1px;border-bottom-style:var(--tw-border-style);border-bottom-width:0;border-top-right-radius:0;flex-shrink:0;justify-content:center;align-items:center;width:auto;display:flex}}.ifacebox .ifacebox-head.cbi-tooltip-container{background-color:#0000;position:static}.ifacebox .ifacebox-head.cbi-tooltip-container .cbi-tooltip{bottom:0;left:0}.ifacebox .ifacebox-head.active{border-color:var(--brand);background-color:var(--brand);color:var(--on-brand)}.ifacebox .ifacebox-body{justify-content:center;align-items:stretch;gap:var(--spacing);border-bottom-right-radius:calc(var(--radius-base) * 2);border-bottom-left-radius:calc(var(--radius-base) * 2);width:100%;padding:calc(var(--spacing) * 3);text-align:center;color:var(--text);flex-direction:column;flex:1;display:flex}@media not all and (min-width:48rem){.ifacebox .ifacebox-body{border-bottom-right-radius:calc(var(--radius-base) * 3);border-bottom-left-radius:calc(var(--radius-base) * 3)}#cbi-network-interface :is(.ifacebox .ifacebox-body){border-top-right-radius:calc(var(--radius-base) * 3);border-bottom-right-radius:calc(var(--radius-base) * 3);padding-block:calc(var(--spacing) * 2);padding-right:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 4);border-bottom-left-radius:0;flex-direction:row;align-items:center}}.ifacebox .ifacebox-body>img{width:calc(var(--spacing) * 5);margin-inline:auto}:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span{color:var(--text)}@media not all and (min-width:48rem){:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}}.network-status-table :is(.ifacebox .ifacebox-body>span){width:100%}.ifacebox .ifacebox-body>span .cbi-tooltip-container+.cbi-tooltip-container{margin-left:var(--spacing)}.ifacebox .ifacebox-body>span .cbi-tooltip{transition-delay:.2s}.ifacebox .ifacebox-body>span .nowrap{display:inline-block}.ifacebox .ifacebox-body>span>.nowrap:not(:last-child){margin-bottom:var(--spacing)}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5);flex-shrink:0}.ifacebox .ifacebox-body>div{width:100%;display:block}:where(.ifacebox .ifacebox-body>div>:not(:last-child)){--tw-space-y-reverse:0;margin-block:0}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-body>div){flex:1;width:auto}:where(#cbi-network-interface :is(.ifacebox .ifacebox-body>div)>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}}.ifacebox .ifacebox-body .cbi-tooltip-container{cursor:help;color:var(--text);justify-content:center;align-items:center;display:inline-flex;position:static}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{bottom:0}@media (min-width:48rem){.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{left:0}}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip .nowrap{white-space:nowrap}.ifacebox .ifacebox-body small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4);display:block}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-body small){margin-top:0}}.network-status-table .ifacebox-body{justify-content:space-around;align-items:center;gap:calc(var(--spacing) * 2);flex-direction:column;flex:1;height:100%;display:flex}.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 1.5)}}.network-status-table .ifacebox-body .ifacebadge{min-width:calc(var(--spacing) * 55);flex:1}#modal_overlay{pointer-events:none;background-color:#0000;display:none;position:fixed;top:0;bottom:0;overflow:auto}.modal-overlay-active #modal_overlay{pointer-events:auto;z-index:100;background-color:var(--scrim);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);grid-template-columns:repeat(1,minmax(0,1fr));place-items:center;display:grid;inset:0}#modal_overlay>.modal{width:var(--container-5xl);gap:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding:calc(var(--spacing) * 6);overflow-wrap:break-word;white-space:normal;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;display:flex;position:relative}@media not all and (min-width:48rem){#modal_overlay>.modal{gap:calc(var(--spacing) * 3);width:100%;padding:calc(var(--spacing) * 4)}}#modal_overlay>.modal h4{text-align:center;margin-bottom:0}#modal_overlay>.modal h4 em{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand)}#modal_overlay>.modal h5{margin-block:calc(var(--spacing) * 3);color:var(--text)}#modal_overlay>.modal p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text)}#modal_overlay>.modal>ul{border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 3);overflow:auto}#modal_overlay>.modal label.btn{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text)}@media (hover:hover){#modal_overlay>.modal label.btn:hover{border-color:var(--hairline)}}#modal_overlay>.modal pre{overflow:auto}#modal_overlay>.modal pre.errors{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}#modal_overlay>.modal pre+pre{margin-top:calc(var(--spacing) * 3)}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 4);flex-shrink:0;display:flex}@media not all and (min-width:48rem){#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 1.5);padding:calc(var(--spacing) * 2.5)}}#modal_overlay>.modal div.left{justify-content:flex-start}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.right{justify-content:flex-end}#modal_overlay>.modal.uci-dialog ins,#modal_overlay>.modal.uci-dialog del,#modal_overlay>.modal.uci-dialog var{font-family:var(--font-mono);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);font-style:normal;text-decoration-line:none}#modal_overlay>.modal.uci-dialog ins{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}#modal_overlay>.modal.uci-dialog del{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}#modal_overlay>.modal.uci-dialog var{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}#modal_overlay>.modal.uci-dialog .uci-change-legend{margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 4);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}@media not all and (min-width:48rem){#modal_overlay>.modal.uci-dialog .uci-change-legend{gap:calc(var(--spacing) * 2);padding:calc(var(--spacing) * 3);grid-template-columns:repeat(1,minmax(0,1fr))}}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label del,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var{height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);justify-content:center;align-items:center;display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var del{margin-left:var(--spacing);height:calc(var(--spacing) * 4);min-width:calc(var(--spacing) * 4);padding-inline:var(--spacing)}#modal_overlay>.modal.uci-dialog .uci-change-list{margin-top:calc(var(--spacing) * 4)}:where(#modal_overlay>.modal.uci-dialog .uci-change-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}#modal_overlay>.modal.uci-dialog .uci-change-list h5{margin-top:calc(var(--spacing) * 6);margin-bottom:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text)}#modal_overlay>.modal.uci-dialog .uci-change-list h5:first-child{margin-top:0}#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:block}:is(#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del) strong{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}#modal_overlay>.modal.uci-dialog .uci-change-list var{border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}#modal_overlay>.modal.uci-dialog .uci-change-list var ins,#modal_overlay>.modal.uci-dialog .uci-change-list var del{margin-left:var(--spacing);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));display:inline-block}@media not all and (min-width:48rem){.mobile-menu-overlay{visibility:hidden;z-index:60;background-color:var(--mega-menu-bg);opacity:0;position:fixed;inset:0}}@media (min-width:48rem){.mobile-menu-overlay{display:none}}@media not all and (min-width:48rem){.mobile-menu-overlay.mobile-menu-open{visibility:visible;opacity:1;transition-property:visibility,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.mobile-menu-overlay .mobile-nav{width:100%;height:100%;padding-top:calc(var(--spacing) * 14);flex-direction:column;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-body{min-height:0;padding-inline:calc(var(--spacing) * 5);padding-top:calc(var(--spacing) * 6);flex-direction:column;flex:1;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-body .mobile-nav-label{margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted)}.mobile-menu-overlay .mobile-nav .mobile-nav-list{--tw-translate-y:calc(var(--spacing) * -2);min-height:0;translate:var(--tw-translate-x) var(--tw-translate-y);row-gap:calc(var(--spacing) * 4);overscroll-behavior:contain;padding:0;padding-bottom:calc(var(--spacing) * 5);opacity:0;flex-direction:column;flex:1;margin:0;list-style-type:none;display:flex;overflow-y:auto}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item{flex-shrink:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .nav-row{min-height:calc(var(--spacing) * 13);justify-content:space-between;gap:calc(var(--spacing) * 3);padding-inline:0;padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);background-color:#0000;border-radius:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .nav-row .nav-icon{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-submenu .mobile-nav-submenu-list{padding:0;padding-left:calc(var(--spacing) * 6);margin:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-submenu .mobile-nav-subitem .mobile-nav-sublink{min-height:calc(var(--spacing) * 10);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));align-items:center}.mobile-menu-overlay .mobile-nav .mobile-nav-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 5);padding-top:calc(var(--spacing) * 4);padding-bottom:max(1rem, env(safe-area-inset-bottom));flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-footer-action{align-items:center;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-logout{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s}@media (hover:hover){.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-logout:hover{color:var(--brand)}}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .theme-switcher .theme-option{padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing)}.mobile-menu-overlay.mobile-menu-open .mobile-nav-list{--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y);opacity:1;transition-property:translate,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out)}body.mobile-navigation-open>header{z-index:70;background-color:#0000}}[data-nav-type=mega-menu] .desktop-menu-overlay{pointer-events:none;visibility:hidden;z-index:60;background-color:var(--mega-menu-scrim);opacity:0;--tw-backdrop-blur:blur(var(--blur-lg));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:opacity,visibility;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.22s;--tw-ease:cubic-bezier(.4,0,.6,1);transition-duration:.22s;transition-timing-function:cubic-bezier(.4,0,.6,1);position:fixed;inset:0}@media not all and (min-width:48rem){[data-nav-type=mega-menu] .desktop-menu-overlay{display:none}}[data-nav-type=mega-menu] .desktop-menu-overlay.active{pointer-events:auto;visibility:visible;opacity:1}table.table,.table{margin-bottom:calc(var(--spacing) * 3);border-collapse:separate;--tw-border-spacing-x:0;--tw-border-spacing-y:0;width:100%;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);overflow:visible}@media not all and (min-width:48rem){table.table,.table{border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;margin-inline:0;display:block;overflow:visible}}:is(table.table,.table)[width="100%"]{width:100%}:is(table.table,.table)[width="33%"]{width:33.3333%}:is(table.table,.table) .cbi-section-table-titles{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content);content:var(--tw-content);border-color:var(--hairline);content:var(--tw-content);padding-inline:calc(var(--spacing) * 3);content:var(--tw-content);padding-block:calc(var(--spacing) * 3);content:var(--tw-content);vertical-align:middle;content:var(--tw-content);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-content:attr(data-title);content:var(--tw-content);content:var(--tw-content);display:table-cell}@media not all and (min-width:48rem){:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex:0 0 100%;display:flex}}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content)}@media (min-width:48rem){:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}}:is(:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):not([data-title]),:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):has(td.cbi-section-table-titles)):before{content:var(--tw-content);--tw-content:none;content:none}:is(table.table,.table) .cbi-section-table-titles.named:before{content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);content:var(--tw-content);color:var(--text-subtle);content:var(--tw-content);text-transform:uppercase}@media not all and (min-width:48rem){:is(table.table,.table) tbody,:is(table.table,.table) .tbody{display:block}:is(table.table,.table) tr,:is(table.table,.table) .tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):has(.cbi-progressbar){justify-content:center;align-items:center;display:flex}}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th):first-child{border-top-left-radius:calc(var(--radius-base) * 2)}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th):last-child{border-top-right-radius:calc(var(--radius-base) * 2)}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-style:var(--tw-border-style);border-bottom-width:0}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-descr{display:none}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-1,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-2{background-color:#0000}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-1{flex:2rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-1{width:calc(var(--spacing) * 20);max-width:calc(var(--spacing) * 28)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{white-space:normal}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{flex:2 2 4rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{width:calc(var(--spacing) * 32);max-width:calc(var(--spacing) * 40)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-3{flex:3 3 6rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-3{width:calc(var(--spacing) * 44);max-width:calc(var(--spacing) * 52)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-4{flex:4 4 8rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-4{width:calc(var(--spacing) * 56);max-width:calc(var(--spacing) * 64)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-5{flex:5 5 10rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-5{width:calc(var(--spacing) * 68);max-width:calc(var(--spacing) * 76)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-6{flex:6 6 12rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-6{width:calc(var(--spacing) * 80);max-width:calc(var(--spacing) * 88)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-7{flex:7 7 14rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-7{width:calc(var(--spacing) * 92);max-width:calc(var(--spacing) * 100)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-8{flex:8 8 16rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-8{width:calc(var(--spacing) * 104);max-width:calc(var(--spacing) * 112)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-9{flex:9 9 18rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-9{width:calc(var(--spacing) * 116);max-width:calc(var(--spacing) * 124)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-10{flex:0 0 100%;max-width:calc(100vw - 40px)}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-10{width:calc(var(--spacing) * 128);max-width:calc(var(--spacing) * 136)}}:is(table.table,.table) th,:is(table.table,.table) .th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 3);text-align:left;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--text-subtle);text-transform:uppercase}@media not all and (min-width:48rem){:is(table.table,.table) th,:is(table.table,.table) .th{border-style:var(--tw-border-style);background-color:#0000;border-width:0;flex:50%}}#cbi-samba4 :is(:is(table.table,.table) th,:is(table.table,.table) .th){padding-inline:calc(var(--spacing) * .5);padding-block:calc(var(--spacing) * 1.5)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{width:100%}@media not all and (min-width:48rem){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{flex:0 0 100%}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{width:33.3333%}@media not all and (min-width:48rem){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{flex:0 0 33.333%}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]{cursor:pointer;-webkit-user-select:none;user-select:none}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:after{content:var(--tw-content);margin-left:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}@media (hover:hover){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:hover{background-color:var(--hover-faint)}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=asc]:after{--tw-content:"▲";content:var(--tw-content)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=desc]:after{--tw-content:"▼";content:var(--tw-content)}:is(table.table,.table)[id*=status_leases] .td{max-width:calc(var(--spacing) * 62)}@media not all and (min-width:48rem){:is(table.table,.table)[id*=status_leases] .td{max-width:100%}}:is(table.table,.table) td,:is(table.table,.table) .td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 3);vertical-align:middle;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));overflow-wrap:break-word;white-space:normal;display:table-cell}@media not all and (min-width:48rem){:is(table.table,.table) td,:is(table.table,.table) .td{border-style:var(--tw-border-style);padding-inline:var(--spacing);padding-block:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));border-width:0;flex:50%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content);--tw-content:attr(data-title);content:var(--tw-content);content:var(--tw-content);display:none}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{margin-bottom:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);display:block}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content)}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}}#cbi-samba4 :is(:is(table.table,.table) td,:is(table.table,.table) .td){padding-inline:calc(var(--spacing) * .5);padding-block:calc(var(--spacing) * 1.5)}[data-page=admin-system-mounts] :is(:is(table.table,.table) td,:is(table.table,.table) .td){max-width:calc(var(--spacing) * 104)}@media not all and (min-width:48rem){[data-page=admin-system-mounts] :is(:is(table.table,.table) td,:is(table.table,.table) .td){max-width:100%}#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td){padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);flex:0 0 100%}}#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content)}@media not all and (min-width:48rem){#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td):before{margin-bottom:calc(var(--spacing) * 1.5)}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=text],:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=password],:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){min-width:fit-content}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{word-break:break-all}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{margin-bottom:var(--spacing);text-align:left;flex-basis:100%;align-self:flex-start}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.DummyValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.Button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.FlagValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=dvalue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=fvalue]{flex-basis:50%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions{flex:0 0 100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div{width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div>.cbi-button{flex:1}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>.cbi-button{width:100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{width:100%}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{flex:0 0 100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{width:33.3333%}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{flex:0 0 33.333%}[data-page=admin-network-network] :is(:is(table.table,.table) td,:is(table.table,.table) .td)[data-name=_ifacebox],[data-page=admin-network-network] :is(:is(table.table,.table) td,:is(table.table,.table) .td)[data-name=_ifacestat]{flex-basis:100%}}.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell{width:auto!important}#content_syslog{margin:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){#content_syslog{margin:var(--spacing)}}#content_syslog>div{align-items:center;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#content_syslog>div{column-gap:calc(var(--spacing) * 1.5)}}#content_syslog>div>select,#content_syslog>div>input{margin-block:0!important}@media not all and (min-width:48rem){#content_syslog>div>.cbi-input-select,#content_syslog>div>.cbi-input-text{min-width:calc(var(--spacing) * 45)}}#content_syslog>.syslog-view{display:block}#syslog,#log_textarea{width:100%;font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}#syslog{margin-bottom:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media not all and (min-width:48rem){#syslog{padding:calc(var(--spacing) * 3)}}#content_syslog.log-enhanced>#syslog{display:none}.syslog-view{width:100%;margin-bottom:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media not all and (min-width:48rem){.syslog-view{padding:calc(var(--spacing) * 3)}}.syslog-view{font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);--tw-outline-style:none;outline-style:none;overflow-x:auto}.syslog-view:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring)}.syslog-view .log-row{border-radius:calc(var(--radius-base) * .75);width:max-content;min-width:100%;padding-inline:calc(var(--spacing) * 2);white-space:pre}.syslog-view .log-row:hover{background-color:var(--hover-faint)}.syslog-view ::selection{background-color:var(--info-surface);color:var(--text)}.syslog-view .log-time{color:var(--text-subtle)}@media (min-width:48rem){.syslog-view .log-time{vertical-align:bottom;min-width:24ch;display:inline-block}}.syslog-view .log-sev{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}@media (min-width:48rem){.syslog-view .log-sev{vertical-align:bottom;min-width:16ch;display:inline-block}}.syslog-view .log-tag{color:var(--text-muted)}@media (min-width:48rem){.syslog-view .log-tag{vertical-align:bottom;min-width:18ch;display:inline-block}}.syslog-view .lv-info .log-sev{color:var(--info)}.syslog-view .lv-notice .log-sev{color:var(--success)}.syslog-view .lv-warn .log-sev{color:var(--warning)}.syslog-view .lv-debug,.syslog-view .lv-debug .log-sev,.syslog-view .lv-debug .log-tag{color:var(--text-subtle)}.syslog-view .lv-err,.syslog-view .lv-crit{background-color:var(--danger-surface)}:is(.syslog-view .lv-err,.syslog-view .lv-crit):hover{background-color:var(--danger-surface-hover)}:is(.syslog-view .lv-err,.syslog-view .lv-crit) .log-sev{color:var(--danger)}.cbi-input-invalid,.cbi-value-error{border-color:var(--danger)!important}:is(.cbi-input-invalid,.cbi-value-error):focus{--tw-ring-color:var(--danger)!important}.cbi-value{gap:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 1.5);flex-flow:wrap;display:flex}@media not all and (min-width:48rem){.cbi-value{gap:calc(var(--spacing) * 1.5);padding-block:var(--spacing);flex-direction:column}}.cbi-value.hidden{display:none}.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 3)}@media not all and (min-width:48rem){.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 2)}}.cbi-value>.cbi-value-title{padding-top:var(--spacing);text-align:right;--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}@media not all and (min-width:48rem){.cbi-value>.cbi-value-title{text-align:left;width:auto}}@media (min-width:48rem){.cbi-value>.cbi-value-title{flex:0 0 12rem}}.cbi-value>.cbi-value-field{flex:1;max-width:100%}.cbi-value>.cbi-value-field:has(>.cbi-dropdown[disabled]){cursor:not-allowed}.cbi-value>.cbi-value-field .cbi-value-description{margin-top:var(--spacing);padding-left:calc(var(--spacing) * 4);--tw-leading:1;overflow-wrap:break-word;color:var(--text-muted);line-height:1;position:relative}.cbi-value>.cbi-value-field .cbi-value-description:not(:empty):before{content:var(--tw-content);content:var(--tw-content);left:calc(var(--spacing) * -.5);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);background-color:var(--info);content:var(--tw-content);-webkit-mask:var(--icon-info) center/cover no-repeat;-webkit-mask:var(--icon-info) center/cover no-repeat;-webkit-mask:var(--icon-info) center/cover no-repeat;mask:var(--icon-info) center/cover no-repeat;display:inline-block;position:absolute}.cbi-value>.cbi-section,.cbi-value>.cbi-tblsection{width:100%}.cbi-dynlist{width:max-content;max-width:calc(var(--spacing) * 120);align-items:flex-start;gap:calc(var(--spacing) * 3);flex-direction:column;display:inline-flex}@media not all and (min-width:48rem){.cbi-dynlist{max-width:100%!important}}.cbi-dynlist .item{pointer-events:auto;cursor:move;align-items:flex-start;gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface);padding-block:calc(var(--spacing) * 3);padding-right:calc(var(--spacing) * 10);padding-left:calc(var(--spacing) * 4);word-break:break-all;--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,box-shadow,opacity,border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-user-select:text;user-select:text;flex-direction:column;align-self:stretch;transition-duration:.15s;display:inline-flex;position:relative;overflow:hidden}@media not all and (min-width:48rem){.cbi-dynlist .item{width:100%;padding-block:calc(var(--spacing) * 2.5);padding-right:calc(var(--spacing) * 8);padding-left:calc(var(--spacing) * 3)}}.cbi-dynlist .item:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * 2.5);content:var(--tw-content);right:calc(var(--spacing) * 2);content:var(--tw-content);content:var(--tw-content);height:calc(var(--spacing) * 6);content:var(--tw-content);width:calc(var(--spacing) * 6);content:var(--tw-content);content:var(--tw-content);cursor:pointer;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);border-radius:calc(var(--radius-base) * 1.5);content:var(--tw-content);background-color:var(--surface-sunken);content:var(--tw-content);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);content:var(--tw-content);color:var(--text-muted);--tw-content:"×";content:var(--tw-content);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-dynlist .item.dragging{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);cursor:grabbing;opacity:.5;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-dynlist .item.drag-over{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y);border-color:var(--brand);background-color:var(--brand-subtle);--tw-shadow:var(--app-shadow-md);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--brand-subtle)}.cbi-dynlist .item>span,.cbi-dynlist .item>code{pointer-events:none;border-radius:var(--radius-base);width:100%;font-family:var(--font-mono);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.cbi-dynlist .placeholder{word-break:break-all}.cbi-dynlist .add-item{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-width:1px;border-color:var(--hairline);padding-inline:var(--spacing);padding-block:var(--spacing);transition-property:border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;align-self:stretch;transition-duration:.15s;display:inline-flex}@media (hover:hover){.cbi-dynlist .add-item:hover{border-color:var(--hairline);background-color:var(--surface-sunken)}}.cbi-dynlist .add-item>input{min-width:calc(var(--spacing) * 61);flex:1}.cbi-dynlist .add-item>.cbi-button{min-height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;justify-content:center;align-items:center;padding-block:0;display:inline-flex}.cbi-dynlist .add-item>.cbi-button:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-tabmenu{margin-bottom:var(--spacing);align-items:center;gap:var(--spacing);border-radius:calc(var(--radius-base) * 4);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:var(--spacing);display:flex;overflow-x:auto}.cbi-tabmenu li{flex-shrink:0;min-width:fit-content;margin:0;list-style-type:none;position:relative}.cbi-tabmenu li[data-errors]:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -1.5);content:var(--tw-content);z-index:20;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 4);content:var(--tw-content);min-width:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--danger);content:var(--tw-content);padding-inline:calc(var(--spacing) * 1.5);content:var(--tw-content);padding-block:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);color:var(--on-brand);--tw-content:attr(data-errors);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-tabmenu li[data-errors]>a{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}.cbi-tabmenu li>a{border-radius:calc(var(--radius-base) * 4);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--text-muted);text-decoration-line:none;display:block}@media (hover:hover){.cbi-tabmenu li>a:hover{color:var(--text)}}.cbi-tabmenu li.cbi-tab a{background-color:var(--text);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--surface);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-tab-title]{visibility:hidden;height:0;overflow:hidden}[data-tab-active=true]{visibility:visible;height:auto;overflow:visible}#tabmenu{margin-bottom:calc(var(--spacing) * 8);width:100%}.tabs{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);align-items:center;gap:0;display:flex;position:relative;overflow-x:auto}.tabs a{padding-inline:calc(var(--spacing) * 8);padding-block:calc(var(--spacing) * 4);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:block}@media (hover:hover){.tabs a:hover{color:var(--text);text-decoration-line:none}}.tabs>li.active{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--text)}.tabs>li.active>a{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text)}.cbi-section-node-tabbed{margin-top:calc(var(--spacing) * 6)}.cmdk-trigger{margin-right:calc(var(--spacing) * 4);width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8);cursor:pointer;border-radius:var(--radius-base);border-style:var(--tw-border-style);color:var(--text);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;flex-shrink:0;place-items:center;padding:0;transition-duration:.15s;display:grid;position:relative}body:not([data-nav-type=sidebar]) .cmdk-trigger{margin-left:auto}.cmdk-trigger:before{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;mask:var(--icon-search) center/contain no-repeat;background-color:currentColor}.cmdk-trigger:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cmdk-trigger:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cmdk-trigger:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.cmdk-panel{top:calc(var(--spacing) * 24);z-index:120;--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);width:min(36rem,100vw - 2.5rem);translate:var(--tw-translate-x) var(--tw-translate-y);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:color-mix(in oklab, var(--surface) 85%, transparent);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-xl));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:fixed;left:50%;overflow:hidden}@starting-style{.cmdk-panel{--tw-translate-y:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y)}}@starting-style{.cmdk-panel{opacity:0}}@media not all and (min-width:48rem){.cmdk-panel{border-style:var(--tw-border-style);background-color:var(--bg);--tw-shadow:0 0 #0000;width:auto;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur: ;-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);--tw-backdrop-saturate:saturate(100%);border-width:0;border-radius:0;flex-direction:column;display:flex;inset:0;translate:none}}.cmdk-panel .cmdk-inputrow{align-items:center;gap:calc(var(--spacing) * 3);padding-inline:calc(var(--spacing) * 5);padding-block:calc(var(--spacing) * 3.5);display:flex}@media not all and (min-width:48rem){.cmdk-panel .cmdk-inputrow{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5)}}.cmdk-panel .cmdk-inputrow:before{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);color:var(--text-subtle);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;mask:var(--icon-search) center/contain no-repeat;background-color:currentColor;flex-shrink:0}.cmdk-panel .cmdk-inputrow .cmdk-input{border-style:var(--tw-border-style);width:100%;min-width:0;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:var(--text);background-color:#0000;border-width:0;border-radius:0;flex:1;padding:0}.cmdk-panel .cmdk-inputrow .cmdk-input::placeholder{color:var(--text-subtle)}.cmdk-panel .cmdk-inputrow .cmdk-input{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cmdk-panel .cmdk-inputrow .cmdk-input:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;outline-style:none}.cmdk-panel .cmdk-inputrow .cmdk-clear{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);color:var(--text-subtle);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;flex-shrink:0;place-items:center;padding:0;transition-duration:.15s;display:grid}.cmdk-panel .cmdk-inputrow .cmdk-clear:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-x) center/contain no-repeat;-webkit-mask:var(--icon-x) center/contain no-repeat;-webkit-mask:var(--icon-x) center/contain no-repeat;mask:var(--icon-x) center/contain no-repeat;background-color:currentColor}.cmdk-panel .cmdk-inputrow .cmdk-clear:hover{color:var(--text)}.cmdk-input:placeholder-shown~:is(.cmdk-panel .cmdk-inputrow .cmdk-clear){display:none}.cmdk-panel .cmdk-inputrow .cmdk-cancel{cursor:pointer;border-style:var(--tw-border-style);padding:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--brand);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;border-width:0;flex-shrink:0;display:none}@media not all and (min-width:48rem){.cmdk-panel .cmdk-inputrow .cmdk-cancel{display:block}}.cmdk-panel .cmdk-list{max-height:calc(var(--spacing) * 80);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 2);overflow-y:auto}.cmdk-panel .cmdk-list:empty{display:none}@media not all and (min-width:48rem){.cmdk-panel .cmdk-list{overscroll-behavior:contain;flex:1;max-height:none}}.cmdk-panel .cmdk-list .cmdk-row{align-items:center;gap:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);text-decoration-line:none;display:flex}.cmdk-panel .cmdk-list .cmdk-row .cmdk-title{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.cmdk-panel .cmdk-list .cmdk-row .cmdk-group-name{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-subtle);flex-shrink:0;margin-left:auto}.cmdk-panel .cmdk-list .cmdk-row mark{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand);background-color:#0000}.cmdk-panel .cmdk-list .cmdk-row.is-selected{background-color:var(--brand-subtle)}.cmdk-panel .cmdk-list .cmdk-row.is-selected .cmdk-title{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}.cmdk-panel .cmdk-list .cmdk-empty{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 6);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-subtle)}.cmdk-panel .cmdk-footer{align-items:center;gap:calc(var(--spacing) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-subtle);display:flex}@media not all and (min-width:48rem){.cmdk-panel .cmdk-footer{display:none}}.cmdk-panel .cmdk-footer .cmdk-hint-close{margin-left:auto}.cmdk-panel .cmdk-footer kbd{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);color:var(--text-muted);padding-block:1px;font-size:11px}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.cmdk-panel{background-color:var(--surface)}}@media (prefers-reduced-transparency:reduce){.cmdk-panel{background-color:var(--surface)}}body[data-bg] .page-bg{--page-bg:var(--main-bg);--page-bg-lqip:var(--main-bg-lqip)}body[data-bg] #maincontent{background:var(--bg);position:relative}@supports (color:color-mix(in lab, red, red)){body[data-bg] #maincontent{background:color-mix(in srgb,var(--bg) 55%,transparent)}}body[data-bg] header,body[data-bg] .sidebar-panel-inner{-webkit-backdrop-filter:blur(var(--main-bg-blur,20px)) saturate(150%);backdrop-filter:blur(var(--main-bg-blur,20px)) saturate(150%);background:var(--bg)}@supports (color:color-mix(in lab, red, red)){body[data-bg] header,body[data-bg] .sidebar-panel-inner{background:color-mix(in srgb,var(--bg) var(--main-bg-alpha,67%),transparent)}}body[data-bg] .page-bg:before{pointer-events:none;z-index:1;--tw-content:"";content:var(--tw-content);background:var(--bg);position:absolute;inset:0}@supports (color:color-mix(in lab, red, red)){body[data-bg] .page-bg:before{background:color-mix(in srgb,var(--bg) var(--main-bg-scrim,20%),transparent)}}body[data-bg] #maincontent .cbi-section{background:var(--surface)}@supports (color:color-mix(in lab, red, red)){body[data-bg] #maincontent .cbi-section{background:color-mix(in srgb,var(--surface) var(--main-bg-alpha,67%),transparent)}}.hidden{display:none!important}@media (min-width:48rem){.left{text-align:left!important}}.left:not(td){text-align:left!important}@media (min-width:48rem){.right{text-align:right!important}}.right:not(td){text-align:right!important}@media (min-width:48rem){.top{vertical-align:top!important}}.top:not(td){vertical-align:top!important}@media (min-width:48rem){.bottom{vertical-align:bottom!important}}.bottom:not(td){vertical-align:bottom!important}@media (min-width:48rem){.center{text-align:center!important}}.center:not(td){text-align:center!important}@media (min-width:48rem){.middle{vertical-align:middle!important}}.middle:not(td){vertical-align:middle!important}@media (min-width:48rem){.nowrap:not(span){white-space:nowrap}}.nowrap:not(span):not(td){white-space:nowrap}@keyframes aurora-fade-in{0%{opacity:0}}.fade-in{animation:.25s both aurora-fade-in}.fade-out{pointer-events:none;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.spinning{display:inline-block;position:relative;padding-left:calc(var(--spacing) * 8)!important}.spinning:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);animation:var(--animate-spin);content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-spinning) center/cover no-repeat;-webkit-mask:var(--icon-spinning) center/cover no-repeat;-webkit-mask:var(--icon-spinning) center/cover no-repeat;mask:var(--icon-spinning) center/cover no-repeat;background-color:currentColor;position:absolute;top:50%;left:6px}#view>.spinning:first-child{min-height:calc(var(--spacing) * 48);place-items:center;width:fit-content;margin-inline:auto;display:grid}@media not all and (min-width:48rem){#view>.spinning:first-child{min-height:calc(100dvh - 4rem)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-property:none!important;animation:none!important}.spinning:before{animation:var(--animate-spin)!important}}@media (prefers-reduced-transparency:reduce){*,:before,:after{-webkit-backdrop-filter:none!important;backdrop-filter:none!important}:root{--mega-menu-bg:var(--surface-overlay)}body[data-bg]{--main-bg-alpha:100%}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}} +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-content:"";--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-border-style:solid;--tw-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components,utilities;:root{--bg:#f7fafc;--surface:#fff;--text:#121a22;--brand:#0085b7;--on-brand:#fff;--link:#0085b7;--info:#0e5794;--warning:#643e00;--success:#004f3e;--danger:#8d1925;--text-muted:#5f666d;--text-subtle:#7f858b;--surface-sunken:#f4f7fa;--surface-overlay:#fff;--hairline:#121a2221;--hover-faint:#ebeff2;--brand-hover:#0073a3;--brand-subtle:#ddecf5;--brand-subtle-hover:#d0dfe8;--focus-ring:#0085b799;--progress-start:#64aed5;--progress-end:#0085b7;--info-surface:#deefff;--warning-surface:#ffedd6;--success-surface:#d3f8eb;--danger-surface:#ffe8e6;--danger-surface-hover:#f9d9d7;--control-bg:#fff;--scrim:#0009;--mega-menu-bg:#f1f7fa;--mega-menu-scrim:#0d1c2a61;--app-shadow-sm:0 1px 3px #0000000f, 0 1px 2px #0000000a;--app-shadow-md:0 4px 16px #00000014, 0 1px 3px #0000000a;--app-shadow-lg:0 12px 32px #0000001f;--app-opacity-disabled:.4;--font-sans:"Lato", ui-sans-serif, system-ui, sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;--spacing:.25rem;--content-width-centered:80rem;--radius-base:.5rem}@supports (color:lab(0% 0 0)){:root{--bg:lab(98.1553% -.760227 -1.25223);--surface:lab(100% 0 0);--text:lab(8.89727% -1.68239 -6.93074);--brand:lab(51.3503% -19.237 -40.2116);--on-brand:lab(100% 0 0);--link:lab(51.3503% -19.237 -40.2116);--info:lab(35.5745% -2.86636 -40.2468);--warning:lab(30.2236% 14.0359 42.8654);--success:lab(29.3859% -35.8952 5.0677);--danger:lab(31.1495% 47.9256 25.8661);--text-muted:lab(42.8254% -1.57365 -4.8763);--text-subtle:lab(55.3248% -1.4126 -4.053);--surface-sunken:lab(97.114% -.949115 -1.56456);--surface-overlay:lab(100.011% -.760317 -1.25225);--hairline:lab(8.89727% -1.68239 -6.93074/.13);--hover-faint:lab(94.2168% -1.13726 -1.87657);--brand-hover:lab(44.3401% -18.0233 -40.0589);--brand-subtle:lab(92.5794% -3.9458 -6.17858);--brand-subtle-hover:lab(87.9391% -3.94133 -6.17628);--focus-ring:lab(51.3503% -19.237 -40.2116/.6);--progress-start:lab(67.4852% -15.7175 -27.197);--progress-end:lab(51.3503% -19.237 -40.2116);--info-surface:lab(93.5628% -4.16487 -14.7881);--warning-surface:lab(94.8007% 4.75499 15.6111);--success-surface:lab(94.7525% -14.2308 2.09508);--danger-surface:lab(93.849% 11.2841 5.29771);--danger-surface-hover:lab(89.2089% 11.2856 5.30034);--control-bg:lab(100.011% -.760317 -1.25225);--scrim:lab(0% 0 0/.6);--mega-menu-bg:lab(96.7742% -1.51286 -2.50006);--mega-menu-scrim:lab(9.40633% -2.1807 -11.9349/.38);--app-shadow-sm:0 1px 3px lab(0% 0 0/.06), 0 1px 2px lab(0% 0 0/.04);--app-shadow-md:0 4px 16px lab(0% 0 0/.08), 0 1px 3px lab(0% 0 0/.04);--app-shadow-lg:0 12px 32px lab(0% 0 0/.12)}}[data-darkmode=true]{--bg:#05070e;--surface:#141822;--text:#f9fafb;--brand:#00958e;--on-brand:#fff;--link:#00958e;--info:#90c1ff;--warning:#f0ba59;--success:#51bd85;--danger:#f17070;--text-muted:#909297;--text-subtle:#5d6067;--surface-sunken:#0a0e17;--surface-overlay:#181d27;--hairline:#f9fafb1a;--hover-faint:#f9fafb0d;--brand-hover:#00837d;--brand-subtle:#061a20;--brand-subtle-hover:#0f242a;--focus-ring:#00958e99;--progress-start:#006261;--progress-end:#00958e;--info-surface:#21344c;--warning-surface:#45310b;--success-surface:#153524;--danger-surface:#541f20;--danger-surface-hover:#602a2a;--control-bg:#0a0e17;--scrim:#0009;--mega-menu-bg:#0a0e17;--mega-menu-scrim:#00000080;--app-shadow-sm:0 4px 12px #0000004d;--app-shadow-md:0 10px 28px #0000006b;--app-shadow-lg:0 20px 48px #0000008c;--app-opacity-disabled:.3}@supports (color:lab(0% 0 0)){[data-darkmode=true]{--bg:lab(1.93894% .0855997 -3.22397);--surface:lab(8.24713% -.0405461 -7.31381);--text:lab(98.252% -.0618994 -.756907);--brand:lab(55.0978% -44.5567 -7.62978);--on-brand:lab(100% 0 0);--link:lab(55.0978% -44.5567 -7.62978);--info:lab(76.3382% -4.43128 -38.7);--warning:lab(79.1996% 12.6808 55.9505);--success:lab(69.2339% -42.392 18.6731);--danger:lab(63.5705% 50.8105 25.3639);--text-muted:lab(60.5379% -.225931 -3.05105);--text-subtle:lab(40.6865% -.278354 -4.23647);--surface-sunken:lab(3.9802% .0812709 -5.64623);--surface-overlay:lab(10.5702% -.0939444 -7.33123);--hairline:lab(98.252% -.0618994 -.756907/.1);--hover-faint:lab(98.252% -.0618994 -.756907/.05);--brand-hover:lab(49.2976% -44.6964 -7.56882);--brand-subtle:lab(7.95734% -6.34954 -6.72844);--brand-subtle-hover:lab(12.602% -6.92477 -6.76408);--focus-ring:lab(55.0986% -44.5682 -7.59286/.6);--progress-start:lab(36.8833% -28.7182 -7.50749);--progress-end:lab(55.0978% -44.5567 -7.62978);--info-surface:lab(20.893% -1.69295 -17.5199);--warning-surface:lab(22.2973% 6.18184 26.7927);--success-surface:lab(19.4608% -16.2551 7.16286);--danger-surface:lab(20.3014% 25.4342 12.827);--danger-surface-hover:lab(24.9464% 25.3964 12.6412);--control-bg:lab(3.9802% .0812709 -5.64623);--scrim:lab(0% 0 0/.6);--mega-menu-bg:lab(3.9802% .0812709 -5.64623);--mega-menu-scrim:lab(0% 0 0/.5);--app-shadow-sm:0 4px 12px lab(0% 0 0/.3);--app-shadow-md:0 10px 28px lab(0% 0 0/.42);--app-shadow-lg:0 20px 48px lab(0% 0 0/.55)}}:root{--icon-activity:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012h4l3%208l4%20-16l3%208h4'%20/%3e%3c/svg%3e");--icon-adjustments:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%2010a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M6%204v4'%20/%3e%3cpath%20d='M6%2012v8'%20/%3e%3cpath%20d='M10%2016a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M12%204v10'%20/%3e%3cpath%20d='M12%2018v2'%20/%3e%3cpath%20d='M16%207a2%202%200%201%200%204%200a2%202%200%200%200%20-4%200'%20/%3e%3cpath%20d='M18%204v1'%20/%3e%3cpath%20d='M18%209v11'%20/%3e%3c/svg%3e");--icon-apps:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%205a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M4%2015a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M14%2015a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v4a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-4'%20/%3e%3cpath%20d='M14%207l6%200'%20/%3e%3cpath%20d='M17%204l0%206'%20/%3e%3c/svg%3e");--icon-arrow-down:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M5.22%208.22a.75.75%200%200%201%201.06%200L10%2011.94l3.72-3.72a.75.75%200%201%201%201.06%201.06l-4.25%204.25a.75.75%200%200%201-1.06%200L5.22%209.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-arrow-down-dark:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23ffffff'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M5.22%208.22a.75.75%200%200%201%201.06%200L10%2011.94l3.72-3.72a.75.75%200%201%201%201.06%201.06l-4.25%204.25a.75.75%200%200%201-1.06%200L5.22%209.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-arrow-right:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2020%2020'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M8.22%205.22a.75.75%200%200%201%201.06%200l4.25%204.25a.75.75%200%200%201%200%201.06l-4.25%204.25a.75.75%200%200%201-1.06-1.06L11.94%2010L8.22%206.28a.75.75%200%200%201%200-1.06'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-box:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203l8%204.5l0%209l-8%204.5l-8%20-4.5l0%20-9l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l0%209'%20/%3e%3cpath%20d='M12%2012l-8%20-4.5'%20/%3e%3c/svg%3e");--icon-category:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M4%204h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M14%204h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M4%2014h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M14%2017a3%203%200%201%200%206%200a3%203%200%201%200%20-6%200'%20/%3e%3c/svg%3e");--icon-chart-bar:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2013a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v6a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-6'%20/%3e%3cpath%20d='M15%209a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v10a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-10'%20/%3e%3cpath%20d='M9%205a1%201%200%200%201%201%20-1h4a1%201%200%200%201%201%201v14a1%201%200%200%201%20-1%201h-4a1%201%200%200%201%20-1%20-1l0%20-14'%20/%3e%3cpath%20d='M4%2020h14'%20/%3e%3c/svg%3e");--icon-check:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20d='M918.8%2083.7c-43.5-30.3-104-19.5-134.6%2024.1l-425.8%20606-127-135.7c-36.4-38.9-98.1-41.1-137-4.8-39%2036.2-41.1%2097.7-4.7%20136.6l206.5%20220.7c4.7%205%209.8%209.4%2015.1%2013.1.7.5%201.4%201%202.2%201.5%2043.5%2030.3%20104%2019.5%20134.6-24.1l494-703.2c30.7-43.5%2020.1-103.9-23.3-134.2z'/%3e%3c/svg%3e");--icon-cpu:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M5%206a1%201%200%200%201%201%20-1h12a1%201%200%200%201%201%201v12a1%201%200%200%201%20-1%201h-12a1%201%200%200%201%20-1%20-1l0%20-12'%20/%3e%3cpath%20d='M9%209h6v6h-6l0%20-6'%20/%3e%3cpath%20d='M3%2010h2'%20/%3e%3cpath%20d='M3%2014h2'%20/%3e%3cpath%20d='M10%203v2'%20/%3e%3cpath%20d='M14%203v2'%20/%3e%3cpath%20d='M21%2010h-2'%20/%3e%3cpath%20d='M21%2014h-2'%20/%3e%3cpath%20d='M14%2021v-2'%20/%3e%3cpath%20d='M10%2021v-2'%20/%3e%3c/svg%3e");--icon-error:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%209v4'%20/%3e%3cpath%20d='M10.363%203.591l-8.106%2013.534a1.914%201.914%200%200%200%201.636%202.871h16.214a1.914%201.914%200%200%200%201.636%20-2.87l-8.106%20-13.536a1.914%201.914%200%200%200%20-3.274%200'%20/%3e%3cpath%20d='M12%2016h.01'%20/%3e%3c/svg%3e");--icon-gauge:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%201%200%2018%200a9%209%200%201%200%20-18%200'%20/%3e%3cpath%20d='M11%2012a1%201%200%201%200%202%200a1%201%200%201%200%20-2%200'%20/%3e%3cpath%20d='M13.41%2010.59l2.59%20-2.59'%20/%3e%3cpath%20d='M7%2012a5%205%200%200%201%205%20-5'%20/%3e%3c/svg%3e");--icon-info:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%20width='24'%20height='24'%20fill='%23000000'%20style='opacity:1;'%3e%3cpath%20fill-rule='evenodd'%20d='M15%208A7%207%200%201%201%201%208a7%207%200%200%201%2014%200M9%205a1%201%200%201%201-2%200a1%201%200%200%201%202%200M6.75%208a.75.75%200%200%200%200%201.5h.75v1.75a.75.75%200%200%200%201.5%200v-2.5A.75.75%200%200%200%208.25%208z'%20clip-rule='evenodd'/%3e%3c/svg%3e");--icon-package:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203l8%204.5l0%209l-8%204.5l-8%20-4.5l0%20-9l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l8%20-4.5'%20/%3e%3cpath%20d='M12%2012l0%209'%20/%3e%3cpath%20d='M12%2012l-8%20-4.5'%20/%3e%3cpath%20d='M16%205.25l-8%204.5'%20/%3e%3c/svg%3e");--icon-phone:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M5%204h4l2%205l-2.5%201.5a11%2011%200%200%200%205%205l1.5%20-2.5l5%202v4a2%202%200%200%201%20-2%202a16%2016%200%200%201%20-15%20-15a2%202%200%200%201%202%20-2'%20/%3e%3c/svg%3e");--icon-radio:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e");--icon-refresh:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%2011a8.1%208.1%200%200%200%20-15.5%20-2m-.5%20-4v4h4'%20/%3e%3cpath%20d='M4%2013a8.1%208.1%200%200%200%2015.5%202m.5%204v-4h-4'%20/%3e%3c/svg%3e");--icon-refresh-off:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%2011a8.1%208.1%200%200%200%20-11.271%20-6.305m-2.41%201.624a8.083%208.083%200%200%200%20-1.819%202.681m-.5%20-4v4h4'%20/%3e%3cpath%20d='M4%2013a8.1%208.1%200%200%200%2013.671%204.691m2.329%20-1.691v-1h-1'%20/%3e%3cpath%20d='M3%203l18%2018'%20/%3e%3c/svg%3e");--icon-router:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2015a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4a2%202%200%200%201%20-2%202h-14a2%202%200%200%201%20-2%20-2l0%20-4'%20/%3e%3cpath%20d='M17%2017l0%20.01'%20/%3e%3cpath%20d='M13%2017l0%20.01'%20/%3e%3cpath%20d='M15%2013l0%20-2'%20/%3e%3cpath%20d='M11.75%208.75a4%204%200%200%201%206.5%200'%20/%3e%3cpath%20d='M8.5%206.5a8%208%200%200%201%2013%200'%20/%3e%3c/svg%3e");--icon-search:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20/%3e%3cpath%20d='M21%2021l-6%20-6'%20/%3e%3c/svg%3e");--icon-server:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%207a3%203%200%200%201%203%20-3h12a3%203%200%200%201%203%203v2a3%203%200%200%201%20-3%203h-12a3%203%200%200%201%20-3%20-3v-2'%20/%3e%3cpath%20d='M3%2015a3%203%200%200%201%203%20-3h12a3%203%200%200%201%203%203v2a3%203%200%200%201%20-3%203h-12a3%203%200%200%201%20-3%20-3l0%20-2'%20/%3e%3cpath%20d='M7%208l0%20.01'%20/%3e%3cpath%20d='M7%2016l0%20.01'%20/%3e%3cpath%20d='M11%208h6'%20/%3e%3cpath%20d='M11%2016h6'%20/%3e%3c/svg%3e");--icon-settings:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M10.325%204.317c.426%20-1.756%202.924%20-1.756%203.35%200a1.724%201.724%200%200%200%202.573%201.066c1.543%20-.94%203.31%20.826%202.37%202.37a1.724%201.724%200%200%200%201.065%202.572c1.756%20.426%201.756%202.924%200%203.35a1.724%201.724%200%200%200%20-1.066%202.573c.94%201.543%20-.826%203.31%20-2.37%202.37a1.724%201.724%200%200%200%20-2.572%201.065c-.426%201.756%20-2.924%201.756%20-3.35%200a1.724%201.724%200%200%200%20-2.573%20-1.066c-1.543%20.94%20-3.31%20-.826%20-2.37%20-2.37a1.724%201.724%200%200%200%20-1.065%20-2.572c-1.756%20-.426%20-1.756%20-2.924%200%20-3.35a1.724%201.724%200%200%200%201.066%20-2.573c-.94%20-1.543%20.826%20-3.31%202.37%20-2.37c1%20.608%202.296%20.07%202.572%20-1.065'%20/%3e%3cpath%20d='M9%2012a3%203%200%201%200%206%200a3%203%200%200%200%20-6%200'%20/%3e%3c/svg%3e");--icon-shield:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M12%203a12%2012%200%200%200%208.5%203a12%2012%200%200%201%20-8.5%2015a12%2012%200%200%201%20-8.5%20-15a12%2012%200%200%200%208.5%20-3'%20/%3e%3c/svg%3e");--icon-spinning:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20opacity='.05'%20d='M512%2085.333c235.648%200%20426.667%20191.019%20426.667%20426.667S747.648%20938.667%20512%20938.667%2085.333%20747.648%2085.333%20512%20276.352%2085.333%20512%2085.333zm0%20128a298.667%20298.667%200%201%200%200%20597.334%20298.667%20298.667%200%200%200%200-597.334z'/%3e%3cpath%20d='M813.696%20813.696c166.613-166.613%20166.613-436.779%200-603.392s-436.779-166.613-603.392%200a64%2064%200%200%200%2090.496%2090.496%20298.667%20298.667%200%201%201%20422.4%20422.4%2064%2064%200%200%200%2090.496%2090.496z'/%3e%3c/svg%3e");--icon-tag:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M6.5%207.5a1%201%200%201%200%202%200a1%201%200%201%200%20-2%200'%20/%3e%3cpath%20d='M3%206v5.172a2%202%200%200%200%20.586%201.414l7.71%207.71a2.41%202.41%200%200%200%203.408%200l5.592%20-5.592a2.41%202.41%200%200%200%200%20-3.408l-7.71%20-7.71a2%202%200%200%200%20-1.414%20-.586h-5.172a3%203%200%200%200%20-3%203'%20/%3e%3c/svg%3e");--icon-world:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%201%200%2018%200a9%209%200%200%200%20-18%200'%20/%3e%3cpath%20d='M3.6%209h16.8'%20/%3e%3cpath%20d='M3.6%2015h16.8'%20/%3e%3cpath%20d='M11.5%203a17%2017%200%200%200%200%2018'%20/%3e%3cpath%20d='M12.5%203a17%2017%200%200%201%200%2018'%20/%3e%3c/svg%3e");--icon-x:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M18%206l-12%2012'%20/%3e%3cpath%20d='M6%206l12%2012'%20/%3e%3c/svg%3e")}html{background-color:var(--bg);min-height:100dvh;font-family:var(--font-sans);--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-darkmode=true]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html body{background-color:var(--bg);min-height:100dvh}.page-bg{pointer-events:none;background-image:var(--page-bg-lqip,var(--page-bg));background-position:50%;background-repeat:no-repeat;background-size:cover;position:fixed;inset:0;transform:translateZ(0)}.page-bg:after{pointer-events:none;background-image:var(--page-bg);opacity:0;--tw-content:"";content:var(--tw-content);background-position:50%;background-repeat:no-repeat;background-size:cover;transition:opacity .5s;position:absolute;inset:0}.page-bg.full-loaded:after{opacity:1}:not(html){scrollbar-width:thin;scrollbar-color:var(--text-muted) transparent}html{scrollbar-width:thin;scrollbar-color:var(--text-muted) var(--surface)}html body{min-height:100dvh;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);flex-direction:column;display:flex;position:relative}html body.modal-overlay-active{height:100vh;overflow:hidden}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text)}h1{margin-bottom:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 6);font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}@media not all and (min-width:48rem){h1{padding-left:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}}h2{margin-bottom:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}@media not all and (min-width:48rem){h2{margin-bottom:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 4);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}}h3{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}@media not all and (min-width:48rem){h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}@media not all and (min-width:48rem){h4{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}h5{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}@media not all and (min-width:48rem){h5{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}h6{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}@media not all and (min-width:48rem){h6{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}hr{margin-block:calc(var(--spacing) * 6);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline)}@media not all and (min-width:48rem){hr{margin-block:calc(var(--spacing) * 4)}}strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}abbr{cursor:help}p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text)}pre{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-wrap:break-word;white-space:pre-wrap;color:var(--text-muted);display:block}code{border-radius:calc(var(--radius-base) * .5);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-muted)}a{color:var(--link);text-decoration-line:none}@media (hover:hover){a:hover{text-decoration-line:underline}}var{font-family:var(--font-mono);color:var(--link)}small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text)}em{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);font-style:italic}header{z-index:40;margin-bottom:calc(var(--spacing) * 2);background-color:var(--bg);position:sticky;top:0}header .header-content{z-index:10;height:calc(var(--spacing) * 14);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex;position:relative}@media not all and (min-width:48rem){header .header-content{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2)}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container{pointer-events:none;visibility:hidden;z-index:0;height:calc(var(--mega-menu-height,0px) + 3.5rem + 3rem);inset-inline:0;width:100%;position:absolute;top:0;overflow:clip}@media not all and (min-width:48rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active,[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{visibility:visible}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active{pointer-events:auto}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.22s;--tw-ease:cubic-bezier(.4,0,.6,1);transition-duration:.22s;transition-timing-function:cubic-bezier(.4,0,.6,1)}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet{height:calc(var(--mega-menu-height,0px) + 3.5rem);--tw-translate-y:-100%;translate:var(--tw-translate-x) var(--tw-translate-y);background-color:var(--mega-menu-bg);transition-property:translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-ease:cubic-bezier(.4,0,.6,1);inset-inline:0;transition-timing-function:cubic-bezier(.4,0,.6,1);position:absolute;top:0;overflow:hidden}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet:after{content:var(--tw-content);pointer-events:none;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);border-bottom-style:var(--tw-border-style);content:var(--tw-content);border-bottom-width:1px;border-color:var(--hairline);content:var(--tw-content);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-content:"";content:var(--tw-content);position:absolute;inset:0}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-sheet:after{content:var(--tw-content);transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-canvas{--tw-translate-y:100%;translate:var(--tw-translate-x) var(--tw-translate-y);transition-property:translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:var(--mega-menu-duration,.3s);transition-duration:var(--mega-menu-duration,.3s);--tw-ease:cubic-bezier(.4,0,.6,1);transition-timing-function:cubic-bezier(.4,0,.6,1);position:absolute;inset:0}@media (prefers-reduced-motion:reduce){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-menu-canvas{transition-property:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active .desktop-menu-sheet,[data-nav-type=mega-menu] :is(header) .desktop-menu-container.active .desktop-menu-canvas{--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y)}[data-nav-type=mega-menu] :is(header) .desktop-menu-container.closing .desktop-menu-sheet:after{content:var(--tw-content);opacity:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container>.desktop-menu-board{display:none}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav{pointer-events:none;inset-inline:0;top:calc(var(--spacing) * 14);--tw-translate-y:calc(var(--spacing) * 1.5);max-width:72rem;max-height:calc(100dvh - 3.5rem);translate:var(--tw-translate-x) var(--tw-translate-y);column-gap:calc(var(--spacing) * 8);overscroll-behavior:contain;padding-inline:calc(var(--spacing) * 10);padding-top:calc(var(--spacing) * 13);padding-bottom:calc(var(--spacing) * 8);opacity:0;transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);grid-template-columns:12rem minmax(0,1fr) 13rem;margin-inline:auto;display:grid;position:absolute;overflow-y:auto}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav{max-width:44rem;padding-inline:calc(var(--spacing) * 8);grid-template-columns:repeat(1,minmax(0,1fr))}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav.active{pointer-events:auto;--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y);opacity:1}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor{align-self:flex-start}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor .desktop-nav-title{align-items:center;gap:calc(var(--spacing) * 2.5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);display:flex}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-anchor .desktop-nav-title:before{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;background-color:currentColor;flex-shrink:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list{grid-auto-flow:column;grid-template-rows:repeat(var(--menu-rows,6),auto);place-content:flex-start;column-gap:calc(var(--spacing) * 8);row-gap:var(--spacing);display:grid}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li{margin:0;list-style-type:none}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a{border-radius:calc(var(--radius-base) * 1.5);width:fit-content;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));white-space:nowrap;color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a:hover{background-color:var(--hover-faint)}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-nav-list>li>a.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board{gap:calc(var(--spacing) * 2);border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--hairline);padding-left:calc(var(--spacing) * 7);flex-direction:column;align-self:flex-start;display:flex}@media not all and (min-width:64rem){[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board{display:none}}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-label{margin-bottom:calc(var(--spacing) * .5);--tw-font-weight:var(--font-weight-medium);font-size:11px;font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--text-subtle);text-transform:uppercase}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line{align-items:flex-start;gap:calc(var(--spacing) * 2.5);max-width:100%;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);display:flex}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);--tw-content:"";content:var(--tw-content);background-color:currentColor;flex-shrink:0}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line .board-text{--tw-leading:calc(var(--spacing) * 4);min-width:0;line-height:calc(var(--spacing) * 4);overflow-wrap:anywhere}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-host:before{-webkit-mask:var(--icon-router) center/contain no-repeat;-webkit-mask:var(--icon-router) center/contain no-repeat;-webkit-mask:var(--icon-router) center/contain no-repeat;mask:var(--icon-router) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-model:before{-webkit-mask:var(--icon-cpu) center/contain no-repeat;-webkit-mask:var(--icon-cpu) center/contain no-repeat;-webkit-mask:var(--icon-cpu) center/contain no-repeat;mask:var(--icon-cpu) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-firmware:before{-webkit-mask:var(--icon-package) center/contain no-repeat;-webkit-mask:var(--icon-package) center/contain no-repeat;-webkit-mask:var(--icon-package) center/contain no-repeat;mask:var(--icon-package) center/contain no-repeat}[data-nav-type=mega-menu] :is(header) .desktop-menu-container .desktop-nav .desktop-menu-board .board-line-kernel:before{-webkit-mask:var(--icon-tag) center/contain no-repeat;-webkit-mask:var(--icon-tag) center/contain no-repeat;-webkit-mask:var(--icon-tag) center/contain no-repeat;mask:var(--icon-tag) center/contain no-repeat}[data-nav-type=mega-menu] :is(header):has(.desktop-menu-container:is(.active,.closing)){z-index:70}header .brand{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:color,transform;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex-shrink:0;text-decoration-line:none;transition-duration:.15s;display:inline-block}@media (hover:hover){header .brand:hover{--tw-translate-y:calc(var(--spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y);color:var(--brand)}}@media not all and (min-width:48rem){header .brand{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));flex:1}}@media (min-width:48rem){[data-nav-type=sidebar] :is(header .brand){display:none}[data-nav-type=sidebar].sidebar-collapsed :is(header .brand){transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:inline-block}@starting-style{[data-nav-type=sidebar].sidebar-collapsed :is(header .brand){opacity:0}}}header .nav{z-index:60;--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);align-items:center;gap:var(--spacing);margin:0;padding:0;list-style-type:none;display:flex;position:absolute;left:50%}@media not all and (min-width:48rem){header .nav{display:none}}header .nav>li{position:relative}header .nav>li .menu{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){header .nav>li .menu:hover{background-color:var(--hover-faint)}}header .nav>li .menu.menu-active{background-color:var(--brand-subtle);color:var(--brand)}header .nav>li .desktop-nav{pointer-events:none;z-index:40;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;padding-inline:0;padding-top:0;transition-duration:.15s;left:0}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav){margin-top:calc(var(--spacing) * 2);min-width:calc(var(--spacing) * 48);position:absolute;top:100%}header .nav>li .desktop-nav.active{pointer-events:auto;opacity:1}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list){row-gap:var(--spacing);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding-block:calc(var(--spacing) * 2);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);flex-direction:column;display:flex}header .nav>li .desktop-nav .desktop-nav-list>li{margin:0;list-style-type:none}header .nav>li .desktop-nav .desktop-nav-list>li>a{white-space:nowrap;color:var(--text);text-decoration-line:none;display:block}[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list>li>a){margin-inline:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){[data-nav-type=dropdown] :is(header .nav>li .desktop-nav .desktop-nav-list>li>a):hover{background-color:var(--hover-faint)}}header .nav>li .desktop-nav .desktop-nav-list>li>a.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}header .navigation-controls{margin-right:calc(var(--spacing) * 3);flex-shrink:0;align-items:center;display:flex}@media (min-width:48rem){header .navigation-controls{display:none}[data-nav-type=sidebar] :is(header .navigation-controls){display:flex}[data-nav-type=sidebar]:not(.sidebar-collapsed) :is(header .navigation-controls) .navigation-toggle-line-bottom{stroke-dasharray:15 15}}header .navigation-controls .navigation-toggle{cursor:pointer;border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;border-radius:0;padding:0;transition-duration:.15s}@media (hover:hover){header .navigation-controls .navigation-toggle:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}header .navigation-controls .navigation-toggle:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}header .navigation-controls .navigation-toggle svg{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);color:var(--text)}header .navigation-controls .navigation-toggle .navigation-toggle-line{transform-box:fill-box;transform-origin:50%;transition-property:transform,opacity,stroke-dasharray;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-in-out);transition-duration:.15s;transition-timing-function:var(--ease-in-out)}@media (min-width:48rem){[data-nav-type=sidebar] :is(header .navigation-controls .navigation-toggle .navigation-toggle-line){--tw-duration:.25s;transition-duration:.25s}}header .navigation-controls .navigation-toggle .navigation-toggle-line-bottom{stroke-dasharray:7.5 15}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-top{transform:translateY(5px)rotate(45deg)}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-middle{opacity:0;transform:scaleX(.35)}header .navigation-controls .navigation-toggle.is-expanded .navigation-toggle-line-bottom{stroke-dasharray:15 15;transform:translateY(-5px)rotate(-45deg)}header #indicators{gap:calc(var(--spacing) * 5);flex-direction:row-reverse;flex-shrink:0;display:flex}@media (min-width:48rem){header #indicators{gap:calc(var(--spacing) * 8)}}header #indicators span[data-indicator]{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;font-size:0;transition-duration:.15s}header #indicators span[data-indicator]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);content:var(--tw-content);color:var(--text);background-color:currentColor;position:absolute}@media (hover:hover){header #indicators span[data-indicator]:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}header #indicators span[data-indicator]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}header #indicators span[data-indicator][data-indicator=media_error]:before{content:var(--tw-content);-webkit-mask:var(--icon-error) center/cover no-repeat;-webkit-mask:var(--icon-error) center/cover no-repeat;-webkit-mask:var(--icon-error) center/cover no-repeat;mask:var(--icon-error) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask:var(--icon-refresh) center/cover no-repeat;-webkit-mask:var(--icon-refresh) center/cover no-repeat;-webkit-mask:var(--icon-refresh) center/cover no-repeat;mask:var(--icon-refresh) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;-webkit-mask:var(--icon-refresh-off) center/cover no-repeat;mask:var(--icon-refresh-off) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=uci-changes]{position:relative}header #indicators span[data-indicator][data-indicator=uci-changes]:before{content:var(--tw-content);-webkit-mask:var(--icon-settings) center/cover no-repeat;-webkit-mask:var(--icon-settings) center/cover no-repeat;-webkit-mask:var(--icon-settings) center/cover no-repeat;mask:var(--icon-settings) center/cover no-repeat}header #indicators span[data-indicator][data-indicator=uci-changes][data-count]:not([data-count="0"]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -.5);content:var(--tw-content);z-index:10;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 3);content:var(--tw-content);min-width:calc(var(--spacing) * 3);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--danger);content:var(--tw-content);padding-inline:calc(var(--spacing) * .5);content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);--tw-font-weight:var(--font-weight-bold);font-size:8px;line-height:1;font-weight:var(--font-weight-bold);content:var(--tw-content);color:var(--on-brand);content:var(--tw-content);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-content:attr(data-count);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:flex;position:absolute}body[data-nav-type=sidebar]{--sidebar-w-full:17rem;--sidebar-w:var(--sidebar-w-full)}@media (min-width:48rem){body[data-nav-type=sidebar]{grid-template-columns:var(--sidebar-w) minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);display:grid;overflow-x:clip}body[data-nav-type=sidebar].sidebar-collapsed{--sidebar-w:0rem}body[data-nav-type=sidebar]>header{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);grid-row-start:1;grid-column-start:2;margin-bottom:0}body[data-nav-type=sidebar]>.sidebar-panel{grid-row:1/span 2;grid-column-start:1}body[data-nav-type=sidebar]>#maincontent{min-width:0;padding-top:calc(var(--spacing) * 2);width:100%;max-width:none;padding-inline:calc(var(--spacing) * 8);grid-row-start:2;grid-column-start:2}}body[data-nav-type=sidebar] .header-crumb{align-items:center;gap:calc(var(--spacing) * 2);min-width:0;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-muted);margin-block:0;margin-left:0;margin-right:auto;padding:0;list-style-type:none;display:none;overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar] .header-crumb{display:flex}}body[data-nav-type=sidebar] .header-crumb li{white-space:nowrap;margin:0;list-style-type:none}body[data-nav-type=sidebar] .header-crumb .crumb-sep{opacity:.5}body[data-nav-type=sidebar] .header-crumb .current{text-overflow:ellipsis;white-space:nowrap;--tw-font-weight:var(--font-weight-medium);min-width:0;font-weight:var(--font-weight-medium);color:var(--text);overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar].sidebar-collapsed .header-crumb{margin-left:calc(var(--spacing) * 6)}}body[data-nav-type=sidebar] .sidebar-panel{border-radius:0;width:100%;height:100dvh;display:none;position:sticky;top:0;overflow:hidden}@media (min-width:48rem){body[data-nav-type=sidebar] .sidebar-panel{display:block}}body[data-nav-type=sidebar].sidebar-collapsed .sidebar-panel{visibility:hidden}body[data-nav-type=sidebar] .sidebar-panel-inner{height:100%;width:var(--sidebar-w-full);border-right-style:var(--tw-border-style);border-right-width:1px;border-color:var(--hairline);background-color:var(--bg);flex-direction:column;display:flex;overflow:hidden}body[data-nav-type=sidebar].sidebar-collapsed .sidebar-panel-inner{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}@media (min-width:48rem){body[data-nav-type=sidebar].sidebar-anim-open>header,body[data-nav-type=sidebar].sidebar-anim-open>#maincontent,body[data-nav-type=sidebar].sidebar-anim-open .sidebar-panel-inner{animation:sidebar-run-in .25s var(--ease-in-out) both}body[data-nav-type=sidebar].sidebar-anim-close>header,body[data-nav-type=sidebar].sidebar-anim-close>#maincontent{animation:sidebar-run-back .25s var(--ease-in-out) both}body[data-nav-type=sidebar].sidebar-anim-close .sidebar-panel{visibility:visible;width:var(--sidebar-w-full);position:fixed;top:0;left:0}body[data-nav-type=sidebar].sidebar-anim-close .sidebar-panel-inner{animation:sidebar-run-out .25s var(--ease-in-out) both}}body[data-nav-type=sidebar] .sidebar-head{box-sizing:content-box;height:calc(var(--spacing) * 14);align-items:center;gap:calc(var(--spacing) * 2.5);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 4);flex-shrink:0;display:flex}body[data-nav-type=sidebar] .sidebar-head .sidebar-logo{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * .75);flex-shrink:0}body[data-nav-type=sidebar] .sidebar-head .sidebar-brand{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex:1;text-decoration-line:none;transition-duration:.15s;overflow:hidden}@media (hover:hover){body[data-nav-type=sidebar] .sidebar-head .sidebar-brand:hover{color:var(--brand)}}body[data-nav-type=sidebar] .sidebar-list{flex:1;margin:0;list-style-type:none}:where(body[data-nav-type=sidebar] .sidebar-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}body[data-nav-type=sidebar] .sidebar-list{padding:calc(var(--spacing) * 3);overflow-y:auto}body[data-nav-type=sidebar] .sidebar-list li{margin:0;list-style-type:none}body[data-nav-type=sidebar] .sidebar-list .nav-row{gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}body[data-nav-type=sidebar] .sidebar-list .nav-icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}body[data-nav-type=sidebar] .sidebar-submenu{min-height:0;margin:0;list-style-type:none}:where(body[data-nav-type=sidebar] .sidebar-submenu>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}body[data-nav-type=sidebar] .sidebar-submenu{padding:0;padding-left:calc(var(--spacing) * 6.5);overflow:hidden}body[data-nav-type=sidebar] .sidebar-submenu .navigation-sublink{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}body[data-nav-type=sidebar] .sidebar-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 3);flex-shrink:0}body[data-nav-type=sidebar] .sidebar-footer .nav-link{color:var(--text-muted)}@media (hover:hover){body[data-nav-type=sidebar] .sidebar-footer .nav-link:hover{color:var(--text)}}@keyframes sidebar-run-in{0%{translate:calc(-1 * var(--sidebar-w-full)) 0}}@keyframes sidebar-run-back{0%{translate:var(--sidebar-w-full) 0}}@keyframes sidebar-run-out{to{translate:calc(-1 * var(--sidebar-w-full)) 0}}#luci-nav-progress{pointer-events:none;z-index:80;height:calc(var(--spacing) * .5);--tw-gradient-position:to right;width:0;position:fixed;top:0;left:0}@supports (background-image:linear-gradient(in lab, red, red)){#luci-nav-progress{--tw-gradient-position:to right in oklab}}#luci-nav-progress{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-start);--tw-gradient-to:var(--progress-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;--tw-ease:var(--ease-out);transition-duration:.3s;transition-timing-function:var(--ease-out)}#luci-nav-progress[data-state=done]{opacity:0;transition:width .3s ease-out,opacity .15s ease-in .15s}#luci-nav-status{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}#maincontent{width:95.8333%;min-height:calc(100vh - 4rem);max-width:var(--content-width-centered);padding-inline:calc(var(--spacing) * 4);--tw-outline-style:none;outline-style:none;margin-inline:auto}@media not all and (min-width:48rem){#maincontent{width:100%;padding-inline:calc(var(--spacing) * 3)}}#maincontent .view-staging{visibility:hidden;height:0;overflow:hidden}#maincontent #view{--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;margin-inline:0;padding:0}#maincontent #view:empty{display:none}@media (min-width:48rem){#maincontent #view{padding:0}}#maincontent #view.view-leaving{cursor:progress;opacity:.6;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}#maincontent #view .cbi-title-section{margin-bottom:calc(var(--spacing) * 6);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}@media not all and (min-width:48rem){#maincontent #view .cbi-title-section{margin-inline:calc(var(--spacing) * 2);margin-bottom:calc(var(--spacing) * 3)}}#maincontent #view .controls{margin:calc(var(--spacing) * 2);align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent #view .controls{margin:var(--spacing);gap:calc(var(--spacing) * 2)}}#maincontent #view .controls label input[type=radio],#maincontent #view .controls label input[type=checkbox]{margin-right:var(--spacing);vertical-align:middle}#maincontent #view div[style]>svg:where([data-darkmode=true],[data-darkmode=true] *){background-color:var(--surface)!important}#maincontent #view div[style]>svg line[style]:where([data-darkmode=true],[data-darkmode=true] *){stroke:var(--text)!important}#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-bottom:calc(var(--spacing) * 6);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text-muted)}@media not all and (min-width:48rem){#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-inline:calc(var(--spacing) * 2);margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}#maincontent .cbi-page-actions{margin-top:calc(var(--spacing) * 6);justify-content:flex-end;align-items:center;gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-top:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent .cbi-page-actions{margin-inline:calc(var(--spacing) * 2);margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 2);padding-top:calc(var(--spacing) * 3)}}#maincontent .zone-forwards{align-items:stretch;gap:calc(var(--spacing) * 2);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);flex-wrap:nowrap;display:flex}#maincontent .zone-forwards>span{flex-shrink:0;flex-basis:calc(var(--spacing) * 8);color:var(--text-muted);justify-content:center;align-self:center;align-items:center;display:flex}#maincontent .zone-forwards .zone-src,#maincontent .zone-forwards .zone-dest{gap:calc(var(--spacing) * 1.5);flex-direction:column;flex:1;display:flex}footer{margin-top:calc(var(--spacing) * 2);min-height:calc(var(--spacing) * 16);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);flex-wrap:wrap;justify-content:space-between;align-items:center;display:flex}footer a{color:var(--brand)}footer span{text-align:center;display:inline-block}footer .breadcrumb{align-items:center;gap:var(--spacing);background-color:var(--surface-overlay);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;transition-duration:.15s;display:flex}@media (hover:hover){footer .breadcrumb:hover{background-color:var(--surface)}}footer .breadcrumb li{list-style-type:none}footer .breadcrumb li.active a{color:var(--text)}.control-group{margin-top:var(--spacing)}.control-group,.cbi-page-actions>div,.cbi-section-actions>div{align-items:center;gap:calc(var(--spacing) * 2);flex-flow:row;display:flex}@media not all and (min-width:48rem){.control-group,.cbi-page-actions>div,.cbi-section-actions>div{gap:var(--spacing);flex-wrap:wrap}}.nav-row{cursor:pointer;appearance:none;border-style:var(--tw-border-style);text-align:left;--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-user-select:none;user-select:none;background-color:#0000;border-width:0;align-items:center;text-decoration-line:none;transition-duration:.15s;display:flex}@media (hover:hover){.nav-row:hover{text-decoration-line:none}}.nav-row:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.nav-link{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:block}@media (hover:hover){.nav-link:hover{background-color:var(--hover-faint);text-decoration-line:none}}.navigation-direct{color:var(--text)}@media (hover:hover){.navigation-direct:hover{color:var(--text)}}.navigation-direct.is-active-page{background-color:var(--brand-subtle);color:var(--brand)}@media (hover:hover){.navigation-direct.is-active-page:hover{color:var(--brand)}}:where(.sidebar-list) .nav-row{color:var(--text-muted)}@media (hover:hover){:where(.sidebar-list) .nav-row:hover{color:var(--text)}:where(.sidebar-list) .navigation-direct:hover{background-color:var(--hover-faint)}}.navigation-group-toggle:after{content:var(--tw-content);width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);opacity:.55;content:var(--tw-content);transition-property:transform,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.25s;--tw-content:"";content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;background-color:currentColor;flex-shrink:0;transition-duration:.25s}@media (hover:hover){.navigation-group-toggle:hover:after{content:var(--tw-content);opacity:1}}.navigation-group.is-expanded>.navigation-group-toggle{color:var(--brand)}.navigation-group.is-expanded>.navigation-group-toggle:after{content:var(--tw-content);rotate:90deg}.navigation-group.is-active-group>.navigation-group-toggle{color:var(--brand)}.nav-icon{opacity:.55;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;-webkit-mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;mask:var(--menu-icon,var(--icon-category)) center/contain no-repeat;background-color:currentColor;flex-shrink:0;transition-duration:.15s}.nav-label,.nav-category-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.navigation-direct:hover .nav-icon,.navigation-group-toggle:hover .nav-icon,.navigation-direct.is-active-page .nav-icon,.navigation-group.is-expanded>.navigation-group-toggle .nav-icon,.navigation-group.is-active-group>.navigation-group-toggle .nav-icon{opacity:1}.navigation-group-region{opacity:0;transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);grid-template-rows:0fr;display:grid}.navigation-group.is-expanded>.navigation-group-region{opacity:1;grid-template-rows:1fr}.navigation-submenu-list{min-height:0;list-style-type:none;overflow:hidden}.navigation-sublink{border-radius:calc(var(--radius-base) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s;display:flex;position:relative}@media (hover:hover){.navigation-sublink:hover{background-color:var(--hover-faint);color:var(--text)}}.navigation-sublink.is-active-page{background-color:var(--brand-subtle);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand)}@media (hover:hover){.navigation-sublink.is-active-page:hover{color:var(--brand)}}.nav-category-preview{text-overflow:ellipsis;white-space:nowrap;padding-bottom:var(--spacing);color:var(--text-subtle);overflow:hidden}.nav-category-preview .nav-preview-current{color:var(--brand)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=status]{--menu-icon:var(--icon-activity)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=statistics]{--menu-icon:var(--icon-chart-bar)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=nlbw]{--menu-icon:var(--icon-gauge)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=system]{--menu-icon:var(--icon-settings)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=services]{--menu-icon:var(--icon-apps)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=nas]{--menu-icon:var(--icon-server)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=control]{--menu-icon:var(--icon-adjustments)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=network]{--menu-icon:var(--icon-world)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=vpn]{--menu-icon:var(--icon-shield)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=docker]{--menu-icon:var(--icon-box)}:is(.desktop-nav-title,.navigation-direct,.navigation-group-toggle)[data-section=asterisk]{--menu-icon:var(--icon-phone)}.theme-switcher{background-color:var(--surface-sunken);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;align-items:center;gap:0;transition-duration:.15s;display:inline-flex;position:relative}@media not all and (min-width:48rem){.theme-switcher{padding-block:calc(var(--spacing) * .5)}}.theme-switcher{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}.theme-switcher:before{content:var(--tw-content);content:var(--tw-content);top:var(--spacing);content:var(--tw-content);left:var(--spacing);content:var(--tw-content);z-index:0;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--surface-overlay);content:var(--tw-content);--tw-shadow:var(--app-shadow-md);width:calc(33.333% - .5rem);height:calc(100% - .5rem);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.25s;border-radius:3.40282e38px;transition-duration:.25s;position:absolute}@media not all and (min-width:48rem){footer .theme-switcher{display:none}}.theme-switcher .theme-option{z-index:10;cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-radius:3.40282e38px;transition-duration:.15s;display:flex;position:relative}@media (hover:hover){.theme-switcher .theme-option:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.theme-switcher .theme-option:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.theme-switcher .theme-option input[type=radio]{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.theme-switcher .theme-option .theme-icon{color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;justify-content:center;align-items:center;transition-duration:.15s;display:flex}.theme-switcher .theme-option .theme-icon svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}.theme-switcher .theme-option .theme-label{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:none}.theme-switcher .theme-option.active .theme-icon{color:var(--text)}.theme-switcher .theme-option.active .theme-icon svg{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.theme-switcher .theme-option.active .theme-label,.theme-switcher .theme-option:hover:not(.active) .theme-icon,.theme-switcher .theme-option:hover:not(.active) .theme-label{color:var(--text)}.theme-switcher:has(.theme-option[data-theme=device].active):before{content:var(--tw-content);--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.theme-switcher:has(.theme-option[data-theme=light].active):before{content:var(--tw-content);--tw-translate-x:calc(100% + .5rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.theme-switcher:has(.theme-option[data-theme=dark].active):before{content:var(--tw-content);--tw-translate-x:calc(200% + 1rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.floating-toolbar{pointer-events:none;right:calc(var(--spacing) * 4);bottom:calc(var(--spacing) * 4);z-index:40;flex-direction:column;align-items:center;display:flex;position:fixed}@media not all and (min-width:48rem){.floating-toolbar{right:calc(var(--spacing) * 3);bottom:calc(var(--spacing) * 3)}}.floating-toolbar .toolbar-list{margin-bottom:calc(var(--spacing) * 2.5);align-items:center;gap:calc(var(--spacing) * 2.5);flex-direction:column;display:flex}@media not all and (min-width:48rem){.floating-toolbar .toolbar-list{margin-bottom:calc(var(--spacing) * 2);gap:calc(var(--spacing) * 2)}}.floating-toolbar .toolbar-btn{pointer-events:auto;width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11);cursor:pointer;background-color:var(--surface-overlay);color:var(--text-muted);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-radius:3.40282e38px;place-items:center;display:grid}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}}.floating-toolbar .toolbar-btn{transition:translate .32s cubic-bezier(.34,1.25,.5,1),scale .32s cubic-bezier(.34,1.25,.5,1),opacity .22s,visibility .32s,background-color .15s,color .15s;transition-delay:var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),0s,0s}.floating-toolbar .toolbar-btn:hover{background-color:var(--hover-faint);color:var(--text)}.floating-toolbar .toolbar-btn:active{scale:.92}.floating-toolbar .toolbar-btn:not(.toggle){--fab-d:calc((var(--fab-n,1) - 1 - var(--fab-i,0)) * 60ms);text-decoration-line:none}.floating-toolbar .toolbar-btn:not(.toggle):active{--fab-d:0s}.floating-toolbar .toolbar-btn:not(.toggle) .icon{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);-webkit-mask:var(--fab-icon) center/contain no-repeat;-webkit-mask:var(--fab-icon) center/contain no-repeat;-webkit-mask:var(--fab-icon) center/contain no-repeat;mask:var(--fab-icon) center/contain no-repeat;background-color:currentColor;flex-shrink:0}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn:not(.toggle) .icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}}.floating-toolbar .toolbar-btn.toggle{border-style:var(--tw-border-style);color:var(--text-subtle);border-width:0}@media (hover:hover){.floating-toolbar .toolbar-btn.toggle:hover{color:var(--text)}}.floating-toolbar .toolbar-btn.toggle .icon{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);transition-property:rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out);place-items:center;display:grid}@media not all and (min-width:48rem){.floating-toolbar .toolbar-btn.toggle .icon{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}}.floating-toolbar .toolbar-btn.toggle .icon svg{width:100%;height:100%}.floating-toolbar.collapsed .toolbar-btn:not(.toggle){pointer-events:none;visibility:hidden;opacity:0;--tw-translate-y:calc((var(--fab-n,1) - var(--fab-i,0)) * 3.375rem);scale:.35;translate:var(--tw-translate-x) var(--tw-translate-y);--fab-d:calc(var(--fab-i,0) * 60ms)}@media not all and (min-width:48rem){.floating-toolbar.collapsed .toolbar-btn:not(.toggle){--tw-translate-y:calc((var(--fab-n,1) - var(--fab-i,0)) * 3rem);translate:var(--tw-translate-x) var(--tw-translate-y)}}.floating-toolbar.collapsed .toolbar-btn.toggle .icon{rotate:45deg}button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transition-property:background-color,border-color,transform;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-width:1px;transition-duration:.15s;display:inline-flex}@media not all and (min-width:48rem){button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}}:is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button)[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){white-space:nowrap;flex:none;width:auto;display:inline-flex}@media not all and (min-width:48rem){.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){min-height:calc(var(--spacing) * 9);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down{border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text)}@media (hover:hover){:is(.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down):hover{background-color:var(--hover-faint)}}.drag-handle{border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text-muted)}@media (hover:hover){.drag-handle:hover{background-color:var(--hover-faint)}}.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit{border-color:var(--brand);background-color:var(--brand);color:var(--on-brand)}@media (hover:hover){:is(.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit):hover{background-color:var(--brand-hover)}}.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save{background-color:var(--brand-subtle);color:var(--brand);border-color:#0000}@media (hover:hover){:is(.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save):hover{background-color:var(--brand-subtle-hover)}}.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove{background-color:var(--danger-surface);color:var(--danger);border-color:#0000}@media (hover:hover){:is(.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove):hover{background-color:var(--danger-surface-hover)}}input:disabled{cursor:not-allowed;opacity:var(--app-opacity-disabled)}input[type=text],input[type=password],.cbi-input-text,.cbi-input{width:calc(var(--spacing) * 52.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);max-width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);position:relative}:is(input[type=text],input[type=password],.cbi-input-text,.cbi-input)::placeholder{color:var(--text-muted)}input[type=text],input[type=password],.cbi-input-text,.cbi-input{--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}:is(input[type=text],input[type=password],.cbi-input-text,.cbi-input):focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.table.cbi-section-table :is(input[type=text],input[type=password],.cbi-input-text,.cbi-input){width:100%}.cbi-input-text{min-width:calc(var(--spacing) * 20)}@media not all and (min-width:48rem){.cbi-input-text{min-width:calc(var(--spacing) * 14)}}#localtime{min-width:calc(var(--spacing) * 70)}input[type=radio],input[type=checkbox]{margin-right:calc(var(--spacing) * 3);height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);cursor:pointer;appearance:none;vertical-align:middle;display:inline-block;position:relative}:is(input[type=radio],input[type=checkbox]):before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);height:calc(var(--spacing) * 4);content:var(--tw-content);width:calc(var(--spacing) * 4);content:var(--tw-content);border-style:var(--tw-border-style);content:var(--tw-content);border-width:1px;border-color:var(--hairline);content:var(--tw-content);background-color:var(--control-bg);content:var(--tw-content);transition-property:background-color,border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;transition-duration:.15s;position:absolute;top:0;left:0}:is(input[type=radio],input[type=checkbox]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * .5);content:var(--tw-content);left:calc(var(--spacing) * .5);content:var(--tw-content);height:calc(var(--spacing) * 3);content:var(--tw-content);width:calc(var(--spacing) * 3);content:var(--tw-content);background-color:var(--on-brand);content:var(--tw-content);opacity:0;content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;transition-duration:.15s;position:absolute}:is(input[type=radio],input[type=checkbox]):checked:before{content:var(--tw-content);border-color:var(--brand);content:var(--tw-content);background-color:var(--brand)}:is(input[type=radio],input[type=checkbox]):checked:after{content:var(--tw-content);opacity:1}@media (hover:hover){:is(input[type=radio],input[type=checkbox]):hover:before{content:var(--tw-content);border-color:var(--hairline)}}:is(input[type=radio],input[type=checkbox]):focus:before{content:var(--tw-content);border-color:var(--brand);content:var(--tw-content);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);--tw-ring-color:var(--focus-ring);content:var(--tw-content);--tw-outline-style:none;outline-style:none}:is(input[type=radio],input[type=checkbox]):disabled{cursor:not-allowed}input[type=radio]:before{content:var(--tw-content);border-radius:3.40282e38px}input[type=radio]:after{content:var(--tw-content);-webkit-mask:var(--icon-radio) center/cover no-repeat;-webkit-mask:var(--icon-radio) center/cover no-repeat;-webkit-mask:var(--icon-radio) center/cover no-repeat;mask:var(--icon-radio) center/cover no-repeat}input[type=checkbox]:before{content:var(--tw-content);border-radius:calc(var(--radius-base) * .5)}input[type=checkbox]:after{content:var(--tw-content);-webkit-mask:var(--icon-check) center/cover no-repeat;-webkit-mask:var(--icon-check) center/cover no-repeat;-webkit-mask:var(--icon-check) center/cover no-repeat;mask:var(--icon-check) center/cover no-repeat}.cbi-checkbox{vertical-align:middle;align-items:center;display:inline-flex;position:relative}textarea{min-height:calc(var(--spacing) * 24);resize:vertical;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text)}textarea::placeholder{color:var(--text-muted)}textarea{--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}textarea:focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}textarea[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}select{max-width:100%;min-width:calc(var(--spacing) * 52.5);appearance:none;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--control-bg);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 10);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}select:focus{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}@media (min-width:48rem){select{max-width:calc(var(--spacing) * 100)}}select{background-image:var(--icon-arrow-down);background-position:right .75rem center;background-repeat:no-repeat;background-size:16px}select:where([data-darkmode=true],[data-darkmode=true] *){background-image:var(--icon-arrow-down-dark)}select[disabled]{cursor:not-allowed;opacity:var(--app-opacity-disabled)}.cbi-dropdown{white-space:nowrap;--tw-shadow:var(--app-shadow-sm);min-width:fit-content;max-width:100%;height:fit-content;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;align-items:center;padding:0;display:inline-flex}.cbi-dropdown[disabled]{pointer-events:none;opacity:var(--app-opacity-disabled)}.cbi-dropdown:not(.btn):not(.cbi-button){max-width:100%;min-width:calc(var(--spacing) * 52.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface)}@media (min-width:48rem){.cbi-dropdown:not(.btn):not(.cbi-button){max-width:calc(var(--spacing) * 100)}}.cbi-dropdown:not(.btn):not(.cbi-button)>ul>li[placeholder]{display:none}.cbi-dropdown>ul{align-items:center;gap:calc(var(--spacing) * .5);flex-wrap:nowrap;flex:1;margin:0;list-style-type:none;display:flex;overflow:hidden}@media not all and (min-width:48rem){.cbi-dropdown>ul{flex-wrap:wrap}}.cbi-dropdown>ul>li{align-items:center;gap:var(--spacing);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);margin:0;list-style-type:none;display:none;overflow:hidden}.cbi-dropdown>ul>li[display]{display:flex!important}.cbi-dropdown>ul>li .hide-open{display:block}.cbi-dropdown>ul>li .hide-close{display:none}.cbi-dropdown>ul>li>form{pointer-events:none;display:none}.cbi-dropdown>ul>li>label{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.cbi-dropdown>ul>li img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);vertical-align:middle;flex:none}.cbi-dropdown>ul>li span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.cbi-dropdown>ul.dropdown{z-index:50;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);--tw-shadow:var(--app-shadow-lg);width:fit-content;min-width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);position:absolute;left:0;overflow-y:auto}.cbi-dropdown>ul.dropdown>li{min-height:calc(var(--spacing) * 9);cursor:pointer;width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted)}@media (hover:hover){.cbi-dropdown>ul.dropdown>li:hover{background-color:var(--brand-subtle)}}.cbi-dropdown>ul.preview{display:none}.cbi-dropdown[empty]>ul{max-width:1px;max-height:1px}.cbi-dropdown[empty]>ul>li,.cbi-dropdown[optional][open]>ul.dropdown>li[placeholder]{display:block}.cbi-dropdown[open]{border-color:var(--brand);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);position:relative}.cbi-dropdown[open]>ul.dropdown{width:auto;max-width:none;display:block}.cbi-dropdown[open]>ul.dropdown>li{display:flex}.cbi-dropdown[open]>ul.dropdown>li[selected]{background-color:var(--brand-subtle);color:var(--brand)}.cbi-dropdown[open]>ul.dropdown>li[unselectable]{opacity:var(--app-opacity-disabled)}.cbi-dropdown[open]>ul.dropdown>li .hide-open{display:none}.cbi-dropdown[open]>ul.dropdown>li .hide-close{display:block}.cbi-dropdown[open]>ul.preview{display:flex}:is(.cbi-dropdown[multiple][more],.cbi-dropdown[multiple][empty])>.more{padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);flex:none;display:flex}.cbi-dropdown[multiple][empty]>.more{flex:1}.cbi-dropdown[multiple][open]>ul.dropdown>li>form{align-items:center;display:flex}.cbi-dropdown[multiple]>ul>li>label{display:flex}.cbi-dropdown>.open{cursor:pointer;border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:currentColor;flex:none;justify-content:center;align-items:center;display:flex}.cbi-dropdown>.more{display:none}.cbi-tooltip{z-index:110;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--text);opacity:0;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:absolute;inset-inline-start:-10000px}.cbi-tooltip.error{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}.cbi-tooltip.success{border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}.cbi-tooltip.info{border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}.cbi-tooltip.notice{border-color:var(--hairline);background-color:var(--warning-surface);color:var(--warning)}.cbi-tooltip-container,[data-tooltip]{cursor:help;white-space:nowrap;text-underline-offset:2px;text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;display:inline-block;position:relative}:is(.cbi-tooltip-container,[data-tooltip]) .cbi-tooltip{visibility:hidden;--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:0;transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out)}:is(.cbi-tooltip-container,[data-tooltip]):hover .cbi-tooltip{visibility:visible;--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;inset-inline-start:auto}[data-tip]:not([data-tip=""]){position:relative}[data-tip]:not([data-tip=""]):after{content:attr(data-tip);pointer-events:none;z-index:110;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:var(--radius-base);background-color:var(--text);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--bg);opacity:0;transition-property:opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:absolute}[data-tip]:not([data-tip=""]):not([data-tip-pos]):after,[data-tip]:not([data-tip=""])[data-tip-pos=top]:after{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);bottom:calc(100% + .5rem);left:50%}[data-tip]:not([data-tip=""])[data-tip-pos=bottom]:after{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:calc(100% + .5rem);left:50%}[data-tip]:not([data-tip=""])[data-tip-pos=left]:after{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:50%;right:calc(100% + .625rem)}[data-tip]:not([data-tip=""])[data-tip-pos=right]:after{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);top:50%;left:calc(100% + .625rem)}[data-tip]:not([data-tip=""]):focus-visible:after{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;transition-delay:.3s}@media (hover:hover){[data-tip]:not([data-tip=""]):hover:after{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;transition-delay:.3s}}.alert-message{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text)}@media not all and (min-width:48rem){.alert-message{margin-inline:0;margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 4)}}.modal .alert-message{margin-bottom:0}.login-shell .alert-message{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2.5);text-align:center;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));margin-bottom:0}@media not all and (min-width:48rem){.login-shell .alert-message{padding-inline:calc(var(--spacing) * .5)}}.alert-message.success{border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}.alert-message.info{border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}.alert-message.warning,.alert-message.notice{border-color:var(--hairline);background-color:var(--warning-surface);color:var(--warning)}.alert-message.error,.alert-message.danger{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}.alert-message h4,.alert-message h5,.alert-message pre,.alert-message ul,.alert-message li,.alert-message p{border-style:var(--tw-border-style);color:inherit;background-color:#0000;border-width:0}.alert-message h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}@media not all and (min-width:48rem){.alert-message h4{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}@media not all and (min-width:48rem){.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.alert-message .right{margin-top:calc(var(--spacing) * 4)}@media not all and (min-width:48rem){.alert-message .right{margin-top:calc(var(--spacing) * 3)}}.cbi-progressbar{height:calc(var(--spacing) * 3.5);cursor:help;background-color:var(--surface-sunken);border-radius:3.40282e38px;width:100%;position:relative;overflow:hidden}.cbi-progressbar:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);border-radius:calc(var(--radius-base) * 2);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);white-space:nowrap;content:var(--tw-content);color:var(--text);--tw-content:attr(title);content:var(--tw-content);position:absolute;top:50%;left:50%}@media not all and (min-width:48rem){.cbi-progressbar{height:calc(var(--spacing) * 4)}.cbi-progressbar:before{content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}}@media not all and (min-width:40rem){[data-page=admin-system-package-manager] .cbi-progressbar:before{content:var(--tw-content);font-size:10px}}.cbi-progressbar>div{--tw-gradient-position:to right;height:100%}@supports (background-image:linear-gradient(in lab, red, red)){.cbi-progressbar>div{--tw-gradient-position:to right in oklab}}.cbi-progressbar>div{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-start);--tw-gradient-to:var(--progress-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.label{background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);color:var(--text);text-transform:uppercase;border-radius:3.40282e38px}.label.important{background-color:var(--info-surface);color:var(--info)}.label.warning{background-color:var(--danger-surface);color:var(--danger)}.label.success{background-color:var(--success-surface);color:var(--success)}.label.notice{background-color:var(--warning-surface);color:var(--warning)}.zonebadge{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text);display:inline-flex;overflow:visible}@media not all and (min-width:48rem){.zonebadge{gap:var(--spacing);padding-inline:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.zonebadge[style*=--zone-color-rgb]{border-color:#0000;background-color:rgb(var(--zone-color-rgb),.7)!important}.zonebadge[style*=--zone-color-rgb] em{color:var(--text)}.zonebadge.zonebadge-empty{--tw-border-style:dashed;--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text-muted);background-color:#0000;border-style:dashed;font-style:italic}.ifacebadge>.zonebadge{padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);border-radius:3.40282e38px}.cbi-dropdown .zonebadge{padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.ifacebadge{cursor:default;align-items:center;gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--text);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:box-shadow,border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;flex-wrap:nowrap;transition-duration:.15s;display:inline-flex}@media (hover:hover){.ifacebadge:hover{border-color:var(--hairline);background-color:var(--surface-sunken);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media not all and (min-width:48rem){.ifacebadge{gap:calc(var(--spacing) * 1.5);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.zonebadge>.ifacebadge{border-radius:calc(var(--radius-base) * 2);padding-inline:calc(var(--spacing) * 1.5);padding-block:0}.zonebadge>.ifacebadge img{margin-right:var(--spacing);width:calc(var(--spacing) * 4)}.cbi-dropdown .ifacebadge{gap:var(--spacing);border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){.cbi-dropdown .ifacebadge:hover{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.cbi-dropdown .ifacebadge img{margin-right:var(--spacing);width:calc(var(--spacing) * 4)}.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}@media not all and (min-width:48rem){.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 4)}}.ifacebadge>span>.nowrap{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}@media not all and (min-width:48rem){.ifacebadge>span>.nowrap{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}}.ifacebadge.ifacebadge-active{border-color:var(--brand);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.ifacebadge.large{min-width:200px;padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex:1}@media not all and (min-width:48rem){.ifacebadge.large{min-width:180px;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5)}}.cbi-section{margin-bottom:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 2);padding:calc(var(--spacing) * 5);overflow:visible}@media not all and (min-width:48rem){.cbi-section{padding:calc(var(--spacing) * 3)}}.cbi-section[data-tab-title]{margin:0;padding:0}.cbi-section[data-tab-active=true]{margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 5)}@media not all and (min-width:48rem){.cbi-section[data-tab-active=true]{padding:calc(var(--spacing) * 3)}}#maincontent .cbi-section{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-section>.cbi-title{justify-content:space-between;align-items:flex-start;display:flex}.cbi-section>.cbi-title>h3{flex:1}.cbi-section>.cbi-title>h3 .label[data-clickable]{background-color:var(--surface-sunken);color:var(--text);width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7);cursor:pointer;justify-content:center;align-items:center;padding:0;display:inline-flex}.cbi-section>.cbi-title>h3 .label[data-clickable]:before{content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;background-color:currentColor;transition-duration:.15s}@media (hover:hover){.cbi-section>.cbi-title>h3 .label[data-clickable]:hover{--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.cbi-section>.cbi-title>h3 .label[data-clickable]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}@media not all and (min-width:48rem){.cbi-section>.cbi-title>h3 .label[data-clickable]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;font-size:0;position:relative}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.15s;content:var(--tw-content);--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);background-color:currentColor;position:absolute}@media (hover:hover){.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:hover:before{content:var(--tw-content);--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:active:before{content:var(--tw-content);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;rotate:0deg}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;-webkit-mask:var(--icon-arrow-right) center/cover no-repeat;mask:var(--icon-arrow-right) center/cover no-repeat;rotate:90deg}.cbi-section legend{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.cbi-section h3{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-bottom:calc(var(--spacing) * 4);color:var(--text)}@media not all and (min-width:48rem){.cbi-section h3{padding-bottom:calc(var(--spacing) * 2);margin-inline:0}.cbi-section div[style*=display\:grid]{gap:calc(var(--spacing) * 3);grid-template-columns:repeat(2,minmax(0,1fr))!important}}.cbi-section div[style*=display\:grid]:has(>.ifacebox){place-items:center}.cbi-section .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:nowrap;display:flex}@media not all and (min-width:48rem){.cbi-section .network-status-table{flex-direction:column}}.cbi-section .cbi-section-create{margin-top:calc(var(--spacing) * 6);align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){.cbi-section .cbi-section-create{margin-inline:0;margin-top:calc(var(--spacing) * 5);align-items:stretch;gap:calc(var(--spacing) * 3);flex-direction:column}}.cbi-section .cbi-section-create>div{flex:none}@media not all and (min-width:48rem){.cbi-section .cbi-section-create>div{flex:1;width:100%}}.ifacebox{min-width:calc(var(--spacing) * 28);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);text-align:center;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;align-items:stretch;display:inline-flex;position:relative;overflow:visible}@media (hover:hover){.ifacebox:hover{border-color:var(--hairline);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media not all and (min-width:48rem){.ifacebox{min-width:calc(var(--spacing) * 30);border-radius:calc(var(--radius-base) * 3);border-color:var(--hairline);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex:1}#cbi-network-interface .ifacebox{flex-direction:row}}@media (min-width:48rem){#cbi-network-interface .ifacebox{min-width:calc(var(--spacing) * 38)}}.ifacebox .ifacebox-head{border-top-left-radius:calc(var(--radius-base) * 2);border-top-right-radius:calc(var(--radius-base) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);width:100%;padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);text-align:center;--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--text);transition-property:background-color,border-color,color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media not all and (min-width:48rem){.ifacebox .ifacebox-head{border-top-left-radius:calc(var(--radius-base) * 3);border-top-right-radius:calc(var(--radius-base) * 3);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}}.ifacebox .ifacebox-head[style*=--zone-color-rgb]{background-color:rgb(var(--zone-color-rgb),.75)!important}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-head){border-top-left-radius:calc(var(--radius-base) * 3);border-bottom-left-radius:calc(var(--radius-base) * 3);border-right-style:var(--tw-border-style);border-right-width:1px;border-bottom-style:var(--tw-border-style);border-bottom-width:0;border-top-right-radius:0;flex-shrink:0;justify-content:center;align-items:center;width:auto;display:flex}}.ifacebox .ifacebox-head.cbi-tooltip-container{background-color:#0000;position:static}.ifacebox .ifacebox-head.cbi-tooltip-container .cbi-tooltip{bottom:0;left:0}.ifacebox .ifacebox-head.active{border-color:var(--brand);background-color:var(--brand);color:var(--on-brand)}.ifacebox .ifacebox-body{justify-content:center;align-items:stretch;gap:var(--spacing);border-bottom-right-radius:calc(var(--radius-base) * 2);border-bottom-left-radius:calc(var(--radius-base) * 2);width:100%;padding:calc(var(--spacing) * 3);text-align:center;color:var(--text);flex-direction:column;flex:1;display:flex}@media not all and (min-width:48rem){.ifacebox .ifacebox-body{border-bottom-right-radius:calc(var(--radius-base) * 3);border-bottom-left-radius:calc(var(--radius-base) * 3)}#cbi-network-interface :is(.ifacebox .ifacebox-body){border-top-right-radius:calc(var(--radius-base) * 3);border-bottom-right-radius:calc(var(--radius-base) * 3);padding-block:calc(var(--spacing) * 2);padding-right:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 4);border-bottom-left-radius:0;flex-direction:row;align-items:center}}.ifacebox .ifacebox-body>img{width:calc(var(--spacing) * 5);margin-inline:auto}:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span{color:var(--text)}@media not all and (min-width:48rem){:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}}.network-status-table :is(.ifacebox .ifacebox-body>span){width:100%}.ifacebox .ifacebox-body>span .cbi-tooltip-container+.cbi-tooltip-container{margin-left:var(--spacing)}.ifacebox .ifacebox-body>span .cbi-tooltip{transition-delay:.2s}.ifacebox .ifacebox-body>span .nowrap{display:inline-block}.ifacebox .ifacebox-body>span>.nowrap:not(:last-child){margin-bottom:var(--spacing)}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5);flex-shrink:0}.ifacebox .ifacebox-body>div{width:100%;display:block}:where(.ifacebox .ifacebox-body>div>:not(:last-child)){--tw-space-y-reverse:0;margin-block:0}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-body>div){flex:1;width:auto}:where(#cbi-network-interface :is(.ifacebox .ifacebox-body>div)>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}}.ifacebox .ifacebox-body .cbi-tooltip-container{cursor:help;color:var(--text);justify-content:center;align-items:center;display:inline-flex;position:static}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{bottom:0}@media (min-width:48rem){.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{left:0}}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip .nowrap{white-space:nowrap}.ifacebox .ifacebox-body small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4);display:block}@media not all and (min-width:48rem){#cbi-network-interface :is(.ifacebox .ifacebox-body small){margin-top:0}}.network-status-table .ifacebox-body{justify-content:space-around;align-items:center;gap:calc(var(--spacing) * 2);flex-direction:column;flex:1;height:100%;display:flex}.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 1.5)}}.network-status-table .ifacebox-body .ifacebadge{min-width:calc(var(--spacing) * 55);flex:1}#modal_overlay{pointer-events:none;background-color:#0000;display:none;position:fixed;top:0;bottom:0;overflow:auto}.modal-overlay-active #modal_overlay{pointer-events:auto;z-index:100;background-color:var(--scrim);--tw-backdrop-blur:blur(var(--blur-md));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);grid-template-columns:repeat(1,minmax(0,1fr));place-items:center;display:grid;inset:0}#modal_overlay>.modal{width:var(--container-5xl);gap:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-overlay);padding:calc(var(--spacing) * 6);overflow-wrap:break-word;white-space:normal;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;display:flex;position:relative}@media not all and (min-width:48rem){#modal_overlay>.modal{gap:calc(var(--spacing) * 3);width:100%;padding:calc(var(--spacing) * 4)}}#modal_overlay>.modal h4{text-align:center;margin-bottom:0}#modal_overlay>.modal h4 em{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand)}#modal_overlay>.modal h5{margin-block:calc(var(--spacing) * 3);color:var(--text)}#modal_overlay>.modal p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--text)}#modal_overlay>.modal>ul{border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 3);overflow:auto}#modal_overlay>.modal label.btn{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);color:var(--text)}@media (hover:hover){#modal_overlay>.modal label.btn:hover{border-color:var(--hairline)}}#modal_overlay>.modal pre{overflow:auto}#modal_overlay>.modal pre.errors{border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}#modal_overlay>.modal pre+pre{margin-top:calc(var(--spacing) * 3)}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 4);flex-shrink:0;display:flex}@media not all and (min-width:48rem){#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 1.5);padding:calc(var(--spacing) * 2.5)}}#modal_overlay>.modal div.left{justify-content:flex-start}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.right{justify-content:flex-end}#modal_overlay>.modal.uci-dialog ins,#modal_overlay>.modal.uci-dialog del,#modal_overlay>.modal.uci-dialog var{font-family:var(--font-mono);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);font-style:normal;text-decoration-line:none}#modal_overlay>.modal.uci-dialog ins{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--success-surface);color:var(--success)}#modal_overlay>.modal.uci-dialog del{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--danger-surface);color:var(--danger)}#modal_overlay>.modal.uci-dialog var{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--info-surface);color:var(--info)}#modal_overlay>.modal.uci-dialog .uci-change-legend{margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 4);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}@media not all and (min-width:48rem){#modal_overlay>.modal.uci-dialog .uci-change-legend{gap:calc(var(--spacing) * 2);padding:calc(var(--spacing) * 3);grid-template-columns:repeat(1,minmax(0,1fr))}}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label del,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var{height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);justify-content:center;align-items:center;display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var del{margin-left:var(--spacing);height:calc(var(--spacing) * 4);min-width:calc(var(--spacing) * 4);padding-inline:var(--spacing)}#modal_overlay>.modal.uci-dialog .uci-change-list{margin-top:calc(var(--spacing) * 4)}:where(#modal_overlay>.modal.uci-dialog .uci-change-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}#modal_overlay>.modal.uci-dialog .uci-change-list h5{margin-top:calc(var(--spacing) * 6);margin-bottom:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 1.5);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text)}#modal_overlay>.modal.uci-dialog .uci-change-list h5:first-child{margin-top:0}#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del{border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:block}:is(#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del) strong{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}#modal_overlay>.modal.uci-dialog .uci-change-list var{border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}#modal_overlay>.modal.uci-dialog .uci-change-list var ins,#modal_overlay>.modal.uci-dialog .uci-change-list var del{margin-left:var(--spacing);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));display:inline-block}@media not all and (min-width:48rem){.mobile-menu-overlay{visibility:hidden;z-index:60;background-color:var(--mega-menu-bg);opacity:0;position:fixed;inset:0}}@media (min-width:48rem){.mobile-menu-overlay{display:none}}@media not all and (min-width:48rem){.mobile-menu-overlay.mobile-menu-open{visibility:visible;opacity:1;transition-property:visibility,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.mobile-menu-overlay .mobile-nav{width:100%;height:100%;padding-top:calc(var(--spacing) * 14);flex-direction:column;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-body{min-height:0;padding-inline:calc(var(--spacing) * 5);padding-top:calc(var(--spacing) * 6);flex-direction:column;flex:1;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-body .mobile-nav-label{margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text-muted)}.mobile-menu-overlay .mobile-nav .mobile-nav-list{--tw-translate-y:calc(var(--spacing) * -2);min-height:0;translate:var(--tw-translate-x) var(--tw-translate-y);row-gap:calc(var(--spacing) * 4);overscroll-behavior:contain;padding:0;padding-bottom:calc(var(--spacing) * 5);opacity:0;flex-direction:column;flex:1;margin:0;list-style-type:none;display:flex;overflow-y:auto}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item{flex-shrink:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .nav-row{min-height:calc(var(--spacing) * 13);justify-content:space-between;gap:calc(var(--spacing) * 3);padding-inline:0;padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);background-color:#0000;border-radius:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .nav-row .nav-icon{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-submenu .mobile-nav-submenu-list{padding:0;padding-left:calc(var(--spacing) * 6);margin:0}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-submenu .mobile-nav-subitem .mobile-nav-sublink{min-height:calc(var(--spacing) * 10);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));align-items:center}.mobile-menu-overlay .mobile-nav .mobile-nav-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 5);padding-top:calc(var(--spacing) * 4);padding-bottom:max(1rem, env(safe-area-inset-bottom));flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-footer-action{align-items:center;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-logout{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--text);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;text-decoration-line:none;transition-duration:.15s}@media (hover:hover){.mobile-menu-overlay .mobile-nav .mobile-nav-footer .mobile-nav-logout:hover{color:var(--brand)}}.mobile-menu-overlay .mobile-nav .mobile-nav-footer .theme-switcher .theme-option{padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing)}.mobile-menu-overlay.mobile-menu-open .mobile-nav-list{--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y);opacity:1;transition-property:translate,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;--tw-ease:var(--ease-out);transition-duration:.25s;transition-timing-function:var(--ease-out)}body.mobile-navigation-open>header{z-index:70;background-color:#0000}}[data-nav-type=mega-menu] .desktop-menu-overlay{pointer-events:none;visibility:hidden;z-index:60;background-color:var(--mega-menu-scrim);opacity:0;--tw-backdrop-blur:blur(var(--blur-lg));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:opacity,visibility;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.22s;--tw-ease:cubic-bezier(.4,0,.6,1);transition-duration:.22s;transition-timing-function:cubic-bezier(.4,0,.6,1);position:fixed;inset:0}@media not all and (min-width:48rem){[data-nav-type=mega-menu] .desktop-menu-overlay{display:none}}[data-nav-type=mega-menu] .desktop-menu-overlay.active{pointer-events:auto;visibility:visible;opacity:1}table.table,.table{margin-bottom:calc(var(--spacing) * 3);border-collapse:separate;--tw-border-spacing-x:0;--tw-border-spacing-y:0;width:100%;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);overflow:visible}@media not all and (min-width:48rem){table.table,.table{border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;margin-inline:0;display:block;overflow:visible}}:is(table.table,.table)[width="100%"]{width:100%}:is(table.table,.table)[width="33%"]{width:33.3333%}:is(table.table,.table) .cbi-section-table-titles{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content);content:var(--tw-content);border-color:var(--hairline);content:var(--tw-content);padding-inline:calc(var(--spacing) * 3);content:var(--tw-content);padding-block:calc(var(--spacing) * 3);content:var(--tw-content);vertical-align:middle;content:var(--tw-content);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-content:attr(data-title);content:var(--tw-content);content:var(--tw-content);display:table-cell}@media not all and (min-width:48rem){:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex:0 0 100%;display:flex}}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content)}@media (min-width:48rem){:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}}:is(:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):not([data-title]),:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):has(td.cbi-section-table-titles)):before{content:var(--tw-content);--tw-content:none;content:none}:is(table.table,.table) .cbi-section-table-titles.named:before{content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);content:var(--tw-content);color:var(--text-subtle);content:var(--tw-content);text-transform:uppercase}@media not all and (min-width:48rem){:is(table.table,.table) tbody,:is(table.table,.table) .tbody{display:block}:is(table.table,.table) tr,:is(table.table,.table) .tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):has(.cbi-progressbar){justify-content:center;align-items:center;display:flex}}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th):first-child{border-top-left-radius:calc(var(--radius-base) * 2)}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th):last-child{border-top-right-radius:calc(var(--radius-base) * 2)}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-style:var(--tw-border-style);border-bottom-width:0}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-descr{display:none}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-1,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-2{background-color:#0000}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-1{flex:2rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-1{width:calc(var(--spacing) * 20);max-width:calc(var(--spacing) * 28)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{white-space:normal}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{flex:2 2 4rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-2{width:calc(var(--spacing) * 32);max-width:calc(var(--spacing) * 40)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-3{flex:3 3 6rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-3{width:calc(var(--spacing) * 44);max-width:calc(var(--spacing) * 52)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-4{flex:4 4 8rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-4{width:calc(var(--spacing) * 56);max-width:calc(var(--spacing) * 64)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-5{flex:5 5 10rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-5{width:calc(var(--spacing) * 68);max-width:calc(var(--spacing) * 76)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-6{flex:6 6 12rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-6{width:calc(var(--spacing) * 80);max-width:calc(var(--spacing) * 88)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-7{flex:7 7 14rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-7{width:calc(var(--spacing) * 92);max-width:calc(var(--spacing) * 100)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-8{flex:8 8 16rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-8{width:calc(var(--spacing) * 104);max-width:calc(var(--spacing) * 112)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-9{flex:9 9 18rem}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-9{width:calc(var(--spacing) * 116);max-width:calc(var(--spacing) * 124)}}@media not all and (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-10{flex:0 0 100%;max-width:calc(100vw - 40px)}}@media (min-width:48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr)>.col-10{width:calc(var(--spacing) * 128);max-width:calc(var(--spacing) * 136)}}:is(table.table,.table) th,:is(table.table,.table) .th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 3);text-align:left;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--text-subtle);text-transform:uppercase}@media not all and (min-width:48rem){:is(table.table,.table) th,:is(table.table,.table) .th{border-style:var(--tw-border-style);background-color:#0000;border-width:0;flex:50%}}#cbi-samba4 :is(:is(table.table,.table) th,:is(table.table,.table) .th){padding-inline:calc(var(--spacing) * .5);padding-block:calc(var(--spacing) * 1.5)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{width:100%}@media not all and (min-width:48rem){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{flex:0 0 100%}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{width:33.3333%}@media not all and (min-width:48rem){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{flex:0 0 33.333%}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]{cursor:pointer;-webkit-user-select:none;user-select:none}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:after{content:var(--tw-content);margin-left:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}@media (hover:hover){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:hover{background-color:var(--hover-faint)}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=asc]:after{--tw-content:"▲";content:var(--tw-content)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=desc]:after{--tw-content:"▼";content:var(--tw-content)}:is(table.table,.table)[id*=status_leases] .td{max-width:calc(var(--spacing) * 62)}@media not all and (min-width:48rem){:is(table.table,.table)[id*=status_leases] .td{max-width:100%}}:is(table.table,.table) td,:is(table.table,.table) .td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 3);vertical-align:middle;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));overflow-wrap:break-word;white-space:normal;display:table-cell}@media not all and (min-width:48rem){:is(table.table,.table) td,:is(table.table,.table) .td{border-style:var(--tw-border-style);padding-inline:var(--spacing);padding-block:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));border-width:0;flex:50%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content);--tw-content:attr(data-title);content:var(--tw-content);content:var(--tw-content);display:none}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{margin-bottom:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);display:block}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content)}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}}#cbi-samba4 :is(:is(table.table,.table) td,:is(table.table,.table) .td){padding-inline:calc(var(--spacing) * .5);padding-block:calc(var(--spacing) * 1.5)}[data-page=admin-system-mounts] :is(:is(table.table,.table) td,:is(table.table,.table) .td){max-width:calc(var(--spacing) * 104)}@media not all and (min-width:48rem){[data-page=admin-system-mounts] :is(:is(table.table,.table) td,:is(table.table,.table) .td){max-width:100%}#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td){padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);flex:0 0 100%}}#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content)}@media not all and (min-width:48rem){#wifi_assoclist_table :is(:is(table.table,.table) td,:is(table.table,.table) .td):before{margin-bottom:calc(var(--spacing) * 1.5)}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=text],:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=password],:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){min-width:fit-content}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{overflow-wrap:anywhere}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{margin-bottom:var(--spacing);text-align:left;flex-basis:100%;align-self:flex-start}}@media (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{max-width:65ch}}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.DummyValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.Button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.FlagValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=dvalue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=fvalue]{flex-basis:50%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions{flex:0 0 100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div{width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div>.cbi-button{flex:1}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>.cbi-button{width:100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{width:100%}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{flex:0 0 100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{width:33.3333%}@media not all and (min-width:48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{flex:0 0 33.333%}[data-page=admin-network-network] :is(:is(table.table,.table) td,:is(table.table,.table) .td)[data-name=_ifacebox],[data-page=admin-network-network] :is(:is(table.table,.table) td,:is(table.table,.table) .td)[data-name=_ifacestat]{flex-basis:100%}}.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell{width:auto!important}#content_syslog{margin:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){#content_syslog{margin:var(--spacing)}}#content_syslog>div{align-items:center;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#content_syslog>div{column-gap:calc(var(--spacing) * 1.5)}}#content_syslog>div>select,#content_syslog>div>input{margin-block:0!important}@media not all and (min-width:48rem){#content_syslog>div>.cbi-input-select,#content_syslog>div>.cbi-input-text{min-width:calc(var(--spacing) * 45)}}#content_syslog>.syslog-view{display:block}#syslog,#log_textarea{width:100%;font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}#syslog{margin-bottom:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media not all and (min-width:48rem){#syslog{padding:calc(var(--spacing) * 3)}}#content_syslog.log-enhanced>#syslog{display:none}.syslog-view{width:100%;margin-bottom:calc(var(--spacing) * 5);border-radius:calc(var(--radius-base) * 3);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:calc(var(--spacing) * 6);color:var(--text);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media not all and (min-width:48rem){.syslog-view{padding:calc(var(--spacing) * 3)}}.syslog-view{font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);--tw-outline-style:none;outline-style:none;overflow-x:auto}.syslog-view:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring)}.syslog-view .log-row{border-radius:calc(var(--radius-base) * .75);width:max-content;min-width:100%;padding-inline:calc(var(--spacing) * 2);white-space:pre}.syslog-view .log-row:hover{background-color:var(--hover-faint)}.syslog-view ::selection{background-color:var(--info-surface);color:var(--text)}.syslog-view .log-time{color:var(--text-subtle)}@media (min-width:48rem){.syslog-view .log-time{vertical-align:bottom;min-width:24ch;display:inline-block}}.syslog-view .log-sev{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}@media (min-width:48rem){.syslog-view .log-sev{vertical-align:bottom;min-width:16ch;display:inline-block}}.syslog-view .log-tag{color:var(--text-muted)}@media (min-width:48rem){.syslog-view .log-tag{vertical-align:bottom;min-width:18ch;display:inline-block}}.syslog-view .lv-info .log-sev{color:var(--info)}.syslog-view .lv-notice .log-sev{color:var(--success)}.syslog-view .lv-warn .log-sev{color:var(--warning)}.syslog-view .lv-debug,.syslog-view .lv-debug .log-sev,.syslog-view .lv-debug .log-tag{color:var(--text-subtle)}.syslog-view .lv-err,.syslog-view .lv-crit{background-color:var(--danger-surface)}:is(.syslog-view .lv-err,.syslog-view .lv-crit):hover{background-color:var(--danger-surface-hover)}:is(.syslog-view .lv-err,.syslog-view .lv-crit) .log-sev{color:var(--danger)}.cbi-input-invalid,.cbi-value-error{border-color:var(--danger)!important}:is(.cbi-input-invalid,.cbi-value-error):focus{--tw-ring-color:var(--danger)!important}.cbi-value{gap:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 1.5);flex-flow:wrap;display:flex}@media not all and (min-width:48rem){.cbi-value{gap:calc(var(--spacing) * 1.5);padding-block:var(--spacing);flex-direction:column}}.cbi-value.hidden{display:none}.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 3)}@media not all and (min-width:48rem){.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 2)}}.cbi-value>.cbi-value-title{padding-top:var(--spacing);text-align:right;--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}@media not all and (min-width:48rem){.cbi-value>.cbi-value-title{text-align:left;width:auto}}@media (min-width:48rem){.cbi-value>.cbi-value-title{flex:0 0 12rem}}.cbi-value>.cbi-value-field{flex:1;max-width:100%}.cbi-value>.cbi-value-field:has(>.cbi-dropdown[disabled]){cursor:not-allowed}.cbi-value>.cbi-value-field .cbi-value-description{margin-top:var(--spacing);padding-left:calc(var(--spacing) * 4);--tw-leading:1;overflow-wrap:break-word;color:var(--text-muted);line-height:1;position:relative}.cbi-value>.cbi-value-field .cbi-value-description:not(:empty):before{content:var(--tw-content);content:var(--tw-content);left:calc(var(--spacing) * -.5);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);background-color:var(--info);content:var(--tw-content);-webkit-mask:var(--icon-info) center/cover no-repeat;-webkit-mask:var(--icon-info) center/cover no-repeat;-webkit-mask:var(--icon-info) center/cover no-repeat;mask:var(--icon-info) center/cover no-repeat;display:inline-block;position:absolute}.cbi-value>.cbi-section,.cbi-value>.cbi-tblsection{width:100%}.cbi-dynlist{width:max-content;max-width:calc(var(--spacing) * 120);align-items:flex-start;gap:calc(var(--spacing) * 3);flex-direction:column;display:inline-flex}@media not all and (min-width:48rem){.cbi-dynlist{max-width:100%!important}}.cbi-dynlist .item{pointer-events:auto;cursor:move;align-items:flex-start;gap:calc(var(--spacing) * 2);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface);padding-block:calc(var(--spacing) * 3);padding-right:calc(var(--spacing) * 10);padding-left:calc(var(--spacing) * 4);word-break:break-all;--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,box-shadow,opacity,border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;-webkit-user-select:text;user-select:text;flex-direction:column;align-self:stretch;transition-duration:.15s;display:inline-flex;position:relative;overflow:hidden}@media not all and (min-width:48rem){.cbi-dynlist .item{width:100%;padding-block:calc(var(--spacing) * 2.5);padding-right:calc(var(--spacing) * 8);padding-left:calc(var(--spacing) * 3)}}.cbi-dynlist .item:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * 2.5);content:var(--tw-content);right:calc(var(--spacing) * 2);content:var(--tw-content);content:var(--tw-content);height:calc(var(--spacing) * 6);content:var(--tw-content);width:calc(var(--spacing) * 6);content:var(--tw-content);content:var(--tw-content);cursor:pointer;content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);border-radius:calc(var(--radius-base) * 1.5);content:var(--tw-content);background-color:var(--surface-sunken);content:var(--tw-content);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);content:var(--tw-content);color:var(--text-muted);--tw-content:"×";content:var(--tw-content);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-dynlist .item.dragging{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);cursor:grabbing;opacity:.5;--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-dynlist .item.drag-over{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y);border-color:var(--brand);background-color:var(--brand-subtle);--tw-shadow:var(--app-shadow-md);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--brand-subtle)}.cbi-dynlist .item>span,.cbi-dynlist .item>code{pointer-events:none;border-radius:var(--radius-base);width:100%;font-family:var(--font-mono);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.cbi-dynlist .placeholder{word-break:break-all}.cbi-dynlist .add-item{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-width:1px;border-color:var(--hairline);padding-inline:var(--spacing);padding-block:var(--spacing);transition-property:border-color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;align-self:stretch;transition-duration:.15s;display:inline-flex}@media (hover:hover){.cbi-dynlist .add-item:hover{border-color:var(--hairline);background-color:var(--surface-sunken)}}.cbi-dynlist .add-item>input{min-width:calc(var(--spacing) * 61);flex:1}.cbi-dynlist .add-item>.cbi-button{min-height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;justify-content:center;align-items:center;padding-block:0;display:inline-flex}.cbi-dynlist .add-item>.cbi-button:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-tabmenu{margin-bottom:var(--spacing);align-items:center;gap:var(--spacing);border-radius:calc(var(--radius-base) * 4);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding:var(--spacing);display:flex;overflow-x:auto}.cbi-tabmenu li{flex-shrink:0;min-width:fit-content;margin:0;list-style-type:none;position:relative}.cbi-tabmenu li[data-errors]:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -1.5);content:var(--tw-content);z-index:20;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 4);content:var(--tw-content);min-width:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--danger);content:var(--tw-content);padding-inline:calc(var(--spacing) * 1.5);content:var(--tw-content);padding-block:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);color:var(--on-brand);--tw-content:attr(data-errors);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-tabmenu li[data-errors]>a{border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}.cbi-tabmenu li>a{border-radius:calc(var(--radius-base) * 4);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--text-muted);text-decoration-line:none;display:block}@media (hover:hover){.cbi-tabmenu li>a:hover{color:var(--text)}}.cbi-tabmenu li.cbi-tab a{background-color:var(--text);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--surface);--tw-shadow:var(--app-shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}[data-tab-title]{visibility:hidden;height:0;overflow:hidden}[data-tab-active=true]{visibility:visible;height:auto;overflow:visible}#tabmenu{margin-bottom:calc(var(--spacing) * 8);width:100%}.tabs{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);align-items:center;gap:0;display:flex;position:relative;overflow-x:auto}.tabs a{padding-inline:calc(var(--spacing) * 8);padding-block:calc(var(--spacing) * 4);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--text-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s;display:block}@media (hover:hover){.tabs a:hover{color:var(--text);text-decoration-line:none}}.tabs>li.active{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--text)}.tabs>li.active>a{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--text)}.cbi-section-node-tabbed{margin-top:calc(var(--spacing) * 6)}.cmdk-trigger{margin-right:calc(var(--spacing) * 4);width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8);cursor:pointer;border-radius:var(--radius-base);border-style:var(--tw-border-style);color:var(--text);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;flex-shrink:0;place-items:center;padding:0;transition-duration:.15s;display:grid;position:relative}body:not([data-nav-type=sidebar]) .cmdk-trigger{margin-left:auto}.cmdk-trigger:before{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;mask:var(--icon-search) center/contain no-repeat;background-color:currentColor}.cmdk-trigger:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cmdk-trigger:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cmdk-trigger:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--focus-ring);--tw-outline-style:none;outline-style:none}.cmdk-panel{top:calc(var(--spacing) * 24);z-index:120;--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);width:min(36rem,100vw - 2.5rem);translate:var(--tw-translate-x) var(--tw-translate-y);border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:color-mix(in oklab, var(--surface) 85%, transparent);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-xl));--tw-backdrop-saturate:saturate(150%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);position:fixed;left:50%;overflow:hidden}@starting-style{.cmdk-panel{--tw-translate-y:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y)}}@starting-style{.cmdk-panel{opacity:0}}@media not all and (min-width:48rem){.cmdk-panel{border-style:var(--tw-border-style);background-color:var(--bg);--tw-shadow:0 0 #0000;width:auto;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur: ;-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);--tw-backdrop-saturate:saturate(100%);border-width:0;border-radius:0;flex-direction:column;display:flex;inset:0;translate:none}}.cmdk-panel .cmdk-inputrow{align-items:center;gap:calc(var(--spacing) * 3);padding-inline:calc(var(--spacing) * 5);padding-block:calc(var(--spacing) * 3.5);display:flex}@media not all and (min-width:48rem){.cmdk-panel .cmdk-inputrow{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--hairline);background-color:var(--surface);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5)}}.cmdk-panel .cmdk-inputrow:before{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);color:var(--text-subtle);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;-webkit-mask:var(--icon-search) center/contain no-repeat;mask:var(--icon-search) center/contain no-repeat;background-color:currentColor;flex-shrink:0}.cmdk-panel .cmdk-inputrow .cmdk-input{border-style:var(--tw-border-style);width:100%;min-width:0;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:var(--text);background-color:#0000;border-width:0;border-radius:0;flex:1;padding:0}.cmdk-panel .cmdk-inputrow .cmdk-input::placeholder{color:var(--text-subtle)}.cmdk-panel .cmdk-inputrow .cmdk-input{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cmdk-panel .cmdk-inputrow .cmdk-input:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;outline-style:none}.cmdk-panel .cmdk-inputrow .cmdk-clear{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);color:var(--text-subtle);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;flex-shrink:0;place-items:center;padding:0;transition-duration:.15s;display:grid}.cmdk-panel .cmdk-inputrow .cmdk-clear:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);--tw-content:"";content:var(--tw-content);-webkit-mask:var(--icon-x) center/contain no-repeat;-webkit-mask:var(--icon-x) center/contain no-repeat;-webkit-mask:var(--icon-x) center/contain no-repeat;mask:var(--icon-x) center/contain no-repeat;background-color:currentColor}.cmdk-panel .cmdk-inputrow .cmdk-clear:hover{color:var(--text)}.cmdk-input:placeholder-shown~:is(.cmdk-panel .cmdk-inputrow .cmdk-clear){display:none}.cmdk-panel .cmdk-inputrow .cmdk-cancel{cursor:pointer;border-style:var(--tw-border-style);padding:var(--spacing);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--brand);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;border-width:0;flex-shrink:0;display:none}@media not all and (min-width:48rem){.cmdk-panel .cmdk-inputrow .cmdk-cancel{display:block}}.cmdk-panel .cmdk-list{max-height:calc(var(--spacing) * 80);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding:calc(var(--spacing) * 2);overflow-y:auto}.cmdk-panel .cmdk-list:empty{display:none}@media not all and (min-width:48rem){.cmdk-panel .cmdk-list{overscroll-behavior:contain;flex:1;max-height:none}}.cmdk-panel .cmdk-list .cmdk-row{align-items:center;gap:calc(var(--spacing) * 3);border-radius:calc(var(--radius-base) * 1.5);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);text-decoration-line:none;display:flex}.cmdk-panel .cmdk-list .cmdk-row .cmdk-title{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.cmdk-panel .cmdk-list .cmdk-row .cmdk-group-name{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-subtle);flex-shrink:0;margin-left:auto}.cmdk-panel .cmdk-list .cmdk-row mark{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--brand);background-color:#0000}.cmdk-panel .cmdk-list .cmdk-row.is-selected{background-color:var(--brand-subtle)}.cmdk-panel .cmdk-list .cmdk-row.is-selected .cmdk-title{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}.cmdk-panel .cmdk-list .cmdk-empty{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 6);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text-subtle)}.cmdk-panel .cmdk-footer{align-items:center;gap:calc(var(--spacing) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--hairline);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-subtle);display:flex}@media not all and (min-width:48rem){.cmdk-panel .cmdk-footer{display:none}}.cmdk-panel .cmdk-footer .cmdk-hint-close{margin-left:auto}.cmdk-panel .cmdk-footer kbd{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--surface-sunken);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);color:var(--text-muted);padding-block:1px;font-size:11px}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.cmdk-panel{background-color:var(--surface)}}@media (prefers-reduced-transparency:reduce){.cmdk-panel{background-color:var(--surface)}}body[data-bg] .page-bg{--page-bg:var(--main-bg);--page-bg-lqip:var(--main-bg-lqip)}body[data-bg] #maincontent{background:var(--bg);position:relative}@supports (color:color-mix(in lab, red, red)){body[data-bg] #maincontent{background:color-mix(in srgb,var(--bg) 55%,transparent)}}body[data-bg] header,body[data-bg] .sidebar-panel-inner{-webkit-backdrop-filter:blur(var(--main-bg-blur,20px)) saturate(150%);backdrop-filter:blur(var(--main-bg-blur,20px)) saturate(150%);background:var(--bg)}@supports (color:color-mix(in lab, red, red)){body[data-bg] header,body[data-bg] .sidebar-panel-inner{background:color-mix(in srgb,var(--bg) var(--main-bg-alpha,67%),transparent)}}body[data-bg] .page-bg:before{pointer-events:none;z-index:1;--tw-content:"";content:var(--tw-content);background:var(--bg);position:absolute;inset:0}@supports (color:color-mix(in lab, red, red)){body[data-bg] .page-bg:before{background:color-mix(in srgb,var(--bg) var(--main-bg-scrim,20%),transparent)}}body[data-bg] #maincontent .cbi-section{background:var(--surface)}@supports (color:color-mix(in lab, red, red)){body[data-bg] #maincontent .cbi-section{background:color-mix(in srgb,var(--surface) var(--main-bg-alpha,67%),transparent)}}.hidden{display:none!important}@media (min-width:48rem){.left{text-align:left!important}}.left:not(td){text-align:left!important}@media (min-width:48rem){.right{text-align:right!important}}.right:not(td){text-align:right!important}@media (min-width:48rem){.top{vertical-align:top!important}}.top:not(td){vertical-align:top!important}@media (min-width:48rem){.bottom{vertical-align:bottom!important}}.bottom:not(td){vertical-align:bottom!important}@media (min-width:48rem){.center{text-align:center!important}}.center:not(td){text-align:center!important}@media (min-width:48rem){.middle{vertical-align:middle!important}}.middle:not(td){vertical-align:middle!important}@media (min-width:48rem){.nowrap:not(span){white-space:nowrap}}.nowrap:not(span):not(td){white-space:nowrap}@keyframes aurora-fade-in{0%{opacity:0}}.fade-in{animation:.25s both aurora-fade-in}.fade-out{pointer-events:none;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.25s;transition-duration:.25s}.spinning{display:inline-block;position:relative;padding-left:calc(var(--spacing) * 8)!important}.spinning:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);animation:var(--animate-spin);content:var(--tw-content);content:var(--tw-content);-webkit-mask:var(--icon-spinning) center/cover no-repeat;-webkit-mask:var(--icon-spinning) center/cover no-repeat;-webkit-mask:var(--icon-spinning) center/cover no-repeat;mask:var(--icon-spinning) center/cover no-repeat;background-color:currentColor;position:absolute;top:50%;left:6px}#view>.spinning:first-child{min-height:calc(var(--spacing) * 48);place-items:center;width:fit-content;margin-inline:auto;display:grid}@media not all and (min-width:48rem){#view>.spinning:first-child{min-height:calc(100dvh - 4rem)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-property:none!important;animation:none!important}.spinning:before{animation:var(--animate-spin)!important}}@media (prefers-reduced-transparency:reduce){*,:before,:after{-webkit-backdrop-filter:none!important;backdrop-filter:none!important}:root{--mega-menu-bg:var(--surface-overlay)}body[data-bg]{--main-bg-alpha:100%}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}} diff --git a/luci-theme-footstrap/Makefile b/luci-theme-footstrap/Makefile index 279334594..afafa02f6 100644 --- a/luci-theme-footstrap/Makefile +++ b/luci-theme-footstrap/Makefile @@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap FOOTSTRAP_VERSION?= ifneq ($(FOOTSTRAP_VERSION),) PKG_VERSION:=$(FOOTSTRAP_VERSION) -PKG_RELEASE:=71 +PKG_RELEASE:=72 endif LUCI_TITLE:=Footstrap Theme diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js index 8e7e6497a..7672d60fd 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js @@ -853,6 +853,18 @@ function anchorRef() { } let _anchorPending = null; +/* WHY THE LAST ENGINE-OFF CORRECTION DID OR DID NOT WRITE — the `applyAnchor()` twin of `_lateWhy`, + * exported as `anchorWhy()` for the sweep. The engine-OFF cell of `/admin/network/dhcp @390 top + * compact` corrected at 1034 ms and 1885 ms on firefox with `theme said: null`, i.e. through this + * path and not `lateDrift()`, and `applyAnchor()` has five ways to return without a write that all + * read as "late" from outside. Named here so that finding says which. */ +let _anchorWhy = null; +const _anchorTrail = []; +function awhy(w) { + _anchorWhy = w; + _anchorTrail.push(w + '@' + Math.round(performance.now())); + if (_anchorTrail.length > 8) _anchorTrail.shift(); +} let _anchorFrame = 0; /* dev switch: `localStorage.fsAnchor = 'off'` stops the theme writing the scroll offset at all, * which is the one thing here that can move a page nobody is touching */ @@ -886,7 +898,17 @@ let _lateFrame = 0; * try from, or read the engine as having already done the job — and each guess cost a push. One * short string, set at every exit, ends that: the finding names the line instead of the silence. */ let _lateWhy = null; -function why(w) { _lateWhy = w; } +/* THE LAST EIGHT, WITH THE CLOCK — task trail. One last word is ambiguous: a correction whose `settle` + * has not run yet and one that ran, exited, and was re-armed by a later mutation both read `armed` at + * the end of the sweep's window. Seen on firefox, /admin/network/dhcp @390 top large, engine on: + * `theme said: armed` with the correction landing at 1744 ms. `performance.now()`, the clock the sweep + * measures the refill on, so the gate can print each entry relative to it. */ +const _lateTrail = []; +function why(w) { + _lateWhy = w; + _lateTrail.push(w + '@' + Math.round(performance.now())); + if (_lateTrail.length > 8) _lateTrail.shift(); +} function lateDrift(ref, grow, floorShrink) { /* the reference from BEFORE this tick, captured by the caller: one taken after the mutation @@ -1200,8 +1222,9 @@ function settleDeferredFloor(offsetBefore, shrink) { } function scheduleAnchor(ref) { - if (!ref || !anchorEnabled()) return; - if (_anchorPending) return; + if (!ref) return awhy('no-reference'); + if (!anchorEnabled()) return awhy('anchoring-off'); + if (_anchorPending) return awhy('pending-kept-first'); _anchorPending = ref; if (_anchorFrame) return; _anchorFrame = requestAnimationFrame(() => { @@ -1234,7 +1257,7 @@ function applyAnchor(ref) { * `sawClamp()` is the pixel `holdFloor()` watched the clamp land on, and it stands only while * the offset has not left it — a reader who really is scrolling has moved off it by definition, * so this reopens the guard for exactly one case and no other. */ - if (scrolling() && !sawClamp()) return; + if (scrolling() && !sawClamp()) return awhy('refused-moving'); /* through scroller(), not a second probe: two copies of the same question can answer * differently within one frame */ const sc = scroller(); @@ -1247,14 +1270,15 @@ function applyAnchor(ref) { * collapse clamps the offset to zero, which is the worst version of this fault rather than the * one case to sit out. */ if (ref.by != null) { - if (ref.by < 1) return; + if (ref.by < 1) return awhy('by-under-1'); writeOffset(sc, at + ref.by); + awhy('wrote-by-' + Math.round(ref.by)); return true; } - if (at <= 0) return; - if (!ref.el.isConnected) return; + if (at <= 0) return awhy('at-top'); + if (!ref.el.isConnected) return awhy('reference-gone'); const drift = ref.el.getBoundingClientRect().top - ref.top; - if (Math.abs(drift) < 1) return; /* nothing needed correcting here */ + if (Math.abs(drift) < 1) return awhy('no-drift'); /* nothing needed correcting here */ /* A definite write is a definite miss — task trust: any recovery streak counted so far said * nothing about THIS tick, and this tick just proved the engine did not do the job on its own. * (Recovery evidence itself is gathered earlier, in the mutation callback — see TRUST_RECOVERY @@ -1267,8 +1291,9 @@ function applyAnchor(ref) { * is the most a single tick can honestly account for — where `innerHeight` is unreadable those * 200px are the whole ceiling — plus whatever the engine is on record for having clamped away * (`slack`, see anchorFor()). */ - if (Math.abs(drift) > (window.innerHeight || 0) + 200 + (ref.slack || 0)) return; + if (Math.abs(drift) > (window.innerHeight || 0) + 200 + (ref.slack || 0)) return awhy('drift-too-big'); writeOffset(sc, at + drift); + awhy('wrote-' + Math.round(drift)); return true; } @@ -1437,9 +1462,17 @@ function observeContent() { * win"). This is the discriminator that survives both: a batch that removed nodes, added none * and left the floored box no taller is a removal, and a removal is not a page to correct * against. A synchronous `dom.content()` — every real poll tick — delivers its removals and - * its additions in ONE batch and is untouched. */ + * its additions in ONE batch and is untouched. + * + * AND ONLY WHERE THE FLOORED BOX DID NOT SHRINK. The first cut skipped every pure removal and + * that took out the correction REPEAT's pad removal between refills needs: the pad goes, the + * floor comes down with it, and `floorShrink` is carried into `lateDrift()` exactly so the clamp + * that follows gets put back. CI on cbcfd5d: `refill 2/3 left the reader -60px off, corrected + * never` on chromium and firefox, /admin/network/dhcp @390, both stands. The transient this + * guard is for is the empty half of a refill, where the floor HOLDS the box — so floorShrink + * is 0 there and non-zero on a real shrink. */ if (trustEngine) { - if (took && !gave && grew <= 0) why('emptying'); + if (took && !gave && grew <= 0 && floorShrink <= 1) why('emptying'); else lateDrift(settled, grew, floorShrink); } else scheduleAnchor(ref); @@ -1544,6 +1577,9 @@ return baseclass.extend({ scrolling, /* unmarked, for tools/scroll-anchor.mjs — see `_lateWhy` */ lateWhy: () => _lateWhy, + lateTrail: () => _lateTrail.slice(), + anchorWhy: () => _anchorWhy, + anchorTrail: () => _anchorTrail.slice(), deferMeasurement, /* -> the offset this file last took a reference at, or null before it has taken one. diff --git a/luci-theme-shadcn/.dev/src/media/components/_form.css b/luci-theme-shadcn/.dev/src/media/components/_form.css index bed3b9a27..2468d92a6 100644 --- a/luci-theme-shadcn/.dev/src/media/components/_form.css +++ b/luci-theme-shadcn/.dev/src/media/components/_form.css @@ -4,7 +4,7 @@ } .cbi-value { - @apply flex flex-row flex-wrap gap-4 py-1.5; + @apply flex flex-row flex-wrap gap-4 py-1.5 max-md:flex-col max-md:gap-1.5 max-md:py-1; &.hidden { @apply hidden; @@ -15,7 +15,7 @@ } > .cbi-value-title { - @apply text-foreground pt-1 text-right text-sm font-medium md:flex-[0_0_10rem]; + @apply text-foreground pt-1 text-right text-sm font-medium max-md:text-left md:flex-[0_0_10rem]; } > .cbi-value-field { @@ -41,7 +41,7 @@ } .cbi-dynlist { - @apply inline-flex w-max max-w-96 flex-col items-start gap-3; + @apply inline-flex w-max max-w-96 flex-col items-start gap-3 max-md:max-w-full; .item { @apply border-border bg-panel-bg pointer-events-auto relative inline-flex cursor-move flex-col items-start gap-2 self-stretch overflow-hidden rounded-lg border py-3 pr-9 pl-4 break-all shadow-sm transition-all duration-200 select-text; @@ -80,17 +80,3 @@ } } } - -@media (max-width: 768px) { - .cbi-value { - @apply flex-col gap-1.5 py-1; - - > .cbi-value-title { - @apply text-left; - } - } - - .cbi-dynlist { - @apply max-w-full; - } -} diff --git a/luci-theme-shadcn/.dev/src/media/components/_table.css b/luci-theme-shadcn/.dev/src/media/components/_table.css index 2274cafb4..07dcc9ba5 100644 --- a/luci-theme-shadcn/.dev/src/media/components/_table.css +++ b/luci-theme-shadcn/.dev/src/media/components/_table.css @@ -1,6 +1,6 @@ table.table, .table { - @apply border-border mb-4 w-full border-separate border-spacing-0 overflow-visible rounded-lg border; + @apply border-border mb-4 w-full border-separate border-spacing-0 overflow-visible rounded-lg border max-md:block max-md:rounded-none max-md:border-0 max-md:shadow-none; &[width="100%"] { @apply w-full; @@ -27,9 +27,14 @@ table.table, @apply before:bg-label-surface before:rounded-tl-lg; } + tbody, + .tbody { + @apply max-md:block; + } + tr, .tr { - @apply hover:bg-label-surface transition-colors duration-200; + @apply hover:bg-label-surface max-md:border-border transition-colors duration-200 max-md:flex max-md:flex-wrap max-md:border-b max-md:px-2 max-md:py-2; &:first-child { &:not([data-title]) { @@ -69,7 +74,7 @@ table.table, th, .th { - @apply border-border bg-label-surface border-b px-3 py-2.5 text-left text-sm font-medium backdrop-blur-sm; + @apply border-border bg-label-surface border-b px-3 py-2.5 text-left text-sm font-medium backdrop-blur-sm max-md:hidden; &[width="100%"] { @apply w-full; @@ -91,8 +96,8 @@ table.table, td, .td { - @apply border-border table-cell border-b px-3 py-2.5 align-middle text-sm break-words whitespace-normal; - @apply before:hidden before:content-[attr(data-title)]; + @apply border-border table-cell border-b px-3 py-2.5 align-middle text-sm break-words whitespace-normal max-md:flex-[1_1_50%] max-md:border-0 max-md:px-1 max-md:py-1; + @apply before:hidden before:content-[attr(data-title)] before:max-md:mb-1 before:max-md:block before:max-md:text-xs before:max-md:font-semibold; > input[type="text"], > input[type="password"], @@ -109,76 +114,38 @@ table.table, } &.cbi-value-field { - @apply break-all; + /* Mobile cards: value fields stack one per row — + the row title and long match-rule cells get the full width — while + display-only widgets below pair up two per row. */ + @apply wrap-anywhere max-md:mb-1 max-md:basis-full max-md:self-start max-md:text-left md:max-w-prose; + + &[data-widget="CBI.DummyValue"], + &[data-widget="CBI.Button"], + &[data-widget="CBI.FlagValue"], + &[data-widget="dvalue"], + &[data-widget="button"], + &[data-widget="fvalue"] { + @apply max-md:basis-1/2; + } + } + + &.cbi-section-actions { + @apply max-md:flex-[0_0_100%]; } &.cbi-section-actions > div > .cbi-button { @apply flex-1; } + > .cbi-button { + @apply max-md:w-full; + } + &[width="100%"] { - @apply w-full; + @apply w-full max-md:flex-[0_0_100%]; } &[width="33%"] { - @apply w-1/3; - } - } -} - -/* Mobile responsive — rows become stacked cards */ -@media (max-width: 768px) { - table.table, - .table { - @apply block w-full overflow-visible rounded-none border-0 shadow-none; - - tbody, - .tbody { - @apply block; - } - - tr, - .tr { - @apply border-border flex flex-wrap border-b px-2 py-2; - } - - th, - .th { - @apply hidden; - } - - td, - .td { - @apply flex-[1_1_50%] border-0 px-1 py-1 text-sm; - @apply before:mb-1 before:block before:text-xs before:font-semibold; - - &.cbi-value-field { - /* Mobile cards: value fields stack one per row — - the row title and long match-rule cells get the full width — while - display-only widgets below pair up two per row. */ - @apply mb-1 basis-full self-start text-left; - - &[data-widget="CBI.DummyValue"], - &[data-widget="CBI.Button"], - &[data-widget="CBI.FlagValue"], - &[data-widget="dvalue"], - &[data-widget="button"], - &[data-widget="fvalue"] { - @apply basis-1/2; - } - } - - &.cbi-section-actions { - @apply flex-[0_0_100%]; - } - > .cbi-button { - @apply w-full; - } - &[width="100%"] { - @apply flex-[0_0_100%]; - } - &[width="33%"] { - @apply flex-[0_0_33.333%]; - } + @apply w-1/3 max-md:flex-[0_0_33.333%]; } } } diff --git a/luci-theme-shadcn/Makefile b/luci-theme-shadcn/Makefile index 00d4c9104..51f161bcc 100644 --- a/luci-theme-shadcn/Makefile +++ b/luci-theme-shadcn/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=A modern sidebar LuCI theme for OpenWrt, built with shadcn/ui design language. LUCI_DEPENDS:=+luci-base -PKG_VERSION:=0.5.2 -PKG_RELEASE:=1 +PKG_VERSION:=0.5.3 +PKG_RELEASE:=2 PKG_LICENSE:=Apache-2.0 LUCI_MINIFY_CSS:= diff --git a/luci-theme-shadcn/htdocs/luci-static/shadcn/main.css b/luci-theme-shadcn/htdocs/luci-static/shadcn/main.css index 116416733..b02ebb52b 100644 --- a/luci-theme-shadcn/htdocs/luci-static/shadcn/main.css +++ b/luci-theme-shadcn/htdocs/luci-static/shadcn/main.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-ease:initial;--tw-content:"";--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-space-y-reverse:0;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:.25rem;--breakpoint-md:48rem;--container-xs:20rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base) * .5);--radius-md:calc(var(--radius-base) * .75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base) * 1.5);--shadow-sm:var(--shadow-sm);--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-sm:8px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base) * .5);--color-sidebar-fg:var(--sidebar-foreground);--color-terminal-fg:var(--terminal-foreground)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.fixed{position:fixed}.relative{position:relative}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.block{display:block}.hidden{display:none}.inline{display:inline}.overflow-y-auto{overflow-y:auto}.border{border-style:var(--tw-border-style);border-width:1px}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.select-all{-webkit-user-select:all;user-select:all}}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-cyrillic-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-greek-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-greek-wght-normal.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-vietnamese-wght-normal.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--bg:oklch(98.5% .004 275);--surface:oklch(100% 0 0);--text:oklch(18% .02 275);--brand:oklch(56.7% .158 275);--on-brand:oklch(100% 0 0);--success:oklch(58% .15 150);--warning:oklch(70% .13 75);--danger:oklch(55% .2 25);--info:oklch(58% .13 250);--overlay-base:oklch(0% 0 0);--background:oklch(98.5% .004 275);--foreground:oklch(18% .02 275);--primary:oklch(56.7% .158 275);--primary-foreground:oklch(100% 0 0);--panel-bg:oklch(100% 0 0);--destructive:oklch(55% .2 25);--ring:oklch(56.7% .158 275);--border:oklch(89.65% .0058 275);--input:oklch(89.65% .0058 275);--sidebar-bg:oklch(98.5% .004 275);--sidebar-foreground:oklch(18% .02 275);--sidebar-accent-fg:oklch(18% .02 275);--sidebar-accent:oklch(94.5% .004 275);--sidebar-hover-bg:oklch(94.5% .004 275);--login-path-stroke:oklch(56.7% .158 275);--progress-bar-end:oklch(56.7% .158 275);--destructive-fg:oklch(100% 0 0);--success-fg:oklch(100% 0 0);--info-fg:oklch(100% 0 0);--warning-fg:oklch(20% .05 75);--terminal-foreground:oklch(85% .08 155);--terminal-hover:oklch(85% .08 155/.06);--muted-foreground:oklch(52.62% .0131 275);--secondary-foreground:oklch(30.08% .0176 275);--sidebar-muted:oklch(52.62% .0131 275);--focus-ring:oklch(56.7% .158 275/.5);--muted:oklch(95% .004 275);--secondary:oklch(93.5% .004 275);--label-surface:oklch(96.3% .004 275);--panel-border:oklch(89.65% .0058 275);--primary-hover:oklch(62.7% .158 275);--sidebar-active-bg:oklch(56.7% .158 275/.12);--sidebar-active-fg:oklch(48.7% .158 275);--sidebar-border:oklch(89.65% .0058 275);--terminal-bg:oklch(14% .02 264);--warning-soft-fg:oklch(42% .12 75);--progress-bar-start:oklch(74.02% .0948 275);--login-left-bg:oklch(93.5% .004 275);--primary-a5:oklch(56.7% .158 275/.05);--primary-a10:oklch(56.7% .158 275/.1);--primary-a15:oklch(56.7% .158 275/.15);--primary-a20:oklch(56.7% .158 275/.2);--primary-a25:oklch(56.7% .158 275/.25);--primary-a60:oklch(56.7% .158 275/.6);--primary-a70:oklch(56.7% .158 275/.7);--primary-a90:oklch(56.7% .158 275/.9);--destructive-a8:oklch(55% .2 25/.08);--destructive-a10:oklch(55% .2 25/.1);--destructive-a20:oklch(55% .2 25/.2);--destructive-a30:oklch(55% .2 25/.3);--destructive-a40:oklch(55% .2 25/.4);--destructive-a50:oklch(55% .2 25/.5);--destructive-a60:oklch(55% .2 25/.6);--destructive-a70:oklch(55% .2 25/.7);--destructive-a80:oklch(55% .2 25/.8);--destructive-a90:oklch(55% .2 25/.9);--foreground-a5:oklch(18% .02 275/.05);--foreground-a30:oklch(18% .02 275/.3);--secondary-a80:oklch(93.5% .004 275/.8);--muted-a30:oklch(95% .004 275/.3);--muted-a80:oklch(95% .004 275/.8);--muted-foreground-a70:oklch(52.62% .0131 275/.7);--success-a10:oklch(58% .15 150/.1);--success-a15:oklch(58% .15 150/.15);--success-a30:oklch(58% .15 150/.3);--success-a40:oklch(58% .15 150/.4);--success-a80:oklch(58% .15 150/.8);--warning-a10:oklch(70% .13 75/.1);--warning-a15:oklch(70% .13 75/.15);--warning-a30:oklch(70% .13 75/.3);--warning-a40:oklch(70% .13 75/.4);--info-a10:oklch(58% .13 250/.1);--info-a15:oklch(58% .13 250/.15);--info-a30:oklch(58% .13 250/.3);--info-a40:oklch(58% .13 250/.4);--info-a80:oklch(58% .13 250/.8);--border-a60:oklch(89.65% .0058 275/.6);--border-a80:oklch(89.65% .0058 275/.8);--input-a30:oklch(89.65% .0058 275/.3);--label-surface-a50:oklch(96.3% .004 275/.5);--overlay-base-a50:oklch(0% 0 0/.5);--overlay-base-a60:oklch(0% 0 0/.6);--background-a60:oklch(98.5% .004 275/.6);--ring-a50:oklch(56.7% .158 275/.5);--font-sans:"Inter Variable", ui-sans-serif, system-ui, sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;--radius-base:.5rem;--shadow-sm:0 1px 3px 0 oklch(0% 0 0/.1), 0 1px 2px -1px oklch(0% 0 0/.1)}[data-darkmode=true]{--bg:oklch(15.9% .005 264);--surface:oklch(20.5% .004 264);--text:oklch(90% .006 264);--brand:oklch(56.7% .158 275);--on-brand:oklch(100% 0 0);--success:oklch(63.7% .175 147);--warning:oklch(80% .12 80);--danger:oklch(63% .16 25);--info:oklch(70% .1 250);--overlay-base:oklch(0% 0 0);--background:oklch(15.9% .005 264);--foreground:oklch(90% .006 264);--primary:oklch(56.7% .158 275);--primary-foreground:oklch(100% 0 0);--panel-bg:oklch(20.5% .004 264);--destructive:oklch(63% .16 25);--ring:oklch(56.7% .158 275);--border:oklch(26.27% .0051 264);--input:oklch(26.27% .0051 264);--sidebar-bg:oklch(15.9% .005 264);--sidebar-foreground:oklch(90% .006 264);--sidebar-accent-fg:oklch(90% .006 264);--sidebar-accent:oklch(23% .004 264);--sidebar-hover-bg:oklch(23% .004 264);--login-path-stroke:oklch(56.7% .158 275);--progress-bar-end:oklch(56.7% .158 275);--destructive-fg:oklch(100% 0 0);--success-fg:oklch(100% 0 0);--info-fg:oklch(100% 0 0);--warning-fg:oklch(20% .05 75);--terminal-foreground:oklch(85% .08 155);--terminal-hover:oklch(85% .08 155/.06);--muted-foreground:oklch(58.14% .0056 264);--secondary-foreground:oklch(78.89% .0059 264);--sidebar-muted:oklch(58.14% .0056 264);--focus-ring:oklch(56.7% .158 275/.5);--muted:oklch(18.9% .005 264);--secondary:oklch(22.5% .004 264);--label-surface:oklch(19.5% .004 264);--panel-border:oklch(90% .006 264/.08);--primary-hover:oklch(62.7% .158 275);--sidebar-active-bg:oklch(56.7% .158 275/.14);--sidebar-active-fg:oklch(78.7% .158 275);--sidebar-border:oklch(90% .006 264/.08);--terminal-bg:oklch(12% .02 264);--warning-soft-fg:oklch(86% .1 85);--progress-bar-start:oklch(42.22% .0964 274.8);--login-left-bg:oklch(13.4% .005 264);--primary-a5:oklch(56.7% .158 275/.05);--primary-a10:oklch(56.7% .158 275/.1);--primary-a15:oklch(56.7% .158 275/.15);--primary-a20:oklch(56.7% .158 275/.2);--primary-a25:oklch(56.7% .158 275/.25);--primary-a60:oklch(56.7% .158 275/.6);--primary-a70:oklch(56.7% .158 275/.7);--primary-a90:oklch(56.7% .158 275/.9);--destructive-a8:oklch(63% .16 25/.08);--destructive-a10:oklch(63% .16 25/.1);--destructive-a20:oklch(63% .16 25/.2);--destructive-a30:oklch(63% .16 25/.3);--destructive-a40:oklch(63% .16 25/.4);--destructive-a50:oklch(63% .16 25/.5);--destructive-a60:oklch(63% .16 25/.6);--destructive-a70:oklch(63% .16 25/.7);--destructive-a80:oklch(63% .16 25/.8);--destructive-a90:oklch(63% .16 25/.9);--foreground-a5:oklch(90% .006 264/.05);--foreground-a30:oklch(90% .006 264/.3);--secondary-a80:oklch(22.5% .004 264/.8);--muted-a30:oklch(18.9% .005 264/.3);--muted-a80:oklch(18.9% .005 264/.8);--muted-foreground-a70:oklch(58.14% .0056 264/.7);--success-a10:oklch(63.7% .175 147/.1);--success-a15:oklch(63.7% .175 147/.15);--success-a30:oklch(63.7% .175 147/.3);--success-a40:oklch(63.7% .175 147/.4);--success-a80:oklch(63.7% .175 147/.8);--warning-a10:oklch(80% .12 80/.1);--warning-a15:oklch(80% .12 80/.15);--warning-a30:oklch(80% .12 80/.3);--warning-a40:oklch(80% .12 80/.4);--info-a10:oklch(70% .1 250/.1);--info-a15:oklch(70% .1 250/.15);--info-a30:oklch(70% .1 250/.3);--info-a40:oklch(70% .1 250/.4);--info-a80:oklch(70% .1 250/.8);--border-a60:oklch(26.27% .0051 264/.6);--border-a80:oklch(26.27% .0051 264/.8);--input-a30:oklch(26.27% .0051 264/.3);--label-surface-a50:oklch(19.5% .004 264/.5);--overlay-base-a50:oklch(0% 0 0/.5);--overlay-base-a60:oklch(0% 0 0/.6);--background-a60:oklch(15.9% .005 264/.6);--ring-a50:oklch(56.7% .158 275/.5)}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea){scrollbar-color:var(--foreground-a30) transparent;scrollbar-width:thin}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar{width:8px;height:8px}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-track{background-color:#0000}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-corner{background-color:#0000}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-thumb{background-color:var(--foreground-a30);border-radius:9999px}html{background-color:var(--background);font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground)}html body{flex-wrap:wrap;height:100dvh;display:flex}html body.modal-overlay-active{overflow:hidden}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--foreground)}h1{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}h2{margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}h5{margin-bottom:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}h6{margin-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}hr{margin-block:calc(var(--spacing) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border)}strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}abbr{cursor:help}p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--foreground)}pre{border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--muted);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-wrap:break-word;white-space:pre-wrap;color:var(--muted-foreground);display:block}code{border-radius:calc(var(--radius-base) * .5);background-color:var(--muted);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground)}a{color:var(--primary);text-decoration-line:none}@media (hover:hover){a:hover{text-decoration-line:underline}}var{font-family:var(--font-mono);color:var(--primary)}small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--muted-foreground)}em{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground);font-style:italic}#sidebar{background-color:var(--sidebar-bg);width:220px;height:100%;transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-direction:column;flex-shrink:0;transition-duration:.2s;display:flex;overflow:hidden}@media not all and (width>=48rem){#sidebar{top:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0);z-index:40;--tw-translate-x:-100%;width:240px;translate:var(--tw-translate-x) var(--tw-translate-y);--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));height:100dvh;position:fixed}#sidebar[data-drawer-open=true]{--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}}#sidebar .icon-expand{display:none}@media (width>=48rem){html[data-sidebar-collapsed=true] #sidebar{width:calc(var(--spacing) * 12)}html[data-sidebar-collapsed=true] #sidebar .sidebar-brand-text,html[data-sidebar-collapsed=true] #sidebar .sidebar-label,html[data-sidebar-collapsed=true] #sidebar .sidebar-chevron,html[data-sidebar-collapsed=true] #sidebar .icon-collapse{display:none}html[data-sidebar-collapsed=true] #sidebar .icon-expand{display:block}html[data-sidebar-collapsed=true] #sidebar .sidebar-accordion-sub{display:none!important}}.sidebar-header{height:calc(var(--spacing) * 14);padding-inline:calc(var(--spacing) * 3);flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.sidebar-brand{min-width:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * 2);text-overflow:ellipsis;white-space:nowrap;color:var(--sidebar-foreground);flex:1;text-decoration-line:none;display:flex;overflow:hidden}.sidebar-logo{flex-shrink:0}.sidebar-brand-text{text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);overflow:hidden}.sidebar-toggle{height:calc(var(--spacing) * 7);width:calc(var(--spacing) * 7);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-toggle:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-toggle svg,.sidebar-toggle img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-nav{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex:1;overflow:hidden auto}.sidebar-nav-item,.sidebar-accordion-item{margin-bottom:calc(var(--spacing) * .5)}:is(.sidebar-nav-item,.sidebar-accordion-item).active>.sidebar-nav-parent{color:var(--sidebar-active-fg)}.sidebar-nav-parent{cursor:pointer;appearance:none;justify-content:flex-start;align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;transition-duration:.15s;display:flex}.sidebar-nav-parent:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-nav-parent .sidebar-icon{flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-nav-parent .sidebar-icon svg,.sidebar-nav-parent .sidebar-icon img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-nav-parent .sidebar-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.sidebar-nav-parent .sidebar-chevron{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-shrink:0;margin-left:auto;transition-duration:.2s}.sidebar-nav-parent .sidebar-chevron svg,.sidebar-nav-parent .sidebar-chevron img{height:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5)}.sidebar-accordion-item[data-open=true]>.sidebar-nav-parent{background-color:var(--sidebar-active-bg);color:var(--sidebar-active-fg)}.sidebar-accordion-item[data-open=true] .sidebar-chevron{rotate:180deg}.sidebar-accordion-sub{visibility:hidden;opacity:0;transition-property:grid-template-rows,opacity,visibility;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out);grid-template-rows:0fr;display:grid;overflow:hidden}.sidebar-accordion-sub>*{min-height:calc(var(--spacing) * 0);align-self:flex-start}.sidebar-accordion-item[data-open=true]>.sidebar-accordion-sub{visibility:visible;opacity:1;grid-template-rows:1fr}.sidebar-sub-list{margin-left:calc(var(--spacing) * 4);border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--sidebar-border);padding-left:calc(var(--spacing) * 2);list-style-type:none}.sidebar-sub-item{margin-bottom:calc(var(--spacing) * .5)}.sidebar-sub-item.active .sidebar-sub-link{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-sub-link{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:block}.sidebar-sub-link:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-collapsed-popover{z-index:50;min-width:calc(var(--spacing) * 44);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding-block:calc(var(--spacing) * 1);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);position:fixed;overflow:hidden}.sidebar-collapsed-popover-title{padding-inline:calc(var(--spacing) * 3);padding-top:calc(var(--spacing) * 1.5);padding-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.sidebar-collapsed-popover-list{margin:calc(var(--spacing) * 0);padding:calc(var(--spacing) * 0);list-style-type:none}.sidebar-collapsed-popover-link{margin-inline:calc(var(--spacing) * 1);border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:block}.sidebar-collapsed-popover-link:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-collapsed-popover-link.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--sidebar-border);padding:calc(var(--spacing) * 2);padding-bottom:max(.5rem, env(safe-area-inset-bottom));flex-shrink:0}.sidebar-logout{align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:calc(var(--radius-base) * .75);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:flex}.sidebar-logout:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-logout.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-logout .sidebar-icon{flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-logout .sidebar-icon svg,.sidebar-logout .sidebar-icon img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-logout .sidebar-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}#main-wrapper{background-color:var(--background);height:100%;padding-block:calc(var(--spacing) * 2);padding-right:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 0);flex-direction:column;flex:1;display:flex;overflow:hidden}@media not all and (width>=48rem){#main-wrapper{padding:calc(var(--spacing) * 0);flex-basis:100%}}.content-card{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;flex:1;display:flex;overflow:hidden}@media not all and (width>=48rem){.content-card{--tw-border-style:none;--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-style:none;border-radius:0}}.card-header{height:calc(var(--spacing) * 12);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);padding-inline:calc(var(--spacing) * 4);flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.card-header-left,.card-header-right{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.topbar-hamburger{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;justify-content:center;align-items:center;display:none}@media not all and (width>=48rem){.topbar-hamburger{display:flex}}.topbar-hamburger:hover{background-color:var(--muted)}.topbar-hamburger svg,.topbar-hamburger img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5)}.topbar-breadcrumb{align-items:center;gap:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:flex}.topbar-breadcrumb .breadcrumb-item{color:var(--muted-foreground)}.topbar-breadcrumb .breadcrumb-item.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground)}.topbar-breadcrumb .breadcrumb-sep{color:var(--muted-foreground)}.topbar-breadcrumb .breadcrumb-sep svg,.topbar-breadcrumb .breadcrumb-sep img{height:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5)}button.topbar-icon-btn{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}button.topbar-icon-btn:hover{background-color:var(--muted);color:var(--foreground)}button.topbar-icon-btn img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);flex-shrink:0}.topbar-indicators{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.topbar-indicators span[data-indicator]>img{display:none}.topbar-indicators span[data-indicator]{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));flex-shrink:0;justify-content:center;align-items:center;font-size:0;display:inline-flex;position:relative}.topbar-indicators span[data-indicator]:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;flex-shrink:0;display:block;position:relative;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.topbar-indicators span[data-indicator]:hover{background-color:var(--muted);color:var(--foreground)}.topbar-indicators span[data-indicator][data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%200%201%209-9%209.75%209.75%200%200%201%206.74%202.74L21%208'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M21%2012a9%209%200%200%201-9%209%209.75%209.75%200%200%201-6.74-2.74L3%2016'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%200%201%209-9%209.75%209.75%200%200%201%206.74%202.74L21%208'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M21%2012a9%209%200%200%201-9%209%209.75%209.75%200%200%201-6.74-2.74L3%2016'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw-off'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%208L18.74%205.74A9.75%209.75%200%200%200%2012%203C11%203%2010.03%203.16%209.13%203.47'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3cpath%20d='M3%2012C3%209.51%204%207.26%205.64%205.64'/%3e%3cpath%20d='m3%2016%202.26%202.26A9.75%209.75%200%200%200%2012%2021c2.49%200%204.74-1%206.36-2.64'/%3e%3cpath%20d='M21%2012c0%201-.16%201.97-.47%202.87'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M22%2022%202%202'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw-off'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%208L18.74%205.74A9.75%209.75%200%200%200%2012%203C11%203%2010.03%203.16%209.13%203.47'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3cpath%20d='M3%2012C3%209.51%204%207.26%205.64%205.64'/%3e%3cpath%20d='m3%2016%202.26%202.26A9.75%209.75%200%200%200%2012%2021c2.49%200%204.74-1%206.36-2.64'/%3e%3cpath%20d='M21%2012c0%201-.16%201.97-.47%202.87'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M22%2022%202%202'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=media_error]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-alert-circle'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cline%20x1='12'%20x2='12'%20y1='8'%20y2='12'/%3e%3cline%20x1='12'%20x2='12.01'%20y1='16'%20y2='16'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-alert-circle'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cline%20x1='12'%20x2='12'%20y1='8'%20y2='12'/%3e%3cline%20x1='12'%20x2='12.01'%20y1='16'%20y2='16'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=uci-changes]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-settings'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915'%20/%3e%3ccircle%20cx='12'%20cy='12'%20r='3'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-settings'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915'%20/%3e%3ccircle%20cx='12'%20cy='12'%20r='3'%20/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=uci-changes][data-count]:not([data-count="0"]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -.5);content:var(--tw-content);z-index:10;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 3);content:var(--tw-content);min-width:calc(var(--spacing) * 3);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--primary);content:var(--tw-content);padding-inline:calc(var(--spacing) * .5);content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);--tw-font-weight:var(--font-weight-bold);font-size:8px;line-height:1;font-weight:var(--font-weight-bold);content:var(--tw-content);color:var(--primary-foreground);--tw-content:attr(data-count);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:flex;position:absolute}#maincontent{padding:calc(var(--spacing) * 6);flex:1;overflow-y:auto}@media not all and (width>=48rem){#maincontent{padding:calc(var(--spacing) * 4)}}#maincontent h1{margin-bottom:calc(var(--spacing) * 4);border-style:var(--tw-border-style);padding-left:calc(var(--spacing) * 0);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);border-width:0}#maincontent h2{margin-bottom:calc(var(--spacing) * 3);border-style:var(--tw-border-style);padding-left:calc(var(--spacing) * 0);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);border-width:0}#maincontent h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--muted-foreground)}#maincontent .cbi-page-actions{margin-top:calc(var(--spacing) * 4);justify-content:flex-end;align-items:center;gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding-top:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}#maincontent div[style]>svg:where([data-darkmode=true],[data-darkmode=true] *){background-color:var(--surface)!important}#maincontent div[style]>svg line[style]:where([data-darkmode=true],[data-darkmode=true] *){stroke:var(--text)!important}#maincontent .zone-forwards{align-items:stretch;gap:calc(var(--spacing) * 2);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);flex-wrap:nowrap;display:flex}#maincontent .zone-forwards>span{flex-shrink:0;flex-basis:calc(var(--spacing) * 8);color:var(--muted-foreground);justify-content:center;align-self:center;align-items:center;display:flex}#maincontent .zone-forwards .zone-src,#maincontent .zone-forwards .zone-dest{gap:calc(var(--spacing) * 1.5);flex-direction:column;flex:1;display:flex}#maincontent .controls{align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}#maincontent .controls label input[type=radio],#maincontent .controls label input[type=checkbox]{margin-right:calc(var(--spacing) * 1);vertical-align:middle}#maincontent .cbi-title-section{margin-bottom:calc(var(--spacing) * 4);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}#maincontent .control-group{margin-top:calc(var(--spacing) * 1)}#maincontent .control-group,#maincontent .cbi-page-actions>div,#maincontent .cbi-section-actions>div{align-items:center;gap:calc(var(--spacing) * 2);flex-flow:row;display:flex}#sidebar-overlay{pointer-events:none;inset:calc(var(--spacing) * 0);z-index:30;background-color:var(--overlay-base-a50);opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;position:absolute}@media (width>=48rem){#sidebar-overlay{display:none}}#sidebar-overlay.active{pointer-events:auto;opacity:1}button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;border-width:1px;transition-duration:.2s;display:inline-flex}:is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button)[disabled]{cursor:not-allowed;opacity:.4}.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){white-space:nowrap}.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down{border-color:var(--secondary);background-color:var(--secondary);color:var(--secondary-foreground)}@media (hover:hover){:is(.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down):hover{background-color:var(--secondary-a80)}}.drag-handle{border-color:var(--muted);background-color:var(--muted);color:var(--muted-foreground)}@media (hover:hover){.drag-handle:hover{background-color:var(--muted-a80)}}.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit{border-color:var(--primary);background-color:var(--primary);color:var(--primary-foreground)}@media (hover:hover){:is(.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit):hover{background-color:var(--primary-a90)}}.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save{border-color:var(--primary-a25);background-color:var(--primary-a15);color:var(--primary)}@media (hover:hover){:is(.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save):hover{background-color:var(--primary-a25)}}.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove{border-color:var(--destructive);background-color:var(--destructive);color:var(--destructive-fg)}@media (hover:hover){:is(.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove):hover{background-color:var(--destructive-a90)}}input:disabled{cursor:not-allowed;opacity:.4}input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input{width:calc(var(--spacing) * 52.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);max-width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;position:relative}:is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input)::placeholder{color:var(--muted-foreground-a70)}:is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input):focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}.table.cbi-section-table :is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input){width:100%}.cbi-input-text{min-width:calc(var(--spacing) * 20)}#localtime{min-width:calc(var(--spacing) * 64)}textarea{min-height:calc(var(--spacing) * 24);resize:vertical;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}textarea::placeholder{color:var(--muted-foreground-a70)}textarea:focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}textarea[disabled]{cursor:not-allowed;opacity:.4}input[type=radio],input[type=checkbox]{margin-right:calc(var(--spacing) * 3);height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);cursor:pointer;appearance:none;vertical-align:middle;display:inline-block;position:relative}:is(input[type=radio],input[type=checkbox]):disabled{cursor:not-allowed}:is(input[type=radio],input[type=checkbox]):before{content:var(--tw-content);content:var(--tw-content);inset:calc(var(--spacing) * 0);content:var(--tw-content);border-radius:calc(var(--radius-base) * .5);content:var(--tw-content);border-style:var(--tw-border-style);content:var(--tw-content);border-width:1px;border-color:var(--input);content:var(--tw-content);background-color:var(--background);content:var(--tw-content);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.2s;transition-duration:.2s;position:absolute}:is(input[type=radio],input[type=checkbox]):after{content:var(--tw-content);content:var(--tw-content);inset:calc(var(--spacing) * 0);content:var(--tw-content);background-color:var(--primary-foreground);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);opacity:0;content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.2s;transition-duration:.2s;position:absolute;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}:is(input[type=radio],input[type=checkbox]):checked:before{content:var(--tw-content);border-color:var(--primary);content:var(--tw-content);background-color:var(--primary)}:is(input[type=radio],input[type=checkbox]):checked:after{content:var(--tw-content);opacity:1}:is(input[type=radio],input[type=checkbox]):focus:before{content:var(--tw-content);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);--tw-ring-color:var(--ring);content:var(--tw-content);--tw-outline-style:none;outline-style:none}input[type=radio]:before{content:var(--tw-content);border-radius:3.40282e38px}input[type=radio]:after{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e")}input[type=checkbox]:after{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e")}.cbi-checkbox{vertical-align:middle;align-items:center;display:inline-flex;position:relative}select{max-width:100%;min-width:calc(var(--spacing) * 52.5);appearance:none;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 9);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}select:focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}select:disabled{cursor:not-allowed;opacity:.4}@media (width>=48rem){select{max-width:calc(var(--spacing) * 100)}}select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238888a0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-position:right .6rem center;background-repeat:no-repeat;background-size:16px}[data-darkmode=true] select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238c8ca8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}.cbi-dropdown{min-width:fit-content;max-width:100%;height:fit-content;padding:calc(var(--spacing) * 0);white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-shrink:0;align-items:center;transition-duration:.2s;display:inline-flex;position:relative}.cbi-dropdown[disabled]{pointer-events:none;opacity:.4}.cbi-dropdown:not(.btn):not(.cbi-button){max-width:100%;min-width:calc(var(--spacing) * 52.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background)}@media (width>=48rem){.cbi-dropdown:not(.btn):not(.cbi-button){max-width:calc(var(--spacing) * 100)}}.cbi-dropdown:not(.btn):not(.cbi-button)>ul>li[placeholder]{display:none}.cbi-dropdown>ul{margin:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * .5);flex-wrap:nowrap;flex:1;list-style-type:none;display:flex;overflow:hidden}.cbi-dropdown>ul>li{margin:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * 1);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);list-style-type:none;display:none;overflow:hidden}.cbi-dropdown>ul>li[display]{display:flex!important}.cbi-dropdown>ul>li .hide-open{display:block}.cbi-dropdown>ul>li .hide-close{display:none}.cbi-dropdown>ul>li>form{pointer-events:none;display:none}.cbi-dropdown>ul>li>label{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.cbi-dropdown>ul>li img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);vertical-align:middle;flex:none}.cbi-dropdown>ul>li span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.cbi-dropdown>ul.dropdown{left:calc(var(--spacing) * 0);z-index:50;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);width:fit-content;min-width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);position:absolute;overflow-y:auto}.cbi-dropdown>ul.dropdown>li{min-height:calc(var(--spacing) * 9);cursor:pointer;width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground)}@media (hover:hover){.cbi-dropdown>ul.dropdown>li:hover{background-color:var(--muted)}}.cbi-dropdown>ul.preview{display:none}.cbi-dropdown[empty]>ul{max-width:1px;max-height:1px}.cbi-dropdown[empty]>ul>li,.cbi-dropdown[optional][open]>ul.dropdown>li[placeholder]{display:block}.cbi-dropdown[open]{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring)}.cbi-dropdown[open]>ul.dropdown{width:auto;max-width:none;display:block}.cbi-dropdown[open]>ul.dropdown>li{display:flex}.cbi-dropdown[open]>ul.dropdown>li[selected]{background-color:var(--primary-a15);color:var(--primary)}.cbi-dropdown[open]>ul.dropdown>li[unselectable]{opacity:.4}.cbi-dropdown[open]>ul.dropdown>li .hide-open{display:none}.cbi-dropdown[open]>ul.dropdown>li .hide-close{display:block}.cbi-dropdown[open]>ul.preview{display:flex}:is(.cbi-dropdown[multiple][more],.cbi-dropdown[multiple][empty])>.more{padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);flex:none;display:flex}.cbi-dropdown[multiple][empty]>.more{flex:1}.cbi-dropdown[multiple][open]>ul.dropdown>li>form{align-items:center;display:flex}.cbi-dropdown[multiple]>ul>li>label{display:flex}.cbi-dropdown>.open{cursor:pointer;border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--input);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:currentColor;flex:none;justify-content:center;align-items:center;display:flex}.cbi-dropdown>.more{display:none}.cbi-tooltip{z-index:50;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border-a60);background-color:var(--panel-bg);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--foreground);opacity:0;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out);position:absolute;inset-inline-start:-10000px}.cbi-tooltip.error{border-color:var(--destructive-a40);background-color:var(--destructive);color:var(--destructive-fg)}.cbi-tooltip.success{border-color:var(--success-a40);background-color:var(--success);color:var(--success-fg)}.cbi-tooltip.info{border-color:var(--info-a40);background-color:var(--info);color:var(--info-fg)}.cbi-tooltip.notice{border-color:var(--warning-a40);background-color:var(--warning);color:var(--warning-fg)}.cbi-tooltip-container,[data-tooltip]{cursor:help;white-space:nowrap;text-underline-offset:2px;transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;transition-duration:.2s;display:inline-block;position:relative}:is(.cbi-tooltip-container,[data-tooltip]) .cbi-tooltip{visibility:hidden;--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:0;transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out)}:is(.cbi-tooltip-container,[data-tooltip]):hover .cbi-tooltip{visibility:visible;--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;inset-inline-start:auto}.alert-message{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);background-color:var(--muted);padding:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);border-width:1px}.alert-message.success{border-color:var(--success-a30);background-color:var(--success-a10);color:var(--success)}.alert-message.info{border-color:var(--info-a30);background-color:var(--info-a10);color:var(--info)}.alert-message.warning,.alert-message.notice{border-color:var(--warning-a30);background-color:var(--warning-a10);color:var(--warning-soft-fg)}.alert-message.error,.alert-message.danger{border-color:var(--destructive-a30);background-color:var(--destructive-a10);color:var(--destructive)}.alert-message h4,.alert-message h5,.alert-message pre,.alert-message ul,.alert-message li,.alert-message p{border-style:var(--tw-border-style);color:inherit;background-color:#0000;border-width:0}.alert-message h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.alert-message .right{margin-top:calc(var(--spacing) * 3)}.cbi-progressbar{height:calc(var(--spacing) * 2.5);cursor:help;background-color:var(--secondary);border-radius:3.40282e38px;width:100%;position:relative;overflow:hidden}.cbi-progressbar:before{content:var(--tw-content);content:var(--tw-content);inset-inline:calc(var(--spacing) * 0);content:var(--tw-content);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);text-align:center;content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);white-space:nowrap;content:var(--tw-content);color:var(--foreground);--tw-content:attr(title);content:var(--tw-content);font-size:10px;line-height:1;position:absolute;top:50%}.cbi-progressbar>div{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-bar-start);--tw-gradient-to:var(--progress-bar-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));height:100%;transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;transition-duration:.3s}.label{background-color:var(--muted);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--muted-foreground);border-radius:3.40282e38px;align-items:center;display:inline-flex}.label.important{background-color:var(--info-a15);color:var(--info)}.label.warning{background-color:var(--warning-a15);color:var(--warning-soft-fg)}.label.success{background-color:var(--success-a15);color:var(--success)}.label.notice{background-color:var(--warning-a15);color:var(--warning-soft-fg)}.zonebadge{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--secondary);background-color:var(--secondary);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--secondary-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;display:inline-flex;overflow:visible}.zonebadge[style*=--zone-color-rgb]{border-color:#0000;background-color:rgb(var(--zone-color-rgb),.6)!important}.zonebadge.zonebadge-empty{--tw-border-style:dashed;border-style:dashed;border-color:var(--border);--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--muted-foreground);background-color:#0000;font-style:italic}.ifacebadge>.zonebadge{padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * .5);border-radius:3.40282e38px}.cbi-dropdown .zonebadge{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.ifacebadge{cursor:default;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-wrap:nowrap;transition-duration:.2s;display:inline-flex}.zonebadge>.ifacebadge{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * 0)}.zonebadge>.ifacebadge img{margin-right:calc(var(--spacing) * 1);width:calc(var(--spacing) * 4)}.cbi-dropdown .ifacebadge{gap:calc(var(--spacing) * 1);border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.cbi-dropdown .ifacebadge img{margin-right:calc(var(--spacing) * 1);width:calc(var(--spacing) * 4)}.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}.ifacebadge>span .nowrap{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}.ifacebadge.ifacebadge-active{border-color:var(--primary);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.ifacebadge.large{min-width:calc(var(--spacing) * 48);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex:1}.cbi-section{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);padding:calc(var(--spacing) * 4);overflow:visible}.cbi-section[data-tab-title]{margin:calc(var(--spacing) * 0);padding:calc(var(--spacing) * 0)}.cbi-section[data-tab-active=true]{margin-bottom:calc(var(--spacing) * 4);padding:calc(var(--spacing) * 4)}.cbi-section>.cbi-title{justify-content:space-between;align-items:flex-start;display:flex}.cbi-section>.cbi-title>h3{flex:1}.cbi-section>.cbi-title>h3 .label[data-clickable]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * .5);background-color:var(--label-surface);padding:calc(var(--spacing) * 0);color:var(--foreground);justify-content:center;align-items:center;display:inline-flex}@media (hover:hover){.cbi-section>.cbi-title>h3 .label[data-clickable]:hover{background-color:var(--muted)}}.cbi-section>.cbi-title>h3 .label[data-clickable]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);cursor:pointer;font-size:0;position:relative}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-down'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m6%209%206%206%206-6'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-down'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m6%209%206%206%206-6'%20/%3e%3c/svg%3e")}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-up'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m18%2015-6-6-6%206'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-up'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m18%2015-6-6-6%206'%20/%3e%3c/svg%3e")}.cbi-section legend{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.cbi-section h3{margin-bottom:calc(var(--spacing) * 3);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-bottom:calc(var(--spacing) * 3);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.cbi-section .cbi-section-create{margin-top:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}.cbi-section .cbi-section-create>div{flex:none}.cbi-section .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}@media (width>=48rem){.cbi-section .network-status-table{flex-wrap:nowrap}}.cbi-section div[style*=display\:grid]:has(>.ifacebox){place-items:center}.ifacebox{min-width:calc(var(--spacing) * 32);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);flex-direction:column;align-items:stretch;display:inline-flex;position:relative;overflow:visible}@media (width>=48rem){#cbi-network-interface .ifacebox{min-width:calc(var(--spacing) * 38)}}.ifacebox .ifacebox-head{border-top-left-radius:var(--radius-base);border-top-right-radius:var(--radius-base);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--label-surface);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}.ifacebox .ifacebox-head[style*=--zone-color-rgb]{background-color:rgb(var(--zone-color-rgb),.65)!important}.ifacebox .ifacebox-head.cbi-tooltip-container{background-color:#0000;position:static}.ifacebox .ifacebox-head.cbi-tooltip-container .cbi-tooltip{bottom:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0)}.ifacebox .ifacebox-head.active{border-color:var(--primary);background-color:var(--primary);color:var(--primary-foreground)}.ifacebox .ifacebox-body{justify-content:center;align-items:stretch;gap:calc(var(--spacing) * 1);border-bottom-right-radius:var(--radius-base);border-bottom-left-radius:var(--radius-base);width:100%;padding:calc(var(--spacing) * 3);text-align:center;color:var(--foreground);flex-direction:column;flex:1;display:flex}.ifacebox .ifacebox-body>img{width:calc(var(--spacing) * 5);margin-inline:auto}:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span .cbi-tooltip{--tw-animation-delay:.2s;transition-delay:.2s;animation-delay:.2s}.ifacebox .ifacebox-body>span .nowrap{display:inline-block}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5);flex-shrink:0}.ifacebox .ifacebox-body>div{width:100%;display:block}:where(.ifacebox .ifacebox-body>div>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body .cbi-tooltip-container{cursor:help;color:var(--foreground);justify-content:center;align-items:center;display:inline-flex;position:static}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{bottom:calc(var(--spacing) * 0)}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip .nowrap{white-space:nowrap}.ifacebox .ifacebox-body small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4);display:block}.network-status-table .ifacebox-body{justify-content:space-around;align-items:center;gap:calc(var(--spacing) * 2);flex-direction:column;flex:1;height:100%;display:flex}.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}.network-status-table .ifacebox-body .ifacebadge{min-width:calc(var(--spacing) * 55);flex:1}#modal_overlay{pointer-events:none;top:calc(var(--spacing) * 0);bottom:calc(var(--spacing) * 0);background-color:#0000;display:none;position:fixed;overflow:auto}.modal-overlay-active #modal_overlay{pointer-events:auto;inset:calc(var(--spacing) * 0);z-index:50;background-color:var(--overlay-base-a60);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);place-items:center;display:grid}#modal_overlay>.modal{width:100%;max-width:var(--container-2xl);gap:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding:calc(var(--spacing) * 6);overflow-wrap:break-word;white-space:normal;--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-lg));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);flex-direction:column;display:flex}#modal_overlay>.modal h4{margin-bottom:calc(var(--spacing) * 0);text-align:center}#modal_overlay>.modal h4 em{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--primary)}#modal_overlay>.modal h5{margin-block:calc(var(--spacing) * 3);color:var(--foreground)}#modal_overlay>.modal p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--foreground)}#modal_overlay>.modal>ul{border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);padding:calc(var(--spacing) * 3);overflow:auto}#modal_overlay>.modal label.btn{border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);color:var(--foreground)}@media (hover:hover){#modal_overlay>.modal label.btn:hover{border-color:var(--border)}}#modal_overlay>.modal pre{overflow:auto}#modal_overlay>.modal pre.errors{border-color:var(--destructive-a60);background-color:var(--destructive-a20);color:var(--destructive)}#modal_overlay>.modal pre+pre{margin-top:calc(var(--spacing) * 3)}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding:calc(var(--spacing) * 4);flex-shrink:0;display:flex}#modal_overlay>.modal div.left{justify-content:flex-start}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.right{justify-content:flex-end}#modal_overlay>.modal.uci-dialog ins,#modal_overlay>.modal.uci-dialog del,#modal_overlay>.modal.uci-dialog var{font-family:var(--font-mono);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);font-style:normal;text-decoration-line:none}#modal_overlay>.modal.uci-dialog ins{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--success);background-color:var(--success-a80);color:var(--success-fg)}#modal_overlay>.modal.uci-dialog del{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--destructive);background-color:var(--destructive-a80);color:var(--destructive-fg)}#modal_overlay>.modal.uci-dialog var{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--info);background-color:var(--info-a80);color:var(--info-fg)}#modal_overlay>.modal.uci-dialog .uci-change-legend{margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 3);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);padding:calc(var(--spacing) * 4);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground);display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label del,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var{height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);justify-content:center;align-items:center;display:flex}#modal_overlay>.modal.uci-dialog .uci-change-list{margin-top:calc(var(--spacing) * 4)}:where(#modal_overlay>.modal.uci-dialog .uci-change-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}#modal_overlay>.modal.uci-dialog .uci-change-list h5{margin-top:calc(var(--spacing) * 4);margin-bottom:calc(var(--spacing) * 2);border-radius:var(--radius-base);background-color:var(--muted);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}#modal_overlay>.modal.uci-dialog .uci-change-list h5:first-child{margin-top:calc(var(--spacing) * 0)}#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del{border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:block}:is(#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del) strong{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}#modal_overlay>.modal.uci-dialog .uci-change-list var{border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}#modal_overlay>.modal.uci-dialog .uci-change-list var ins,#modal_overlay>.modal.uci-dialog .uci-change-list var del{margin-left:calc(var(--spacing) * 1);padding-inline:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-block:1px;display:inline-block}table.table,.table{margin-bottom:calc(var(--spacing) * 4);border-collapse:separate;--tw-border-spacing-x:calc(var(--spacing) * 0);--tw-border-spacing-y:calc(var(--spacing) * 0);width:100%;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);overflow:visible}:is(table.table,.table)[width="100%"]{width:100%}:is(table.table,.table)[width="33%"]{width:33.3333%}:is(table.table,.table) .cbi-section-table-titles{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content);content:var(--tw-content);border-bottom-style:var(--tw-border-style);content:var(--tw-content);border-bottom-width:1px;border-color:var(--border);content:var(--tw-content);padding-inline:calc(var(--spacing) * 3);content:var(--tw-content);padding-block:calc(var(--spacing) * 2.5);content:var(--tw-content);vertical-align:middle;content:var(--tw-content);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-content:attr(data-title);content:var(--tw-content);display:table-cell}:is(:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):not([data-title]),:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):has(td.cbi-section-table-titles)):before{content:var(--tw-content);--tw-content:none;content:none}:is(table.table,.table) .cbi-section-table-titles.named:before{content:var(--tw-content);border-top-left-radius:var(--radius-base);content:var(--tw-content);background-color:var(--label-surface)}:is(table.table,.table) tr,:is(table.table,.table) .tr{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}@media (hover:hover){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):hover{background-color:var(--label-surface)}}@media (width>=48rem){:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child:not([data-title]) .th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child:not([data-title]) .td):first-child{border-top-left-radius:var(--radius-base)}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .td):last-child{border-top-right-radius:var(--radius-base)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-left-radius:var(--radius-base)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td:first-child{border-bottom-left-radius:var(--radius-base)}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td:last-child{border-bottom-right-radius:var(--radius-base)}}@media not all and (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-descr{display:none}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-1{background-color:var(--panel-bg)}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-2{background-color:var(--label-surface-a50)}:is(table.table,.table) th,:is(table.table,.table) .th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{width:100%}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{width:33.3333%}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]{cursor:pointer;-webkit-user-select:none;user-select:none}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:after{content:var(--tw-content);margin-left:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}@media (hover:hover){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:hover{background-color:var(--label-surface)}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=asc]:after{--tw-content:"▲";content:var(--tw-content)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=desc]:after{--tw-content:"▼";content:var(--tw-content)}:is(table.table,.table) td,:is(table.table,.table) .td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));overflow-wrap:break-word;white-space:normal;display:table-cell}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content);--tw-content:attr(data-title);content:var(--tw-content);display:none}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=text],:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=password],:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){min-width:fit-content}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{word-break:break-all}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div>.cbi-button{flex:1}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{width:33.3333%}@media (width<=768px){table.table,.table{border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;display:block;overflow:visible}:is(table.table,.table) tbody,:is(table.table,.table) .tbody{display:block}:is(table.table,.table) tr,:is(table.table,.table) .tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}:is(table.table,.table) th,:is(table.table,.table) .th{display:none}:is(table.table,.table) td,:is(table.table,.table) .td{border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));border-width:0;flex:50%}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content);margin-bottom:calc(var(--spacing) * 1);content:var(--tw-content);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);display:block}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{margin-bottom:calc(var(--spacing) * 1);text-align:left;flex-basis:100%;align-self:flex-start}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.DummyValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.Button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.FlagValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=dvalue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=fvalue]{flex-basis:50%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions{flex:0 0 100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>.cbi-button{width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{flex:0 0 100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{flex:0 0 33.333%}}.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell{width:auto!important}#content_syslog>div{align-items:center;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}#content_syslog>div>select,#content_syslog>div>input{margin-block:calc(var(--spacing) * 0)!important}#content_syslog>.syslog-view{display:block}#syslog,#log_textarea{width:100%;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}#syslog{margin-bottom:calc(var(--spacing) * 5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--terminal-bg);padding:calc(var(--spacing) * 4);color:var(--terminal-foreground)}#content_syslog.log-enhanced>#syslog{display:none}.syslog-view{margin-bottom:calc(var(--spacing) * 5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--terminal-bg);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 4);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:1.7;color:var(--terminal-foreground);--tw-outline-style:none;outline-style:none;line-height:1.7;overflow-x:auto}.syslog-view:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring-a50)}.syslog-view .log-row{border-radius:calc(var(--radius-base) * .5);width:max-content;min-width:100%;padding-inline:calc(var(--spacing) * 2);white-space:pre}.syslog-view .log-row:hover{background-color:var(--terminal-hover)}.syslog-view ::selection{background-color:var(--info-a40)}.syslog-view .log-time{opacity:.55}.syslog-view .log-sev{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.syslog-view .log-tag{opacity:.8}@media (width>=48rem){.syslog-view .log-time,.syslog-view .log-sev,.syslog-view .log-tag{vertical-align:bottom;display:inline-block}.syslog-view .log-time{min-width:24ch}.syslog-view .log-sev{min-width:16ch}.syslog-view .log-tag{min-width:18ch}}.syslog-view .lv-info .log-sev{color:var(--info)}.syslog-view .lv-notice .log-sev{color:var(--success)}.syslog-view .lv-warn .log-sev{color:var(--warning)}.syslog-view .lv-debug{opacity:.5}.syslog-view .lv-err,.syslog-view .lv-crit{background-color:var(--destructive-a20)}:is(.syslog-view .lv-err,.syslog-view .lv-crit):hover{background-color:var(--destructive-a30)}:is(.syslog-view .lv-err,.syslog-view .lv-crit) .log-sev{color:var(--destructive)}.cbi-input-invalid,.cbi-value-error{border-color:var(--destructive-a70)!important}:is(.cbi-input-invalid,.cbi-value-error):focus{--tw-ring-color:var(--destructive-a40)!important}.cbi-value{gap:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 1.5);flex-flow:wrap;display:flex}.cbi-value.hidden{display:none}.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 3)}.cbi-value>.cbi-value-title{padding-top:calc(var(--spacing) * 1);text-align:right;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground)}@media (width>=48rem){.cbi-value>.cbi-value-title{flex:0 0 10rem}}.cbi-value>.cbi-value-field{flex:1;max-width:100%}.cbi-value>.cbi-value-field:has(>.cbi-dropdown[disabled]){cursor:not-allowed}.cbi-value>.cbi-value-field .cbi-value-description{margin-top:calc(var(--spacing) * 1);padding-left:calc(var(--spacing) * 5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:1;overflow-wrap:break-word;color:var(--muted-foreground);line-height:1;position:relative}.cbi-value>.cbi-value-field .cbi-value-description:not(:empty):before{content:var(--tw-content);content:var(--tw-content);left:calc(var(--spacing) * 0);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);background-color:var(--primary);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);display:inline-block;position:absolute;-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-info'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cpath%20d='M12%2016v-4'/%3e%3cpath%20d='M12%208h.01'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-info'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cpath%20d='M12%2016v-4'/%3e%3cpath%20d='M12%208h.01'/%3e%3c/svg%3e");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.cbi-value>.cbi-section,.cbi-value>.cbi-tblsection{width:100%}.cbi-dynlist{width:max-content;max-width:calc(var(--spacing) * 96);align-items:flex-start;gap:calc(var(--spacing) * 3);flex-direction:column;display:inline-flex}.cbi-dynlist .item{pointer-events:auto;cursor:move;align-items:flex-start;gap:calc(var(--spacing) * 2);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding-block:calc(var(--spacing) * 3);padding-right:calc(var(--spacing) * 9);padding-left:calc(var(--spacing) * 4);word-break:break-all;--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;-webkit-user-select:text;user-select:text;flex-direction:column;align-self:stretch;transition-duration:.2s;display:inline-flex;position:relative;overflow:hidden}.cbi-dynlist .item:after{content:"×";top:calc(var(--spacing) * 2);right:calc(var(--spacing) * 2);height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);cursor:pointer;border-radius:calc(var(--radius-base) * .5);background-color:var(--muted);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-dynlist .item.dragging{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);cursor:grabbing;opacity:.5;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-dynlist .item.drag-over{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y);border-color:var(--primary-a60);background-color:var(--primary-a5);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring)}.cbi-dynlist .item>span,.cbi-dynlist .item>code{pointer-events:none;border-radius:calc(var(--radius-base) * .5);width:100%;font-family:var(--font-mono);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.cbi-dynlist .placeholder{word-break:break-all}.cbi-dynlist .add-item{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * 1);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;background-color:#0000;align-self:stretch;transition-duration:.2s;display:inline-flex}@media (hover:hover){.cbi-dynlist .add-item:hover{border-color:var(--border-a80);background-color:var(--muted-a30)}}.cbi-dynlist .add-item>input{min-width:calc(var(--spacing) * 56);flex:1}.cbi-dynlist .add-item>.cbi-button{min-height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 0);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.cbi-dynlist .add-item>.cbi-button:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}@media (width<=768px){.cbi-value{gap:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * 1);flex-direction:column}.cbi-value>.cbi-value-title{text-align:left}.cbi-dynlist{max-width:100%}}.cbi-tabmenu{margin-bottom:calc(var(--spacing) * 2);min-height:calc(var(--spacing) * 9);align-items:center;gap:calc(var(--spacing) * 0);border-radius:var(--radius-base);background-color:var(--muted);width:fit-content;max-width:100%;color:var(--muted-foreground);padding:3px;display:inline-flex;overflow-x:auto}.cbi-tabmenu li{margin:calc(var(--spacing) * 0);flex-shrink:0;min-width:fit-content;list-style-type:none;position:relative}.cbi-tabmenu li[data-errors]:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -1.5);content:var(--tw-content);z-index:20;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 4);content:var(--tw-content);min-width:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--destructive);content:var(--tw-content);padding-inline:calc(var(--spacing) * 1);content:var(--tw-content);padding-block:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);color:var(--destructive-fg);--tw-content:attr(data-errors);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-tabmenu li[data-errors]>a{border-style:var(--tw-border-style);border-width:1px;border-color:var(--destructive-a50)}.cbi-tabmenu li>a{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--muted-foreground);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-width:1px;border-color:#0000;justify-content:center;align-items:center;text-decoration-line:none;display:inline-flex}@media (hover:hover){.cbi-tabmenu li>a:hover{color:var(--foreground)}}.cbi-tabmenu li>a:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring-a50);--tw-outline-style:none;outline-style:none}.cbi-tabmenu li.cbi-tab>a{background-color:var(--background);color:var(--foreground);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-tabmenu li.cbi-tab>a:where([data-darkmode=true],[data-darkmode=true] *){border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--input-a30)}[data-tab-title]{visibility:hidden;height:calc(var(--spacing) * 0);overflow:hidden}[data-tab-active=true]{visibility:visible;height:auto;overflow:visible}#tabmenu{margin-bottom:calc(var(--spacing) * 6);width:100%}.tabs{align-items:center;gap:calc(var(--spacing) * 0);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);display:flex;position:relative;overflow-x:auto}.tabs a{padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 3);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;display:block}@media (hover:hover){.tabs a:hover{color:var(--foreground);text-decoration-line:none}}.tabs>li.active{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--foreground)}.tabs>li.active>a{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.cbi-section-node-tabbed{margin-top:calc(var(--spacing) * 4)}button.cmdk-trigger{height:calc(var(--spacing) * 8);cursor:pointer;align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);padding-right:calc(var(--spacing) * 1.5);padding-left:calc(var(--spacing) * 7.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground);background-color:#0000;display:flex;position:relative}@media not all and (width>=48rem){button.cmdk-trigger{width:calc(var(--spacing) * 8);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);border-width:0;justify-content:center}}button.cmdk-trigger:before{pointer-events:none;left:calc(var(--spacing) * 2.5);width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);--tw-content:"";content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat}@media not all and (width>=48rem){button.cmdk-trigger:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);position:static}}button.cmdk-trigger:hover{border-color:var(--muted-foreground)}@media not all and (width>=48rem){button.cmdk-trigger:hover{background-color:var(--muted)}}.cmdk-trigger-label{text-overflow:ellipsis;white-space:nowrap;text-align:left;overflow:hidden}@media not all and (width>=48rem){.cmdk-trigger-label{display:none}}.cmdk-trigger-key{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);padding-block:1px}@media not all and (width>=48rem){.cmdk-trigger-key{display:none}}#cmdk-overlay{inset:calc(var(--spacing) * 0);z-index:50;background-color:var(--overlay-base-a60);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);justify-content:center;align-items:flex-start;display:flex;position:fixed}@media not all and (width>=48rem){#cmdk-overlay{--tw-backdrop-blur: ;-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);background-color:#0000}}#cmdk-overlay[hidden]{display:none}.cmdk-panel{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);width:min(560px,100vw - 32px);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);flex-direction:column;margin-top:15vh;display:flex;overflow:hidden}@starting-style{.cmdk-panel{--tw-translate-y:calc(var(--spacing) * -1.5);translate:var(--tw-translate-x) var(--tw-translate-y)}}@starting-style{.cmdk-panel{opacity:0}}@media not all and (width>=48rem){.cmdk-panel{margin-top:calc(var(--spacing) * 0);border-style:var(--tw-border-style);width:100%;height:100dvh;padding-top:env(safe-area-inset-top);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;transition-property:none}}.cmdk-inputrow{height:calc(var(--spacing) * 12);align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--panel-border);padding-right:calc(var(--spacing) * 3);padding-left:calc(var(--spacing) * 10);flex-shrink:0;display:flex;position:relative}@media not all and (width>=48rem){.cmdk-inputrow{height:calc(var(--spacing) * 14);padding-right:calc(var(--spacing) * 1.5)}}.cmdk-inputrow:before{pointer-events:none;left:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);color:var(--muted-foreground);--tw-content:"";content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat}.cmdk-inputrow:has(input.cmdk-input:placeholder-shown) button.cmdk-clear{display:none}input.cmdk-input{height:100%;min-width:calc(var(--spacing) * 0);border-style:var(--tw-border-style);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;background-color:#0000;border-width:0;outline-style:none;flex:1}@media not all and (width>=48rem){input.cmdk-input{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}input.cmdk-input:focus{border-style:var(--tw-border-style);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;border-width:0;outline-style:none}button.cmdk-clear{width:calc(var(--spacing) * 5.5);height:calc(var(--spacing) * 5.5);cursor:pointer;border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);background-color:#0000;border-width:0;border-radius:3.40282e38px;flex-shrink:0;justify-content:center;align-items:center;display:flex}button.cmdk-clear:before{width:calc(var(--spacing) * 3.25);height:calc(var(--spacing) * 3.25);--tw-content:"";content:var(--tw-content);background-color:currentColor;-webkit-mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-x'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M18%206%206%2018'%20/%3e%3cpath%20d='m6%206%2012%2012'%20/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-x'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M18%206%206%2018'%20/%3e%3cpath%20d='m6%206%2012%2012'%20/%3e%3c/svg%3e") 50%/contain no-repeat}button.cmdk-clear:hover{background-color:var(--muted);color:var(--foreground)}button.cmdk-cancel{cursor:pointer;border-style:var(--tw-border-style);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--primary);background-color:#0000;border-width:0;flex-shrink:0;display:none}@media not all and (width>=48rem){button.cmdk-cancel{padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 1.5);display:block}}.cmdk-list{overscroll-behavior:contain;max-height:342px;padding:calc(var(--spacing) * 1);overflow-y:auto}@media not all and (width>=48rem){.cmdk-list{max-height:none;padding:calc(var(--spacing) * 2);padding-bottom:calc(.75rem + env(safe-area-inset-bottom));flex:1}}.cmdk-group{padding-inline:calc(var(--spacing) * 2);padding-top:calc(var(--spacing) * 2.5);padding-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--muted-foreground)}.cmdk-row{cursor:pointer;justify-content:flex-start;align-items:center;gap:calc(var(--spacing) * 2);border-radius:var(--radius-base);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);background-color:#0000;border-width:0;text-decoration-line:none;display:flex}@media not all and (width>=48rem){.cmdk-row{min-height:calc(var(--spacing) * 11);padding-inline:calc(var(--spacing) * 2.5)}}.cmdk-row:hover{text-decoration-line:none}.cmdk-row img.shadcn-icon{width:calc(var(--spacing) * 3.75);height:calc(var(--spacing) * 3.75);flex-shrink:0}.cmdk-row mark{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--primary);background-color:#0000}.cmdk-row .cmdk-title{min-width:calc(var(--spacing) * 0);text-overflow:ellipsis;white-space:nowrap;--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground);overflow:hidden}.cmdk-row .cmdk-group-name{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);flex-shrink:0;margin-left:auto}.cmdk-row .cmdk-check{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);color:var(--primary);background-color:currentColor;flex-shrink:0;margin-left:auto;display:block;-webkit-mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e") 50%/contain no-repeat}.cmdk-row.is-selected{background-color:var(--muted)}.cmdk-empty{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 7);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground)}.cmdk-footer{align-items:center;gap:calc(var(--spacing) * 3.5);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--panel-border);background-color:var(--background-a60);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);flex-shrink:0;display:flex}@media not all and (width>=48rem){.cmdk-footer{display:none}}.cmdk-footer kbd{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-block:1px}.cmdk-footer .cmdk-hint{align-items:center;gap:calc(var(--spacing) * 1.5);display:flex}.cmdk-footer .cmdk-hint-close{margin-left:auto}@view-transition{navigation:auto}#sidebar{view-transition-name:shadcn-sidebar}@media (prefers-reduced-motion:reduce){@view-transition{navigation:none}}#luci-nav-progress{pointer-events:none;top:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0);z-index:80;height:calc(var(--spacing) * .5);width:calc(var(--spacing) * 0);--tw-gradient-position:to right;position:fixed}@supports (background-image:linear-gradient(in lab, red, red)){#luci-nav-progress{--tw-gradient-position:to right in oklab}}#luci-nav-progress{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-bar-start);--tw-gradient-to:var(--progress-bar-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;--tw-ease:var(--ease-out);transition-duration:.3s;transition-timing-function:var(--ease-out)}#luci-nav-progress[data-state=done]{opacity:0;transition:width .3s ease-out,opacity .15s ease-in .15s}#luci-nav-status{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}#maincontent{--tw-outline-style:none;outline-style:none}#maincontent .view-staging{visibility:hidden;height:calc(var(--spacing) * 0);overflow:hidden}#maincontent #view.view-leaving{cursor:progress;opacity:.6;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}.hidden{display:none!important}.left{text-align:left!important}@media (width>=48rem){.left:is(td){text-align:left!important}}.right{text-align:right!important}@media (width>=48rem){.right:is(td){text-align:right!important}}.center{text-align:center!important}@media (width>=48rem){.center:is(td){text-align:center!important}}.top{vertical-align:top!important}@media (width>=48rem){.top:is(td){vertical-align:top!important}}.bottom{vertical-align:bottom!important}@media (width>=48rem){.bottom:is(td){vertical-align:bottom!important}}.middle{vertical-align:middle!important}@media (width>=48rem){.middle:is(td){vertical-align:middle!important}}.nowrap:not(span){white-space:nowrap}.fade-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none);--tw-duration:.4s;--tw-enter-opacity:0;--tw-animation-fill-mode:backwards;transition-duration:.4s;animation-fill-mode:backwards}.fade-out{pointer-events:none;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.4s;transition-duration:.4s}.spinning{position:relative;padding-left:calc(var(--spacing) * 7)!important}.spinning:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);top:50%;left:calc(var(--spacing) * 1.5);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);animation:var(--animate-spin);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-loader-2'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%2012a9%209%200%201%201-6.219-8.56'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-loader-2'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%2012a9%209%200%201%201-6.219-8.56'/%3e%3c/svg%3e");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}#view>.spinning:first-child{min-height:calc(var(--spacing) * 48);place-items:center;width:fit-content;margin-inline:auto;display:grid}html{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-darkmode=true]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}.card-header img,.login-input-icon img,.login-pw-toggle img,img.shadcn-icon{filter:brightness(0)saturate()}html[data-darkmode=true] .card-header img,html[data-darkmode=true] .login-input-icon img,html[data-darkmode=true] .login-pw-toggle img,html[data-darkmode=true] img.shadcn-icon{filter:brightness(0)saturate()invert()}.card-header img,img.shadcn-icon,#sidebar img.shadcn-icon{opacity:.65}html[data-darkmode=true] #sidebar img.shadcn-icon{opacity:.7}.card-header button:hover img,#sidebar .sidebar-nav-item.active img,#sidebar .sidebar-accordion-item.active img,#sidebar .sidebar-nav-parent:hover img{opacity:1}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}} +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-ease:initial;--tw-content:"";--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-space-y-reverse:0;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:.25rem;--breakpoint-md:48rem;--container-xs:20rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base) * .5);--radius-md:calc(var(--radius-base) * .75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base) * 1.5);--shadow-sm:var(--shadow-sm);--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-sm:8px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base) * .5);--color-sidebar-fg:var(--sidebar-foreground);--color-terminal-fg:var(--terminal-foreground)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.fixed{position:fixed}.relative{position:relative}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.block{display:block}.hidden{display:none}.inline{display:inline}.overflow-y-auto{overflow-y:auto}.border{border-style:var(--tw-border-style);border-width:1px}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.select-all{-webkit-user-select:all;user-select:all}}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-cyrillic-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-greek-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-greek-wght-normal.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-vietnamese-wght-normal.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/luci-static/shadcn/inter-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--bg:oklch(98.5% .004 275);--surface:oklch(100% 0 0);--text:oklch(18% .02 275);--brand:oklch(56.7% .158 275);--on-brand:oklch(100% 0 0);--success:oklch(58% .15 150);--warning:oklch(70% .13 75);--danger:oklch(55% .2 25);--info:oklch(58% .13 250);--overlay-base:oklch(0% 0 0);--background:oklch(98.5% .004 275);--foreground:oklch(18% .02 275);--primary:oklch(56.7% .158 275);--primary-foreground:oklch(100% 0 0);--panel-bg:oklch(100% 0 0);--destructive:oklch(55% .2 25);--ring:oklch(56.7% .158 275);--border:oklch(89.65% .0058 275);--input:oklch(89.65% .0058 275);--sidebar-bg:oklch(98.5% .004 275);--sidebar-foreground:oklch(18% .02 275);--sidebar-accent-fg:oklch(18% .02 275);--sidebar-accent:oklch(94.5% .004 275);--sidebar-hover-bg:oklch(94.5% .004 275);--login-path-stroke:oklch(56.7% .158 275);--progress-bar-end:oklch(56.7% .158 275);--destructive-fg:oklch(100% 0 0);--success-fg:oklch(100% 0 0);--info-fg:oklch(100% 0 0);--warning-fg:oklch(20% .05 75);--terminal-foreground:oklch(85% .08 155);--terminal-hover:oklch(85% .08 155/.06);--muted-foreground:oklch(52.62% .0131 275);--secondary-foreground:oklch(30.08% .0176 275);--sidebar-muted:oklch(52.62% .0131 275);--focus-ring:oklch(56.7% .158 275/.5);--muted:oklch(95% .004 275);--secondary:oklch(93.5% .004 275);--label-surface:oklch(96.3% .004 275);--panel-border:oklch(89.65% .0058 275);--primary-hover:oklch(62.7% .158 275);--sidebar-active-bg:oklch(56.7% .158 275/.12);--sidebar-active-fg:oklch(48.7% .158 275);--sidebar-border:oklch(89.65% .0058 275);--terminal-bg:oklch(14% .02 264);--warning-soft-fg:oklch(42% .12 75);--progress-bar-start:oklch(74.02% .0948 275);--login-left-bg:oklch(93.5% .004 275);--primary-a5:oklch(56.7% .158 275/.05);--primary-a10:oklch(56.7% .158 275/.1);--primary-a15:oklch(56.7% .158 275/.15);--primary-a20:oklch(56.7% .158 275/.2);--primary-a25:oklch(56.7% .158 275/.25);--primary-a60:oklch(56.7% .158 275/.6);--primary-a70:oklch(56.7% .158 275/.7);--primary-a90:oklch(56.7% .158 275/.9);--destructive-a8:oklch(55% .2 25/.08);--destructive-a10:oklch(55% .2 25/.1);--destructive-a20:oklch(55% .2 25/.2);--destructive-a30:oklch(55% .2 25/.3);--destructive-a40:oklch(55% .2 25/.4);--destructive-a50:oklch(55% .2 25/.5);--destructive-a60:oklch(55% .2 25/.6);--destructive-a70:oklch(55% .2 25/.7);--destructive-a80:oklch(55% .2 25/.8);--destructive-a90:oklch(55% .2 25/.9);--foreground-a5:oklch(18% .02 275/.05);--foreground-a30:oklch(18% .02 275/.3);--secondary-a80:oklch(93.5% .004 275/.8);--muted-a30:oklch(95% .004 275/.3);--muted-a80:oklch(95% .004 275/.8);--muted-foreground-a70:oklch(52.62% .0131 275/.7);--success-a10:oklch(58% .15 150/.1);--success-a15:oklch(58% .15 150/.15);--success-a30:oklch(58% .15 150/.3);--success-a40:oklch(58% .15 150/.4);--success-a80:oklch(58% .15 150/.8);--warning-a10:oklch(70% .13 75/.1);--warning-a15:oklch(70% .13 75/.15);--warning-a30:oklch(70% .13 75/.3);--warning-a40:oklch(70% .13 75/.4);--info-a10:oklch(58% .13 250/.1);--info-a15:oklch(58% .13 250/.15);--info-a30:oklch(58% .13 250/.3);--info-a40:oklch(58% .13 250/.4);--info-a80:oklch(58% .13 250/.8);--border-a60:oklch(89.65% .0058 275/.6);--border-a80:oklch(89.65% .0058 275/.8);--input-a30:oklch(89.65% .0058 275/.3);--label-surface-a50:oklch(96.3% .004 275/.5);--overlay-base-a50:oklch(0% 0 0/.5);--overlay-base-a60:oklch(0% 0 0/.6);--background-a60:oklch(98.5% .004 275/.6);--ring-a50:oklch(56.7% .158 275/.5);--font-sans:"Inter Variable", ui-sans-serif, system-ui, sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;--radius-base:.5rem;--shadow-sm:0 1px 3px 0 oklch(0% 0 0/.1), 0 1px 2px -1px oklch(0% 0 0/.1)}[data-darkmode=true]{--bg:oklch(15.9% .005 264);--surface:oklch(20.5% .004 264);--text:oklch(90% .006 264);--brand:oklch(56.7% .158 275);--on-brand:oklch(100% 0 0);--success:oklch(63.7% .175 147);--warning:oklch(80% .12 80);--danger:oklch(63% .16 25);--info:oklch(70% .1 250);--overlay-base:oklch(0% 0 0);--background:oklch(15.9% .005 264);--foreground:oklch(90% .006 264);--primary:oklch(56.7% .158 275);--primary-foreground:oklch(100% 0 0);--panel-bg:oklch(20.5% .004 264);--destructive:oklch(63% .16 25);--ring:oklch(56.7% .158 275);--border:oklch(26.27% .0051 264);--input:oklch(26.27% .0051 264);--sidebar-bg:oklch(15.9% .005 264);--sidebar-foreground:oklch(90% .006 264);--sidebar-accent-fg:oklch(90% .006 264);--sidebar-accent:oklch(23% .004 264);--sidebar-hover-bg:oklch(23% .004 264);--login-path-stroke:oklch(56.7% .158 275);--progress-bar-end:oklch(56.7% .158 275);--destructive-fg:oklch(100% 0 0);--success-fg:oklch(100% 0 0);--info-fg:oklch(100% 0 0);--warning-fg:oklch(20% .05 75);--terminal-foreground:oklch(85% .08 155);--terminal-hover:oklch(85% .08 155/.06);--muted-foreground:oklch(58.14% .0056 264);--secondary-foreground:oklch(78.89% .0059 264);--sidebar-muted:oklch(58.14% .0056 264);--focus-ring:oklch(56.7% .158 275/.5);--muted:oklch(18.9% .005 264);--secondary:oklch(22.5% .004 264);--label-surface:oklch(19.5% .004 264);--panel-border:oklch(90% .006 264/.08);--primary-hover:oklch(62.7% .158 275);--sidebar-active-bg:oklch(56.7% .158 275/.14);--sidebar-active-fg:oklch(78.7% .158 275);--sidebar-border:oklch(90% .006 264/.08);--terminal-bg:oklch(12% .02 264);--warning-soft-fg:oklch(86% .1 85);--progress-bar-start:oklch(42.22% .0964 274.8);--login-left-bg:oklch(13.4% .005 264);--primary-a5:oklch(56.7% .158 275/.05);--primary-a10:oklch(56.7% .158 275/.1);--primary-a15:oklch(56.7% .158 275/.15);--primary-a20:oklch(56.7% .158 275/.2);--primary-a25:oklch(56.7% .158 275/.25);--primary-a60:oklch(56.7% .158 275/.6);--primary-a70:oklch(56.7% .158 275/.7);--primary-a90:oklch(56.7% .158 275/.9);--destructive-a8:oklch(63% .16 25/.08);--destructive-a10:oklch(63% .16 25/.1);--destructive-a20:oklch(63% .16 25/.2);--destructive-a30:oklch(63% .16 25/.3);--destructive-a40:oklch(63% .16 25/.4);--destructive-a50:oklch(63% .16 25/.5);--destructive-a60:oklch(63% .16 25/.6);--destructive-a70:oklch(63% .16 25/.7);--destructive-a80:oklch(63% .16 25/.8);--destructive-a90:oklch(63% .16 25/.9);--foreground-a5:oklch(90% .006 264/.05);--foreground-a30:oklch(90% .006 264/.3);--secondary-a80:oklch(22.5% .004 264/.8);--muted-a30:oklch(18.9% .005 264/.3);--muted-a80:oklch(18.9% .005 264/.8);--muted-foreground-a70:oklch(58.14% .0056 264/.7);--success-a10:oklch(63.7% .175 147/.1);--success-a15:oklch(63.7% .175 147/.15);--success-a30:oklch(63.7% .175 147/.3);--success-a40:oklch(63.7% .175 147/.4);--success-a80:oklch(63.7% .175 147/.8);--warning-a10:oklch(80% .12 80/.1);--warning-a15:oklch(80% .12 80/.15);--warning-a30:oklch(80% .12 80/.3);--warning-a40:oklch(80% .12 80/.4);--info-a10:oklch(70% .1 250/.1);--info-a15:oklch(70% .1 250/.15);--info-a30:oklch(70% .1 250/.3);--info-a40:oklch(70% .1 250/.4);--info-a80:oklch(70% .1 250/.8);--border-a60:oklch(26.27% .0051 264/.6);--border-a80:oklch(26.27% .0051 264/.8);--input-a30:oklch(26.27% .0051 264/.3);--label-surface-a50:oklch(19.5% .004 264/.5);--overlay-base-a50:oklch(0% 0 0/.5);--overlay-base-a60:oklch(0% 0 0/.6);--background-a60:oklch(15.9% .005 264/.6);--ring-a50:oklch(56.7% .158 275/.5)}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea){scrollbar-color:var(--foreground-a30) transparent;scrollbar-width:thin}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar{width:8px;height:8px}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-track{background-color:#0000}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-corner{background-color:#0000}:where(html,.sidebar-nav,#maincontent,.cmdk-list,.cbi-dropdown>ul.dropdown,#modal_overlay,#modal_overlay>.modal>ul,#modal_overlay>.modal pre,.cbi-tabmenu,.tabs,textarea)::-webkit-scrollbar-thumb{background-color:var(--foreground-a30);border-radius:9999px}html{background-color:var(--background);font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground)}html body{flex-wrap:wrap;height:100dvh;display:flex}html body.modal-overlay-active{overflow:hidden}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);color:var(--foreground)}h1{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}h2{margin-bottom:calc(var(--spacing) * 3);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}h5{margin-bottom:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}h6{margin-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}hr{margin-block:calc(var(--spacing) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border)}strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}abbr{cursor:help}p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--foreground)}pre{border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--muted);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-wrap:break-word;white-space:pre-wrap;color:var(--muted-foreground);display:block}code{border-radius:calc(var(--radius-base) * .5);background-color:var(--muted);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground)}a{color:var(--primary);text-decoration-line:none}@media (hover:hover){a:hover{text-decoration-line:underline}}var{font-family:var(--font-mono);color:var(--primary)}small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--muted-foreground)}em{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground);font-style:italic}#sidebar{background-color:var(--sidebar-bg);width:220px;height:100%;transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-direction:column;flex-shrink:0;transition-duration:.2s;display:flex;overflow:hidden}@media not all and (width>=48rem){#sidebar{top:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0);z-index:40;--tw-translate-x:-100%;width:240px;translate:var(--tw-translate-x) var(--tw-translate-y);--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));height:100dvh;position:fixed}#sidebar[data-drawer-open=true]{--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}}#sidebar .icon-expand{display:none}@media (width>=48rem){html[data-sidebar-collapsed=true] #sidebar{width:calc(var(--spacing) * 12)}html[data-sidebar-collapsed=true] #sidebar .sidebar-brand-text,html[data-sidebar-collapsed=true] #sidebar .sidebar-label,html[data-sidebar-collapsed=true] #sidebar .sidebar-chevron,html[data-sidebar-collapsed=true] #sidebar .icon-collapse{display:none}html[data-sidebar-collapsed=true] #sidebar .icon-expand{display:block}html[data-sidebar-collapsed=true] #sidebar .sidebar-accordion-sub{display:none!important}}.sidebar-header{height:calc(var(--spacing) * 14);padding-inline:calc(var(--spacing) * 3);flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.sidebar-brand{min-width:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * 2);text-overflow:ellipsis;white-space:nowrap;color:var(--sidebar-foreground);flex:1;text-decoration-line:none;display:flex;overflow:hidden}.sidebar-logo{flex-shrink:0}.sidebar-brand-text{text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);overflow:hidden}.sidebar-toggle{height:calc(var(--spacing) * 7);width:calc(var(--spacing) * 7);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-toggle:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-toggle svg,.sidebar-toggle img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-nav{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex:1;overflow:hidden auto}.sidebar-nav-item,.sidebar-accordion-item{margin-bottom:calc(var(--spacing) * .5)}:is(.sidebar-nav-item,.sidebar-accordion-item).active>.sidebar-nav-parent{color:var(--sidebar-active-fg)}.sidebar-nav-parent{cursor:pointer;appearance:none;justify-content:flex-start;align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;background-color:#0000;border-width:0;transition-duration:.15s;display:flex}.sidebar-nav-parent:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-nav-parent .sidebar-icon{flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-nav-parent .sidebar-icon svg,.sidebar-nav-parent .sidebar-icon img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-nav-parent .sidebar-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.sidebar-nav-parent .sidebar-chevron{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-shrink:0;margin-left:auto;transition-duration:.2s}.sidebar-nav-parent .sidebar-chevron svg,.sidebar-nav-parent .sidebar-chevron img{height:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5)}.sidebar-accordion-item[data-open=true]>.sidebar-nav-parent{background-color:var(--sidebar-active-bg);color:var(--sidebar-active-fg)}.sidebar-accordion-item[data-open=true] .sidebar-chevron{rotate:180deg}.sidebar-accordion-sub{visibility:hidden;opacity:0;transition-property:grid-template-rows,opacity,visibility;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out);grid-template-rows:0fr;display:grid;overflow:hidden}.sidebar-accordion-sub>*{min-height:calc(var(--spacing) * 0);align-self:flex-start}.sidebar-accordion-item[data-open=true]>.sidebar-accordion-sub{visibility:visible;opacity:1;grid-template-rows:1fr}.sidebar-sub-list{margin-left:calc(var(--spacing) * 4);border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--sidebar-border);padding-left:calc(var(--spacing) * 2);list-style-type:none}.sidebar-sub-item{margin-bottom:calc(var(--spacing) * .5)}.sidebar-sub-item.active .sidebar-sub-link{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-sub-link{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:block}.sidebar-sub-link:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-collapsed-popover{z-index:50;min-width:calc(var(--spacing) * 44);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding-block:calc(var(--spacing) * 1);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);position:fixed;overflow:hidden}.sidebar-collapsed-popover-title{padding-inline:calc(var(--spacing) * 3);padding-top:calc(var(--spacing) * 1.5);padding-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.sidebar-collapsed-popover-list{margin:calc(var(--spacing) * 0);padding:calc(var(--spacing) * 0);list-style-type:none}.sidebar-collapsed-popover-link{margin-inline:calc(var(--spacing) * 1);border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:block}.sidebar-collapsed-popover-link:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-collapsed-popover-link.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-footer{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--sidebar-border);padding:calc(var(--spacing) * 2);padding-bottom:max(.5rem, env(safe-area-inset-bottom));flex-shrink:0}.sidebar-logout{align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:calc(var(--radius-base) * .75);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--sidebar-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none;display:flex}.sidebar-logout:hover{background-color:var(--sidebar-accent);color:var(--sidebar-accent-fg)}.sidebar-logout.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--sidebar-active-fg)}.sidebar-logout .sidebar-icon{flex-shrink:0;justify-content:center;align-items:center;display:flex}.sidebar-logout .sidebar-icon svg,.sidebar-logout .sidebar-icon img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4)}.sidebar-logout .sidebar-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}#main-wrapper{background-color:var(--background);height:100%;padding-block:calc(var(--spacing) * 2);padding-right:calc(var(--spacing) * 2);padding-left:calc(var(--spacing) * 0);flex-direction:column;flex:1;display:flex;overflow:hidden}@media not all and (width>=48rem){#main-wrapper{padding:calc(var(--spacing) * 0);flex-basis:100%}}.content-card{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-direction:column;flex:1;display:flex;overflow:hidden}@media not all and (width>=48rem){.content-card{--tw-border-style:none;--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-style:none;border-radius:0}}.card-header{height:calc(var(--spacing) * 12);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);padding-inline:calc(var(--spacing) * 4);flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.card-header-left,.card-header-right{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.topbar-hamburger{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;justify-content:center;align-items:center;display:none}@media not all and (width>=48rem){.topbar-hamburger{display:flex}}.topbar-hamburger:hover{background-color:var(--muted)}.topbar-hamburger svg,.topbar-hamburger img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5)}.topbar-breadcrumb{align-items:center;gap:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:flex}.topbar-breadcrumb .breadcrumb-item{color:var(--muted-foreground)}.topbar-breadcrumb .breadcrumb-item.active{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground)}.topbar-breadcrumb .breadcrumb-sep{color:var(--muted-foreground)}.topbar-breadcrumb .breadcrumb-sep svg,.topbar-breadcrumb .breadcrumb-sep img{height:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5)}button.topbar-icon-btn{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}button.topbar-icon-btn:hover{background-color:var(--muted);color:var(--foreground)}button.topbar-icon-btn img{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);flex-shrink:0}.topbar-indicators{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.topbar-indicators span[data-indicator]>img{display:none}.topbar-indicators span[data-indicator]{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:calc(var(--radius-base) * .75);color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));flex-shrink:0;justify-content:center;align-items:center;font-size:0;display:inline-flex;position:relative}.topbar-indicators span[data-indicator]:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;flex-shrink:0;display:block;position:relative;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.topbar-indicators span[data-indicator]:hover{background-color:var(--muted);color:var(--foreground)}.topbar-indicators span[data-indicator][data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%200%201%209-9%209.75%209.75%200%200%201%206.74%202.74L21%208'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M21%2012a9%209%200%200%201-9%209%209.75%209.75%200%200%201-6.74-2.74L3%2016'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M3%2012a9%209%200%200%201%209-9%209.75%209.75%200%200%201%206.74%202.74L21%208'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M21%2012a9%209%200%200%201-9%209%209.75%209.75%200%200%201-6.74-2.74L3%2016'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw-off'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%208L18.74%205.74A9.75%209.75%200%200%200%2012%203C11%203%2010.03%203.16%209.13%203.47'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3cpath%20d='M3%2012C3%209.51%204%207.26%205.64%205.64'/%3e%3cpath%20d='m3%2016%202.26%202.26A9.75%209.75%200%200%200%2012%2021c2.49%200%204.74-1%206.36-2.64'/%3e%3cpath%20d='M21%2012c0%201-.16%201.97-.47%202.87'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M22%2022%202%202'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-refresh-cw-off'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%208L18.74%205.74A9.75%209.75%200%200%200%2012%203C11%203%2010.03%203.16%209.13%203.47'/%3e%3cpath%20d='M8%2016H3v5'/%3e%3cpath%20d='M3%2012C3%209.51%204%207.26%205.64%205.64'/%3e%3cpath%20d='m3%2016%202.26%202.26A9.75%209.75%200%200%200%2012%2021c2.49%200%204.74-1%206.36-2.64'/%3e%3cpath%20d='M21%2012c0%201-.16%201.97-.47%202.87'/%3e%3cpath%20d='M21%203v5h-5'/%3e%3cpath%20d='M22%2022%202%202'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=media_error]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-alert-circle'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cline%20x1='12'%20x2='12'%20y1='8'%20y2='12'/%3e%3cline%20x1='12'%20x2='12.01'%20y1='16'%20y2='16'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-alert-circle'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cline%20x1='12'%20x2='12'%20y1='8'%20y2='12'/%3e%3cline%20x1='12'%20x2='12.01'%20y1='16'%20y2='16'/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=uci-changes]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-settings'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915'%20/%3e%3ccircle%20cx='12'%20cy='12'%20r='3'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-settings'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915'%20/%3e%3ccircle%20cx='12'%20cy='12'%20r='3'%20/%3e%3c/svg%3e")}.topbar-indicators span[data-indicator][data-indicator=uci-changes][data-count]:not([data-count="0"]):after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -.5);content:var(--tw-content);z-index:10;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 3);content:var(--tw-content);min-width:calc(var(--spacing) * 3);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--primary);content:var(--tw-content);padding-inline:calc(var(--spacing) * .5);content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);--tw-font-weight:var(--font-weight-bold);font-size:8px;line-height:1;font-weight:var(--font-weight-bold);content:var(--tw-content);color:var(--primary-foreground);--tw-content:attr(data-count);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:flex;position:absolute}#maincontent{padding:calc(var(--spacing) * 6);flex:1;overflow-y:auto}@media not all and (width>=48rem){#maincontent{padding:calc(var(--spacing) * 4)}}#maincontent h1{margin-bottom:calc(var(--spacing) * 4);border-style:var(--tw-border-style);padding-left:calc(var(--spacing) * 0);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight);border-width:0}#maincontent h2{margin-bottom:calc(var(--spacing) * 3);border-style:var(--tw-border-style);padding-left:calc(var(--spacing) * 0);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);border-width:0}#maincontent h3{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}#maincontent .cbi-map-descr,#maincontent .cbi-section-descr{margin-bottom:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--muted-foreground)}#maincontent .cbi-page-actions{margin-top:calc(var(--spacing) * 4);justify-content:flex-end;align-items:center;gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding-top:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}#maincontent div[style]>svg:where([data-darkmode=true],[data-darkmode=true] *){background-color:var(--surface)!important}#maincontent div[style]>svg line[style]:where([data-darkmode=true],[data-darkmode=true] *){stroke:var(--text)!important}#maincontent .zone-forwards{align-items:stretch;gap:calc(var(--spacing) * 2);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);flex-wrap:nowrap;display:flex}#maincontent .zone-forwards>span{flex-shrink:0;flex-basis:calc(var(--spacing) * 8);color:var(--muted-foreground);justify-content:center;align-self:center;align-items:center;display:flex}#maincontent .zone-forwards .zone-src,#maincontent .zone-forwards .zone-dest{gap:calc(var(--spacing) * 1.5);flex-direction:column;flex:1;display:flex}#maincontent .controls{align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}#maincontent .controls label input[type=radio],#maincontent .controls label input[type=checkbox]{margin-right:calc(var(--spacing) * 1);vertical-align:middle}#maincontent .cbi-title-section{margin-bottom:calc(var(--spacing) * 4);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}#maincontent .control-group{margin-top:calc(var(--spacing) * 1)}#maincontent .control-group,#maincontent .cbi-page-actions>div,#maincontent .cbi-section-actions>div{align-items:center;gap:calc(var(--spacing) * 2);flex-flow:row;display:flex}#sidebar-overlay{pointer-events:none;inset:calc(var(--spacing) * 0);z-index:30;background-color:var(--overlay-base-a50);opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;position:absolute}@media (width>=48rem){#sidebar-overlay{display:none}}#sidebar-overlay.active{pointer-events:auto;opacity:1}button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;border-width:1px;transition-duration:.2s;display:inline-flex}:is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button)[disabled]{cursor:not-allowed;opacity:.4}.td :is(button,input[type=button],input[type=submit],input[type=reset],.btn,.cbi-button){white-space:nowrap}.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down{border-color:var(--secondary);background-color:var(--secondary);color:var(--secondary-foreground)}@media (hover:hover){:is(.btn,.cbi-button,.cbi-button-default,.cbi-button-download,.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down):hover{background-color:var(--secondary-a80)}}.drag-handle{border-color:var(--muted);background-color:var(--muted);color:var(--muted-foreground)}@media (hover:hover){.drag-handle:hover{background-color:var(--muted-a80)}}.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit{border-color:var(--primary);background-color:var(--primary);color:var(--primary-foreground)}@media (hover:hover){:is(.btn.primary,.cbi-button-action,.cbi-button-apply,.cbi-button-reload,.cbi-button-add,.cbi-button-edit):hover{background-color:var(--primary-a90)}}.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save{border-color:var(--primary-a25);background-color:var(--primary-a15);color:var(--primary)}@media (hover:hover){:is(.cbi-button-positive,.cbi-button-fieldadd,.cbi-button-save):hover{background-color:var(--primary-a25)}}.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove{border-color:var(--destructive);background-color:var(--destructive);color:var(--destructive-fg)}@media (hover:hover){:is(.cbi-button-negative,.cbi-section-remove .cbi-button,.cbi-button-reset,.cbi-button-remove):hover{background-color:var(--destructive-a90)}}input:disabled{cursor:not-allowed;opacity:.4}input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input{width:calc(var(--spacing) * 52.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);max-width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;position:relative}:is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input)::placeholder{color:var(--muted-foreground-a70)}:is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input):focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}.table.cbi-section-table :is(input[type=text],input[type=password],input[type=number],input[type=email],.cbi-input-text,.cbi-input){width:100%}.cbi-input-text{min-width:calc(var(--spacing) * 20)}#localtime{min-width:calc(var(--spacing) * 64)}textarea{min-height:calc(var(--spacing) * 24);resize:vertical;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}textarea::placeholder{color:var(--muted-foreground-a70)}textarea:focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}textarea[disabled]{cursor:not-allowed;opacity:.4}input[type=radio],input[type=checkbox]{margin-right:calc(var(--spacing) * 3);height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);cursor:pointer;appearance:none;vertical-align:middle;display:inline-block;position:relative}:is(input[type=radio],input[type=checkbox]):disabled{cursor:not-allowed}:is(input[type=radio],input[type=checkbox]):before{content:var(--tw-content);content:var(--tw-content);inset:calc(var(--spacing) * 0);content:var(--tw-content);border-radius:calc(var(--radius-base) * .5);content:var(--tw-content);border-style:var(--tw-border-style);content:var(--tw-content);border-width:1px;border-color:var(--input);content:var(--tw-content);background-color:var(--background);content:var(--tw-content);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.2s;transition-duration:.2s;position:absolute}:is(input[type=radio],input[type=checkbox]):after{content:var(--tw-content);content:var(--tw-content);inset:calc(var(--spacing) * 0);content:var(--tw-content);background-color:var(--primary-foreground);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);opacity:0;content:var(--tw-content);transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));content:var(--tw-content);--tw-duration:.2s;transition-duration:.2s;position:absolute;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}:is(input[type=radio],input[type=checkbox]):checked:before{content:var(--tw-content);border-color:var(--primary);content:var(--tw-content);background-color:var(--primary)}:is(input[type=radio],input[type=checkbox]):checked:after{content:var(--tw-content);opacity:1}:is(input[type=radio],input[type=checkbox]):focus:before{content:var(--tw-content);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);content:var(--tw-content);--tw-ring-color:var(--ring);content:var(--tw-content);--tw-outline-style:none;outline-style:none}input[type=radio]:before{content:var(--tw-content);border-radius:3.40282e38px}input[type=radio]:after{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='currentColor'%3e%3ccircle%20cx='12'%20cy='12'%20r='6'/%3e%3c/svg%3e")}input[type=checkbox]:after{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e")}.cbi-checkbox{vertical-align:middle;align-items:center;display:inline-flex;position:relative}select{max-width:100%;min-width:calc(var(--spacing) * 52.5);appearance:none;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 9);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}select:focus{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring);--tw-outline-style:none;outline-style:none}select:disabled{cursor:not-allowed;opacity:.4}@media (width>=48rem){select{max-width:calc(var(--spacing) * 100)}}select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238888a0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-position:right .6rem center;background-repeat:no-repeat;background-size:16px}[data-darkmode=true] select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238c8ca8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}.cbi-dropdown{min-width:fit-content;max-width:100%;height:fit-content;padding:calc(var(--spacing) * 0);white-space:nowrap;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-shrink:0;align-items:center;transition-duration:.2s;display:inline-flex;position:relative}.cbi-dropdown[disabled]{pointer-events:none;opacity:.4}.cbi-dropdown:not(.btn):not(.cbi-button){max-width:100%;min-width:calc(var(--spacing) * 52.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background)}@media (width>=48rem){.cbi-dropdown:not(.btn):not(.cbi-button){max-width:calc(var(--spacing) * 100)}}.cbi-dropdown:not(.btn):not(.cbi-button)>ul>li[placeholder]{display:none}.cbi-dropdown>ul{margin:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * .5);flex-wrap:nowrap;flex:1;list-style-type:none;display:flex;overflow:hidden}.cbi-dropdown>ul>li{margin:calc(var(--spacing) * 0);align-items:center;gap:calc(var(--spacing) * 1);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);list-style-type:none;display:none;overflow:hidden}.cbi-dropdown>ul>li[display]{display:flex!important}.cbi-dropdown>ul>li .hide-open{display:block}.cbi-dropdown>ul>li .hide-close{display:none}.cbi-dropdown>ul>li>form{pointer-events:none;display:none}.cbi-dropdown>ul>li>label{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.cbi-dropdown>ul>li img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);vertical-align:middle;flex:none}.cbi-dropdown>ul>li span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.cbi-dropdown>ul.dropdown{left:calc(var(--spacing) * 0);z-index:50;border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);width:fit-content;min-width:100%;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);position:absolute;overflow-y:auto}.cbi-dropdown>ul.dropdown>li{min-height:calc(var(--spacing) * 9);cursor:pointer;width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground)}@media (hover:hover){.cbi-dropdown>ul.dropdown>li:hover{background-color:var(--muted)}}.cbi-dropdown>ul.preview{display:none}.cbi-dropdown[empty]>ul{max-width:1px;max-height:1px}.cbi-dropdown[empty]>ul>li,.cbi-dropdown[optional][open]>ul.dropdown>li[placeholder]{display:block}.cbi-dropdown[open]{border-color:var(--primary);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring)}.cbi-dropdown[open]>ul.dropdown{width:auto;max-width:none;display:block}.cbi-dropdown[open]>ul.dropdown>li{display:flex}.cbi-dropdown[open]>ul.dropdown>li[selected]{background-color:var(--primary-a15);color:var(--primary)}.cbi-dropdown[open]>ul.dropdown>li[unselectable]{opacity:.4}.cbi-dropdown[open]>ul.dropdown>li .hide-open{display:none}.cbi-dropdown[open]>ul.dropdown>li .hide-close{display:block}.cbi-dropdown[open]>ul.preview{display:flex}:is(.cbi-dropdown[multiple][more],.cbi-dropdown[multiple][empty])>.more{padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);flex:none;display:flex}.cbi-dropdown[multiple][empty]>.more{flex:1}.cbi-dropdown[multiple][open]>ul.dropdown>li>form{align-items:center;display:flex}.cbi-dropdown[multiple]>ul>li>label{display:flex}.cbi-dropdown>.open{cursor:pointer;border-left-style:var(--tw-border-style);border-left-width:1px;border-color:var(--input);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:currentColor;flex:none;justify-content:center;align-items:center;display:flex}.cbi-dropdown>.more{display:none}.cbi-tooltip{z-index:50;width:max-content;max-width:var(--container-xs);--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border-a60);background-color:var(--panel-bg);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));overflow-wrap:normal;word-break:normal;white-space:normal;color:var(--foreground);opacity:0;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out);position:absolute;inset-inline-start:-10000px}.cbi-tooltip.error{border-color:var(--destructive-a40);background-color:var(--destructive);color:var(--destructive-fg)}.cbi-tooltip.success{border-color:var(--success-a40);background-color:var(--success);color:var(--success-fg)}.cbi-tooltip.info{border-color:var(--info-a40);background-color:var(--info);color:var(--info-fg)}.cbi-tooltip.notice{border-color:var(--warning-a40);background-color:var(--warning);color:var(--warning-fg)}.cbi-tooltip-container,[data-tooltip]{cursor:help;white-space:nowrap;text-underline-offset:2px;transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;transition-duration:.2s;display:inline-block;position:relative}:is(.cbi-tooltip-container,[data-tooltip]) .cbi-tooltip{visibility:hidden;--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:0;transition-property:visibility,opacity,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;--tw-ease:var(--ease-out);transition-duration:.2s;transition-timing-function:var(--ease-out)}:is(.cbi-tooltip-container,[data-tooltip]):hover .cbi-tooltip{visibility:visible;--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;inset-inline-start:auto}.alert-message{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);background-color:var(--muted);padding:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--foreground);border-width:1px}.alert-message.success{border-color:var(--success-a30);background-color:var(--success-a10);color:var(--success)}.alert-message.info{border-color:var(--info-a30);background-color:var(--info-a10);color:var(--info)}.alert-message.warning,.alert-message.notice{border-color:var(--warning-a30);background-color:var(--warning-a10);color:var(--warning-soft-fg)}.alert-message.error,.alert-message.danger{border-color:var(--destructive-a30);background-color:var(--destructive-a10);color:var(--destructive)}.alert-message h4,.alert-message h5,.alert-message pre,.alert-message ul,.alert-message li,.alert-message p{border-style:var(--tw-border-style);color:inherit;background-color:#0000;border-width:0}.alert-message h4{margin-bottom:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.alert-message p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.alert-message .right{margin-top:calc(var(--spacing) * 3)}.cbi-progressbar{height:calc(var(--spacing) * 2.5);cursor:help;background-color:var(--secondary);border-radius:3.40282e38px;width:100%;position:relative;overflow:hidden}.cbi-progressbar:before{content:var(--tw-content);content:var(--tw-content);inset-inline:calc(var(--spacing) * 0);content:var(--tw-content);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);text-align:center;content:var(--tw-content);content:var(--tw-content);--tw-leading:1;content:var(--tw-content);white-space:nowrap;content:var(--tw-content);color:var(--foreground);--tw-content:attr(title);content:var(--tw-content);font-size:10px;line-height:1;position:absolute;top:50%}.cbi-progressbar>div{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-bar-start);--tw-gradient-to:var(--progress-bar-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));height:100%;transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;transition-duration:.3s}.label{background-color:var(--muted);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--muted-foreground);border-radius:3.40282e38px;align-items:center;display:inline-flex}.label.important{background-color:var(--info-a15);color:var(--info)}.label.warning{background-color:var(--warning-a15);color:var(--warning-soft-fg)}.label.success{background-color:var(--success-a15);color:var(--success)}.label.notice{background-color:var(--warning-a15);color:var(--warning-soft-fg)}.zonebadge{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--secondary);background-color:var(--secondary);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--secondary-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;display:inline-flex;overflow:visible}.zonebadge[style*=--zone-color-rgb]{border-color:#0000;background-color:rgb(var(--zone-color-rgb),.6)!important}.zonebadge.zonebadge-empty{--tw-border-style:dashed;border-style:dashed;border-color:var(--border);--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--muted-foreground);background-color:#0000;font-style:italic}.ifacebadge>.zonebadge{padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * .5);border-radius:3.40282e38px}.cbi-dropdown .zonebadge{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.ifacebadge{cursor:default;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;flex-wrap:nowrap;transition-duration:.2s;display:inline-flex}.zonebadge>.ifacebadge{border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * 0)}.zonebadge>.ifacebadge img{margin-right:calc(var(--spacing) * 1);width:calc(var(--spacing) * 4)}.cbi-dropdown .ifacebadge{gap:calc(var(--spacing) * 1);border-radius:calc(var(--radius-base) * .75);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}.cbi-dropdown .ifacebadge img{margin-right:calc(var(--spacing) * 1);width:calc(var(--spacing) * 4)}.ifacebadge>img,.ifacebadge>.cbi-tooltip-container>img{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}.ifacebadge>span .nowrap{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}.ifacebadge.ifacebadge-active{border-color:var(--primary);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.ifacebadge.large{min-width:calc(var(--spacing) * 48);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex:1}.cbi-section{margin-bottom:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);padding:calc(var(--spacing) * 4);overflow:visible}.cbi-section[data-tab-title]{margin:calc(var(--spacing) * 0);padding:calc(var(--spacing) * 0)}.cbi-section[data-tab-active=true]{margin-bottom:calc(var(--spacing) * 4);padding:calc(var(--spacing) * 4)}.cbi-section>.cbi-title{justify-content:space-between;align-items:flex-start;display:flex}.cbi-section>.cbi-title>h3{flex:1}.cbi-section>.cbi-title>h3 .label[data-clickable]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * .5);background-color:var(--label-surface);padding:calc(var(--spacing) * 0);color:var(--foreground);justify-content:center;align-items:center;display:inline-flex}@media (hover:hover){.cbi-section>.cbi-title>h3 .label[data-clickable]:hover{background-color:var(--muted)}}.cbi-section>.cbi-title>h3 .label[data-clickable]:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);cursor:pointer;font-size:0;position:relative}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status]:before{content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=active]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-down'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m6%209%206%206%206-6'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-down'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m6%209%206%206%206-6'%20/%3e%3c/svg%3e")}.cbi-section>.cbi-title>h3 span[data-indicator=poll-status][data-style=inactive]:before{content:var(--tw-content);-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-up'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m18%2015-6-6-6%206'%20/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-chevron-up'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='m18%2015-6-6-6%206'%20/%3e%3c/svg%3e")}.cbi-section legend{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.cbi-section h3{margin-bottom:calc(var(--spacing) * 3);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-bottom:calc(var(--spacing) * 3);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.cbi-section .cbi-section-create{margin-top:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}.cbi-section .cbi-section-create>div{flex:none}.cbi-section .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}@media (width>=48rem){.cbi-section .network-status-table{flex-wrap:nowrap}}.cbi-section div[style*=display\:grid]:has(>.ifacebox){place-items:center}.ifacebox{min-width:calc(var(--spacing) * 32);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);flex-direction:column;align-items:stretch;display:inline-flex;position:relative;overflow:visible}@media (width>=48rem){#cbi-network-interface .ifacebox{min-width:calc(var(--spacing) * 38)}}.ifacebox .ifacebox-head{border-top-left-radius:var(--radius-base);border-top-right-radius:var(--radius-base);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--label-surface);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}.ifacebox .ifacebox-head[style*=--zone-color-rgb]{background-color:rgb(var(--zone-color-rgb),.65)!important}.ifacebox .ifacebox-head.cbi-tooltip-container{background-color:#0000;position:static}.ifacebox .ifacebox-head.cbi-tooltip-container .cbi-tooltip{bottom:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0)}.ifacebox .ifacebox-head.active{border-color:var(--primary);background-color:var(--primary);color:var(--primary-foreground)}.ifacebox .ifacebox-body{justify-content:center;align-items:stretch;gap:calc(var(--spacing) * 1);border-bottom-right-radius:var(--radius-base);border-bottom-left-radius:var(--radius-base);width:100%;padding:calc(var(--spacing) * 3);text-align:center;color:var(--foreground);flex-direction:column;flex:1;display:flex}.ifacebox .ifacebox-body>img{width:calc(var(--spacing) * 5);margin-inline:auto}:where(.ifacebox .ifacebox-body>span>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body>span .cbi-tooltip{--tw-animation-delay:.2s;transition-delay:.2s;animation-delay:.2s}.ifacebox .ifacebox-body>span .nowrap{display:inline-block}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5);flex-shrink:0}.ifacebox .ifacebox-body>div{width:100%;display:block}:where(.ifacebox .ifacebox-body>div>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)))}.ifacebox .ifacebox-body .cbi-tooltip-container{cursor:help;color:var(--foreground);justify-content:center;align-items:center;display:inline-flex;position:static}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip{bottom:calc(var(--spacing) * 0)}.ifacebox .ifacebox-body .cbi-tooltip-container .cbi-tooltip .nowrap{white-space:nowrap}.ifacebox .ifacebox-body small{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4);display:block}.network-status-table .ifacebox-body{justify-content:space-around;align-items:center;gap:calc(var(--spacing) * 2);flex-direction:column;flex:1;height:100%;display:flex}.network-status-table .ifacebox-body>div{gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}.network-status-table .ifacebox-body .ifacebadge{min-width:calc(var(--spacing) * 55);flex:1}#modal_overlay{pointer-events:none;top:calc(var(--spacing) * 0);bottom:calc(var(--spacing) * 0);background-color:#0000;display:none;position:fixed;overflow:auto}.modal-overlay-active #modal_overlay{pointer-events:auto;inset:calc(var(--spacing) * 0);z-index:50;background-color:var(--overlay-base-a60);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);place-items:center;display:grid}#modal_overlay>.modal{width:100%;max-width:var(--container-2xl);gap:calc(var(--spacing) * 4);border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding:calc(var(--spacing) * 6);overflow-wrap:break-word;white-space:normal;--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-backdrop-blur:blur(var(--blur-lg));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);flex-direction:column;display:flex}#modal_overlay>.modal h4{margin-bottom:calc(var(--spacing) * 0);text-align:center}#modal_overlay>.modal h4 em{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--primary)}#modal_overlay>.modal h5{margin-block:calc(var(--spacing) * 3);color:var(--foreground)}#modal_overlay>.modal p{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);color:var(--foreground)}#modal_overlay>.modal>ul{border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);padding:calc(var(--spacing) * 3);overflow:auto}#modal_overlay>.modal label.btn{border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);color:var(--foreground)}@media (hover:hover){#modal_overlay>.modal label.btn:hover{border-color:var(--border)}}#modal_overlay>.modal pre{overflow:auto}#modal_overlay>.modal pre.errors{border-color:var(--destructive-a60);background-color:var(--destructive-a20);color:var(--destructive)}#modal_overlay>.modal pre+pre{margin-top:calc(var(--spacing) * 3)}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.left,#modal_overlay>.modal div.right{gap:calc(var(--spacing) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding:calc(var(--spacing) * 4);flex-shrink:0;display:flex}#modal_overlay>.modal div.left{justify-content:flex-start}#modal_overlay>.modal .button-row,#modal_overlay>.modal div.right{justify-content:flex-end}#modal_overlay>.modal.uci-dialog ins,#modal_overlay>.modal.uci-dialog del,#modal_overlay>.modal.uci-dialog var{font-family:var(--font-mono);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);font-style:normal;text-decoration-line:none}#modal_overlay>.modal.uci-dialog ins{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--success);background-color:var(--success-a80);color:var(--success-fg)}#modal_overlay>.modal.uci-dialog del{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--destructive);background-color:var(--destructive-a80);color:var(--destructive-fg)}#modal_overlay>.modal.uci-dialog var{border-radius:calc(var(--radius-base) * .5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--info);background-color:var(--info-a80);color:var(--info-fg)}#modal_overlay>.modal.uci-dialog .uci-change-legend{margin-top:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 3);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--background-a60);padding:calc(var(--spacing) * 4);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground);display:flex}#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label ins,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label del,#modal_overlay>.modal.uci-dialog .uci-change-legend .uci-change-legend-label var{height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);justify-content:center;align-items:center;display:flex}#modal_overlay>.modal.uci-dialog .uci-change-list{margin-top:calc(var(--spacing) * 4)}:where(#modal_overlay>.modal.uci-dialog .uci-change-list>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}#modal_overlay>.modal.uci-dialog .uci-change-list h5{margin-top:calc(var(--spacing) * 4);margin-bottom:calc(var(--spacing) * 2);border-radius:var(--radius-base);background-color:var(--muted);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}#modal_overlay>.modal.uci-dialog .uci-change-list h5:first-child{margin-top:calc(var(--spacing) * 0)}#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del{border-radius:var(--radius-base);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:block}:is(#modal_overlay>.modal.uci-dialog .uci-change-list ins,#modal_overlay>.modal.uci-dialog .uci-change-list del) strong{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}#modal_overlay>.modal.uci-dialog .uci-change-list var{border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:inline-block}#modal_overlay>.modal.uci-dialog .uci-change-list var ins,#modal_overlay>.modal.uci-dialog .uci-change-list var del{margin-left:calc(var(--spacing) * 1);padding-inline:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-block:1px;display:inline-block}table.table,.table{margin-bottom:calc(var(--spacing) * 4);border-collapse:separate;--tw-border-spacing-x:calc(var(--spacing) * 0);--tw-border-spacing-y:calc(var(--spacing) * 0);width:100%;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);overflow:visible}@media not all and (width>=48rem){table.table,.table{border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;display:block}}:is(table.table,.table)[width="100%"]{width:100%}:is(table.table,.table)[width="33%"]{width:33.3333%}:is(table.table,.table) .cbi-section-table-titles{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):before{content:var(--tw-content);content:var(--tw-content);border-bottom-style:var(--tw-border-style);content:var(--tw-content);border-bottom-width:1px;border-color:var(--border);content:var(--tw-content);padding-inline:calc(var(--spacing) * 3);content:var(--tw-content);padding-block:calc(var(--spacing) * 2.5);content:var(--tw-content);vertical-align:middle;content:var(--tw-content);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-content:attr(data-title);content:var(--tw-content);display:table-cell}:is(:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):not([data-title]),:is(:is(table.table,.table) .cbi-section-table-titles.named,:is(table.table,.table) .cbi-section-table-descr.named,:is(table.table,.table) .cbi-section-table-row[data-title]):has(td.cbi-section-table-titles)):before{content:var(--tw-content);--tw-content:none;content:none}:is(table.table,.table) .cbi-section-table-titles.named:before{content:var(--tw-content);border-top-left-radius:var(--radius-base);content:var(--tw-content);background-color:var(--label-surface)}@media not all and (width>=48rem){:is(table.table,.table) tbody,:is(table.table,.table) .tbody{display:block}}:is(table.table,.table) tr,:is(table.table,.table) .tr{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}@media (hover:hover){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):hover{background-color:var(--label-surface)}}@media not all and (width>=48rem){:is(table.table,.table) tr,:is(table.table,.table) .tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}}@media (width>=48rem){:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child:not([data-title]) .th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child:not([data-title]) .td):first-child{border-top-left-radius:var(--radius-base)}:is(:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .th,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):first-child .td):last-child{border-top-right-radius:var(--radius-base)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child[data-title]:before{content:var(--tw-content);border-bottom-left-radius:var(--radius-base)}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td:first-child{border-bottom-left-radius:var(--radius-base)}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr):last-child .td:last-child{border-bottom-right-radius:var(--radius-base)}}@media not all and (width>=48rem){:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-titles,:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-section-table-descr{display:none}}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-1{background-color:var(--panel-bg)}:is(:is(table.table,.table) tr,:is(table.table,.table) .tr).cbi-rowstyle-2{background-color:var(--label-surface-a50)}:is(table.table,.table) th,:is(table.table,.table) .th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}@media not all and (width>=48rem){:is(table.table,.table) th,:is(table.table,.table) .th{display:none}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="100%"]{width:100%}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[width="33%"]{width:33.3333%}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]{cursor:pointer;-webkit-user-select:none;user-select:none}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:after{content:var(--tw-content);margin-left:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}@media (hover:hover){:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true]:hover{background-color:var(--label-surface)}}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=asc]:after{--tw-content:"▲";content:var(--tw-content)}:is(:is(table.table,.table) th,:is(table.table,.table) .th)[data-sortable-row=true][data-sort-direction=desc]:after{--tw-content:"▼";content:var(--tw-content)}:is(table.table,.table) td,:is(table.table,.table) .td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));overflow-wrap:break-word;white-space:normal;display:table-cell}@media not all and (width>=48rem){:is(table.table,.table) td,:is(table.table,.table) .td{border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * 1);border-width:0;flex:50%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content);--tw-content:attr(data-title);content:var(--tw-content);content:var(--tw-content);display:none}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{margin-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));display:block}}:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{content:var(--tw-content)}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td):before{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=text],:is(:is(table.table,.table) td,:is(table.table,.table) .td)>input[type=password],:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){width:100%}:is(:is(table.table,.table) td,:is(table.table,.table) .td) select,:is(:is(table.table,.table) td,:is(table.table,.table) .td) .cbi-dropdown:not(.btn):not(.cbi-button){min-width:fit-content}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{overflow-wrap:anywhere}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{margin-bottom:calc(var(--spacing) * 1);text-align:left;flex-basis:100%;align-self:flex-start}}@media (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field{max-width:65ch}}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.DummyValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.Button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=CBI\.FlagValue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=dvalue],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=button],:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-value-field[data-widget=fvalue]{flex-basis:50%}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions{flex:0 0 100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td).cbi-section-actions>div>.cbi-button{flex:1}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)>.cbi-button{width:100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{width:100%}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="100%"]{flex:0 0 100%}}:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{width:33.3333%}@media not all and (width>=48rem){:is(:is(table.table,.table) td,:is(table.table,.table) .td)[width="33%"]{flex:0 0 33.333%}}.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell{width:auto!important}#content_syslog>div{align-items:center;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}#content_syslog>div>select,#content_syslog>div>input{margin-block:calc(var(--spacing) * 0)!important}#content_syslog>.syslog-view{display:block}#syslog,#log_textarea{width:100%;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}#syslog{margin-bottom:calc(var(--spacing) * 5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--terminal-bg);padding:calc(var(--spacing) * 4);color:var(--terminal-foreground)}#content_syslog.log-enhanced>#syslog{display:none}.syslog-view{margin-bottom:calc(var(--spacing) * 5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--terminal-bg);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 4);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:1.7;color:var(--terminal-foreground);--tw-outline-style:none;outline-style:none;line-height:1.7;overflow-x:auto}.syslog-view:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring-a50)}.syslog-view .log-row{border-radius:calc(var(--radius-base) * .5);width:max-content;min-width:100%;padding-inline:calc(var(--spacing) * 2);white-space:pre}.syslog-view .log-row:hover{background-color:var(--terminal-hover)}.syslog-view ::selection{background-color:var(--info-a40)}.syslog-view .log-time{opacity:.55}.syslog-view .log-sev{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.syslog-view .log-tag{opacity:.8}@media (width>=48rem){.syslog-view .log-time,.syslog-view .log-sev,.syslog-view .log-tag{vertical-align:bottom;display:inline-block}.syslog-view .log-time{min-width:24ch}.syslog-view .log-sev{min-width:16ch}.syslog-view .log-tag{min-width:18ch}}.syslog-view .lv-info .log-sev{color:var(--info)}.syslog-view .lv-notice .log-sev{color:var(--success)}.syslog-view .lv-warn .log-sev{color:var(--warning)}.syslog-view .lv-debug{opacity:.5}.syslog-view .lv-err,.syslog-view .lv-crit{background-color:var(--destructive-a20)}:is(.syslog-view .lv-err,.syslog-view .lv-crit):hover{background-color:var(--destructive-a30)}:is(.syslog-view .lv-err,.syslog-view .lv-crit) .log-sev{color:var(--destructive)}.cbi-input-invalid,.cbi-value-error{border-color:var(--destructive-a70)!important}:is(.cbi-input-invalid,.cbi-value-error):focus{--tw-ring-color:var(--destructive-a40)!important}.cbi-value{gap:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 1.5);flex-flow:wrap;display:flex}@media not all and (width>=48rem){.cbi-value{gap:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * 1);flex-direction:column}}.cbi-value.hidden{display:none}.cbi-value+.cbi-value{margin-top:calc(var(--spacing) * 3)}.cbi-value>.cbi-value-title{padding-top:calc(var(--spacing) * 1);text-align:right;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground)}@media not all and (width>=48rem){.cbi-value>.cbi-value-title{text-align:left}}@media (width>=48rem){.cbi-value>.cbi-value-title{flex:0 0 10rem}}.cbi-value>.cbi-value-field{flex:1;max-width:100%}.cbi-value>.cbi-value-field:has(>.cbi-dropdown[disabled]){cursor:not-allowed}.cbi-value>.cbi-value-field .cbi-value-description{margin-top:calc(var(--spacing) * 1);padding-left:calc(var(--spacing) * 5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:1;overflow-wrap:break-word;color:var(--muted-foreground);line-height:1;position:relative}.cbi-value>.cbi-value-field .cbi-value-description:not(:empty):before{content:var(--tw-content);content:var(--tw-content);left:calc(var(--spacing) * 0);content:var(--tw-content);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);background-color:var(--primary);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);display:inline-block;position:absolute;-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-info'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cpath%20d='M12%2016v-4'/%3e%3cpath%20d='M12%208h.01'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-info'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3ccircle%20cx='12'%20cy='12'%20r='10'/%3e%3cpath%20d='M12%2016v-4'/%3e%3cpath%20d='M12%208h.01'/%3e%3c/svg%3e");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.cbi-value>.cbi-section,.cbi-value>.cbi-tblsection{width:100%}.cbi-dynlist{width:max-content;max-width:calc(var(--spacing) * 96);align-items:flex-start;gap:calc(var(--spacing) * 3);flex-direction:column;display:inline-flex}@media not all and (width>=48rem){.cbi-dynlist{max-width:100%}}.cbi-dynlist .item{pointer-events:auto;cursor:move;align-items:flex-start;gap:calc(var(--spacing) * 2);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--panel-bg);padding-block:calc(var(--spacing) * 3);padding-right:calc(var(--spacing) * 9);padding-left:calc(var(--spacing) * 4);word-break:break-all;--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;-webkit-user-select:text;user-select:text;flex-direction:column;align-self:stretch;transition-duration:.2s;display:inline-flex;position:relative;overflow:hidden}.cbi-dynlist .item:after{content:"×";top:calc(var(--spacing) * 2);right:calc(var(--spacing) * 2);height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);cursor:pointer;border-radius:calc(var(--radius-base) * .5);background-color:var(--muted);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--muted-foreground);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-dynlist .item.dragging{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y);cursor:grabbing;opacity:.5;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-dynlist .item.drag-over{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y);border-color:var(--primary-a60);background-color:var(--primary-a5);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring)}.cbi-dynlist .item>span,.cbi-dynlist .item>code{pointer-events:none;border-radius:calc(var(--radius-base) * .5);width:100%;font-family:var(--font-mono);--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.cbi-dynlist .placeholder{word-break:break-all}.cbi-dynlist .add-item{align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * 1);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;background-color:#0000;align-self:stretch;transition-duration:.2s;display:inline-flex}@media (hover:hover){.cbi-dynlist .add-item:hover{border-color:var(--border-a80);background-color:var(--muted-a30)}}.cbi-dynlist .add-item>input{min-width:calc(var(--spacing) * 56);flex:1}.cbi-dynlist .add-item>.cbi-button{min-height:calc(var(--spacing) * 6);min-width:calc(var(--spacing) * 6);cursor:pointer;border-radius:calc(var(--radius-base) * .5);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 0);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.cbi-dynlist .add-item>.cbi-button:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.cbi-tabmenu{margin-bottom:calc(var(--spacing) * 2);min-height:calc(var(--spacing) * 9);align-items:center;gap:calc(var(--spacing) * 0);border-radius:var(--radius-base);background-color:var(--muted);width:fit-content;max-width:100%;color:var(--muted-foreground);padding:3px;display:inline-flex;overflow-x:auto}.cbi-tabmenu li{margin:calc(var(--spacing) * 0);flex-shrink:0;min-width:fit-content;list-style-type:none;position:relative}.cbi-tabmenu li[data-errors]:after{content:var(--tw-content);content:var(--tw-content);top:calc(var(--spacing) * -.5);content:var(--tw-content);right:calc(var(--spacing) * -1.5);content:var(--tw-content);z-index:20;content:var(--tw-content);content:var(--tw-content);min-height:calc(var(--spacing) * 4);content:var(--tw-content);min-width:calc(var(--spacing) * 4);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:var(--destructive);content:var(--tw-content);padding-inline:calc(var(--spacing) * 1);content:var(--tw-content);padding-block:calc(var(--spacing) * .5);content:var(--tw-content);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));content:var(--tw-content);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);content:var(--tw-content);color:var(--destructive-fg);--tw-content:attr(data-errors);content:var(--tw-content);border-radius:3.40282e38px;justify-content:center;align-items:center;display:inline-flex;position:absolute}.cbi-tabmenu li[data-errors]>a{border-style:var(--tw-border-style);border-width:1px;border-color:var(--destructive-a50)}.cbi-tabmenu li>a{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--muted-foreground);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-width:1px;border-color:#0000;justify-content:center;align-items:center;text-decoration-line:none;display:inline-flex}@media (hover:hover){.cbi-tabmenu li>a:hover{color:var(--foreground)}}.cbi-tabmenu li>a:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--ring-a50);--tw-outline-style:none;outline-style:none}.cbi-tabmenu li.cbi-tab>a{background-color:var(--background);color:var(--foreground);--tw-shadow:var(--shadow-sm);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.cbi-tabmenu li.cbi-tab>a:where([data-darkmode=true],[data-darkmode=true] *){border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--input-a30)}[data-tab-title]{visibility:hidden;height:calc(var(--spacing) * 0);overflow:hidden}[data-tab-active=true]{visibility:visible;height:auto;overflow:visible}#tabmenu{margin-bottom:calc(var(--spacing) * 6);width:100%}.tabs{align-items:center;gap:calc(var(--spacing) * 0);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);display:flex;position:relative;overflow-x:auto}.tabs a{padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 3);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;color:var(--muted-foreground);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;display:block}@media (hover:hover){.tabs a:hover{color:var(--foreground);text-decoration-line:none}}.tabs>li.active{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--foreground)}.tabs>li.active>a{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--foreground)}.cbi-section-node-tabbed{margin-top:calc(var(--spacing) * 4)}button.cmdk-trigger{height:calc(var(--spacing) * 8);cursor:pointer;align-items:center;gap:calc(var(--spacing) * 2.5);border-radius:var(--radius-base);border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);padding-right:calc(var(--spacing) * 1.5);padding-left:calc(var(--spacing) * 7.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground);background-color:#0000;display:flex;position:relative}@media not all and (width>=48rem){button.cmdk-trigger{width:calc(var(--spacing) * 8);border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);border-width:0;justify-content:center}}button.cmdk-trigger:before{pointer-events:none;left:calc(var(--spacing) * 2.5);width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);--tw-content:"";content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat}@media not all and (width>=48rem){button.cmdk-trigger:before{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);position:static}}button.cmdk-trigger:hover{border-color:var(--muted-foreground)}@media not all and (width>=48rem){button.cmdk-trigger:hover{background-color:var(--muted)}}.cmdk-trigger-label{text-overflow:ellipsis;white-space:nowrap;text-align:left;overflow:hidden}@media not all and (width>=48rem){.cmdk-trigger-label{display:none}}.cmdk-trigger-key{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);padding-block:1px}@media not all and (width>=48rem){.cmdk-trigger-key{display:none}}#cmdk-overlay{inset:calc(var(--spacing) * 0);z-index:50;background-color:var(--overlay-base-a60);--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);justify-content:center;align-items:flex-start;display:flex;position:fixed}@media not all and (width>=48rem){#cmdk-overlay{--tw-backdrop-blur: ;-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);background-color:#0000}}#cmdk-overlay[hidden]{display:none}.cmdk-panel{border-radius:calc(var(--radius-base) * 1.5);border-style:var(--tw-border-style);border-width:1px;border-color:var(--panel-border);background-color:var(--panel-bg);--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);width:min(560px,100vw - 32px);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;--tw-ease:var(--ease-out);transition-duration:.15s;transition-timing-function:var(--ease-out);flex-direction:column;margin-top:15vh;display:flex;overflow:hidden}@starting-style{.cmdk-panel{--tw-translate-y:calc(var(--spacing) * -1.5);translate:var(--tw-translate-x) var(--tw-translate-y)}}@starting-style{.cmdk-panel{opacity:0}}@media not all and (width>=48rem){.cmdk-panel{margin-top:calc(var(--spacing) * 0);border-style:var(--tw-border-style);width:100%;height:100dvh;padding-top:env(safe-area-inset-top);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-width:0;border-radius:0;transition-property:none}}.cmdk-inputrow{height:calc(var(--spacing) * 12);align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--panel-border);padding-right:calc(var(--spacing) * 3);padding-left:calc(var(--spacing) * 10);flex-shrink:0;display:flex;position:relative}@media not all and (width>=48rem){.cmdk-inputrow{height:calc(var(--spacing) * 14);padding-right:calc(var(--spacing) * 1.5)}}.cmdk-inputrow:before{pointer-events:none;left:calc(var(--spacing) * 3.5);width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);color:var(--muted-foreground);--tw-content:"";content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10%2010m-7%200a7%207%200%201%200%2014%200a7%207%200%201%200%20-14%200'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M21%2021l-6%20-6'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3c/svg%3e") 50%/contain no-repeat}.cmdk-inputrow:has(input.cmdk-input:placeholder-shown) button.cmdk-clear{display:none}input.cmdk-input{height:100%;min-width:calc(var(--spacing) * 0);border-style:var(--tw-border-style);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;background-color:#0000;border-width:0;outline-style:none;flex:1}@media not all and (width>=48rem){input.cmdk-input{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}}input.cmdk-input:focus{border-style:var(--tw-border-style);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;border-width:0;outline-style:none}button.cmdk-clear{width:calc(var(--spacing) * 5.5);height:calc(var(--spacing) * 5.5);cursor:pointer;border-style:var(--tw-border-style);padding:calc(var(--spacing) * 0);color:var(--muted-foreground);background-color:#0000;border-width:0;border-radius:3.40282e38px;flex-shrink:0;justify-content:center;align-items:center;display:flex}button.cmdk-clear:before{width:calc(var(--spacing) * 3.25);height:calc(var(--spacing) * 3.25);--tw-content:"";content:var(--tw-content);background-color:currentColor;-webkit-mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-x'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M18%206%206%2018'%20/%3e%3cpath%20d='m6%206%2012%2012'%20/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-x'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M18%206%206%2018'%20/%3e%3cpath%20d='m6%206%2012%2012'%20/%3e%3c/svg%3e") 50%/contain no-repeat}button.cmdk-clear:hover{background-color:var(--muted);color:var(--foreground)}button.cmdk-cancel{cursor:pointer;border-style:var(--tw-border-style);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--primary);background-color:#0000;border-width:0;flex-shrink:0;display:none}@media not all and (width>=48rem){button.cmdk-cancel{padding-block:calc(var(--spacing) * 1.5);padding-right:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 1.5);display:block}}.cmdk-list{overscroll-behavior:contain;max-height:342px;padding:calc(var(--spacing) * 1);overflow-y:auto}@media not all and (width>=48rem){.cmdk-list{max-height:none;padding:calc(var(--spacing) * 2);padding-bottom:calc(.75rem + env(safe-area-inset-bottom));flex:1}}.cmdk-group{padding-inline:calc(var(--spacing) * 2);padding-top:calc(var(--spacing) * 2.5);padding-bottom:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--muted-foreground)}.cmdk-row{cursor:pointer;justify-content:flex-start;align-items:center;gap:calc(var(--spacing) * 2);border-radius:var(--radius-base);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1.5);text-align:left;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text);background-color:#0000;border-width:0;text-decoration-line:none;display:flex}@media not all and (width>=48rem){.cmdk-row{min-height:calc(var(--spacing) * 11);padding-inline:calc(var(--spacing) * 2.5)}}.cmdk-row:hover{text-decoration-line:none}.cmdk-row img.shadcn-icon{width:calc(var(--spacing) * 3.75);height:calc(var(--spacing) * 3.75);flex-shrink:0}.cmdk-row mark{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--primary);background-color:#0000}.cmdk-row .cmdk-title{min-width:calc(var(--spacing) * 0);text-overflow:ellipsis;white-space:nowrap;--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--foreground);overflow:hidden}.cmdk-row .cmdk-group-name{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);flex-shrink:0;margin-left:auto}.cmdk-row .cmdk-check{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);color:var(--primary);background-color:currentColor;flex-shrink:0;margin-left:auto;display:block;-webkit-mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-check'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M20%206%209%2017l-5-5'/%3e%3c/svg%3e") 50%/contain no-repeat}.cmdk-row.is-selected{background-color:var(--muted)}.cmdk-empty{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 7);text-align:center;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted-foreground)}.cmdk-footer{align-items:center;gap:calc(var(--spacing) * 3.5);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--panel-border);background-color:var(--background-a60);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted-foreground);flex-shrink:0;display:flex}@media not all and (width>=48rem){.cmdk-footer{display:none}}.cmdk-footer kbd{border-radius:calc(var(--radius-base) * .75);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--label-surface);padding-inline:calc(var(--spacing) * 1.5);font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-block:1px}.cmdk-footer .cmdk-hint{align-items:center;gap:calc(var(--spacing) * 1.5);display:flex}.cmdk-footer .cmdk-hint-close{margin-left:auto}@view-transition{navigation:auto}#sidebar{view-transition-name:shadcn-sidebar}@media (prefers-reduced-motion:reduce){@view-transition{navigation:none}}#luci-nav-progress{pointer-events:none;top:calc(var(--spacing) * 0);left:calc(var(--spacing) * 0);z-index:80;height:calc(var(--spacing) * .5);width:calc(var(--spacing) * 0);--tw-gradient-position:to right;position:fixed}@supports (background-image:linear-gradient(in lab, red, red)){#luci-nav-progress{--tw-gradient-position:to right in oklab}}#luci-nav-progress{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:var(--progress-bar-start);--tw-gradient-to:var(--progress-bar-end);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;--tw-ease:var(--ease-out);transition-duration:.3s;transition-timing-function:var(--ease-out)}#luci-nav-progress[data-state=done]{opacity:0;transition:width .3s ease-out,opacity .15s ease-in .15s}#luci-nav-status{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}#maincontent{--tw-outline-style:none;outline-style:none}#maincontent .view-staging{visibility:hidden;height:calc(var(--spacing) * 0);overflow:hidden}#maincontent #view.view-leaving{cursor:progress;opacity:.6;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}.hidden{display:none!important}.left{text-align:left!important}@media (width>=48rem){.left:is(td){text-align:left!important}}.right{text-align:right!important}@media (width>=48rem){.right:is(td){text-align:right!important}}.center{text-align:center!important}@media (width>=48rem){.center:is(td){text-align:center!important}}.top{vertical-align:top!important}@media (width>=48rem){.top:is(td){vertical-align:top!important}}.bottom{vertical-align:bottom!important}@media (width>=48rem){.bottom:is(td){vertical-align:bottom!important}}.middle{vertical-align:middle!important}@media (width>=48rem){.middle:is(td){vertical-align:middle!important}}.nowrap:not(span){white-space:nowrap}.fade-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none);--tw-duration:.4s;--tw-enter-opacity:0;--tw-animation-fill-mode:backwards;transition-duration:.4s;animation-fill-mode:backwards}.fade-out{pointer-events:none;opacity:0;transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.4s;transition-duration:.4s}.spinning{position:relative;padding-left:calc(var(--spacing) * 7)!important}.spinning:before{content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);top:50%;left:calc(var(--spacing) * 1.5);content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4);content:var(--tw-content);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);content:var(--tw-content);animation:var(--animate-spin);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);content:var(--tw-content);background-color:currentColor;position:absolute;-webkit-mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-loader-2'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%2012a9%209%200%201%201-6.219-8.56'/%3e%3c/svg%3e");mask-image:url("data:image/svg+xml,%3c!--%20@license%20lucide-static%20v1.16.0%20-%20ISC%20--%3e%3csvg%20class='lucide%20lucide-loader-2'%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='currentColor'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20d='M21%2012a9%209%200%201%201-6.219-8.56'/%3e%3c/svg%3e");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:cover;mask-size:cover;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}#view>.spinning:first-child{min-height:calc(var(--spacing) * 48);place-items:center;width:fit-content;margin-inline:auto;display:grid}html{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-darkmode=true]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}.card-header img,.login-input-icon img,.login-pw-toggle img,img.shadcn-icon{filter:brightness(0)saturate()}html[data-darkmode=true] .card-header img,html[data-darkmode=true] .login-input-icon img,html[data-darkmode=true] .login-pw-toggle img,html[data-darkmode=true] img.shadcn-icon{filter:brightness(0)saturate()invert()}.card-header img,img.shadcn-icon,#sidebar img.shadcn-icon{opacity:.65}html[data-darkmode=true] #sidebar img.shadcn-icon{opacity:.7}.card-header button:hover img,#sidebar .sidebar-nav-item.active img,#sidebar .sidebar-accordion-item.active img,#sidebar .sidebar-nav-parent:hover img{opacity:1}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}} diff --git a/openlist2/Makefile b/openlist2/Makefile index 49cb2e470..75349ff88 100644 --- a/openlist2/Makefile +++ b/openlist2/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openlist2 PKG_VERSION:=4.2.6 PKG_WEB_VERSION:=4.2.6 -PKG_RELEASE:=15 +PKG_RELEASE:=16 PKG_SOURCE:=openlist-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/OpenListTeam/OpenList/tar.gz/v$(PKG_VERSION)? @@ -51,7 +51,8 @@ define Package/openlist2 SUBMENU:=Web Servers/Proxies TITLE:=A file list program that supports multiple storage URL:=https://doc.oplist.org/ - DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle + DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle +jshn +jsonfilter + PROVIDES:=openlist2-helper endef define Package/openlist2/conffiles @@ -84,10 +85,14 @@ define Package/openlist2/install $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR)) $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/OpenList $(1)/usr/bin/openlist2 - $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d $(1)/etc/openlist2 + $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d $(1)/etc/openlist2 $(1)/etc/uci-defaults + $(INSTALL_DIR) $(1)/usr/libexec $(1)/usr/share/openlist2 $(INSTALL_CONF) $(CURDIR)/files/openlist2.config $(1)/etc/config/openlist2 $(INSTALL_BIN) $(CURDIR)/files/openlist2.init $(1)/etc/init.d/openlist2 - $(INSTALL_DATA) $(CURDIR)/files/data.db $(1)/etc/openlist2/data.db + $(INSTALL_DATA) $(CURDIR)/files/openlist2.common $(1)/usr/share/openlist2/functions.sh + $(INSTALL_BIN) $(CURDIR)/files/openlist2.helper $(1)/usr/libexec/openlist2-helper + $(INSTALL_BIN) $(CURDIR)/files/openlist2.defaults $(1)/etc/uci-defaults/99-openlist2 + $(INSTALL_CONF) $(CURDIR)/files/data.db $(1)/etc/openlist2/data.db endef $(eval $(call Download,openlist-frontend)) diff --git a/openlist2/files/data.db b/openlist2/files/data.db index 6303634cdeb6bf6423780eeba419b255c8c6a493..cb47e56df2b2031fca6ed8d51a62c7a62aa66980 100644 GIT binary patch delta 102 zcmZoTz}Rqrae}lU3j+fK8xX?)^F$qERu%@msV6q3EaDe?z`%czzlqqH}U)PYwE76w&olXfj9h(@JeOvpDX%CmBPU~WX>mz@Ze~?#d`4D zt&)CXadB!%v3@~*PGwqVPL5t~W}aSFv3*)VsffuPL7hDjXuOIyOPw35*9gqDNbi`kd+*an>A!_H~|31p*#2h diff --git a/openlist2/files/openlist2.common b/openlist2/files/openlist2.common new file mode 100644 index 000000000..efaeb604c --- /dev/null +++ b/openlist2/files/openlist2.common @@ -0,0 +1,252 @@ +#!/bin/sh +# Shared validation for the service and its limited LuCI helper. + +openlist2_error() { + printf 'openlist2: %s\n' "$*" >&2 + logger -t openlist2 "$*" 2>/dev/null + return 1 +} + +openlist2_read_scalar() { + # Preserve the value itself, including any trailing newline. Remove only + # the one output terminator emitted by uci/jsonfilter. + OPENLIST2_VALUE="$("$@"; printf '.')" + OPENLIST2_VALUE="${OPENLIST2_VALUE%.}" + OPENLIST2_VALUE="${OPENLIST2_VALUE%' +'}" +} + +openlist2_port() { + local value="$1" + [ "$value" = "-1" ] && [ "${2:-0}" = "1" ] && { printf '%s\n' -1; return 0; } + case "$value" in ''|*[!0-9]*) return 1 ;; esac + value="$(printf '%s' "$value" | sed 's/^0*//')" + [ -n "$value" ] && [ "${#value}" -le 5 ] || return 1 + [ "$value" -ge 1 ] && [ "$value" -le 65535 ] || return 1 + printf '%s\n' "$value" +} + +openlist2_safe_log_path() { + local filename="${1##*/}" + [ "$1" = "/var/log/$filename" ] || return 1 + case "$filename" in ''|*[!A-Za-z0-9._-]*) return 1 ;; esac + printf '%s\n' "$1" | grep -Eq '^/var/log/openlist2([._-][A-Za-z0-9._-]+)?$' || return 1 + # Do not let a root helper follow a user-created log file symlink. + [ ! -L "$1" ] && { [ ! -e "$1" ] || [ -f "$1" ]; } +} + +openlist2_normalize_dir() { + local path="$1" suffix="" part + case "$path" in /*) ;; *) return 1 ;; esac + case "$path" in *' +'*|*' '*|*"$(printf '\r')"*) return 1 ;; esac + if printf '%s' "$path" | LC_ALL=C grep -q '[[:cntrl:]]'; then return 1; fi + path="$(printf '%s' "$path" | sed 's://*:/:g; s:/*$::')" + [ -n "$path" ] || path="/" + case "$path/" in */../*|*/./*) return 1 ;; esac + while [ ! -d "$path" ]; do + [ ! -e "$path" ] && [ ! -L "$path" ] || return 1 + part="${path##*/}" + suffix="/$part$suffix" + path="${path%/*}" + [ -n "$path" ] || path="/" + done + path="$(CDPATH='' cd "$path" 2>/dev/null && pwd -P && printf '.')" || return 1 + path="${path%.}" + path="${path%' +'}" + case "$path" in *' +'*) return 1 ;; esac + if printf '%s' "$path" | LC_ALL=C grep -q '[[:cntrl:]]'; then return 1; fi + [ "$path" != "/" ] || [ -n "$suffix" ] || { printf '/\n'; return 0; } + printf '%s\n' "${path%/}$suffix" +} + +openlist2_contains_path() { + case "$2/" in "$1/"*) return 0 ;; esac + return 1 +} + +openlist2_broad_dir() { + case "$1" in + ''|/|/bin|/boot|/dev|/etc|/home|/lib|/lib64|/media|/mnt|/opt|/overlay|/proc|/root|/rom|/run|/sbin|/srv|/sys|/tmp|/usr|/var|/www|/tmp/log|/tmp/run|/usr/*|/bin/*|/sbin/*|/lib/*|/lib64/*|/dev/*|/proc/*|/sys/*|/rom/*|/overlay/*|/etc/config|/etc/config/*|/etc/dropbear|/etc/dropbear/*|/etc/ssl|/etc/ssl/*|/tmp/log/*|/www/*) + return 0 ;; + esac + return 1 +} + +openlist2_mountpoint() { + [ -d "$1" ] || return 1 + if command -v mountpoint >/dev/null 2>&1; then + mountpoint -q "$1" + return $? + fi + awk -v target="$1" ' + { + p = $5 + gsub(/\\040/, " ", p) + gsub(/\\134/, "\\", p) + if (p == target) found = 1 + } + END { exit !found } + ' /proc/self/mountinfo +} + +openlist2_validate_dirs() { + data_dir="$(openlist2_normalize_dir "$data_dir")" || + { openlist2_error "Data directory must be an absolute directory path without dot segments."; return 1; } + temp_dir="$(openlist2_normalize_dir "$temp_dir")" || + { openlist2_error "Cache directory must be an absolute directory path without dot segments."; return 1; } + bleve_dir="$(openlist2_normalize_dir "${bleve_dir:-$data_dir/bleve}")" || + { openlist2_error "Invalid Bleve index directory."; return 1; } + local path protected + for path in "$data_dir" "$temp_dir" "$bleve_dir"; do + if openlist2_broad_dir "$path" || openlist2_mountpoint "$path"; then + openlist2_error "Use a dedicated subdirectory, not a system directory or mount root: $path" + return 1 + fi + done + case "$temp_dir" in + /mnt/*|/media/*) + path="${temp_dir#/}"; path="${path#*/}" + case "$path" in */*) ;; *) + openlist2_error "Use a cache subdirectory below the disk mount: $temp_dir"; return 1 ;; + esac ;; + esac + if openlist2_contains_path "$temp_dir" "$data_dir" || + openlist2_contains_path "$bleve_dir" "$data_dir" || + openlist2_contains_path "$temp_dir" "$bleve_dir" || + openlist2_contains_path "$bleve_dir" "$temp_dir"; then + openlist2_error "Cache and index directories must be separate and must not contain the data directory." + return 1 + fi + if [ -n "$dist_dir" ]; then + dist_dir="$(openlist2_normalize_dir "$dist_dir")" || return 1 + if openlist2_broad_dir "$dist_dir" || openlist2_mountpoint "$dist_dir" || + openlist2_contains_path "$dist_dir" "$data_dir" || + openlist2_contains_path "$dist_dir" "$temp_dir" || + openlist2_contains_path "$temp_dir" "$dist_dir" || + openlist2_contains_path "$dist_dir" "$bleve_dir" || + openlist2_contains_path "$bleve_dir" "$dist_dir"; then + openlist2_error "Frontend files must be separate from private data, cache and index files." + return 1 + fi + [ -f "$dist_dir/index.html" ] && [ -r "$dist_dir/index.html" ] || + { openlist2_error "The frontend directory must contain a readable index.html."; return 1; } + fi + # shellcheck disable=SC2154 + for path in "$ssl_cert" "$ssl_key"; do + [ -n "$path" ] || continue + protected="$(readlink -f "$path" 2>/dev/null)" || protected="$path" + if openlist2_contains_path "$temp_dir" "$protected" || + { [ -n "$dist_dir" ] && openlist2_contains_path "$dist_dir" "$protected"; }; then + openlist2_error "TLS files must not be inside the cache or public frontend directory." + return 1 + fi + done +} + +openlist2_prepare_dirs() { + local entry identity previous registered marker="$data_dir/.temp-dir" + umask 077 + mkdir -p "$data_dir" "$temp_dir" "$bleve_dir" || + { openlist2_error "Unable to create data, cache or index directory."; return 1; } + [ ! -L "$data_dir/config.json" ] && [ ! -L "$marker" ] || + { openlist2_error "Config and cache ownership files must not be symlinks."; return 1; } + [ ! -e "$data_dir/config.json" ] || [ -f "$data_dir/config.json" ] || + { openlist2_error "config.json must be a regular file."; return 1; } + [ ! -e "$marker" ] || [ -f "$marker" ] || + { openlist2_error "Cache ownership marker must be a regular file."; return 1; } + entry="$(find "$temp_dir" -mindepth 1 -maxdepth 1 -print -quit)" || return 1 + identity="$(stat -c '%d:%i' "$temp_dir")" || return 1 + registered="$(cat "$marker" 2>/dev/null)" + if [ -n "$entry" ] && [ "$registered" != "$(printf '%s\n%s' "$temp_dir" "$identity")" ]; then + # An existing config identifies the old cache on the first upgrade. + # Once registered, an inode/device change must never inherit ownership. + previous="" + if [ ! -e "$marker" ] && [ -s "$data_dir/config.json" ]; then + openlist2_read_scalar jsonfilter -qi "$data_dir/config.json" -e '@.temp_dir' 2>/dev/null + previous="$OPENLIST2_VALUE" + previous="$(openlist2_normalize_dir "$previous")" || previous="" + fi + [ "$previous" = "$temp_dir" ] || + { openlist2_error "Refusing to clear a non-empty, unregistered cache directory. Choose a new empty subdirectory: $temp_dir"; return 1; } + fi + chmod 700 "$data_dir" "$temp_dir" "$bleve_dir" || return 1 + # Keep the marker outside the cache: OpenList clears cache contents. + ( + local marker_tmp + marker_tmp="$(mktemp "$data_dir/.temp-dir.XXXXXX")" || exit 1 + trap 'rm -f "$marker_tmp"' 0 + printf '%s\n%s\n' "$temp_dir" "$identity" > "$marker_tmp" && + chmod 600 "$marker_tmp" && mv -f "$marker_tmp" "$marker" + ) || { openlist2_error "Unable to record cache directory ownership."; return 1; } +} + +openlist2_migrate_config() { + local prefix='openlist2.@openlist2[0]' old_port old_ssl http https changed=0 size backups schema legacy + uci -q get "$prefix" >/dev/null || return 0 + old_port="$(uci -q get "$prefix.port")" + old_ssl="$(uci -q get "$prefix.ssl")" + http="$(uci -q get "$prefix.listen_http_port")" + https="$(uci -q get "$prefix.listen_https_port")" + if { [ -z "$http" ] || [ -z "$https" ]; } && { [ -n "$old_port" ] || [ -n "$old_ssl" ]; }; then + old_port="$(openlist2_port "${old_port:-5244}")" || + { openlist2_error "Invalid legacy listen port; migration stopped."; return 1; } + case "$old_ssl" in 1|on|true|yes|enabled) http="${http:--1}"; https="${https:-$old_port}" ;; *) + http="${http:-$old_port}"; https="${https:--1}" ;; + esac + uci set "$prefix.listen_http_port=$http" && + uci set "$prefix.listen_https_port=$https" || return 1 + changed=1 + fi + if [ -n "$http" ] || [ -n "$https" ]; then + legacy="$(openlist2_port "$old_port" 2>/dev/null)" || legacy="" + if [ -n "$legacy" ]; then + uci set "$prefix.legacy_firewall_port=$legacy" || return 1 + fi + if [ -n "$old_port" ]; then uci -q delete "$prefix.port" || return 1; changed=1; fi + if [ -n "$old_ssl" ]; then uci -q delete "$prefix.ssl" || return 1; changed=1; fi + fi + schema="$(uci -q get "$prefix.config_version")" + if [ "$schema" != "2" ]; then + size="$(uci -q get "$prefix.log_max_size")" + backups="$(uci -q get "$prefix.log_max_backups")" + case "$size:$backups" in + 50:30|10:5) + uci set "$prefix.log_max_size=1" && uci set "$prefix.log_max_backups=3" || return 1 ;; + esac + # These switches have no implementation in OpenList 4.2.6. + uci -q delete "$prefix.upload_task_persistant" + uci -q delete "$prefix.decompress_upload_task_persistant" + uci set "$prefix.config_version=2" || return 1 + changed=1 + fi + # Retry a previously staged migration if its commit failed. + if [ "$changed" = "1" ] || uci -q changes openlist2 | grep -q '\.config_version='; then + uci commit openlist2 || { openlist2_error "Unable to save migrated UCI configuration."; return 1; } + fi + return 0 +} + +openlist2_pasv_ports() { + local values="$1" item first last result="" oldifs="$IFS" noglob=0 + case "$values" in *[!0-9,\ -]*) return 1 ;; esac + case "$-" in *f*) noglob=1 ;; *) set -f ;; esac + IFS=' ,' + for item in $values; do + IFS="$oldifs" + first="${item%%-*}"; last="${item#*-}" + first="$(openlist2_port "$first")" && last="$(openlist2_port "$last")" && + [ "$first" -ge 1024 ] && [ "$first" -le "$last" ] || { + [ "$noglob" = "1" ] || set +f + return 1 + } + if [ "$first" = "$last" ]; then item="$first"; else item="$first-$last"; fi + result="${result:+$result }$item" + IFS=' ,' + done + IFS="$oldifs" + [ "$noglob" = "1" ] || set +f + printf '%s\n' "$result" +} diff --git a/openlist2/files/openlist2.config b/openlist2/files/openlist2.config index 3851fcd2a..ed61fa403 100644 --- a/openlist2/files/openlist2.config +++ b/openlist2/files/openlist2.config @@ -1,5 +1,6 @@ config openlist2 + option config_version '2' option enabled '0' option debug '0' option delayed_start '0' @@ -15,10 +16,12 @@ config openlist2 option tls_insecure_skip_verify '0' option data_dir '/etc/openlist2' option temp_dir '/tmp/openlist2' + option bleve_dir '' + option dist_dir '' option log '1' option log_path '/var/log/openlist2.log' - option log_max_size '50' - option log_max_backups '30' + option log_max_size '1' + option log_max_backups '3' option log_max_age '28' option log_compress '0' option log_filter '0' @@ -44,7 +47,6 @@ config openlist2 option transfer_task_persistant '0' option upload_workers '5' option upload_max_retry '0' - option upload_task_persistant '0' option copy_workers '5' option copy_max_retry '2' option copy_task_persistant '0' @@ -56,7 +58,6 @@ config openlist2 option decompress_task_persistant '0' option decompress_upload_workers '5' option decompress_upload_max_retry '2' - option decompress_upload_task_persistant '0' option allow_retry_canceled '0' option cors_allow_origins '*' option cors_allow_methods '*' @@ -66,6 +67,8 @@ config openlist2 option s3_ssl '0' option ftp '0' option ftp_port '5221' + # Listening ports matching the passive port mapping in OpenList's FTP settings. + # Example: list ftp_pasv_ports '50000-50100' option find_pasv_port_attempts '50' option active_transfer_port_non_20 '0' option idle_timeout '900' diff --git a/openlist2/files/openlist2.defaults b/openlist2/files/openlist2.defaults new file mode 100755 index 000000000..d837d326c --- /dev/null +++ b/openlist2/files/openlist2.defaults @@ -0,0 +1,4 @@ +#!/bin/sh + +. /usr/share/openlist2/functions.sh +openlist2_migrate_config diff --git a/openlist2/files/openlist2.helper b/openlist2/files/openlist2.helper new file mode 100755 index 000000000..fcac0977c --- /dev/null +++ b/openlist2/files/openlist2.helper @@ -0,0 +1,46 @@ +#!/bin/sh +# The ACL grants individual verb names, never this executable with arbitrary arguments. + +. /usr/share/openlist2/functions.sh +umask 077 + +[ "$#" -eq 1 ] || { openlist2_error "Exactly one helper action is required."; exit 64; } + +case "$1" in + log-read|log-clear) + openlist2_read_scalar uci -q get 'openlist2.@openlist2[0].log_path' + log_path="$OPENLIST2_VALUE" + log_path="${log_path:-/var/log/openlist2.log}" + openlist2_safe_log_path "$log_path" || + { openlist2_error "Unsafe log path or non-regular log file."; exit 1; } + if [ "$1" = "log-read" ]; then + [ -e "$log_path" ] || exit 0 + [ -r "$log_path" ] || { openlist2_error "Log file is not readable."; exit 1; } + # Bound output before line selection, including logs with a very long line. + log_data="$(tail -c 16383 "$log_path")" || exit 1 + printf '%s\n' "$log_data" | tail -n 200 + else + [ -e "$log_path" ] || exit 0 + chmod 600 "$log_path" && : > "$log_path" + fi + ;; + password-reset) + openlist2_read_scalar uci -q get 'openlist2.@openlist2[0].data_dir' + data_dir="$OPENLIST2_VALUE" + data_dir="$(openlist2_normalize_dir "${data_dir:-/etc/openlist2}")" || + { openlist2_error "Invalid data directory."; exit 1; } + if openlist2_broad_dir "$data_dir" || openlist2_mountpoint "$data_dir"; then + openlist2_error "Use a dedicated data subdirectory."; exit 1 + fi + [ ! -L "$data_dir/config.json" ] && [ -f "$data_dir/config.json" ] && + [ -s "$data_dir/config.json" ] || + { openlist2_error "Start OpenList once with the saved settings before resetting the password."; exit 1; } + jsonfilter -qi "$data_dir/config.json" -e '@' >/dev/null || + { openlist2_error "Invalid config.json; password was not reset."; exit 1; } + exec /usr/bin/openlist2 admin random --data "$data_dir" --no-prefix + ;; + *) + openlist2_error "Unsupported helper action." + exit 64 + ;; +esac diff --git a/openlist2/files/openlist2.init b/openlist2/files/openlist2.init index d2e25863d..f8515f8f6 100755 --- a/openlist2/files/openlist2.init +++ b/openlist2/files/openlist2.init @@ -1,25 +1,15 @@ #!/bin/sh /etc/rc.common +# UCI config_get assigns variables; rc.common consumes START and USE_PROCD. +# The && chains deliberately handle failure from every command. +# shellcheck disable=SC2034,SC2154,SC2015 . /usr/share/libubox/jshn.sh +. /usr/share/openlist2/functions.sh START=99 USE_PROCD=1 PROG=/usr/bin/openlist2 -is_safe_log_path() { - local path="$1" - local base="${path##*/}" - - case "$path" in - /var/log/*) ;; - *) return 1 ;; - esac - - [ "$path" = "/var/log/$base" ] || return 1 - - printf '%s\n' "$base" | grep -Eq '^openlist2([._-][A-Za-z0-9._-]+)?$' -} - append_dest_port() { local value="$1" @@ -65,19 +55,24 @@ json_add_csv_array() { } get_config() { + # LuCI manages the first section and procd runs one instance. + [ -z "$section_id" ] || return 0 + section_id="$1" uci_changed=0 config_get_bool enabled "$1" enabled 1 - config_get debug "$1" debug 0 - config_get allow_wan "$1" allow_wan 0 + config_get_bool debug "$1" debug 0 + config_get_bool allow_wan "$1" allow_wan 0 config_get delayed_start "$1" delayed_start 0 - config_get force "$1" force 1 + config_get_bool force "$1" force 1 config_get site_url "$1" site_url "" config_get cdn "$1" cdn "" config_get jwt_secret "$1" jwt_secret "" config_get data_dir "$1" data_dir "/etc/openlist2" config_get temp_dir "$1" temp_dir "/tmp/openlist2" + config_get bleve_dir "$1" bleve_dir "" + config_get dist_dir "$1" dist_dir "" config_get token_expires_in "$1" token_expires_in 48 config_get proxy_address "$1" proxy_address "" config_get auto_memory_limit "$1" auto_memory_limit 4 @@ -85,27 +80,27 @@ get_config() { config_get max_block_limit "$1" max_block_limit 0 config_get max_connections "$1" max_connections 0 config_get max_concurrency "$1" max_concurrency 64 - config_get tls_insecure_skip_verify "$1" tls_insecure_skip_verify 0 + config_get_bool tls_insecure_skip_verify "$1" tls_insecure_skip_verify 0 # log - config_get log "$1" log 1 + config_get_bool log "$1" log 1 config_get log_path "$1" log_path '/var/log/openlist2.log' - if ! is_safe_log_path "$log_path"; then + if ! openlist2_safe_log_path "$log_path"; then log_path='/var/log/openlist2.log' - uci -q set openlist2.@openlist2[0].log_path="$log_path" + uci -q set "openlist2.$section_id.log_path=$log_path" || { config_error=1; return 1; } uci_changed=1 fi - config_get log_max_size "$1" log_max_size 50 - config_get log_max_backups "$1" log_max_backups 30 + config_get log_max_size "$1" log_max_size 1 + config_get log_max_backups "$1" log_max_backups 3 config_get log_max_age "$1" log_max_age 28 - config_get log_compress "$1" log_compress 0 - config_get log_filter "$1" log_filter 0 + config_get_bool log_compress "$1" log_compress 0 + config_get_bool log_filter "$1" log_filter 0 config_get log_filter_cidr "$1" log_filter_cidr "" config_get log_filter_path "$1" log_filter_path "" config_get log_filter_method "$1" log_filter_method "" # scheme - config_get force_https "$1" force_https 0 + config_get_bool force_https "$1" force_https 0 config_get ssl_cert "$1" ssl_cert "" config_get ssl_key "$1" ssl_key "" config_get listen_addr "$1" listen_addr "0.0.0.0" @@ -113,8 +108,8 @@ get_config() { config_get listen_https_port "$1" listen_https_port "-1" config_get listen_unix_file "$1" listen_unix_file "" config_get listen_unix_file_perm "$1" listen_unix_file_perm "" - config_get listen_enable_h2c "$1" listen_enable_h2c 0 - config_get listen_enable_h3 "$1" listen_enable_h3 0 + config_get_bool listen_enable_h2c "$1" listen_enable_h2c 0 + config_get_bool listen_enable_h3 "$1" listen_enable_h3 0 # database config_get database_type "$1" database_type "sqlite3" @@ -137,26 +132,24 @@ get_config() { # tasks config_get download_workers "$1" download_workers 5 config_get download_max_retry "$1" download_max_retry 1 - config_get download_task_persistant "$1" download_task_persistant 0 + config_get_bool download_task_persistant "$1" download_task_persistant 0 config_get transfer_workers "$1" transfer_workers 5 config_get transfer_max_retry "$1" transfer_max_retry 2 - config_get transfer_task_persistant "$1" transfer_task_persistant 0 + config_get_bool transfer_task_persistant "$1" transfer_task_persistant 0 config_get upload_workers "$1" upload_workers 5 config_get upload_max_retry "$1" upload_max_retry 0 - config_get upload_task_persistant "$1" upload_task_persistant 0 config_get copy_workers "$1" copy_workers 5 config_get copy_max_retry "$1" copy_max_retry 2 - config_get copy_task_persistant "$1" copy_task_persistant 0 + config_get_bool copy_task_persistant "$1" copy_task_persistant 0 config_get move_workers "$1" move_workers 5 config_get move_max_retry "$1" move_max_retry 2 - config_get move_task_persistant "$1" move_task_persistant 0 + config_get_bool move_task_persistant "$1" move_task_persistant 0 config_get decompress_workers "$1" decompress_workers 5 config_get decompress_max_retry "$1" decompress_max_retry 2 - config_get decompress_task_persistant "$1" decompress_task_persistant 0 + config_get_bool decompress_task_persistant "$1" decompress_task_persistant 0 config_get decompress_upload_workers "$1" decompress_upload_workers 5 config_get decompress_upload_max_retry "$1" decompress_upload_max_retry 2 - config_get decompress_upload_task_persistant "$1" decompress_upload_task_persistant 0 - config_get allow_retry_canceled "$1" allow_retry_canceled 0 + config_get_bool allow_retry_canceled "$1" allow_retry_canceled 0 # cors config_get cors_allow_origins "$1" cors_allow_origins '*' @@ -164,96 +157,205 @@ get_config() { config_get cors_allow_headers "$1" cors_allow_headers '*' # s3 - config_get s3 "$1" s3 0 + config_get_bool s3 "$1" s3 0 config_get s3_port "$1" s3_port 5246 - config_get s3_ssl "$1" s3_ssl 0 + config_get_bool s3_ssl "$1" s3_ssl 0 # ftp - config_get ftp "$1" ftp 0 + config_get_bool ftp "$1" ftp 0 config_get ftp_port "$1" ftp_port 5221 + config_get ftp_pasv_ports "$1" ftp_pasv_ports "" config_get find_pasv_port_attempts "$1" find_pasv_port_attempts 50 - config_get active_transfer_port_non_20 "$1" active_transfer_port_non_20 0 + config_get_bool active_transfer_port_non_20 "$1" active_transfer_port_non_20 0 config_get idle_timeout "$1" idle_timeout 900 config_get connection_timeout "$1" connection_timeout 30 - config_get disable_active_mode "$1" disable_active_mode 0 - config_get default_transfer_binary "$1" default_transfer_binary 0 - config_get enable_active_conn_ip_check "$1" enable_active_conn_ip_check 1 - config_get enable_pasv_conn_ip_check "$1" enable_pasv_conn_ip_check 1 + config_get_bool disable_active_mode "$1" disable_active_mode 0 + config_get_bool default_transfer_binary "$1" default_transfer_binary 0 + config_get_bool enable_active_conn_ip_check "$1" enable_active_conn_ip_check 1 + config_get_bool enable_pasv_conn_ip_check "$1" enable_pasv_conn_ip_check 1 # sftp - config_get sftp "$1" sftp 0 + config_get_bool sftp "$1" sftp 0 config_get sftp_port "$1" sftp_port 5222 # mcp - config_get mcp "$1" mcp 0 + config_get_bool mcp "$1" mcp 0 # init jwt_secret if [ -z "$jwt_secret" ]; then jwt_secret=$(tr -cd "a-zA-Z0-9" < "/dev/urandom" | head -c16) - uci -q set openlist2.@openlist2[0].jwt_secret="$jwt_secret" + [ "${#jwt_secret}" -eq 16 ] || { config_error=1; return 1; } + uci -q set "openlist2.$section_id.jwt_secret=$jwt_secret" || { config_error=1; return 1; } uci_changed=1 fi - [ "$uci_changed" = "1" ] && uci commit openlist2 + if [ "$uci_changed" = "1" ]; then + uci commit openlist2 || { config_error=1; return 1; } + fi + return 0 +} + +validate_config() { + http_port="$(openlist2_port "${listen_http_port:-5244}" 1)" && + https_port="$(openlist2_port "${listen_https_port:--1}" 1)" && + s3_port="$(openlist2_port "$s3_port")" && + ftp_port="$(openlist2_port "$ftp_port")" && + sftp_port="$(openlist2_port "$sftp_port")" || + { openlist2_error "Invalid listen port. Use 1-65535, or -1 to disable HTTP/HTTPS."; return 1; } + if [ "$ftp" = "1" ] && [ "$allow_wan" = "1" ]; then + ftp_pasv_ports="$(openlist2_pasv_ports "$ftp_pasv_ports")" || + { openlist2_error "FTP passive firewall ports must be ports or ranges within 1024-65535."; return 1; } + else + ftp_pasv_ports="" + fi + if [ "$https_port" = "-1" ] && { [ "$listen_enable_h3" = "1" ] || [ "$force_https" = "1" ]; }; then + openlist2_error "Force HTTPS and HTTP/3 require an enabled HTTPS port." + return 1 + fi + if [ "$https_port" != "-1" ] || { [ "$s3" = "1" ] && [ "$s3_ssl" = "1" ]; }; then + local file + for file in "$ssl_cert" "$ssl_key"; do + case "$file" in /*) ;; *) + openlist2_error "HTTPS/S3 TLS requires absolute certificate and key paths."; return 1 ;; + esac + [ -f "$file" ] && [ -r "$file" ] && [ -s "$file" ] || + { openlist2_error "TLS certificate/key is missing, empty or unreadable: $file"; return 1; } + done + fi + if [ -n "$listen_unix_file" ]; then + case "$listen_unix_file" in /*) ;; *) + openlist2_error "Unix socket path must be absolute."; return 1 ;; + esac + [ ! -e "$listen_unix_file" ] || [ -S "$listen_unix_file" ] || + { openlist2_error "Unix socket path is occupied by a non-socket file."; return 1; } + fi + if [ -n "$listen_unix_file_perm" ]; then + printf '%s\n' "$listen_unix_file_perm" | grep -Eq '^[0-7]{3,4}$' || + { openlist2_error "Unix socket permissions must contain 3 or 4 octal digits."; return 1; } + fi + local ports="" port item first last + dest_ports="" + append_dest_port "$http_port" + append_dest_port "$https_port" + [ "$s3" = "1" ] && append_dest_port "$s3_port" + [ "$ftp" = "1" ] && append_dest_port "$ftp_port" + [ "$sftp" = "1" ] && append_dest_port "$sftp_port" + for port in $dest_ports; do + case " $ports " in *" $port "*) + openlist2_error "Enabled services cannot share TCP port $port."; return 1 ;; + esac + ports="$ports $port" + if [ "$ftp" = "1" ]; then + for item in $ftp_pasv_ports; do + first="${item%%-*}"; last="${item#*-}" + if [ "$port" -ge "$first" ] && [ "$port" -le "$last" ]; then + openlist2_error "FTP passive ports must not overlap service port $port."; return 1 + fi + done + fi + done + if [ "$log" = "1" ] && ! [ "$log_max_size" -ge 1 ] 2>/dev/null; then + openlist2_error "Log size must be at least 1 MB." + return 1 + fi + openlist2_validate_dirs +} + +write_config() ( + local config_tmp + umask 077 + config_tmp="$(mktemp "$data_dir/.config.json.XXXXXX")" || exit 1 + trap 'rm -f "$config_tmp"' 0 + trap 'exit 1' HUP INT TERM + json_dump > "$config_tmp" && + jsonfilter -qi "$config_tmp" -e '@' >/dev/null && + chmod 600 "$config_tmp" && + mv -f "$config_tmp" "$data_dir/config.json" +) + +set_firewall_rule() { + local section="$1" name="$2" proto="$3" ports="$4" + if [ -z "$ports" ]; then + if uci -q get "firewall.$section" >/dev/null; then + uci -q delete "firewall.$section" || return 1 + firewall_changed=1 + fi + return 0 + fi + if [ "$(uci -q get "firewall.$section")" = "rule" ] && + [ "$(uci -q get "firewall.$section.name")" = "$name" ] && + [ "$(uci -q get "firewall.$section.src")" = "wan" ] && + [ "$(uci -q get "firewall.$section.target")" = "ACCEPT" ] && + [ "$(uci -q get "firewall.$section.proto")" = "$proto" ] && + [ "$(uci -q get "firewall.$section.dest_port")" = "$ports" ] && + [ "$(uci -q get "firewall.$section.enabled")" = "1" ]; then + return 0 + fi + uci -q delete "firewall.$section" + uci set "firewall.$section=rule" && + uci set "firewall.$section.name=$name" && + uci set "firewall.$section.target=ACCEPT" && + uci set "firewall.$section.src=wan" && + uci set "firewall.$section.proto=$proto" && + uci set "firewall.$section.dest_port=$ports" && + uci set "firewall.$section.enabled=1" || return 1 + firewall_changed=1 } set_firewall() { + local quic_ports="" legacy legacy_ports + firewall_changed=0 + legacy="$(uci -q get 'openlist2.@openlist2[0].legacy_firewall_port')" + legacy_ports="$(uci -q get firewall.openlist.dest_port)" + # Only retire an old rule when the migrated config and rule fingerprint agree. + if [ -n "$legacy" ] && + [ "$(uci -q get firewall.openlist.name)" = "openlist" ] && + [ "$(uci -q get firewall.openlist.src)" = "wan" ] && + [ "$(uci -q get firewall.openlist.target)" = "ACCEPT" ] && + [ "$(uci -q get firewall.openlist.proto)" = "tcp" ]; then + case " $legacy_ports " in *" $legacy "*) + uci -q delete firewall.openlist || return 1 + firewall_changed=1 ;; + esac + fi + dest_ports="" if [ "$external_access" = "allow" ]; then - dest_ports="" append_dest_port "$http_port" append_dest_port "$https_port" [ "$s3" = "1" ] && append_dest_port "$s3_port" - [ "$ftp" = "1" ] && append_dest_port "$ftp_port" + if [ "$ftp" = "1" ]; then + append_dest_port "$ftp_port" + append_dest_port "$ftp_pasv_ports" + fi [ "$sftp" = "1" ] && append_dest_port "$sftp_port" - - uci -q delete firewall.openlist - uci -q delete firewall.openlist2 - uci -q delete firewall.openlist2_quic - if [ -z "$dest_ports" ]; then - uci commit firewall - /etc/init.d/firewall reload >/dev/null 2>&1 - return 0 - fi - - uci set firewall.openlist2=rule - uci set firewall.openlist2.name="openlist2" - uci set firewall.openlist2.target="ACCEPT" - uci set firewall.openlist2.src="wan" - uci set firewall.openlist2.proto="tcp" - uci set firewall.openlist2.dest_port="$dest_ports" - uci set firewall.openlist2.enabled="1" - if [ "$listen_enable_h3" = "1" ] && [ -n "$https_port" ] && [ "$https_port" != "-1" ]; then - uci set firewall.openlist2_quic=rule - uci set firewall.openlist2_quic.name="openlist2 QUIC" - uci set firewall.openlist2_quic.target="ACCEPT" - uci set firewall.openlist2_quic.src="wan" - uci set firewall.openlist2_quic.proto="udp" - uci set firewall.openlist2_quic.dest_port="$https_port" - uci set firewall.openlist2_quic.enabled="1" - fi - uci commit firewall - /etc/init.d/firewall reload >/dev/null 2>&1 - elif [ "$external_access" = "deny" ]; then - uci -q delete firewall.openlist - uci -q delete firewall.openlist2 - uci -q delete firewall.openlist2_quic - uci commit firewall - /etc/init.d/firewall reload >/dev/null 2>&1 + [ "$listen_enable_h3" = "1" ] && quic_ports="$https_port" fi + set_firewall_rule openlist2 openlist2 tcp "$dest_ports" && + set_firewall_rule openlist2_quic "openlist2 QUIC" udp "$quic_ports" || return 1 + if [ "$firewall_changed" = "1" ] || uci -q changes firewall | grep -Eq '^[-+]?firewall\.openlist'; then + uci commit firewall && /etc/init.d/firewall reload || { + openlist2_error "Unable to apply OpenList firewall rules." + return 1 + } + fi + if [ -n "$legacy" ]; then + uci -q delete 'openlist2.@openlist2[0].legacy_firewall_port' && uci commit openlist2 || return 1 + fi + return 0 } start_service() { - config_load openlist2 + openlist2_migrate_config || return 1 + config_load openlist2 || return 1 + section_id="" + config_error=0 config_foreach get_config openlist2 - - # Remove firewall rules when stopping openlist process via uci - external_access="deny" set_firewall - - [ "$enabled" -ne 1 ] && return 1 - mkdir -p "$temp_dir" "$data_dir" - [ -n "$listen_http_port" ] || listen_http_port="5244" - [ -n "$listen_https_port" ] || listen_https_port="-1" - http_port="$listen_http_port" - https_port="$listen_https_port" + [ -n "$section_id" ] && [ "$config_error" = "0" ] || + { openlist2_error "Unable to load or save OpenList configuration."; return 1; } + if [ "$enabled" != "1" ]; then + external_access="deny" set_firewall + return $? + fi + validate_config && openlist2_prepare_dirs || return 1 if [ -e /proc/uptime ]; then boot_uptime="$(awk -F. '{print $1}' /proc/uptime)" [ "$boot_uptime" -lt "120" ] || delayed_start=0 @@ -261,11 +363,13 @@ start_service() { [ "$allow_wan" -eq "1" ] && external_access="allow" || external_access="deny" - set_firewall - - log_dir="${log_path%/*}" - [ "$log_dir" != "$log_path" ] && mkdir -p "$log_dir" - : > "$log_path" + if [ "$log" = "1" ]; then + openlist2_safe_log_path "$log_path" || + { openlist2_error "Unsafe log path or non-regular log file."; return 1; } + log_dir="${log_path%/*}" + mkdir -p "$log_dir" && : >> "$log_path" && chmod 600 "$log_path" || + { openlist2_error "Unable to open the log file."; return 1; } + fi last_launched_version="" if command -v jsonfilter >/dev/null 2>&1 && [ -s "$data_dir/config.json" ]; then @@ -316,8 +420,8 @@ start_service() { json_close_object json_add_string "temp_dir" "$temp_dir" - json_add_string "bleve_dir" "$data_dir/bleve" - json_add_string "dist_dir" "" + json_add_string "bleve_dir" "$bleve_dir" + json_add_string "dist_dir" "$dist_dir" # log json_add_object "log" @@ -363,7 +467,7 @@ start_service() { json_add_object "upload" json_add_int "workers" "$upload_workers" json_add_int "max_retry" "$upload_max_retry" - json_add_boolean "task_persistant" "$upload_task_persistant" + json_add_boolean "task_persistant" 0 json_close_object json_add_object "copy" json_add_int "workers" "$copy_workers" @@ -383,7 +487,7 @@ start_service() { json_add_object "decompress_upload" json_add_int "workers" "$decompress_upload_workers" json_add_int "max_retry" "$decompress_upload_max_retry" - json_add_boolean "task_persistant" "$decompress_upload_task_persistant" + json_add_boolean "task_persistant" 0 json_close_object json_add_boolean "allow_retry_canceled" "$allow_retry_canceled" json_close_object @@ -430,7 +534,8 @@ start_service() { json_add_string "last_launched_version" "$last_launched_version" json_add_string "proxy_address" "$proxy_address" - json_dump > "$data_dir/config.json" + write_config || { openlist2_error "Unable to atomically save config.json; service was not started."; return 1; } + set_firewall || return 1 procd_open_instance openlist2 procd_set_param env OPENLIST_ADMIN_PASSWORD=admin @@ -439,7 +544,8 @@ start_service() { procd_append_param command --data "$data_dir" procd_append_param command --no-prefix [ "$debug" = "1" ] && procd_append_param command --debug - [ "$debug" = "1" ] && procd_set_param stderr 1 + procd_set_param stderr 1 + [ "$debug" = "1" ] && procd_set_param stdout 1 procd_set_param respawn procd_set_param limits core="unlimited" procd_set_param limits nofile="200000 200000" @@ -453,7 +559,6 @@ service_triggers() { reload_service() { stop start - return 0 } stop_service() { diff --git a/openlist2/patches/100-retire-legacy-polyfill.patch b/openlist2/patches/100-retire-legacy-polyfill.patch new file mode 100644 index 000000000..243f298b6 --- /dev/null +++ b/openlist2/patches/100-retire-legacy-polyfill.patch @@ -0,0 +1,16 @@ +Subject: Retire the obsolete OpenWrt polyfill shim without changing custom HTML + +--- a/internal/bootstrap/data/setting.go ++++ b/internal/bootstrap/data/setting.go +@@ -70,6 +70,11 @@ func initSettings() { + continue + } + } ++ // Retire only the exact polyfill shim shipped by old OpenWrt packages. ++ if item.Key == conf.CustomizeHead && stored != nil && ++ stored.Value == "" { ++ migrationValue = stored.Value ++ } + if item.Key != conf.VERSION && stored != nil && + (len(migrationValue) == 0 || stored.Value != migrationValue) { + item.Value = stored.Value diff --git a/wwand/Makefile b/wwand/Makefile index f4b87b4e0..d589289b8 100644 --- a/wwand/Makefile +++ b/wwand/Makefile @@ -10,7 +10,7 @@ # qmi_backend) # wwand-ncm - NCM/ECM backend (DEPENDS wwand) # wwand-mhi - PCIe/MHI transport + drivers (DEPENDS wwand; add a backend) -# wwand-esim - eSIM management (DEPENDS wwand-qmi + wwand-lpac) +# wwand-esim - eSIM management (DEPENDS wwand + lpac; no backend) # A typical QMI router installs `wwand-qmi` (which pulls in `wwand`); add # `wwand-mbim` / `wwand-ncm` for those modems, `wwand-mhi` for a PCIe/MHI modem. # The ucode tree ships PRECOMPILED to bytecode (repo-root CMakeLists.txt, @@ -49,12 +49,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=wwand -PKG_VERSION:=1.6.6_p24 -PKG_RELEASE:=35 +PKG_VERSION:=1.6.6_p28 +PKG_RELEASE:=36 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/ddimension/wwand.git -PKG_SOURCE_VERSION:=74c78019c425c6cbfb3938885046419e4a2ed9ba +PKG_SOURCE_VERSION:=c1a1b0ca732b09c6114d65f9aaa73d7ece02535c PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL-2.0-only @@ -200,6 +200,11 @@ define Package/wwand/install # /etc/config/network now (existing files survive upgrade and are still read). # files/wwand.config is kept in the source tree only as a documented example. $(INSTALL_DIR) $(1)/etc/hotplug.d/usbmisc + $(INSTALL_DIR) $(1)/usr/share/acl.d + # ubus ACL: lets an unprivileged reader (collectd's exec plugin refuses to + # run as root) fetch telemetry. Deliberately NOT `status` — that carries + # iccid/imsi/imei/msisdn and a ubus ACL cannot filter a result. + $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand-acl.json $(1)/usr/share/acl.d/wwand.json $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug $(1)/etc/hotplug.d/usbmisc/20-wwand # net hotplug: NCM modems (no cdc-wdm) + re-enumeration after a mode switch $(INSTALL_DIR) $(1)/etc/hotplug.d/net @@ -393,9 +398,18 @@ define Package/wwand-esim # lpac, or our self-contained static wwand-lpac (bundled wolfSSL+libcurl, no # OpenSSL/mbedtls .so — it PROVIDES lpac, so it satisfies +lpac too). lpac # drives the SM-DP+ download/notification (ES9+ HTTPS on the router); the - # daemon bridges its stdio APDU protocol inline. APDU access uses the modem - # UIM channel, so it also needs the QMI backend. - DEPENDS:=+wwand-qmi +lpac + # daemon bridges its stdio APDU protocol inline. + # + # NO BACKEND DEPENDENCY. This carried +wwand-qmi from the days when the QMI + # UIM logical channel was the only APDU transport. It is not any more: sim.uc + # probes native MBIM UICC -> QMI UIM -> AT (CCHO/CGLA), and all three live in + # the base package, so an NCM-only or MBIM-only box can manage profiles with + # no QMI backend installed at all. The stale dependency was not free — it made + # wwand-esim uninstallable wherever wwand-qmi's kmods do not exist as + # packages, e.g. a build whose QMI drivers are compiled in + # (ddimension/wwand#26). tools/check-packaging.py now fails on a DEPENDS that + # nothing imports, so the next one cannot sit unnoticed. + DEPENDS:=+wwand +lpac endef define Package/wwand-esim/description