diff --git a/golang/golang1.26/Makefile b/golang/golang1.26/Makefile index 1c760ccb..761dea9e 100644 --- a/golang/golang1.26/Makefile +++ b/golang/golang1.26/Makefile @@ -8,10 +8,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=golang1.26 GO_VERSION_MAJOR_MINOR:=1.26 -GO_VERSION_PATCH:=5 +GO_VERSION_PATCH:=6 GO_VERSION_RC:= GO_BOOTSTRAP_VERSION:=bootstrap -PKG_HASH:=495be4bc87176ac567392e5b4116abd98466d33d7b49d41e764ccc6976b2dc42 +PKG_HASH:=a0721c54c688901448d77ad9b3ec7ea7c474730755ff891382e92ecb93ff2cb1 PKG_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_RC),.0)$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH)) PKG_FILE_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_RC),rc$(GO_VERSION_RC))$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH)) diff --git a/luci-app-momo/Makefile b/luci-app-momo/Makefile index 3f854abc..85cbd107 100644 --- a/luci-app-momo/Makefile +++ b/luci-app-momo/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_VERSION:=1.2.1 -PKG_RELEASE:=8 +PKG_RELEASE:=9 LUCI_TITLE:=LuCI Support for momo LUCI_DEPENDS:=+luci-base +momo diff --git a/luci-app-momo/root/usr/share/rpcd/acl.d/luci-app-momo.json b/luci-app-momo/root/usr/share/rpcd/acl.d/luci-app-momo.json index 49d002db..a17666ea 100644 --- a/luci-app-momo/root/usr/share/rpcd/acl.d/luci-app-momo.json +++ b/luci-app-momo/root/usr/share/rpcd/acl.d/luci-app-momo.json @@ -11,7 +11,8 @@ "/etc/momo/profiles/*.json": ["read"], "/etc/momo/subscriptions/*.json": ["read"], "/etc/momo/run/config.json": ["read"], - "/var/log/momo/*.log": ["read"] + "/var/log/momo/*.log": ["read"], + "/tmp/log/momo/*.log": ["read"] } }, "write": { @@ -20,7 +21,8 @@ "/etc/momo/profiles/*.json": ["write"], "/etc/momo/subscriptions/*.json": ["write"], "/etc/momo/run/config.json": ["write"], - "/var/log/momo/*.log": ["write"] + "/var/log/momo/*.log": ["write"], + "/tmp/log/momo/*.log": ["write"] } } } diff --git a/luci-app-nikki/Makefile b/luci-app-nikki/Makefile index c37802cb..0b5841e3 100644 --- a/luci-app-nikki/Makefile +++ b/luci-app-nikki/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_VERSION:=1.26.1 -PKG_RELEASE:=8 +PKG_RELEASE:=9 LUCI_TITLE:=LuCI Support for nikki LUCI_DEPENDS:=+luci-base +nikki diff --git a/luci-app-nikki/root/usr/share/rpcd/acl.d/luci-app-nikki.json b/luci-app-nikki/root/usr/share/rpcd/acl.d/luci-app-nikki.json index f551c22c..d089cf1e 100644 --- a/luci-app-nikki/root/usr/share/rpcd/acl.d/luci-app-nikki.json +++ b/luci-app-nikki/root/usr/share/rpcd/acl.d/luci-app-nikki.json @@ -16,7 +16,8 @@ "/etc/nikki/run/config.yaml": ["read"], "/etc/nikki/run/providers/rule/*": ["read"], "/etc/nikki/run/providers/proxy/*": ["read"], - "/var/log/nikki/*.log": ["read"] + "/var/log/nikki/*.log": ["read"], + "/tmp/log/nikki/*.log": ["read"] } }, "write": { @@ -30,7 +31,8 @@ "/etc/nikki/run/config.yaml": ["write"], "/etc/nikki/run/providers/rule/*": ["write"], "/etc/nikki/run/providers/proxy/*": ["write"], - "/var/log/nikki/*.log": ["write"] + "/var/log/nikki/*.log": ["write"], + "/tmp/log/nikki/*.log": ["write"] } } } diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index bf062c80..d70b02cb 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.8.12 -PKG_RELEASE:=224 +PKG_RELEASE:=225 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ @@ -17,7 +17,6 @@ PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Geoview \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \ - CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \ @@ -97,12 +96,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria select PACKAGE_hysteria default n -config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy - bool "Include NaiveProxy" - depends on !(arc||armeb||loongarch64||mips||mips64||powerpc||TARGET_gemini) - select PACKAGE_naiveproxy - default n - config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client bool "Include Shadowsocks Rust Client" depends on !i386 diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 58266015..1e5f504f 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -661,11 +661,16 @@ end function delete_select_nodes() local ids = http.formvalue("ids") local redirect = http.formvalue("redirect") + local ids_t = {} string.gsub(ids, '[^' .. "," .. ']+', function(w) + ids_t[#ids_t + 1] = w + if (uci_get("@global[0]", "tcp_node") or "") == w then + uci_del('@global[0]', "tcp_node") + end + if (uci_get("@global[0]", "udp_node") or "") == w then + uci_del('@global[0]', "udp_node") + end uci_foreach("socks", function(t) - if t["node"] == w then - uci_del(t[".name"]) - end local changed = false local auto_switch_node_list = uci_get(t[".name"], "autoswitch_backup_node") or {} for i = #auto_switch_node_list, 1, -1 do @@ -677,13 +682,15 @@ function delete_select_nodes() if changed then uci_set(t[".name"], "autoswitch_backup_node", auto_switch_node_list) end + if t["node"] == w then + local new_node = api.get_random_normal_node(ids_t) + if new_node then + uci_set(t[".name"], "node", new_node[".name"]) + else + uci_set(t[".name"], "enabled", "0") + end + end end) - if (uci_get("@global[0]", "tcp_node") or "") == w then - uci_del('@global[0]', "tcp_node") - end - if (uci_get("@global[0]", "udp_node") or "") == w then - uci_del('@global[0]', "udp_node") - end uci_foreach("haproxy_config", function(t) if t["lbss"] == w then uci_del(t[".name"]) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index 2f656b45..a8f0fd50 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -716,6 +716,7 @@ o.rmempty = false s2 = m:section(TypedSection, "socks", translate("Socks Config")) s2.template = "cbi/tblsection" +s2.sortable = true s2.anonymous = true s2.addremove = true s2.extedit = api.url("socks_config", "%s") @@ -810,11 +811,13 @@ o.default = n + 1080 o.datatype = "port" o.rmempty = false +--[[ if has_singbox or has_xray then o = s2:option(Value, "http_port", "HTTP " .. translate("Listen Port")) o.default = 0 o.datatype = "port" end +]]-- local tcp = s.fields["tcp_node"] local udp = s.fields["udp_node"] @@ -863,5 +866,6 @@ end m:appendTemplate("/global/footer", {shunt_list = api.jsonc.stringify(shunt_list)}) m:appendTemplate("/global/status_bottom") +m:appendTemplate("/cbi/sortable", {sectiontype = s2.sectiontype}) return api.return_map(m) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/naive.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/naive.lua deleted file mode 100644 index 621596fd..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/naive.lua +++ /dev/null @@ -1,37 +0,0 @@ -local m, s = ... - -if not api.is_finded("naive") then - return -end - -type_name = "Naiveproxy" - --- [[ Naive ]] - -s.fields["type"]:value(type_name, "NaiveProxy") - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "naive_" - -local function _n(name) - return option_prefix .. name -end - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("https", translate("HTTPS")) -o:value("quic", translate("QUIC")) - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" - -o = s:option(Value, _n("username"), translate("Username")) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index ec76e81f..2bd6d741 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -565,7 +565,7 @@ function get_valid_nodes() local nodes = {} local default_nodes = {} local other_nodes = {} - uci:foreach(c_config, "nodes", function(e) + uci_foreach_c("nodes", function(e) e.id = e[".name"] if e.type and e.remarks then local type_name = e.type @@ -638,7 +638,7 @@ function get_node_list() socks_list = {}, normal_list = {}, } - uci:foreach(c_config, "socks", function(s) + uci_foreach_c("socks", function(s) if s.enabled == "1" and s.node then node_list.socks_list[#node_list.socks_list + 1] = { id = s[".name"], @@ -727,6 +727,29 @@ function get_full_node_remarks(n) return remarks end +function get_random_normal_node(exclude_id) + local exclude_id_lookup = {} + if type(exclude_id) == "table" then + for i, v in ipairs(exclude_id) do + exclude_id_lookup[v] = true + end + elseif type(exclude_id) == "string" then + exclude_id_lookup[exclude_id] = true + end + local normal_list = {} + for k, e in ipairs(get_valid_nodes()) do + if e.node_type == "normal" and not exclude_id_lookup[e[".name"]] then + normal_list[#normal_list + 1] = e + end + end + if #normal_list > 0 then + math.randomseed(os.time()) + local num = math.random(1, #normal_list) + return normal_list[num] + end + return nil +end + function gen_uuid() local uuid = sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)") return uuid diff --git a/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua b/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua deleted file mode 100644 index a29cfafe..00000000 --- a/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua +++ /dev/null @@ -1,42 +0,0 @@ -module("luci.passwall.util_naiveproxy", package.seeall) -local api = require "luci.passwall.api" -local jsonc = api.jsonc - -function gen_config(var) - local node_id = var["node"] - if not node_id then - print("node 不能为空") - return - end - local node = api.uci_get_c(node_id) - local run_type = var["run_type"] - local local_addr = var["local_addr"] - local local_port = var["local_port"] - local server_host = var["server_host"] or (node.address or ""):lower() - local server_port = var["server_port"] or node.port - - if api.is_ipv6(server_host) then - server_host = api.get_ipv6_full(server_host) - end - local server = server_host .. ":" .. server_port - - local config = { - listen = run_type .. "://" .. local_addr .. ":" .. local_port, - proxy = node.protocol .. "://" .. node.username .. ":" .. node.password .. "@" .. server - } - - return jsonc.stringify(config, 1) -end - -_G.gen_config = gen_config - -if arg[1] then - local func =_G[arg[1]] - if func then - local var = nil - if arg[2] then - var = jsonc.parse(arg[2]) - end - print(func(var)) - end -end diff --git a/luci-app-passwall/root/etc/uci-defaults/luci-app-passwall b/luci-app-passwall/root/etc/uci-defaults/luci-app-passwall index aab89174..997c4a78 100644 --- a/luci-app-passwall/root/etc/uci-defaults/luci-app-passwall +++ b/luci-app-passwall/root/etc/uci-defaults/luci-app-passwall @@ -45,6 +45,8 @@ chmod +x /usr/share/passwall/*.sh uci -q delete passwall.@global_xray[0].sniffing uci -q delete passwall.@global_xray[0].route_only +[ "$(uci -q get passwall.@global_haproxy[0].health_check_type)" = "passwall_logic" ] && uci -q set passwall.@global_haproxy[0].health_check_type='script_logic' + for sid in $(uci show passwall | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}'); do if [ -z "$(echo ${sid} | grep '^socks_')" ]; then new_id="socks_$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 5)" diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index d0e91426..84739070 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -13,7 +13,6 @@ LUA_UTIL_PATH=/usr/lib/lua/luci/passwall UTIL_SINGBOX=$LUA_UTIL_PATH/util_sing-box.lua UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua -UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua SINGBOX_BIN=$(first_type $(config_t_get global_app sing_box_file) sing-box) XRAY_BIN=$(first_type $(config_t_get global_app xray_file) xray) @@ -456,13 +455,6 @@ run_socks() { [ -n "$no_run" ] && _args="${_args} no_run=1" run_xray flag=$flag node=$node socks_address=$bind socks_port=$socks_port config_file=$config_file log_file=$log_file ${_args} ;; - naiveproxy) - json_add_string "run_type" "socks" - json_add_string "local_addr" "$bind" - json_add_string "local_port" "$socks_port" - lua $UTIL_NAIVE gen_config "$(json_dump)" > $config_file - [ -n "$no_run" ] || ln_run "$(first_type naive)" naive $log_file "$config_file" - ;; ssr) json_add_string "local_addr" "$bind" json_add_string "local_port" "$socks_port" diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index bd163f0d..cb07e899 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.8.16 -PKG_RELEASE:=89 +PKG_VERSION:=26.8.17 +PKG_RELEASE:=90 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js index 68de0e56..90b5b99e 100644 --- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js +++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js @@ -8,13 +8,6 @@ 'require form'; 'require tools.widgets as widgets'; -const callInitAction = rpc.declare({ - object: 'luci', - method: 'setInitAction', - params: ['name', 'action'], - expect: { result: false } -}); - const callUpnpGetStatus = rpc.declare({ object: 'luci.upnp', method: 'get_status', @@ -350,7 +343,7 @@ return view.extend({ o.modalonly = false; o = s.option(form.Value, 'int_addr', _('IP address'), - _('Enter device\'s IPv4 address, or an address with netmask')); + _('Enter device\'s IPv4 address, or an address and netmask')); o.datatype = 'ip4addr'; o.rmempty = false; o.retain = true; diff --git a/luci-app-upnp/po/it/upnp.po b/luci-app-upnp/po/it/upnp.po index 469aaa2f..184ed098 100644 --- a/luci-app-upnp/po/it/upnp.po +++ b/luci-app-upnp/po/it/upnp.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-05-19 19:36+0200\n" -"PO-Revision-Date: 2025-11-28 22:04+0000\n" -"Last-Translator: niky1987 \n" +"PO-Revision-Date: 2026-07-23 06:18+0000\n" +"Last-Translator: Random \n" "Language-Team: Italian \n" "Language: it\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.15-dev\n" +"X-Generator: Weblate 2026.8.dev0\n" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:183 msgctxt "" @@ -119,7 +119,7 @@ msgstr "Velocità di download" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:144 msgid "Enable PCP/NAT-PMP protocols" -msgstr "Abilita il protocollo PCP/NAT-PMP" +msgstr "Attiva i protocolli PCP/NAT-PMP" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:141 msgid "Enable UPnP IGD protocol" diff --git a/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json b/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json index 6e1fa8fc..f1f9e781 100644 --- a/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json +++ b/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json @@ -3,8 +3,7 @@ "description": "Grant access to UPnP IGD & PCP/NAT-PMP service configuration", "read": { "ubus": { - "luci.upnp": [ "get_status" ], - "luci": [ "setInitAction" ] + "luci.upnp": [ "get_status" ] }, "uci": [ "upnpd" ] }, diff --git a/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md b/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md index 46993f58..45337187 100644 --- a/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md +++ b/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md @@ -11,10 +11,10 @@ address, so they stay local). | Metric | Budget | Track | Source | |---|---|---|---| -| main.css (identity/raw) | ≤ 193 KB | size | production build, 2026-08 (192,201 B; +~2 KB custom-background mode, +~0.5 KB router progress bar / live region) | +| main.css (identity/raw) | ≤ 193 KB | size | production build, 2026-08 (191,899 B; +~2 KB custom-background mode, +~0.5 KB router progress bar / live region; the bar is now Turbo-shaped — width/opacity only, inserted per navigation) | | login.css (identity/raw) | ≤ 12 KB | size | production build, 2026-07 (10,935 B, token-pruned) | | menu-aurora.js (identity/raw) | ≤ 21.5 KB | size | production build, 2026-08 (20,851 B; +1.3 KB for the router's `syncRoute`/`closeSurfaces` hooks) | -| router-aurora.js (identity/raw, Navigation-API browsers only) | ≤ 15 KB | size | production build, 2026-08 (14,568 B: template shells fetched, per-render listener teardown, timeout-as-failure, expiry gate, readonly folding, node css, wildcard actions, progress bar, visibility gate, contract check) | +| router-aurora.js (identity/raw, Navigation-API browsers only) | ≤ 15 KB | size | production build, 2026-08 (14,844 B: template shells fetched, per-render listener teardown, timeout-as-failure, expiry gate, readonly folding, node css, wildcard actions, trickling progress bar, same-URL reload rule, visibility gate, contract check) | | Default logo (identity/raw) | ≤ 16 KB | size | production build, 2026-07 (15,057 B) | | Core admin cold theme assets (identity/raw) | ≤ 267 KB | size | main CSS + menu JS + router JS + default font + logo, 2026-08 (≈266.3 KB; the router is a one-time cost that removes per-click dispatcher work) | | Login cold theme assets, excluding configured background (identity/raw) | ≤ 55 KB | size | login CSS + default font + logo, 2026-07 (49,572 B) | diff --git a/luci-theme-aurora/.claude/skills/aurora-performance/scripts/bench-router.mjs b/luci-theme-aurora/.claude/skills/aurora-performance/scripts/bench-router.mjs index cab34b42..201ed303 100644 --- a/luci-theme-aurora/.claude/skills/aurora-performance/scripts/bench-router.mjs +++ b/luci-theme-aurora/.claude/skills/aurora-performance/scripts/bench-router.mjs @@ -27,8 +27,9 @@ * on the walk): reached same-document, the navigation away is a * full load (poison gate), the one after is same-document again. * Skipped when the walk found no such page. - * hygiene progress bar and live region exist; a hidden tab stops polling - * and a visible one resumes it; the live region carries the title. + * hygiene no progress bar remains after a swap (it is inserted for the + * navigation and removed after its fade), the live region carries + * the title, a hidden tab stops polling and a visible one resumes it. * nodecss a page whose menu.d node declares `css`: its link is enabled on * arrival, disabled (not removed) after leaving, re-enabled without * a duplicate on return. Skipped when no such node is installed. @@ -495,7 +496,7 @@ if (!ONLY || ONLY === "hygiene") { const home = await spaNavigate(p.sessionId, START); await waitViewSettled(p.sessionId); await sleep(1500); const r = JSON.parse(await evaljs(p.sessionId, `(async () => { - const bar = !!document.getElementById('aurora-nav-progress'); + const barGone = !document.getElementById('aurora-nav-progress'); const status = document.getElementById('aurora-nav-status')?.textContent; const wasActive = L.Poll.active(); Object.defineProperty(document, 'hidden', { configurable: true, get: () => true }); @@ -504,10 +505,10 @@ if (!ONLY || ONLY === "hygiene") { Object.defineProperty(document, 'hidden', { configurable: true, get: () => false }); document.dispatchEvent(new Event('visibilitychange')); const shownActive = L.Poll.active(); - return JSON.stringify({ bar, status, title: document.title, wasActive, hiddenActive, shownActive }); + return JSON.stringify({ barGone, status, title: document.title, wasActive, hiddenActive, shownActive }); })()`, true)); out.hygiene = { ...r, sameDoc: nav.sameDoc && home.sameDoc, - ok: nav.sameDoc && home.sameDoc && r.bar && r.status === r.title && r.wasActive && !r.hiddenActive && r.shownActive }; + ok: nav.sameDoc && home.sameDoc && r.barGone && r.status === r.title && r.wasActive && !r.hiddenActive && r.shownActive }; } /* ---------- menu.d node css ---------- */ diff --git a/luci-theme-aurora/.dev/docs/router.md b/luci-theme-aurora/.dev/docs/router.md index 3f121a1d..02fc0c56 100644 --- a/luci-theme-aurora/.dev/docs/router.md +++ b/luci-theme-aurora/.dev/docs/router.md @@ -160,6 +160,16 @@ A `navigate` event is intercepted only when **all** hold: - `event.canIntercept` (same-origin, not cross-document-only), not `hashChange`, no `downloadRequest`, no `formData`, `navigationType !== 'reload'`; +- the destination is **not the document's own URL** (fragment aside). A + same-URL navigation arrives as `navigationType: 'replace'`, not + `'reload'`, yet it is a reload by another name: luci-base's + `ui.changes.apply/revert` end in `window.location = + window.location.href.split('#')[0]` (and the expiry modal's button in the + same) precisely so the server re-renders the shell — a theme switched + under System → Language and Style, a new language, a new hostname, a + changed menu tree — and intercepting it left the swap showing the old + shell until F5. A click on the current page's own link is the same reload + it is in the MPA; - the destination path (minus `L.env.scriptname`) resolves in the menu tree to a **serviceable node** (below); - the document is not **poisoned** (below) and its session is not known to @@ -392,12 +402,22 @@ handler in order: 8. **Focus and announcement.** `#maincontent` (`tabindex=-1`) with `preventScroll`; the new `document.title` is written into `#aurora-nav-status` (`role=status`, `aria-live=polite`), since a - same-document swap fires no load a screen reader would announce. -9. **Progress.** A navigation that outlives 150 ms shows `#aurora-nav-progress`, - a hairline at the top that creeps right while the view renders and - completes on commit (`data-state` active → done); shorter ones stay - silent, overlapping ones share the bar. Reduced motion drops its - transitions, not the bar. + same-document swap fires no load a screen reader would announce. The + landmark carries `outline-none`: iOS WebKit (Safari and Chrome for iOS + alike) paints its focus ring for programmatic focus, and the ring's top + edge just under the sticky header was reported as "a progress bar that + never goes away" — it was never the bar. +9. **Progress.** A navigation that outlives 150 ms gets `#aurora-nav-progress` + inserted — Turbo Drive's bar, in shape: a hairline at the top whose + `width` is driven inline and **trickles** in ever-smaller steps + (`+ (100 - w) / 30` every 300 ms) until commit, so a slow render keeps + visibly moving instead of looking stuck; on commit it fills to 100 %, + fades (`data-state="done"`) and is **removed from the DOM**. Shorter + navigations stay silent, overlapping ones share the bar. The browser's + own progress bar is no help here: it only shows for document loads, + which is exactly what a same-document swap is not — hence GitHub, + YouTube, Turbo/HEY and every nprogress user draw their own. Reduced + motion drops the transitions, not the bar. 10. Any exception → `console.error` (a silent fallback makes every router regression look like "the page is just slow") → `location.href = destination` — a hard full load, never a stuck page. @@ -491,8 +511,8 @@ already 0-byte cache hits. - Unit (`.dev/tests/router.test.js`): resolver against a fixture tree (alias chain, nested firstchild, weights, ineligible, unsatisfied, wildcard args, cycle); URL → segments; patch prefix matching; pragma scan - on a minified head; readonly folding; expiry signals; node css of the - resolved leaf; the contract check. + on a minified head; readonly folding; expiry signals; the same-URL reload + rule; node css of the resolved leaf; the contract check. - Device (`.claude/skills/aurora-performance/scripts/bench-router.mjs`, CDP): 1. full walk of every clickable node in each nav mode, each compared against a real full load of the same URL — `data-page`, @@ -507,8 +527,9 @@ already 0-byte cache hits. own sheets (found on the walk) instead of an injected one — reached same-document and landed on directly (its modules insert before the router boots), leaving is a full load either way; - 5c. hygiene: progress bar and live region present, live region carries the - title, a hidden tab stops polling and a visible one resumes it; + 5c. hygiene: no progress bar left in the DOM after a swap, live region + present and carrying the title, a hidden tab stops polling and a + visible one resumes it; 6. nodecss: a page whose menu.d node declares `css` — link enabled on arrival, disabled after leaving, re-enabled without a duplicate on return (skipped when no installed node declares one); diff --git a/luci-theme-aurora/.dev/src/media/_base.css b/luci-theme-aurora/.dev/src/media/_base.css index 285a8153..04288aa6 100644 --- a/luci-theme-aurora/.dev/src/media/_base.css +++ b/luci-theme-aurora/.dev/src/media/_base.css @@ -4,7 +4,11 @@ * fixed pseudo made the same var(--bg) look mismatched). */ html { - @apply bg-bg min-h-dvh font-sans; + @apply bg-bg min-h-dvh font-sans scheme-light; + + &[data-darkmode="true"] { + @apply scheme-dark; + } body { @apply bg-bg min-h-dvh; diff --git a/luci-theme-aurora/.dev/src/media/_layout.css b/luci-theme-aurora/.dev/src/media/_layout.css index 9285e43a..5bcdd453 100644 --- a/luci-theme-aurora/.dev/src/media/_layout.css +++ b/luci-theme-aurora/.dev/src/media/_layout.css @@ -551,18 +551,16 @@ body[data-nav-type="sidebar"] { } } -/* Router progress (router.md): a hairline across the top that only - appears once a navigation outlives its silent 150 ms, creeps towards - the right while the view renders, and completes on commit. */ +/* Router progress (router.md) — Turbo Drive's bar: inserted by the router + once a navigation outlives its silent 150 ms, width driven inline and + trickling until commit (so a slow render keeps visibly moving), then + filled, faded and removed from the DOM. Only width and opacity move. + Reduced motion drops the transitions, not the bar. */ #aurora-nav-progress { - @apply from-progress-start to-progress-end pointer-events-none fixed inset-x-0 top-0 z-80 h-0.5 origin-left scale-x-0 bg-linear-to-r opacity-0; - - &[data-state="active"] { - @apply scale-x-90 opacity-100 transition-[scale,opacity] duration-[8s] ease-out; - } + @apply from-progress-start to-progress-end pointer-events-none fixed top-0 left-0 z-80 h-0.5 w-0 bg-linear-to-r transition-[width] duration-300 ease-out; &[data-state="done"] { - @apply scale-x-100 opacity-0 transition-[scale,opacity] duration-300 ease-out; + @apply opacity-0 [transition:width_.3s_ease-out,opacity_.15s_ease-in_.15s]; } } @@ -576,7 +574,11 @@ body[data-nav-type="sidebar"] { /* Centred shells (top-bar navigation) clamp here and gutter the remainder. The sidebar shell overrides this — it caps the shell instead, see body[data-nav-type="sidebar"] above. */ - @apply mx-auto min-h-[calc(100vh-4rem)] w-23/24 max-w-(--content-width-centered) px-4 max-md:w-full max-md:px-3; + @apply mx-auto min-h-[calc(100vh-4rem)] w-23/24 max-w-(--content-width-centered) px-4 outline-none max-md:w-full max-md:px-3; + /* outline-none: the router focuses this landmark (tabindex=-1) after a + same-document swap for assistive tech. iOS WebKit paints its focus ring + for programmatic focus, and the ring's top edge just under the sticky + header read as a stuck progress bar; a landmark needs no visible ring. */ /* Router staging (router.md): the incoming region keeps its full width for layout-measuring renders but takes no space and no paint. */ diff --git a/luci-theme-aurora/.dev/src/resource/router-aurora.js b/luci-theme-aurora/.dev/src/resource/router-aurora.js index d39ef3ab..d20645db 100644 --- a/luci-theme-aurora/.dev/src/resource/router-aurora.js +++ b/luci-theme-aurora/.dev/src/resource/router-aurora.js @@ -196,9 +196,6 @@ return baseclass.extend({ const current = this.initialRoute(); if (!current) return; document.querySelector('script[type="speculationrules"]')?.remove(); - this.bar = document.body.appendChild( - E("div", { id: "aurora-nav-progress", "aria-hidden": "true" }), - ); this.status = document.body.appendChild( E("div", { id: "aurora-nav-status", @@ -263,23 +260,43 @@ return baseclass.extend({ }); }, + // Turbo Drive's progress bar, in shape: the element exists only while a + // navigation shows it (inserted after PROGRESS_DELAY, removed after the + // done fade), its width is driven inline and trickles in ever-smaller + // steps until commit, so a slow render never looks stuck. Overlapping + // navigations share the bar. progressStart() { this.pending = (this.pending ?? 0) + 1; clearTimeout(this.progressTimer); - this.progressTimer = setTimeout( - () => (this.bar.dataset.state = "active"), - PROGRESS_DELAY, + this.progressTimer = setTimeout(() => { + if (this.bar) return; + this.bar = document.body.appendChild( + E("div", { id: "aurora-nav-progress", "aria-hidden": "true" }), + ); + this.bar.offsetWidth; // commit the resting width so the first step transitions + this.trickle(10); + }, PROGRESS_DELAY); + }, + + trickle(value) { + if (!this.bar) return; + this.bar.style.width = `${value}%`; + this.trickleTimer = setTimeout( + () => this.trickle(value + (100 - value) / 30), + 300, ); }, progressEnd() { if (--this.pending > 0) return; clearTimeout(this.progressTimer); - if (this.bar.dataset.state !== "active") return; - this.bar.dataset.state = "done"; - this.progressTimer = setTimeout(() => { - if (this.bar.dataset.state === "done") delete this.bar.dataset.state; - }, 300); + clearTimeout(this.trickleTimer); + const bar = this.bar; + if (!bar) return; + this.bar = null; + bar.dataset.state = "done"; + bar.style.width = "100%"; + setTimeout(() => bar.remove(), 300); }, sheets() { @@ -371,6 +388,15 @@ return baseclass.extend({ return data?.access === false; }, + // A navigation to the document's own URL is a reload by another name: + // luci-base reloads after apply/revert with `window.location = href` (a + // "replace" navigation, not a "reload"), expecting the server to re-render + // theme, language, hostname and menu — as does a click on the current + // page's own link. Those go to the server like an F5. + reloads(url) { + return url.split("#")[0] === window.location.href.split("#")[0]; + }, + nodespec(r) { return { ...r.node, readonly: readonlyAlong(this.tree, r.path) }; }, @@ -635,7 +661,8 @@ return baseclass.extend({ ev.hashChange || ev.downloadRequest !== null || ev.formData || - ev.navigationType === "reload" + ev.navigationType === "reload" || + this.reloads(ev.destination.url) ) return; @@ -692,6 +719,8 @@ return baseclass.extend({ await this.commit(view); this.mountPatches(patches); this.status.textContent = document.title; + // #maincontent is outline-none (_layout.css): iOS WebKit rings + // programmatic focus, and that ring read as a stuck progress bar. document.getElementById("maincontent")?.focus({ preventScroll: true }); } catch (err) { console.error("router-aurora:", err); diff --git a/luci-theme-aurora/.dev/tests/router.test.js b/luci-theme-aurora/.dev/tests/router.test.js index 9352db0c..42d12463 100644 --- a/luci-theme-aurora/.dev/tests/router.test.js +++ b/luci-theme-aurora/.dev/tests/router.test.js @@ -336,6 +336,18 @@ test("session expiry is recognised from the same signals luci-base uses", () => assert.equal(router.sessionGone(null, probe), false); }); +test("a navigation to the document's own URL is a reload, not a swap", () => { + const router = loadRouter({ tree }); + const here = "https://r/cgi-bin/luci/admin/status/overview"; + + // luci-base's post-apply/revert `window.location = href.split('#')[0]` + // and the expiry modal's `protocol//host pathname search` are both this. + assert.equal(router.reloads(here), true); + assert.equal(router.reloads(`${here}#tab`), true); + assert.equal(router.reloads(`${here}?x=1`), false); + assert.equal(router.reloads("https://r/cgi-bin/luci/admin/status/logs"), false); +}); + test("a menu.d node css is served for the resolved leaf only", () => { const t = { action: { type: "firstchild" }, diff --git a/luci-theme-aurora/Makefile b/luci-theme-aurora/Makefile index 5c416547..c398e386 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.2.1 -PKG_RELEASE:=67 +PKG_VERSION:=1.2.3 +PKG_RELEASE:=68 PKG_LICENSE:=Apache-2.0 LUCI_MINIFY_CSS:= diff --git a/luci-theme-aurora/htdocs/luci-static/aurora/login.css b/luci-theme-aurora/htdocs/luci-static/aurora/login.css index 998190b5..26e205e8 100644 --- a/luci-theme-aurora/htdocs/luci-static/aurora/login.css +++ b/luci-theme-aurora/htdocs/luci-static/aurora/login.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-content:"";--tw-shadow:0 0 #0000;--tw-inset-shadow:0 0 #0000;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-shadow:0 0 #0000;--tw-border-style:solid;--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%}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--spacing:var(--spacing);--container-md:28rem;--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-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-2xl:calc(var(--radius-base) * 2);--animate-spin:spin 1s linear infinite}}@layer base{*,:before,:after{box-sizing:border-box}body,hr,p,button,input{margin:0}button,input{font:inherit}a{text-decoration-line:none}[hidden]{display:none!important}}@layer components,utilities;:root{--bg:#f7fafc;--surface:#fff;--text:#121a22;--brand:#0085b7;--on-brand:#fff;--danger:#8d1925;--text-muted:#5f666d;--text-subtle:#7f858b;--hairline:#121a2221;--brand-subtle:#ddecf5;--danger-surface:#ffe8e6;--control-bg:#fff;--app-shadow-md:0 4px 16px #00000014, 0 1px 3px #0000000a;--font-sans:"Lato", ui-sans-serif, system-ui, sans-serif;--spacing:.25rem;--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);--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);--hairline:lab(8.89727% -1.68239 -6.93074/.13);--brand-subtle:lab(92.5794% -3.9458 -6.17858);--danger-surface:lab(93.849% 11.2841 5.29771);--control-bg:lab(100.011% -.760317 -1.25225);--app-shadow-md:0 4px 16px lab(0% 0 0/.08), 0 1px 3px lab(0% 0 0/.04)}}[data-darkmode=true]{--bg:#05070e;--surface:#141822;--text:#f9fafb;--brand:#00958e;--on-brand:#fff;--danger:#f17070;--text-muted:#909297;--text-subtle:#5d6067;--hairline:#f9fafb1a;--brand-subtle:#061a20;--danger-surface:#541f20;--control-bg:#0a0e17;--app-shadow-md:0 10px 28px #0000006b}@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);--danger:lab(63.5705% 50.8105 25.3639);--text-muted:lab(60.5379% -.225931 -3.05105);--text-subtle:lab(40.6865% -.278354 -4.23647);--hairline:lab(98.252% -.0618994 -.756907/.1);--brand-subtle:lab(7.95734% -6.34954 -6.72844);--danger-surface:lab(20.3014% 25.4342 12.827);--control-bg:lab(3.9802% .0812709 -5.64623);--app-shadow-md:0 10px 28px lab(0% 0 0/.42)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-property:none!important;animation:none!important}.spinning:before{animation:var(--animate-spin)!important}}html{background-color:var(--bg);min-height:100dvh;font-family:var(--font-sans)}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}@keyframes divider-in{0%{opacity:0;transform:scaleX(.15)}}.login-screen{min-height:100dvh;padding-inline:calc(var(--spacing) * 5);padding-bottom:calc(var(--spacing) * 14);flex-direction:column;justify-content:center;align-items:center;display:flex;position:relative}.login-shell{width:100%;max-width:var(--container-md)}.page-bg{--page-bg:var(--login-bg);--page-bg-lqip:var(--login-bg-lqip)}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(--login-bg-scrim,0%),transparent)}}body[data-bg] .login-card{backdrop-filter:blur(var(--login-bg-blur,0px)) saturate(150%);background:var(--surface)}@supports (color:color-mix(in lab, red, red)){body[data-bg] .login-card{background:color-mix(in srgb,var(--surface) var(--login-bg-alpha,100%),transparent)}}@media (prefers-reduced-transparency:reduce){body[data-bg] .login-card{--login-bg-alpha:100%;backdrop-filter:none!important}}.login-card{gap:calc(var(--spacing) * 7);border-radius:calc(var(--radius-base) * 4);background-color:var(--surface);padding:calc(var(--spacing) * 14);--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;display:flex}@media not all and (width>=48rem){.login-card{border-radius:calc(var(--radius-base) * 3);padding:calc(var(--spacing) * 9)}}.login-brand{align-items:center;gap:calc(var(--spacing) * 3.5);display:flex}.login-divider{border-style:var(--tw-border-style);--tw-gradient-position:to right;border-width:0;width:100%;height:1px;animation:.7s cubic-bezier(.16,1,.3,1) .1s both divider-in}@supports (background-image:linear-gradient(in lab, red, red)){.login-divider{--tw-gradient-position:to right in oklab}}.login-divider{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:transparent;--tw-gradient-via:var(--hairline);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--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));--tw-gradient-to:transparent}.login-logo{height:calc(var(--spacing) * 11);width:calc(var(--spacing) * 11);border-radius:calc(var(--radius-base) * 2);background-color:var(--brand-subtle);--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);--tw-ring-color:var(--brand-subtle);flex-shrink:0;justify-content:center;align-items:center;display:flex}.login-logo img{height:calc(var(--spacing) * 6);width:calc(var(--spacing) * 6)}.login-title{gap:var(--spacing);flex-direction:column;display:flex}.login-hostname{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));font-weight:var(--font-weight-semibold);letter-spacing:var(--tracking-tight);color:var(--text)}.login-subtitle{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text)}.login-form{gap:calc(var(--spacing) * 5);flex-direction:column;display:flex}.login-fields{gap:calc(var(--spacing) * 4);flex-direction:column;display:flex}.login-field{gap:calc(var(--spacing) * 2);flex-direction:column;display:flex}.login-label{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));font-weight:var(--font-weight-semibold);letter-spacing:var(--tracking-widest);color:var(--text);text-transform:uppercase}.input-wrap{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);contain:layout style;position:relative}.input-wrap:after{pointer-events:none;border-radius:calc(var(--radius-2xl) + 1px);border-style:var(--tw-border-style);border-width:2px;border-color:var(--brand);opacity:0;--tw-content:"";content:var(--tw-content);transition:opacity .15s;position:absolute;inset:-1px}.input-wrap:focus-within:after{opacity:1}.login-input{appearance:none;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:var(--text);background-color:#0000;border-width:0;outline-style:none}.login-input::placeholder{color:var(--text-subtle)}.login-error{border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--danger-surface);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));color:var(--danger)}.login-actions{padding-top:calc(var(--spacing) * 4)}.login-submit{cursor:pointer;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);background-color:var(--brand);width:100%;padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));font-weight:var(--font-weight-medium);color:var(--on-brand);border-width:0}@media (hover:hover){.login-submit:hover{opacity:.9}}.login-submit:active{opacity:.8}.login-footer{right:0;bottom:calc(var(--spacing) * 5);padding-inline:calc(var(--spacing) * 5);text-align:center;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);position:absolute;left:0}.login-footer p{white-space:normal}.login-footer a{color:var(--brand)}@media (hover:hover){.login-footer a:hover{text-decoration-line:underline}}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@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-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@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%}@keyframes spin{to{transform:rotate(360deg)}} \ No newline at end of file +@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-content:"";--tw-shadow:0 0 #0000;--tw-inset-shadow:0 0 #0000;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-shadow:0 0 #0000;--tw-border-style:solid;--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%}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--spacing:var(--spacing);--container-md:28rem;--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-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-2xl:calc(var(--radius-base) * 2);--animate-spin:spin 1s linear infinite}}@layer base{*,:before,:after{box-sizing:border-box}body,hr,p,button,input{margin:0}button,input{font:inherit}a{text-decoration-line:none}[hidden]{display:none!important}}@layer components,utilities;:root{--bg:#f7fafc;--surface:#fff;--text:#121a22;--brand:#0085b7;--on-brand:#fff;--danger:#8d1925;--text-muted:#5f666d;--text-subtle:#7f858b;--hairline:#121a2221;--brand-subtle:#ddecf5;--danger-surface:#ffe8e6;--control-bg:#fff;--app-shadow-md:0 4px 16px #00000014, 0 1px 3px #0000000a;--font-sans:"Lato", ui-sans-serif, system-ui, sans-serif;--spacing:.25rem;--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);--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);--hairline:lab(8.89727% -1.68239 -6.93074/.13);--brand-subtle:lab(92.5794% -3.9458 -6.17858);--danger-surface:lab(93.849% 11.2841 5.29771);--control-bg:lab(100.011% -.760317 -1.25225);--app-shadow-md:0 4px 16px lab(0% 0 0/.08), 0 1px 3px lab(0% 0 0/.04)}}[data-darkmode=true]{--bg:#05070e;--surface:#141822;--text:#f9fafb;--brand:#00958e;--on-brand:#fff;--danger:#f17070;--text-muted:#909297;--text-subtle:#5d6067;--hairline:#f9fafb1a;--brand-subtle:#061a20;--danger-surface:#541f20;--control-bg:#0a0e17;--app-shadow-md:0 10px 28px #0000006b}@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);--danger:lab(63.5705% 50.8105 25.3639);--text-muted:lab(60.5379% -.225931 -3.05105);--text-subtle:lab(40.6865% -.278354 -4.23647);--hairline:lab(98.252% -.0618994 -.756907/.1);--brand-subtle:lab(7.95734% -6.34954 -6.72844);--danger-surface:lab(20.3014% 25.4342 12.827);--control-bg:lab(3.9802% .0812709 -5.64623);--app-shadow-md:0 10px 28px lab(0% 0 0/.42)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-property:none!important;animation:none!important}.spinning:before{animation:var(--animate-spin)!important}}html{background-color:var(--bg);min-height:100dvh;font-family:var(--font-sans);color-scheme:light}html[data-darkmode=true]{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}@keyframes divider-in{0%{opacity:0;transform:scaleX(.15)}}.login-screen{min-height:100dvh;padding-inline:calc(var(--spacing) * 5);padding-bottom:calc(var(--spacing) * 14);flex-direction:column;justify-content:center;align-items:center;display:flex;position:relative}.login-shell{width:100%;max-width:var(--container-md)}.page-bg{--page-bg:var(--login-bg);--page-bg-lqip:var(--login-bg-lqip)}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(--login-bg-scrim,0%),transparent)}}body[data-bg] .login-card{backdrop-filter:blur(var(--login-bg-blur,0px)) saturate(150%);background:var(--surface)}@supports (color:color-mix(in lab, red, red)){body[data-bg] .login-card{background:color-mix(in srgb,var(--surface) var(--login-bg-alpha,100%),transparent)}}@media (prefers-reduced-transparency:reduce){body[data-bg] .login-card{--login-bg-alpha:100%;backdrop-filter:none!important}}.login-card{gap:calc(var(--spacing) * 7);border-radius:calc(var(--radius-base) * 4);background-color:var(--surface);padding:calc(var(--spacing) * 14);--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;display:flex}@media not all and (width>=48rem){.login-card{border-radius:calc(var(--radius-base) * 3);padding:calc(var(--spacing) * 9)}}.login-brand{align-items:center;gap:calc(var(--spacing) * 3.5);display:flex}.login-divider{border-style:var(--tw-border-style);--tw-gradient-position:to right;border-width:0;width:100%;height:1px;animation:.7s cubic-bezier(.16,1,.3,1) .1s both divider-in}@supports (background-image:linear-gradient(in lab, red, red)){.login-divider{--tw-gradient-position:to right in oklab}}.login-divider{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:transparent;--tw-gradient-via:var(--hairline);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--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));--tw-gradient-to:transparent}.login-logo{height:calc(var(--spacing) * 11);width:calc(var(--spacing) * 11);border-radius:calc(var(--radius-base) * 2);background-color:var(--brand-subtle);--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);--tw-ring-color:var(--brand-subtle);flex-shrink:0;justify-content:center;align-items:center;display:flex}.login-logo img{height:calc(var(--spacing) * 6);width:calc(var(--spacing) * 6)}.login-title{gap:var(--spacing);flex-direction:column;display:flex}.login-hostname{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));font-weight:var(--font-weight-semibold);letter-spacing:var(--tracking-tight);color:var(--text)}.login-subtitle{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--text)}.login-form{gap:calc(var(--spacing) * 5);flex-direction:column;display:flex}.login-fields{gap:calc(var(--spacing) * 4);flex-direction:column;display:flex}.login-field{gap:calc(var(--spacing) * 2);flex-direction:column;display:flex}.login-label{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));font-weight:var(--font-weight-semibold);letter-spacing:var(--tracking-widest);color:var(--text);text-transform:uppercase}.input-wrap{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);contain:layout style;position:relative}.input-wrap:after{pointer-events:none;border-radius:calc(var(--radius-2xl) + 1px);border-style:var(--tw-border-style);border-width:2px;border-color:var(--brand);opacity:0;--tw-content:"";content:var(--tw-content);transition:opacity .15s;position:absolute;inset:-1px}.input-wrap:focus-within:after{opacity:1}.login-input{appearance:none;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:var(--text);background-color:#0000;border-width:0;outline-style:none}.login-input::placeholder{color:var(--text-subtle)}.login-error{border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);background-color:var(--danger-surface);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));color:var(--danger)}.login-actions{padding-top:calc(var(--spacing) * 4)}.login-submit{cursor:pointer;border-radius:calc(var(--radius-base) * 2);border-style:var(--tw-border-style);background-color:var(--brand);width:100%;padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));font-weight:var(--font-weight-medium);color:var(--on-brand);border-width:0}@media (hover:hover){.login-submit:hover{opacity:.9}}.login-submit:active{opacity:.8}.login-footer{right:0;bottom:calc(var(--spacing) * 5);padding-inline:calc(var(--spacing) * 5);text-align:center;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--text-muted);position:absolute;left:0}.login-footer p{white-space:normal}.login-footer a{color:var(--brand)}@media (hover:hover){.login-footer a:hover{text-decoration-line:underline}}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@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-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@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%}@keyframes spin{to{transform:rotate(360deg)}} \ No newline at end of file diff --git a/luci-theme-aurora/htdocs/luci-static/aurora/main.css b/luci-theme-aurora/htdocs/luci-static/aurora/main.css index ade03219..e6ee7682 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)}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{border-style:var(--tw-border-style);border-width:0}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 .navigation-direct{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));display:flex}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}}#aurora-nav-progress{pointer-events:none;z-index:80;height:calc(var(--spacing) * .5);transform-origin:0;--tw-scale-x:0%;scale:var(--tw-scale-x) var(--tw-scale-y);--tw-gradient-position:to right;inset-inline:0;position:fixed;top:0}@supports (background-image:linear-gradient(in lab, red, red)){#aurora-nav-progress{--tw-gradient-position:to right in oklab}}#aurora-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));opacity:0}#aurora-nav-progress[data-state=active]{--tw-scale-x:90%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:1;transition-property:scale,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:8s;--tw-ease:var(--ease-out);transition-duration:8s;transition-timing-function:var(--ease-out)}#aurora-nav-progress[data-state=done]{--tw-scale-x:100%;scale:var(--tw-scale-x) var(--tw-scale-y);opacity:0;transition-property:scale,opacity;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)}#aurora-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);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 #content_syslog{margin:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){#maincontent #view #content_syslog{margin:var(--spacing)}}#maincontent #view #content_syslog>div{align-items:baseline;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent #view #content_syslog>div{column-gap:calc(var(--spacing) * 1.5)}#maincontent #view #content_syslog>div>.cbi-input-select,#maincontent #view #content_syslog>div>.cbi-input-text{min-width:calc(var(--spacing) * 45)}}#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}#maincontent #syslog,#maincontent #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)}#maincontent #syslog{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){#maincontent #syslog{padding:calc(var(--spacing) * 3)}}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-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);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}@media (hover:hover){.navigation-direct.is-active-page:hover{color:var(--brand)}}.nav-category{cursor:pointer;appearance:none;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) * 3);padding-block:calc(var(--spacing) * 2);text-align:left;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);color:var(--text-muted);--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;-webkit-user-select:none;user-select:none;background-color:#0000;border-width:0;transition-duration:.15s;display:flex}@media (hover:hover){.nav-category:hover{color:var(--text)}}.nav-category: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}.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}}.nav-category-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.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{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;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{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{top:calc(var(--spacing) * 14);z-index:30;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);position:sticky}@media not all and (min-width:48rem){.alert-message{margin-inline:0;margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 4)}}.alert-message.modal{position:static;top:auto}.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) * 1.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{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}@media not all and (min-width:48rem){.ifacebadge>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 .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:wrap;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) * 40);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}td .ifacebox{flex-direction:row}}.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){td :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) * 4);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)}td :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{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:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span .cbi-tooltip-container+.cbi-tooltip-container{margin-left:calc(var(--spacing) * 1.5)}}.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:calc(var(--spacing) * 4)}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span>.nowrap:not(:last-child){margin-bottom:calc(var(--spacing) * 3)}}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 6);flex-shrink:0}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5)}}.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){td :is(.ifacebox .ifacebox-body>div){flex:1;width:auto}:where(td :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){td :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);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 .mobile-nav-link{min-height:calc(var(--spacing) * 13);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);border-style:var(--tw-border-style);width:100%;padding-inline:0;padding-block:calc(var(--spacing) * 2.5);text-align:left;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);--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;border-radius:0;text-decoration-line:none;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-link .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{margin-inline:0;margin-top:0;margin-bottom:calc(var(--spacing) * 2);padding-block:var(--spacing);padding-right:0;padding-left:calc(var(--spacing) * 6)}.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.log-enhanced>#syslog{display:none}.syslog-view{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);width:100%;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);display:block}@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{border-style:var(--tw-border-style);border-width:0}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 .navigation-direct{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));display:flex}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}}#aurora-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)){#aurora-nav-progress{--tw-gradient-position:to right in oklab}}#aurora-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)}#aurora-nav-progress[data-state=done]{opacity:0;transition:width .3s ease-out,opacity .15s ease-in .15s}#aurora-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 #content_syslog{margin:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){#maincontent #view #content_syslog{margin:var(--spacing)}}#maincontent #view #content_syslog>div{align-items:baseline;column-gap:calc(var(--spacing) * 2);flex-wrap:wrap;display:flex}@media not all and (min-width:48rem){#maincontent #view #content_syslog>div{column-gap:calc(var(--spacing) * 1.5)}#maincontent #view #content_syslog>div>.cbi-input-select,#maincontent #view #content_syslog>div>.cbi-input-text{min-width:calc(var(--spacing) * 45)}}#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}#maincontent #syslog,#maincontent #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)}#maincontent #syslog{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){#maincontent #syslog{padding:calc(var(--spacing) * 3)}}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-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);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--brand)}@media (hover:hover){.navigation-direct.is-active-page:hover{color:var(--brand)}}.nav-category{cursor:pointer;appearance:none;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) * 3);padding-block:calc(var(--spacing) * 2);text-align:left;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);color:var(--text-muted);--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;-webkit-user-select:none;user-select:none;background-color:#0000;border-width:0;transition-duration:.15s;display:flex}@media (hover:hover){.nav-category:hover{color:var(--text)}}.nav-category: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}.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}}.nav-category-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.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{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;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{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{top:calc(var(--spacing) * 14);z-index:30;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);position:sticky}@media not all and (min-width:48rem){.alert-message{margin-inline:0;margin-bottom:calc(var(--spacing) * 3);padding:calc(var(--spacing) * 4)}}.alert-message.modal{position:static;top:auto}.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) * 1.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{width:calc(var(--spacing) * 5);flex-shrink:0;align-self:center}@media not all and (min-width:48rem){.ifacebadge>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 .network-status-table{margin-bottom:calc(var(--spacing) * 3);justify-content:space-around;gap:calc(var(--spacing) * 4);flex-wrap:wrap;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) * 40);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}td .ifacebox{flex-direction:row}}.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){td :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) * 4);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)}td :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{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:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span .cbi-tooltip-container+.cbi-tooltip-container{margin-left:calc(var(--spacing) * 1.5)}}.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:calc(var(--spacing) * 4)}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span>.nowrap:not(:last-child){margin-bottom:calc(var(--spacing) * 3)}}.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 6);flex-shrink:0}@media not all and (min-width:48rem){.ifacebox .ifacebox-body>span img{width:calc(var(--spacing) * 5)}}.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){td :is(.ifacebox .ifacebox-body>div){flex:1;width:auto}:where(td :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){td :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);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 .mobile-nav-link{min-height:calc(var(--spacing) * 13);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);border-style:var(--tw-border-style);width:100%;padding-inline:0;padding-block:calc(var(--spacing) * 2.5);text-align:left;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);--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;border-radius:0;text-decoration-line:none;display:flex}.mobile-menu-overlay .mobile-nav .mobile-nav-list .mobile-nav-item .mobile-nav-link .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{margin-inline:0;margin-top:0;margin-bottom:calc(var(--spacing) * 2);padding-block:var(--spacing);padding-right:0;padding-left:calc(var(--spacing) * 6)}.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.log-enhanced>#syslog{display:none}.syslog-view{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);width:100%;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);display:block}@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-aurora/htdocs/luci-static/resources/router-aurora.js b/luci-theme-aurora/htdocs/luci-static/resources/router-aurora.js index bb27b99b..091c3c96 100644 --- a/luci-theme-aurora/htdocs/luci-static/resources/router-aurora.js +++ b/luci-theme-aurora/htdocs/luci-static/resources/router-aurora.js @@ -1 +1 @@ -"use strict";"require baseclass";"require ui";"require poll";"require rpc";const RT=window.L,RENDER_TIMEOUT=15e3,PATCH_ATTR="data-aurora-patch",NODE_CSS_ATTR="data-aurora-node-css",SHELL_ATTR="data-aurora-shell",PROGRESS_DELAY=150,INSTANTIATE=/instantiateView\(\s*['"]([^'"]+)['"]/,supported=()=>"object"==typeof navigation&&null!==navigation&&"function"==typeof navigation.addEventListener&&"function"==typeof NavigateEvent&&"intercept"in NavigateEvent.prototype,nodeWeight=e=>Math.min(e.order??9999,9999)+(e.auth?.login?1e4:0);function firstChild(e){let t=null;for(const[s,n]of Object.entries(e.children??{}))if(n.satisfied&&n.title&&"object"==typeof n.action)if("firstchild"===n.action?.type){if(t&&nodeWeight(t.node)<=nodeWeight(n))continue;firstChild(n)&&(t={name:s,node:n})}else n.firstchild_ineligible||(!t||nodeWeight(t.node)>nodeWeight(n))&&(t={name:s,node:n});return t}function resolve(e,t){let s=e,n=[],i=[],r=0;for(let o=0;o<32;o++){for(;r0&&s.every(e=>!0===e.readonly)}const actionOf=(e,t)=>t.length&&"object"==typeof e?.wildcardaction?e.wildcardaction:e?.action;function viewClass(e){return"view"===e?.type&&e.path?`view.${e.path.replace(/\//g,".")}`:null}const prefixes=e=>{const t=[];let s=null;for(const n of e)t.push(s=null==s?n:`${s}-${n}`);return t},PRAGMA_HEAD=/^(?:\s*["'](?:use strict|require\s[^"']+)["'];)+/,PRAGMA=/["']require\s+([^\s"']+)/g;function pragmaDeps(e){return[...(e.slice(0,4096).match(PRAGMA_HEAD)?.[0]??"").matchAll(PRAGMA)].map(e=>e[1])}const assetUrl=e=>{const t=document.body.dataset.assetVersion;return t?`${e}?v=${t}`:e},moduleUrl=e=>`${RT.env.base_url}/${e.replace(/\./g,"/")}.js${RT.env.resource_version?`?v=${RT.env.resource_version}`:""}`;return baseclass.extend({__init__(){if(!supported()||!RT?.env?.scriptname)return;const e=this.contract();e.length?console.warn(`router-aurora: luci-base surface missing, staying MPA: ${e.join(", ")}`):(this.gen=0,this.seen=new Set,this.warmed=new Set,this.inflight=Promise.resolve(),this.intervals=new Set,this.knownSheets=new WeakSet(this.sheets().filter(e=>e.hasAttribute(SHELL_ATTR)||e.hasAttribute(PATCH_ATTR)||e.hasAttribute(NODE_CSS_ATTR))),this.hostname=document.querySelector(".brand")?.textContent?.trim()||document.title,this.hookIntervals(),this.hookListeners(),this.hookSession(),this.hookVisibility(),Promise.all([ui.menu.load(),RT.require("menu-aurora")]).then(([e,t])=>{this.tree=e,this.menu=t;const s=this.initialRoute();s&&(document.querySelector('script[type="speculationrules"]')?.remove(),this.bar=document.body.appendChild(E("div",{id:"aurora-nav-progress","aria-hidden":"true"})),this.status=document.body.appendChild(E("div",{id:"aurora-nav-status",role:"status","aria-live":"polite","aria-atomic":"true"})),navigation.addEventListener("navigate",e=>this.onNavigate(e)),document.addEventListener("pointerover",e=>this.onIntent(e)),document.addEventListener("pointerdown",e=>this.onIntent(e)),document.addEventListener("focusin",e=>this.onIntent(e)),this.watchInitialRender(s))}))},contract(){const e={L:RT,rpc:rpc,poll:poll,ui:ui,window:window};return["L.view","L.require","L.dom.content","L.env.base_url","L.env.resource","L.env.media","L.Request.addInterceptor","L.uci.load","L.uci.unload","L.uci.state","rpc.addInterceptor","poll.queue","poll.start","poll.stop","poll.active","ui.menu.load","ui.hideModal","ui.hideIndicator","window.E"].filter(t=>null==(t=>t.split(".").reduce((e,t)=>null==e?e:e[t],e))(t))},hookVisibility(){document.addEventListener("visibilitychange",()=>{document.hidden?(this.pausedByVisibility=poll.active(),this.pausedByVisibility&&poll.stop()):this.pausedByVisibility&&(this.pausedByVisibility=!1,this.expired||poll.start())})},progressStart(){this.pending=(this.pending??0)+1,clearTimeout(this.progressTimer),this.progressTimer=setTimeout(()=>this.bar.dataset.state="active",150)},progressEnd(){--this.pending>0||(clearTimeout(this.progressTimer),"active"===this.bar.dataset.state&&(this.bar.dataset.state="done",this.progressTimer=setTimeout(()=>{"done"===this.bar.dataset.state&&delete this.bar.dataset.state},300)))},sheets(){const e=document.getElementById("view");return[...document.querySelectorAll('style, link[rel~="stylesheet"]')].filter(t=>!e?.contains(t))},poisoned(){return this.sheets().some(e=>!this.knownSheets.has(e)&&!e.hasAttribute(PATCH_ATTR)&&!e.hasAttribute(NODE_CSS_ATTR))},hookIntervals(){const e=window.setInterval,t=window.clearInterval,s=this.intervals;window.setInterval=function(...t){const n=e.apply(window,t);return s.add(n),n},window.clearInterval=function(e){return s.delete(e),t.call(window,e)},this.nativeClearInterval=t},hookListeners(){const e=this;for(const t of[window,document]){const s=t.addEventListener,n=t.removeEventListener;t.addEventListener=function(n,i,r){return e.renderWindow?.push({target:t,type:n,fn:i,opts:r}),s.call(this,n,i,r)},t.removeEventListener=function(t,s,i){return e.renderWindow&&(e.renderWindow=e.renderWindow.filter(e=>e.fn!==s||e.type!==t)),n.call(this,t,s,i)}}this.pageListeners=[],this.coldListeners=new Map},hookSession(){RT.Request?.addInterceptor?.(e=>{this.loginRequired(e)&&(this.expired=!0)}),rpc?.addInterceptor?.((e,t)=>{this.sessionGone(e,t)&&(this.expired=!0)})},loginRequired:e=>403===e?.status&&"yes"===e.headers?.get("X-LuCI-Login-Required"),sessionGone(e,t){if("session"!==t?.object||"access"!==t?.method||!e)return!1;if(e.error)return!0;const s=Array.isArray(e.result)?e.result[1]:e.result;return!1===s?.access},nodespec(e){return{...e.node,readonly:readonlyAlong(this.tree,e.path)}},nodeCss:e=>"string"==typeof e.node.css&&e.node.css?e.node.css:null,openRenderWindow(){this.renderWindow=[]},closeRenderWindow(e,t){const s=this.renderWindow??[];if(this.renderWindow=null,t)return this.coldListeners.set(e,s),void(this.pageListeners=[]);const n=this.coldListeners.get(e)??[];for(const e of s)for(const t of n.filter(t=>t.target===e.target&&t.type===e.type))t.target.removeEventListener(t.type,t.fn,t.opts);this.coldListeners.set(e,n.filter(e=>!s.some(t=>t.target===e.target&&t.type===e.type))),this.pageListeners=s},clearViewListeners(){for(const e of this.pageListeners)e.target.removeEventListener(e.type,e.fn,e.opts);this.pageListeners=[]},clearViewIntervals(){for(const e of this.intervals)e!==poll.timer&&(this.nativeClearInterval.call(window,e),this.intervals.delete(e))},segsFromURL(e){const t=new URL(e,window.location.href),s=RT.env.scriptname;return t.origin===window.location.origin&&t.pathname.startsWith(s)?t.pathname.slice(s.length).split("/").filter(Boolean).map(decodeURIComponent):null},route(e,{intent:t=!1}={}){const s=this.segsFromURL(e),n=s&&this.resolve(s);if(!n)return null;const i=actionOf(n.node,n.args),r=viewClass(i),o=i?.path,a="template"===i?.type&&(t?!this.unservable?.has(o):this.templates?.has(o));return r||a?{segs:s,className:r,template:a&&o,url:e,...n}:null},template(e){return this.templates??=new Map,this.templates.has(e.template)?Promise.resolve(this.templates.get(e.template)):(this.templateLoads??=new Map,this.templateLoads.has(e.template)||this.templateLoads.set(e.template,fetch(e.url,{credentials:"same-origin"}).then(e=>e.text()).then(t=>{const s=(new DOMParser).parseFromString(t,"text/html").getElementById("maincontent"),n=s?.querySelector("#tabmenu"),i=s?.querySelector(":scope > footer"),r=[];for(let e=n?.nextSibling;e&&e!==i;e=e.nextSibling)r.push(e);return this.rememberShell(e.template,r)}).finally(()=>this.templateLoads.delete(e.template))),this.templateLoads.get(e.template))},rememberShell(e,t){const s={className:null,nodes:[],scripts:[]};for(const e of t)if("SCRIPT"===e.nodeName){const t=e.textContent.match(INSTANTIATE);t?s.className=`view.${t[1].replace(/\//g,".")}`:e.src||!e.textContent.trim()||/new LuCI\(/.test(e.textContent)||s.scripts.push(e.textContent)}else if(1===e.nodeType&&"view"===e.id)s.nodes.push(E("div",{id:"view"}));else{if(1===e.nodeType&&e.querySelector("#view")){s.className=null;break}s.nodes.push(document.importNode(e,!0))}return s.className?this.templates.set(e,s):(this.unservable??=new Set).add(e),s.className?s:null},resolve(e){return resolve(this.tree,e)},moduleDeps:e=>pragmaDeps(e),patchPrefixes:e=>prefixes(e),initialRoute(){const e=this.route(window.location.href,{intent:!0});if(!e)return null;if(e.template){this.templates??=new Map;const t=this.rememberShell(e.template,this.region().nodes);if(!t)return null;e.className=t.className}this.seen.add(e.className);const t=e.node.title?_(e.node.title):"";return this.titleTail=document.title.startsWith(t)?document.title.slice(t.length):` - ${this.hostname}`,e},watchInitialRender(e){const t=document.getElementById("view");t&&(this.openRenderWindow(),this.inflight=this.rendered(t).finally(()=>this.closeRenderWindow(e.className,!0)),this.inflight.catch(()=>{}))},rendered(e){const t=e=>e.querySelector(":scope > :not(.spinning):not(script)")||0===e.childElementCount&&e.dataset.auroraStarted;return t(e)?Promise.resolve():new Promise((s,n)=>{const i=setTimeout(()=>o(n,new Error("view did not render in time")),15e3),r=new MutationObserver(()=>{t(e)&&o(s)});function o(e,t){clearTimeout(i),r.disconnect(),e(t)}e.dataset.auroraStarted="1",r.observe(e,{childList:!0})})},onIntent(e){const t=e.target?.closest?.("a[href]");if(!t||t.target||t.hasAttribute("download"))return;const s=this.route(t.href,{intent:!0});s&&(s.template?this.template(s).then(e=>e&&this.warm(e.className)).catch(()=>{}):this.seen.has(s.className)||this.warm(s.className))},warm(e){this.warmed.has(e)||(this.warmed.add(e),fetch(moduleUrl(e),{priority:"low",credentials:"same-origin"}).then(e=>e.ok?e.text():"").then(e=>{for(const t of pragmaDeps(e))t.includes(".")&&this.warm(t)}).catch(()=>{}))},onNavigate(e){if(this.bypass)return void(this.bypass=!1);if(!e.canIntercept||e.hashChange||null!==e.downloadRequest||e.formData||"reload"===e.navigationType)return;const t=this.route(e.destination.url);!t||this.expired||this.poisoned()||e.intercept({focusReset:"manual",scroll:"after-transition",handler:()=>this.navigate(t,e)})},async navigate(e,t){const s=++this.gen,n=this.inflight;let i;this.inflight=new Promise(e=>i=e),this.progressStart();try{if(await n,s!==this.gen||t.signal.aborted)return;const i=e.template?await this.template(e):null;if(i&&(e.className=i.className),s!==this.gen||t.signal.aborted)return;if(this.teardown(),await this.flushUci(),s!==this.gen||t.signal.aborted)return;this.setEnvironment(e),this.menu.syncRoute();const r=this.applyPatches(e.request);this.applyNodeCss(this.nodeCss(e));const o=this.stage(i),a=this.rendered(o),l=!this.seen.has(e.className);this.seen.add(e.className),this.openRenderWindow();try{const t=await RT.require(e.className);if(!(t instanceof RT.view))throw new TypeError(`${e.className} is not a LuCI.view`);l||new t.constructor,await a}finally{this.closeRenderWindow(e.className,l)}if(s!==this.gen)return;await this.commit(o),this.mountPatches(r),this.status.textContent=document.title,document.getElementById("maincontent")?.focus({preventScroll:!0})}catch(e){if(console.error("router-aurora:",e),s!==this.gen)return;this.bypass=!0,window.location.href=t.destination.url,await new Promise(()=>{})}finally{this.progressEnd(),i()}},teardown(){poll.queue.length=0,poll.stop(),poll.start(),ui.hideIndicator("poll-status"),this.clearViewIntervals(),this.clearViewListeners(),ui.hideModal(),this.menu.closeSurfaces(),this.unmountPatches()},async flushUci(){const e=RT.uci;if(!e?.state)return;const t=Object.keys({...e.state.values,...e.loaded});if(t.length&&e.unload(t),RT.network){const t=["network","luci"];RT.hasSystemFeature?.("wifi")&&t.push("wireless"),await e.load(t)}},setEnvironment(e){RT.env.requestpath=e.request,RT.env.dispatchpath=e.path,RT.env.pathinfo=`/${e.segs.join("/")}`,RT.env.nodespec=this.nodespec(e),document.body.dataset.page=e.request.join("-"),document.title=e.node.title?`${_(e.node.title)}${this.titleTail}`:this.hostname},region(){const e=document.getElementById("maincontent"),t=document.getElementById("tabmenu"),s=e.querySelector(":scope > footer"),n=[];for(let i=t?t.nextSibling:e.firstChild;i&&i!==s;)n.push(i),i=i.nextSibling;return{main:e,start:t,end:s,nodes:n}},stage(e){const{main:t,start:s,end:n}=this.region(),i=E("div",{class:"view-staging"});for(const e of t.querySelectorAll(":scope > #view"))e.classList.add("view-leaving");if(e){for(const t of e.nodes)i.appendChild(t.cloneNode(!0));for(const t of e.scripts)i.appendChild(E("script",{},t))}else i.appendChild(E("div",{id:"view"}));return t.insertBefore(i,s?s.nextSibling:n??null),i.querySelector("#view")},commit(e){const t=e.parentNode,s=()=>{for(const e of this.region().nodes)e!==t&&(1===e.nodeType&&RT.dom.content(e,null),e.remove());t.replaceWith(...t.childNodes)},n=window.matchMedia("(prefers-reduced-motion: reduce)").matches;if(document.startViewTransition&&!n)return document.startViewTransition(s).updateCallbackDone;s()},applyNodeCss(e){for(const t of document.querySelectorAll(`link[${NODE_CSS_ATTR}]`))t.disabled=t.getAttribute(NODE_CSS_ATTR)!==e;e&&!document.querySelector(`link[${NODE_CSS_ATTR}="${e}"]`)&&document.head.appendChild(E("link",{rel:"stylesheet",href:`${RT.env.resource}/${e}`,[NODE_CSS_ATTR]:e}))},installed:()=>(document.body.dataset.patches??"").split(/\s+/).filter(Boolean),applyPatches(e){const t=new Set(prefixes(e)),s=RT.env.media,n=[];for(const e of this.installed()){const i=e.replace(/\.(css|js)$/,""),r=t.has(i);if(e.endsWith(".css")){let e=document.querySelector(`link[${PATCH_ATTR}="${i}"]`);!e&&r?(e=E("link",{rel:"stylesheet",href:assetUrl(`${s}/patches/${i}.css`),[PATCH_ATTR]:i}),document.head.appendChild(e)):e&&(e.disabled=!r)}else r&&n.push(i)}return n},mountPatches(e){const t=window.aurora?.patches??{};this.live=new Set(e);for(const s of e)if(document.querySelector(`script[${PATCH_ATTR}="${s}"]`))t[s]?.mount?.();else{const e=E("script",{src:assetUrl(`${RT.env.media}/patches/${s}.js`),[PATCH_ATTR]:s});e.addEventListener("load",()=>{this.live.has(s)||window.aurora?.patches?.[s]?.unmount?.()}),document.head.appendChild(e)}},unmountPatches(){this.live=new Set;for(const e in window.aurora?.patches??{})window.aurora.patches[e].unmount?.()}}); \ No newline at end of file +"use strict";"require baseclass";"require ui";"require poll";"require rpc";const RT=window.L,RENDER_TIMEOUT=15e3,PATCH_ATTR="data-aurora-patch",NODE_CSS_ATTR="data-aurora-node-css",SHELL_ATTR="data-aurora-shell",PROGRESS_DELAY=150,INSTANTIATE=/instantiateView\(\s*['"]([^'"]+)['"]/,supported=()=>"object"==typeof navigation&&null!==navigation&&"function"==typeof navigation.addEventListener&&"function"==typeof NavigateEvent&&"intercept"in NavigateEvent.prototype,nodeWeight=e=>Math.min(e.order??9999,9999)+(e.auth?.login?1e4:0);function firstChild(e){let t=null;for(const[s,n]of Object.entries(e.children??{}))if(n.satisfied&&n.title&&"object"==typeof n.action)if("firstchild"===n.action?.type){if(t&&nodeWeight(t.node)<=nodeWeight(n))continue;firstChild(n)&&(t={name:s,node:n})}else n.firstchild_ineligible||(!t||nodeWeight(t.node)>nodeWeight(n))&&(t={name:s,node:n});return t}function resolve(e,t){let s=e,n=[],i=[],r=0;for(let o=0;o<32;o++){for(;r0&&s.every(e=>!0===e.readonly)}const actionOf=(e,t)=>t.length&&"object"==typeof e?.wildcardaction?e.wildcardaction:e?.action;function viewClass(e){return"view"===e?.type&&e.path?`view.${e.path.replace(/\//g,".")}`:null}const prefixes=e=>{const t=[];let s=null;for(const n of e)t.push(s=null==s?n:`${s}-${n}`);return t},PRAGMA_HEAD=/^(?:\s*["'](?:use strict|require\s[^"']+)["'];)+/,PRAGMA=/["']require\s+([^\s"']+)/g;function pragmaDeps(e){return[...(e.slice(0,4096).match(PRAGMA_HEAD)?.[0]??"").matchAll(PRAGMA)].map(e=>e[1])}const assetUrl=e=>{const t=document.body.dataset.assetVersion;return t?`${e}?v=${t}`:e},moduleUrl=e=>`${RT.env.base_url}/${e.replace(/\./g,"/")}.js${RT.env.resource_version?`?v=${RT.env.resource_version}`:""}`;return baseclass.extend({__init__(){if(!supported()||!RT?.env?.scriptname)return;const e=this.contract();e.length?console.warn(`router-aurora: luci-base surface missing, staying MPA: ${e.join(", ")}`):(this.gen=0,this.seen=new Set,this.warmed=new Set,this.inflight=Promise.resolve(),this.intervals=new Set,this.knownSheets=new WeakSet(this.sheets().filter(e=>e.hasAttribute(SHELL_ATTR)||e.hasAttribute(PATCH_ATTR)||e.hasAttribute(NODE_CSS_ATTR))),this.hostname=document.querySelector(".brand")?.textContent?.trim()||document.title,this.hookIntervals(),this.hookListeners(),this.hookSession(),this.hookVisibility(),Promise.all([ui.menu.load(),RT.require("menu-aurora")]).then(([e,t])=>{this.tree=e,this.menu=t;const s=this.initialRoute();s&&(document.querySelector('script[type="speculationrules"]')?.remove(),this.status=document.body.appendChild(E("div",{id:"aurora-nav-status",role:"status","aria-live":"polite","aria-atomic":"true"})),navigation.addEventListener("navigate",e=>this.onNavigate(e)),document.addEventListener("pointerover",e=>this.onIntent(e)),document.addEventListener("pointerdown",e=>this.onIntent(e)),document.addEventListener("focusin",e=>this.onIntent(e)),this.watchInitialRender(s))}))},contract(){const e={L:RT,rpc:rpc,poll:poll,ui:ui,window:window};return["L.view","L.require","L.dom.content","L.env.base_url","L.env.resource","L.env.media","L.Request.addInterceptor","L.uci.load","L.uci.unload","L.uci.state","rpc.addInterceptor","poll.queue","poll.start","poll.stop","poll.active","ui.menu.load","ui.hideModal","ui.hideIndicator","window.E"].filter(t=>null==(t=>t.split(".").reduce((e,t)=>null==e?e:e[t],e))(t))},hookVisibility(){document.addEventListener("visibilitychange",()=>{document.hidden?(this.pausedByVisibility=poll.active(),this.pausedByVisibility&&poll.stop()):this.pausedByVisibility&&(this.pausedByVisibility=!1,this.expired||poll.start())})},progressStart(){this.pending=(this.pending??0)+1,clearTimeout(this.progressTimer),this.progressTimer=setTimeout(()=>{this.bar||(this.bar=document.body.appendChild(E("div",{id:"aurora-nav-progress","aria-hidden":"true"})),this.bar.offsetWidth,this.trickle(10))},150)},trickle(e){this.bar&&(this.bar.style.width=`${e}%`,this.trickleTimer=setTimeout(()=>this.trickle(e+(100-e)/30),300))},progressEnd(){if(--this.pending>0)return;clearTimeout(this.progressTimer),clearTimeout(this.trickleTimer);const e=this.bar;e&&(this.bar=null,e.dataset.state="done",e.style.width="100%",setTimeout(()=>e.remove(),300))},sheets(){const e=document.getElementById("view");return[...document.querySelectorAll('style, link[rel~="stylesheet"]')].filter(t=>!e?.contains(t))},poisoned(){return this.sheets().some(e=>!this.knownSheets.has(e)&&!e.hasAttribute(PATCH_ATTR)&&!e.hasAttribute(NODE_CSS_ATTR))},hookIntervals(){const e=window.setInterval,t=window.clearInterval,s=this.intervals;window.setInterval=function(...t){const n=e.apply(window,t);return s.add(n),n},window.clearInterval=function(e){return s.delete(e),t.call(window,e)},this.nativeClearInterval=t},hookListeners(){const e=this;for(const t of[window,document]){const s=t.addEventListener,n=t.removeEventListener;t.addEventListener=function(n,i,r){return e.renderWindow?.push({target:t,type:n,fn:i,opts:r}),s.call(this,n,i,r)},t.removeEventListener=function(t,s,i){return e.renderWindow&&(e.renderWindow=e.renderWindow.filter(e=>e.fn!==s||e.type!==t)),n.call(this,t,s,i)}}this.pageListeners=[],this.coldListeners=new Map},hookSession(){RT.Request?.addInterceptor?.(e=>{this.loginRequired(e)&&(this.expired=!0)}),rpc?.addInterceptor?.((e,t)=>{this.sessionGone(e,t)&&(this.expired=!0)})},loginRequired:e=>403===e?.status&&"yes"===e.headers?.get("X-LuCI-Login-Required"),sessionGone(e,t){if("session"!==t?.object||"access"!==t?.method||!e)return!1;if(e.error)return!0;const s=Array.isArray(e.result)?e.result[1]:e.result;return!1===s?.access},reloads:e=>e.split("#")[0]===window.location.href.split("#")[0],nodespec(e){return{...e.node,readonly:readonlyAlong(this.tree,e.path)}},nodeCss:e=>"string"==typeof e.node.css&&e.node.css?e.node.css:null,openRenderWindow(){this.renderWindow=[]},closeRenderWindow(e,t){const s=this.renderWindow??[];if(this.renderWindow=null,t)return this.coldListeners.set(e,s),void(this.pageListeners=[]);const n=this.coldListeners.get(e)??[];for(const e of s)for(const t of n.filter(t=>t.target===e.target&&t.type===e.type))t.target.removeEventListener(t.type,t.fn,t.opts);this.coldListeners.set(e,n.filter(e=>!s.some(t=>t.target===e.target&&t.type===e.type))),this.pageListeners=s},clearViewListeners(){for(const e of this.pageListeners)e.target.removeEventListener(e.type,e.fn,e.opts);this.pageListeners=[]},clearViewIntervals(){for(const e of this.intervals)e!==poll.timer&&(this.nativeClearInterval.call(window,e),this.intervals.delete(e))},segsFromURL(e){const t=new URL(e,window.location.href),s=RT.env.scriptname;return t.origin===window.location.origin&&t.pathname.startsWith(s)?t.pathname.slice(s.length).split("/").filter(Boolean).map(decodeURIComponent):null},route(e,{intent:t=!1}={}){const s=this.segsFromURL(e),n=s&&this.resolve(s);if(!n)return null;const i=actionOf(n.node,n.args),r=viewClass(i),o=i?.path,a="template"===i?.type&&(t?!this.unservable?.has(o):this.templates?.has(o));return r||a?{segs:s,className:r,template:a&&o,url:e,...n}:null},template(e){return this.templates??=new Map,this.templates.has(e.template)?Promise.resolve(this.templates.get(e.template)):(this.templateLoads??=new Map,this.templateLoads.has(e.template)||this.templateLoads.set(e.template,fetch(e.url,{credentials:"same-origin"}).then(e=>e.text()).then(t=>{const s=(new DOMParser).parseFromString(t,"text/html").getElementById("maincontent"),n=s?.querySelector("#tabmenu"),i=s?.querySelector(":scope > footer"),r=[];for(let e=n?.nextSibling;e&&e!==i;e=e.nextSibling)r.push(e);return this.rememberShell(e.template,r)}).finally(()=>this.templateLoads.delete(e.template))),this.templateLoads.get(e.template))},rememberShell(e,t){const s={className:null,nodes:[],scripts:[]};for(const e of t)if("SCRIPT"===e.nodeName){const t=e.textContent.match(INSTANTIATE);t?s.className=`view.${t[1].replace(/\//g,".")}`:e.src||!e.textContent.trim()||/new LuCI\(/.test(e.textContent)||s.scripts.push(e.textContent)}else if(1===e.nodeType&&"view"===e.id)s.nodes.push(E("div",{id:"view"}));else{if(1===e.nodeType&&e.querySelector("#view")){s.className=null;break}s.nodes.push(document.importNode(e,!0))}return s.className?this.templates.set(e,s):(this.unservable??=new Set).add(e),s.className?s:null},resolve(e){return resolve(this.tree,e)},moduleDeps:e=>pragmaDeps(e),patchPrefixes:e=>prefixes(e),initialRoute(){const e=this.route(window.location.href,{intent:!0});if(!e)return null;if(e.template){this.templates??=new Map;const t=this.rememberShell(e.template,this.region().nodes);if(!t)return null;e.className=t.className}this.seen.add(e.className);const t=e.node.title?_(e.node.title):"";return this.titleTail=document.title.startsWith(t)?document.title.slice(t.length):` - ${this.hostname}`,e},watchInitialRender(e){const t=document.getElementById("view");t&&(this.openRenderWindow(),this.inflight=this.rendered(t).finally(()=>this.closeRenderWindow(e.className,!0)),this.inflight.catch(()=>{}))},rendered(e){const t=e=>e.querySelector(":scope > :not(.spinning):not(script)")||0===e.childElementCount&&e.dataset.auroraStarted;return t(e)?Promise.resolve():new Promise((s,n)=>{const i=setTimeout(()=>o(n,new Error("view did not render in time")),15e3),r=new MutationObserver(()=>{t(e)&&o(s)});function o(e,t){clearTimeout(i),r.disconnect(),e(t)}e.dataset.auroraStarted="1",r.observe(e,{childList:!0})})},onIntent(e){const t=e.target?.closest?.("a[href]");if(!t||t.target||t.hasAttribute("download"))return;const s=this.route(t.href,{intent:!0});s&&(s.template?this.template(s).then(e=>e&&this.warm(e.className)).catch(()=>{}):this.seen.has(s.className)||this.warm(s.className))},warm(e){this.warmed.has(e)||(this.warmed.add(e),fetch(moduleUrl(e),{priority:"low",credentials:"same-origin"}).then(e=>e.ok?e.text():"").then(e=>{for(const t of pragmaDeps(e))t.includes(".")&&this.warm(t)}).catch(()=>{}))},onNavigate(e){if(this.bypass)return void(this.bypass=!1);if(!e.canIntercept||e.hashChange||null!==e.downloadRequest||e.formData||"reload"===e.navigationType||this.reloads(e.destination.url))return;const t=this.route(e.destination.url);!t||this.expired||this.poisoned()||e.intercept({focusReset:"manual",scroll:"after-transition",handler:()=>this.navigate(t,e)})},async navigate(e,t){const s=++this.gen,n=this.inflight;let i;this.inflight=new Promise(e=>i=e),this.progressStart();try{if(await n,s!==this.gen||t.signal.aborted)return;const i=e.template?await this.template(e):null;if(i&&(e.className=i.className),s!==this.gen||t.signal.aborted)return;if(this.teardown(),await this.flushUci(),s!==this.gen||t.signal.aborted)return;this.setEnvironment(e),this.menu.syncRoute();const r=this.applyPatches(e.request);this.applyNodeCss(this.nodeCss(e));const o=this.stage(i),a=this.rendered(o),l=!this.seen.has(e.className);this.seen.add(e.className),this.openRenderWindow();try{const t=await RT.require(e.className);if(!(t instanceof RT.view))throw new TypeError(`${e.className} is not a LuCI.view`);l||new t.constructor,await a}finally{this.closeRenderWindow(e.className,l)}if(s!==this.gen)return;await this.commit(o),this.mountPatches(r),this.status.textContent=document.title,document.getElementById("maincontent")?.focus({preventScroll:!0})}catch(e){if(console.error("router-aurora:",e),s!==this.gen)return;this.bypass=!0,window.location.href=t.destination.url,await new Promise(()=>{})}finally{this.progressEnd(),i()}},teardown(){poll.queue.length=0,poll.stop(),poll.start(),ui.hideIndicator("poll-status"),this.clearViewIntervals(),this.clearViewListeners(),ui.hideModal(),this.menu.closeSurfaces(),this.unmountPatches()},async flushUci(){const e=RT.uci;if(!e?.state)return;const t=Object.keys({...e.state.values,...e.loaded});if(t.length&&e.unload(t),RT.network){const t=["network","luci"];RT.hasSystemFeature?.("wifi")&&t.push("wireless"),await e.load(t)}},setEnvironment(e){RT.env.requestpath=e.request,RT.env.dispatchpath=e.path,RT.env.pathinfo=`/${e.segs.join("/")}`,RT.env.nodespec=this.nodespec(e),document.body.dataset.page=e.request.join("-"),document.title=e.node.title?`${_(e.node.title)}${this.titleTail}`:this.hostname},region(){const e=document.getElementById("maincontent"),t=document.getElementById("tabmenu"),s=e.querySelector(":scope > footer"),n=[];for(let i=t?t.nextSibling:e.firstChild;i&&i!==s;)n.push(i),i=i.nextSibling;return{main:e,start:t,end:s,nodes:n}},stage(e){const{main:t,start:s,end:n}=this.region(),i=E("div",{class:"view-staging"});for(const e of t.querySelectorAll(":scope > #view"))e.classList.add("view-leaving");if(e){for(const t of e.nodes)i.appendChild(t.cloneNode(!0));for(const t of e.scripts)i.appendChild(E("script",{},t))}else i.appendChild(E("div",{id:"view"}));return t.insertBefore(i,s?s.nextSibling:n??null),i.querySelector("#view")},commit(e){const t=e.parentNode,s=()=>{for(const e of this.region().nodes)e!==t&&(1===e.nodeType&&RT.dom.content(e,null),e.remove());t.replaceWith(...t.childNodes)},n=window.matchMedia("(prefers-reduced-motion: reduce)").matches;if(document.startViewTransition&&!n)return document.startViewTransition(s).updateCallbackDone;s()},applyNodeCss(e){for(const t of document.querySelectorAll(`link[${NODE_CSS_ATTR}]`))t.disabled=t.getAttribute(NODE_CSS_ATTR)!==e;e&&!document.querySelector(`link[${NODE_CSS_ATTR}="${e}"]`)&&document.head.appendChild(E("link",{rel:"stylesheet",href:`${RT.env.resource}/${e}`,[NODE_CSS_ATTR]:e}))},installed:()=>(document.body.dataset.patches??"").split(/\s+/).filter(Boolean),applyPatches(e){const t=new Set(prefixes(e)),s=RT.env.media,n=[];for(const e of this.installed()){const i=e.replace(/\.(css|js)$/,""),r=t.has(i);if(e.endsWith(".css")){let e=document.querySelector(`link[${PATCH_ATTR}="${i}"]`);!e&&r?(e=E("link",{rel:"stylesheet",href:assetUrl(`${s}/patches/${i}.css`),[PATCH_ATTR]:i}),document.head.appendChild(e)):e&&(e.disabled=!r)}else r&&n.push(i)}return n},mountPatches(e){const t=window.aurora?.patches??{};this.live=new Set(e);for(const s of e)if(document.querySelector(`script[${PATCH_ATTR}="${s}"]`))t[s]?.mount?.();else{const e=E("script",{src:assetUrl(`${RT.env.media}/patches/${s}.js`),[PATCH_ATTR]:s});e.addEventListener("load",()=>{this.live.has(s)||window.aurora?.patches?.[s]?.unmount?.()}),document.head.appendChild(e)}},unmountPatches(){this.live=new Set;for(const e in window.aurora?.patches??{})window.aurora.patches[e].unmount?.()}}); \ No newline at end of file diff --git a/luci-theme-footstrap/Makefile b/luci-theme-footstrap/Makefile index 22e38744..ce07ba1f 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:=21 +PKG_RELEASE:=22 endif LUCI_TITLE:=Footstrap Theme diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-chrome.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-chrome.js index a17d54c8..8d08c795 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-chrome.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-chrome.js @@ -4,7 +4,6 @@ 'require fs-fit as fit'; 'require fs-prefs as prefs'; 'require fs-menutree as tree'; -'require fs-version as version'; /* The chrome AROUND the content: the mode menu, the section tabs, the rail toggle, and the * measurements that decide how much room any of it gets. The MAIN menu is not here — it is injected @@ -278,43 +277,6 @@ function publishBarHeight(bar) { root.style.setProperty('--fs-bar-live', `${h}px`); } -/* ---- the theme names itself in the footer, beside LuCI and the distribution ---- - * - * The footer's sentence is about what renders this page: LuCI's version, the distribution's, and — - * since the markup is the theme's — the theme's. Each of the other two is a link to where that - * software lives, so this one is too. - * - * WRITTEN FROM THE CLIENT, and that is the only reason it is here rather than in footer.ut: the - * version is stamped into fs-version.js by file name — the Makefile, tools/stage.sh and dev-sync.sh - * all sed that one literal — so a second copy in a template would be a second stamp site to keep in - * step, and a footer that quietly disagrees with the Appearance tab is worse than no version at all. - * The label is the one fs-version already prints there, dev builds included. - * - * Once per document: the footer survives a client navigation (navigate() sweeps the children of - * .fs-content, and the footer is its sibling), and the guard makes a second call a no-op rather - * than a second copy. No request, no translated string: a proper noun and a number. */ -function nameThemeInFooter() { - const host = document.querySelector('footer.fs-footer span'); - if (!host || host.querySelector('.fs-footer-self')) return; - const self = E('a', { - 'class': 'fs-footer-self', - 'href': version.REPO_URL, - 'target': '_blank', - /* `noreferrer` alone, matching footer.ut's own two anchors: it implies noopener in every - * engine that ships `rel=noreferrer` at all, so the pair reads as two rules where there is - * one. fs-appearance.js's link to the same URL spells both — the two are now in step. */ - 'rel': 'noreferrer' - }, [ version.label() ]); - /* AFTER THE DISTRIBUTION, not at the end. The sentence lists the software that renders the page - * — LuCI, the distribution, the theme — and footer.ut appends one more fragment after them that - * is not a component but a state: "Lua compatibility mode active". Landing behind it read as if - * the theme were part of that notice. Two links means the second is the distribution's; with - * anything else there, appending is still correct. */ - const links = host.querySelectorAll('a'); - if (links.length >= 2) links[1].after(document.createTextNode(' / '), self); - else host.append(document.createTextNode(' / '), self); -} - /* ---- does the right-hand cluster still fit beside the brand? ---- * * The same question as the menu's, one row up, and it cannot be asked the same way. The cluster is @@ -497,7 +459,6 @@ function wireIndicatorCounts() { return baseclass.extend({ setRenderMain, renderChrome, - nameThemeInFooter, wireIndicatorCounts, /* registered with fs-fit by the theme's init(): the bar's "does the menu fit beside the brand" * measurement rides the same engine as the data tables' */ 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 b00a9f38..ae82bf1d 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-fit.js @@ -42,14 +42,46 @@ function schedule() { requestAnimationFrame(() => { _rafPending = false; run(); }); } -/* Watch an element's size. Any change re-fits everything — the fitters are cheap and few. */ +/* WIDTH ONLY, and this is not an optimisation — it is what makes the theme usable on a phone. + * + * Every browser on iOS grows and shrinks the viewport HEIGHT while the user scrolls, because the + * URL bar slides away and comes back; each step of that animation is a resize, and a ResizeObserver + * on #view reports it. Measured with the bar's travel simulated on a 390px viewport — twenty + * height-only steps, width untouched — the fitters ran often enough to rewrite 1054 class + * attributes, each one a forced synchronous layout of a page the user is scrolling. That is the + * juddering reported from an iPhone. + * + * Nothing a fitter asks is about height: `roomFor()`/`overflows()` compare a table against its + * column, `fitChrome()` asks whether the menu fits beside the brand, the rail and the density axes + * change widths. A height-only change cannot alter any of those answers — and the one case that + * looks like a counter-example is not one: a vertical scrollbar appearing takes WIDTH from the + * content box, so the observer sees it as the width change it is. + * + * Per element, because the roots are observed separately and a dialog can resize while #view does + * not. The first entry for an element always counts as a change, so nothing is lost at start-up. */ +const _lastWidth = new WeakMap(); +function onResize(entries) { + let widthMoved = false; + for (const e of entries) { + /* contentRect, not getBoundingClientRect(): the observer already measured it, and asking + * again inside the callback is the forced layout this function exists to avoid. */ + const w = Math.round(e.contentRect.width); + if (_lastWidth.get(e.target) !== w) { + _lastWidth.set(e.target, w); + widthMoved = true; + } + } + if (widthMoved) schedule(); +} + +/* Watch an element's size. A change in WIDTH re-fits everything — the fitters are cheap and few. */ function watch(el) { if (!el) return; /* No feature test: the shipped CSS needs :has() and container queries, both years younger than * ResizeObserver in every engine, so a browser that can render this theme at all has it. The * window-resize fallback that used to sit here was worse than nothing anyway — it cannot see a * rail collapse or a layout toggle, which is the pair this file uses an observer FOR. */ - if (!_ro) _ro = new ResizeObserver(schedule); + if (!_ro) _ro = new ResizeObserver(onResize); _ro.observe(el); } diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-menutree.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-menutree.js index 21f52eb2..200e9d96 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-menutree.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-menutree.js @@ -120,21 +120,47 @@ function resolveSegs(segs) { * Save/Apply footer key their disabled state off, so on a session with narrower ACLs than root's * this is any page whose SECTION is read-only. * - * OR down the path, exactly as check_acl_depends() folds the accumulated list: one read-only acl - * anywhere on it is enough. Feed it the RESOLVED segments, since that is the path the dispatcher - * accumulates over. */ + * AND down the path, not OR — the operator is the whole of this function and it was the wrong one. + * check_acl_depends() (dispatcher.uc:312) is handed ONE list, the concatenation ctx_append() built + * from every node's `depends.acl` along the path (:457-470), and it answers `writable = true` as + * soon as ANY group in that list grants write. So a page is read-only exactly when NO group on the + * path is writable — and since apply_tree_acls() (:436-446) marks a node `readonly` when that + * node's own list yields no write, "no group on the path is writable" is "EVERY acl-bearing node on + * the path is readonly". One read-only ancestor is not enough: a leaf that declares a writable acl + * of its own re-opens the whole path. + * + * Measured, because a source reading is not a verdict: on the 25.12 stand, `admin/status/logs` + * carries the read-only `luci-mod-status-logs` and its child `syslog` was given a writable acl of + * its own; a full load then reported `nodespec.readonly` FALSE while this function said true — the + * same class of disagreement between a click and an F5 that the leaf-only reading used to produce, + * only in the opposite direction, and this time it TAKES AWAY a Save/Apply the server allows. + * + * A node with no `depends.acl` is not evidence either way and is skipped: the dispatcher puts + * nothing into ctx.acls for it. That is also why the answer needs `depends.acl` at all rather than + * the `readonly` flag alone — an acl-bearing node the session may write carries no flag, and is + * therefore indistinguishable from an ungated node without looking at its acl list. /admin/menu + * serves both fields (66 of 243 nodes carry an acl on the stand). + * + * Feed it the RESOLVED segments, since that is the path the dispatcher accumulates over. */ function readonlyForSegs(segs) { let node = _tree; - if (node && node.readonly === true) - return true; + let gated = 0, locked = 0; + const weigh = (n) => { + const acl = n && n.depends && n.depends.acl; + if (!acl || !acl.length) + return; + gated++; + if (n.readonly === true) + locked++; + }; + weigh(node); for (let i = 0; i < segs.length; i++) { node = node && node.children && node.children[segs[i]]; if (!node) - return false; - if (node.readonly === true) - return true; + break; + weigh(node); } - return false; + return gated > 0 && gated === locked; } /* The view class a menu node instantiates, or null if the node isn't SPA-able. The Status→Overview diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-router.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-router.js index f733e937..254ee8b5 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-router.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-router.js @@ -1,6 +1,7 @@ 'use strict'; 'require baseclass'; 'require ui'; +'require rpc'; 'require fs-menutree as tree'; 'require fs-chrome as chrome'; 'require fs-sheets as sheets'; @@ -64,11 +65,11 @@ function clearViewIntervals() { /* …and the ALIAS ITSELF is the first thing that can go — it is the deprecation the paragraph * above is about, so this function cannot be the one place that reads it blind. Every other * `L.Poll` read in this file is guarded, and an unguarded one here throws where a throw costs - * most: navigate() calls this AFTER #view has been swapped for the "Loading view…" spinner and - * BEFORE data-page, pushState and the require, so a TypeError would strand every click on the - * spinner with the old URL and the old menu mark — far worse than the leaked interval this - * exists to sweep. No alias is the same answer as an unreadable timer: do NOTHING, once, - * loudly. */ + * most: navigate() calls this inside the staged render, after the chrome has already switched to + * the incoming page and before its module is required, so a TypeError would leave every click + * showing the previous page's content under the new page's title and menu mark, with the + * navigation dead in a rejected promise — far worse than the leaked interval this exists to + * sweep. No alias is the same answer as an unreadable timer: do NOTHING, once, loudly. */ if (!L.Poll) { warnPollUnreadable('footstrap: L.Poll is gone from this luci-base, so LuCI\'s own tick cannot be ' + 'told apart from a view\'s timers — leaving view intervals alone. fs-router.js needs ' @@ -202,6 +203,120 @@ function flushUciCache() { } let _uciCacheWarned = false; +/* ---- A DEAD SESSION ENDS THE DOCUMENT, AND THE ROUTER MUST NOT BROWSE THROUGH IT ---- + * + * luci-base answers an expired session with `notifySessionExpiry()`: `Poll.stop()` plus a modal + * whose only button reloads the page, which the dispatcher then answers with the login form. Every + * navigation of ours does the opposite of both halves — `ui.hideModal()` and `L.Poll.stop()` + + * `start()` — so the first click after the session died dismissed luci-base's own warning and + * carried on. Measured on the stand before this existed: kill the session from inside the document, + * let one rpc reject (`SessionError`, luci-base's modal up, polling stopped), then click a menu + * link — the router swapped the view, the modal was gone, and the page sat on "Loading view…" with + * every call behind it failing. Only a reload got the user back to a login form. + * + * So the router LEARNS that the session is gone and stops claiming navigations; the next click is a + * real one and the dispatcher turns it into the login page. Nothing is reset — the flag dies with + * the document, exactly as the session did. + * + * WHICH SIGNALS, and they are luci-base's own two decision points rather than a guess (luci.js, + * `setupDOM`): + * + * 1. a `403` carrying `X-LuCI-Login-Required: yes` on any `L.Request` — upstream calls + * `notifySessionExpiry()` on exactly that pair; + * 2. the `session.access` probe luci-base fires after some other call came back `-32002`, when + * that probe REJECTS — which is what upstream's `.catch(notifySessionExpiry)` reacts to. + * + * `access: false` is deliberately NOT one of them, and that is where this differs from the same + * gate in luci-theme-aurora. The probe is declared `expect: { access: true }`, and rpc.js's + * `handleCallReply()` turns a missing or mistyped key into the expectation's own value and + * RESOLVES — so a probe answering `access: false` never reaches upstream's catch and never expires + * anything. It is an ACL answer, and treating it as a dead session would drop a restricted user out + * of the SPA for the rest of the document over a permission they simply do not have. + * + * The probe's rejection is read off the frame the interceptor is handed, because that is all an + * interceptor can see: `handleCallReply()` rejects on a frame that is not JSON-RPC 2.0 or on an + * `error` carrying both a code and a message, so those are the two conditions here. A foreign + * `session.access` call of somebody else's that errors would also match — the cost is one document + * of full loads, which is the safe direction to be wrong in. + * + * NEITHER INTERCEPTOR MAY THROW. luci-base runs both through `Promise.all(...).catch(req.reject)` + * (`luci.js` for Request, `rpc.js` for rpc), so an exception in here would not just be our bug — it + * would reject the caller's request, i.e. break the very page we are trying to protect. Hence the + * try/catch around each body and no optional-chaining shortcuts on shapes we do not own. */ +let _expired = false; +let _sessionWired = false; +function markExpired() { + if (_expired) return; + _expired = true; + /* once per document, and it is the console's least alarming level the house rules allow + * (eslint no-console permits warn and error only): nothing is broken, the session simply + * ended, and the very next click sends the user to a login form. */ + console.warn('footstrap: the LuCI session is gone — every navigation from here is a full load.'); +} +function watchSession() { + if (_sessionWired) return; + _sessionWired = true; + + const req = window.L ? window.L.Request : null; + if (req && typeof req.addInterceptor === 'function') + req.addInterceptor((res) => { + try { + if (res && res.status === 403 && res.headers && + res.headers.get('X-LuCI-Login-Required') === 'yes') + markExpired(); + } + catch (e) { /* see above: an interceptor that throws rejects the caller's request */ } + }); + + if (rpc && typeof rpc.addInterceptor === 'function') + rpc.addInterceptor((msg, r) => { + try { + if (!r || r.object !== 'session' || r.method !== 'access') return; + if (!msg || msg.jsonrpc !== '2.0' || + (msg.error && msg.error.code && msg.error.message)) + markExpired(); + } + catch (e) { /* ditto */ } + }); +} + +/* ---- throw an element away the way luci-base throws one away ---- + * + * `dom.data()` does not live on the element: luci.js keeps it in `dom.registry`, keyed by a + * `data-idref` attribute, and the ONE thing that ever deletes an entry is `dom.content()` + * (luci.js: it walks `[data-idref]` and deletes each key before emptying the node). A plain + * `remove()` therefore leaves the entry — and through it the element and whatever class instance + * was stored on it — reachable for the life of the document. + * + * `#view` is not affected, and that is why this is small: the incoming view's own + * `dom.content(#view, …)` reaps the outgoing page. What the router removes BY HAND is the rest — + * the siblings a template emitted next to `#view`, and the runtime notification banners — and those + * it used to drop with `remove()`. + * + * MEASURED, before writing it: over three pages on the 25.12 stand nothing the sweeps remove + * carries a `data-idref` at all (banners: 0, siblings: 0), and the registry does not grow across + * laps (83 entries after the first lap of four pages, 83 after the third). So this fixes no leak we + * can see today; it closes the class, for the same reason the stackables selector claims a table + * with no LuCI classes — coverage is a contract, and the alternative is discovering it from a + * third-party page nobody here runs. + * + * The bin is what makes the element's OWN entry go too: `dom.content()` reaps descendants of the + * node it is given, never the node itself, so the element is moved into a detached container first + * — which also takes it out of the live tree, i.e. does the removal. Public API only; no reaching + * into `dom.registry`. If luci-base ever moves that surface, the fallback is today's behaviour. */ +function discard(el) { + try { + const dom = window.L ? window.L.dom : null; + if (!dom || typeof dom.content !== 'function') { el.remove(); return; } + const bin = document.createElement('div'); + bin.appendChild(el); + dom.content(bin, null); + } + catch (e) { + el.remove(); + } +} + let _wired = false; /* The pathname whose view is CURRENTLY rendered — popstate compares against it to tell a real * navigation from a mere fragment change (see there). Seeded from the served page. */ @@ -244,6 +359,9 @@ let _curId = null; * goes first: a Map iterates in insertion order and `set` on an existing key does not refresh it, * so the re-save below is delete-then-set. */ const SCROLL_MEM_MAX = 50; +/* The offset a popstate replay must land on, consumed by the commit that puts the page on screen — + * see the popstate handler for why it cannot be replayed any earlier. */ +let _pendingRestore = null; function newEntryId() { return _scrollSess + ':' + (++_histN); } /* adopt the entry we are standing on: reuse its fsid if it has one, stamp one otherwise (entries @@ -354,89 +472,6 @@ function titleHost() { return _titleHost; } -/* The view class the page CURRENTLY on screen wants (what _curPath resolves to). Read by the - * stale-render repair below to tell "the superseded render happened to paint the right view - * anyway" from "it painted the wrong one". */ -function currentViewClass() { - const segs = tree.segsFromPath(_curPath); - const res = segs && tree.resolveSegs(segs); - return tree.viewClassFor(res && res.node); -} - -/* ---- a superseded FIRST render cannot be cancelled, so undo it ---- - * - * _navGen stops a stale require() from calling `new view.constructor()` — but only on the CACHED - * path. On a FIRST visit the require() IS the render (see navigate()): it constructs the view, whose - * __init__ runs load() → render() → dom.content(#view) and registers its pollers, inside a promise - * we do not own. Nothing to cancel. - * - * So the fast double-click is a real bug: click Firewall (uncached), click Wireless 100 ms later. - * navigate(Wireless) flushes L.Poll's queue BEFORE Firewall's poller is added; Firewall then paints - * into the #view that now belongs to Wireless and registers a poller the flush can no longer catch — - * leaving Wireless's URL/title/menu/data-page, Firewall's content, and Firewall's poller running on - * every page afterwards. - * - * Repair by re-running the current navigation: navigate() is exactly the "put the document back the - * way a fresh load leaves it" routine. push=false — the URL never moved, only the DOM under it; if - * it declines (the superseded view injected CSS), the reload does it the hard way. The className - * check terminates this: if the superseded render painted the class the current path wants anyway - * (A → B → A while A was still loading), the DOM and its poller are correct — and with two uncached - * views racing it is also what stops a repair triggering a repair. */ -function repairStaleRender(className) { - if (className === currentViewClass()) - return; - console.warn('footstrap: a superseded view (' + className + ') rendered into the live page; re-rendering ' + _curPath); - if (!navigate(_curPath, false)) - window.location.reload(); -} - -/* ---- the generation must be checked at the PAINT, not at the dispatch ---- - * - * _navGen is checked once, in the require() callback, i.e. BEFORE `new view.constructor()`. But a - * view's __init__ is async — `ready.then(this.load).then(this.render).then(nodes => - * dom.content(document.getElementById('view'), nodes))` — so the DOM write happens two awaits later, - * and every await is a point at which the whole event loop runs, another navigation included. The - * dispatch-time check has expired by the time it matters. - * - * Measured on the router: leave the (cached) package manager for System after 150 ms, and the paints - * into #view land 16010 System, 16490 package-manager — the view we walked away from paints LAST and - * wins, permanently. URL, , data-page and the menu highlight all say System; #view shows - * Software. Only a reload clears it. The cached path is the COMMON one — after warm-up every - * navigation takes it — and it had no guard at all: repairStaleRender() is called only when !cached. - * - * The fix has to be a paint-time check, and there are two constraints on where it can live. - * ClassConstructor DISCARDS __init__'s return value (`this.__init__.apply(this, arguments)`, no - * return), so the construction promise is unreachable — nothing to await. But __init__ resolves - * `this.render` while it builds its chain, i.e. during `new`, so a wrapper installed on the - * prototype BEFORE the construct is the one that gets bound. `new` then returns synchronously (the - * first load() is already a microtask), which is what makes stamping the generation on the INSTANCE - * right after it safe — and it must be the instance, not a map keyed by class name, or A → B → A - * with everything cached would have the second construct's generation overwrite the first's. - * - * A superseded render resolves to a promise that never settles: the chain simply stops before - * dom.content(), so nothing paints and addFooter() never runs. Returning empty nodes instead would - * paint the emptiness over the live page, and throwing would hand LuCI's own .catch an error box to - * render into the page we just opened. - * - * A view instance we did not construct (the singleton require() builds on a FIRST visit — the render - * IS the require, so there is no window in which to arm anything) carries no stamp and is left alone: - * that path is repairStaleRender()'s, and stays its. */ -const _guarded = new WeakSet(); -function armRenderGuard(cls) { - if (_guarded.has(cls)) return; - _guarded.add(cls); - const orig = cls.prototype.render; - cls.prototype.render = function () { - /* unstamped: not ours to judge (see above) */ - const stale = () => this.__fsGen !== undefined && this.__fsGen !== _navGen; - if (stale()) - return new Promise(() => {}); - return Promise.resolve(orig.apply(this, arguments)).then((nodes) => { - /* re-check: render() itself awaits (an RPC, usually), which re-opens the window */ - return stale() ? new Promise(() => {}) : nodes; - }); - }; -} /* The exact URL LuCI.require() will fetch for a class name, cache-bust and all. Matching it * byte-for-byte is what makes a hover prefetch a warm cache hit for the later require(). */ @@ -582,6 +617,223 @@ function seed() { titleHost(); /* before any view can rename the tab — see there */ /* the served page's entry needs an id too, or the first Back TO it has nothing to look up */ adoptEntry(); + + /* ---- THE DOCUMENT'S OWN FIRST RENDER IS THE FIRST LINK IN THE CHAIN ---- + * + * A navigation waits for the previous render because a LuCI view chain resolves `#view` at paint + * time and would otherwise paint into the newer navigation's stage. The very first chain in a + * document is not one of ours — `view.ut`'s inline `instantiateView()` is already running when + * the chrome comes up — and it is subject to exactly the same rule. Left untracked it was a real + * bug, not a theoretical one: measured at 350 ms latency, a click 150 ms after DOMContentLoaded + * ended with the URL, title and menu on System and the Processes the document had been loading + * painted over it, because that chain finished last and found the stage first in tree order. + * + * So the chain starts here, watching the live `#view` with the same observer a staged render + * uses. If the first view has already painted, `renderedIn()` resolves at once and the first + * click waits for nothing. The `.catch` is what keeps a document whose first view never renders + * (an error page, a dead RPC) from turning every later click into a rejected promise — and from + * logging an unhandled rejection at the 15 s mark on a page nobody clicked. */ + const vp = document.getElementById('view'); + if (vp) _inflight = renderedIn(vp).catch(() => {}); +} + +/* ---- THE INCOMING PAGE IS RENDERED OFF SCREEN AND SWAPPED IN WHEN IT IS READY ---- + * + * What this replaces: the router used to empty `#view`, paint luci-base's "Loading view…" spinner + * on a cold route and let the incoming view render into the live page. Two things came with that. + * The user watched an empty page for as long as the module and its data took — measured at 600 ms + * latency, 1800 ms of nothing on a first visit — and a superseded render could not be stopped, so + * the file carried three mechanisms to repair the damage afterwards: a generation stamped on the + * instance, a wrapper around `prototype.render` that made a stale paint hang forever, and a + * re-navigation that undid a stale FIRST render after the fact. + * + * Rendering into a stage removes the damage instead of repairing it. `stageView()` puts a fresh + * `<div id="view">` inside a hidden wrapper as the FIRST child of `.fs-content`, and + * `getElementById` returns the first match in tree order — which is what LuCI's own view chain + * calls, twice: once in `View.__init__` for the spinner and again when the render resolves + * (`DOM.content(document.getElementById('view'), nodes)`). So the incoming view writes into the + * stage while the page the user is reading stays on screen, untouched, until the swap. + * + * HIDDEN, BUT LAID OUT. `visibility: hidden; height: 0; overflow: clip` — never `display: none`. + * Several views size themselves from the element they render into, and they find it the same way + * LuCI does: `view/status/load.js` does `document.querySelector('#view')` and then + * `view.offsetWidth - 2` (bandwidth.js, connections.js and wireless.js repeat it verbatim), so a + * `display: none` stage would hand them a zero width they keep for the life of the instance. The + * stage's width is the container's, exactly what it will be after the swap — measured rather than + * assumed: the Load graph comes out 1222px wide whether the page is reached by a full load or by a + * click. Only the height is taken away, so the page under it does not move. + * + * AND THE SWAP MOVES THE NODES, IT DOES NOT SWAP THE ELEMENT. The other obvious shape — insert the + * staged `#view` and delete the old one — would change the identity of `#view`, and this theme has + * observers bound to that element: `fs-fit`'s content MutationObserver and `fs-appearance`'s view + * observer are registered on the node that existed at chrome init. Swapping the element leaves both + * watching a detached node, i.e. the fitters silently stop re-running on content mutations. So the + * live `#view` keeps its identity and its children are replaced through `dom.content()`, which is + * also what reaps the outgoing page's `data-idref` registry entries. + * + * RENDERS ARE SERIALIZED, and this is what actually retires the repair machinery. Neither an + * in-flight LuCI XHR nor a running `View.__init__` chain can be cancelled — `L.Request` never + * exposes its handle — and every chain resolves `#view` at PAINT time, so a chain started by an + * older navigation would paint into whatever stage is first when it finishes, i.e. into the newer + * navigation's. A navigation therefore waits for the previous one to finish before it stages + * anything; the older chain paints into its own stage, which is then dropped unswapped. The cost is + * stated plainly: a click during a slow first load waits for that load. It buys the deletion of + * three mechanisms that only ever cleaned up afterwards. + * + * COMPLETION IS OBSERVED, NOT ASSUMED. `renderedIn()` watches the stage and resolves when a child + * that is not the spinner appears — or when a mutation leaves it empty, which is how a view that + * renders nothing at all finishes. A render that has not completed within RENDER_TIMEOUT is a + * FAILURE, not a completion: swapping a spinner in and releasing the serialization would let the + * still-running chain paint into a later navigation's stage, so it rejects into the same full-load + * fallback every other error takes. */ +const RENDER_TIMEOUT = 15000; +/* the promise of the render currently in flight — this initial value only covers a document whose + * chrome came up without seed() having run; seed() replaces it with the document's own first render */ +let _inflight = Promise.resolve(); + +function stageView(contentHost) { + const wrapper = document.createElement('div'); + wrapper.className = 'fs-staging'; + const view = document.createElement('div'); + view.id = 'view'; + wrapper.appendChild(view); + /* FIRST in tree order, or getElementById() would keep answering with the live one */ + contentHost.insertBefore(wrapper, contentHost.firstChild); + return { wrapper, view }; +} + +function renderedIn(view) { + /* `.spinning` is luci-base's own placeholder, written by View.__init__ before load() runs; + * a <script> is what a template shell replays. Neither is the page. */ + const painted = () => view.querySelector(':scope > :not(.spinning):not(script)') !== null; + if (painted()) return Promise.resolve(); + return new Promise((resolve, reject) => { + const timer = window.setTimeout(() => { + finish(() => reject(new Error('the view did not render within ' + RENDER_TIMEOUT + ' ms'))); + }, RENDER_TIMEOUT); + const mo = new MutationObserver(() => { + /* an empty render finishes too: the spinner is replaced by nothing at all, which is a + * mutation that leaves no element children behind. No "has it started" flag guards this: + * `painted()` was asked before the observer existed, and an observer only ever fires on a + * mutation, so an empty stage cannot resolve before the render has touched it. */ + if (painted() || view.childElementCount === 0) finish(resolve); + }); + function finish(settle) { + window.clearTimeout(timer); + mo.disconnect(); + settle(); + } + mo.observe(view, { childList: true }); + }); +} + +function dropStage(stage) { + if (stage && stage.wrapper && stage.wrapper.parentNode) discard(stage.wrapper); +} + +/* Put the staged page on screen: clear what the outgoing page left beside `#view`, move the staged + * children into the live `#view` through `dom.content()`, and drop the wrapper. */ +function commitStage(stage, contentHost) { + /* the outgoing page is going off screen now, so the sheets it owned may finally be darkened — + * the half navigate() spared while it was still being read */ + sheets.scopeToCurrentPage(); + sweepAround(contentHost); + const live = liveView(contentHost, stage); + const nodes = Array.from(stage.view.childNodes); + const dom = window.L ? window.L.dom : null; + if (live && dom && typeof dom.content === 'function') + dom.content(live, nodes); + else if (live) + live.replaceChildren(...nodes); + dropStage(stage); +} + +/* The `#view` the document keeps between navigations — the one the observers are bound to. It is + * whichever `#view` is NOT the stage; a document that has none (a template page that emitted no + * `#view` at all) gets one, once. */ +function liveView(contentHost, stage) { + for (const el of contentHost.querySelectorAll(':scope > #view')) + if (el !== stage.view) return el; + const v = document.createElement('div'); + v.id = 'view'; + contentHost.appendChild(v); + return v; +} + +/* Clear what the OUTGOING page left as a SIBLING of #view inside .fs-content: dom.content() + * replaces only #view's OWN children, so anything a page emitted next to it rides along — the + * Status→Overview template emits <h2 name="content">Status</h2> there, hidden only by a + * body[data-page='admin-status-overview'] rule, so after an SPA nav the orphan showed on EVERY page + * until a full reload. Keep only the chrome that legitimately outlives a page (tabs, server + * notices, <noscript>) and the stage itself. + * + * …and the RUNTIME notifications, which live one level up and therefore survived every navigation. + * `ui.addNotification()` does `mc.insertBefore(msg, mc.firstElementChild)` on #maincontent — this + * theme's <main class="fs-main"> — while the sweep above only reaches children of .fs-content, a + * descendant of it. A full load clears them; SPA never did, so "Upload request failed" and every + * third-party banner stacked up over each following page for the rest of the session. The + * .fs-content banners kept above are the SERVER's notices (notices.ut) and legitimately outlive a + * page; these are not the same thing. */ +function sweepAround(contentHost) { + Array.from(contentHost.children).forEach((c) => { + if (c.id !== 'view' && c.id !== 'tabmenu' && !c.classList.contains('fs-staging') && + !c.classList.contains('alert-message') && c.nodeName !== 'NOSCRIPT') + discard(c); + }); + const mainHost = document.getElementById('maincontent'); + if (mainHost) + Array.from(mainHost.children).forEach((c) => { + if (c.classList.contains('alert-message')) discard(c); + }); +} + +/* ---- and something has to say that a slow navigation IS a navigation ---- + * + * With the outgoing page left on screen until the incoming one is ready, a cold route would + * otherwise look like a click that did nothing: the chrome switches instantly (title, URL, menu), + * the content does not move for as long as the module and its first RPC take. The spinner this + * replaced was worse — it threw the page away to say the same thing — but silence is not the + * answer either. + * + * A hairline at the top of the content, shown only when the navigation OUTLIVES `PROGRESS_DELAY`. + * Below that threshold a bar would flash on and off on every warm click, which reads as a glitch + * rather than as progress; above it, it is the browser's own affordance for exactly this. The + * counter is what makes overlapping navigations share one bar. Reduced motion is handled in CSS, + * where the transitions live. */ +const PROGRESS_DELAY = 150; +let _progressPending = 0; +let _progressTimer = 0; +function progressBar() { + let bar = document.getElementById('fs-nav-progress'); + if (!bar) { + bar = document.createElement('div'); + bar.id = 'fs-nav-progress'; + /* it says nothing a screen reader needs: the live region already announces the page, and a + * decorative bar in the accessibility tree is noise on every navigation */ + bar.setAttribute('aria-hidden', 'true'); + /* ON <body>, not in the content column: it is `position: fixed`, and `.fs-shell` carries + * `contain: paint` in the sidebar layout, which would make it position against the shell and + * clip it. Inside `.fs-main` — a column flex container — its 2px were shrunk to zero + * outright. Both measured; see styles/theme/20-shell.css. */ + document.body.insertBefore(bar, document.body.firstChild); + } + return bar; +} +function progressStart() { + _progressPending++; + window.clearTimeout(_progressTimer); + _progressTimer = window.setTimeout(() => { progressBar().dataset.state = 'active'; }, PROGRESS_DELAY); +} +function progressEnd() { + if (--_progressPending > 0) return; + _progressPending = 0; + window.clearTimeout(_progressTimer); + const bar = progressBar(); + if (bar.dataset.state !== 'active') return; + bar.dataset.state = 'done'; + _progressTimer = window.setTimeout(() => { + if (bar.dataset.state === 'done') delete bar.dataset.state; + }, 300); } /* Attempt an in-place navigation to `pathname`. Returns true if handled as a @@ -596,6 +848,11 @@ function navigate(pathname, push, kbd) { * the only exit that leaves BOTH pages correct is a real navigation. See fs-sheets.js. */ if (sheets.documentPoisoned()) return false; + /* …and a document whose session has died is spent in the same way, for a different reason: the + * only page it can still render correctly is the login form, and only a real navigation gets + * there. See watchSession(). */ + if (_expired) return false; + /* `segs` is what the user clicked, `rsegs` the leaf it resolves to; they differ for an * alias/firstchild link, and a full load keeps BOTH — URL and pathinfo as requested, * requestpath/dispatchpath/nodespec/title resolved. Mirror that split exactly, or an F5 @@ -641,94 +898,24 @@ function navigate(pathname, push, kbd) { /* from here on the navigation is committed */ const gen = ++_navGen; + /* THE SAVED OFFSET BELONGS TO THIS NAVIGATION, so it is taken out of the module slot here + * rather than read at the swap. Left in the slot it outlives its own navigation: Back sets it, + * a click supersedes that render before it commits, and the clicked page — a page the user + * never asked to be restored — is scrolled to the Back target's offset, under a generation that + * passes because it is the newer one's. Clearing it on the superseded path is not the answer + * either: a second popstate may legitimately have put ITS offset there by then. Reported in + * review. */ + const restoreTo = _pendingRestore; + _pendingRestore = null; _curPath = pathname; /* what is on screen from now on — read by the popstate handler */ - /* Ensure a #view, and clear what the OUTGOING page left as a SIBLING of #view inside .fs-content: - * dom.content() replaces only #view's OWN children, so anything a page emitted next to it rides - * along — the Status→Overview template emits <h2 name="content">Status</h2> there, hidden only - * by a body[data-page='admin-status-overview'] rule, so after an SPA nav the orphan showed on - * EVERY page until a full reload. Keep only the chrome that legitimately outlives a page (tabs, - * server notices, <noscript>); this also gives a template page that emits no #view a fresh one. */ const contentHost = document.querySelector('.fs-content'); if (!contentHost) return false; - Array.from(contentHost.children).forEach((c) => { - if (c.id !== 'view' && c.id !== 'tabmenu' && - !c.classList.contains('alert-message') && c.nodeName !== 'NOSCRIPT') - c.remove(); - }); - /* …and the RUNTIME notifications, which live one level up and therefore survived every - * navigation. `ui.addNotification()` does `mc.insertBefore(msg, mc.firstElementChild)` on - * #maincontent — this theme's <main class="fs-main"> — while the sweep above only reaches - * children of .fs-content, a descendant of it. A full load clears them; SPA never did, so - * "Upload request failed" and every third-party banner stacked up over each following page for - * the rest of the session (reproduced: the banner outlives a nav, and only F5 removes it). - * The .fs-content banners kept above are the SERVER's notices (notices.ut) and legitimately - * outlive a page; these are not the same thing. */ - const mainHost = document.getElementById('maincontent'); - if (mainHost) - Array.from(mainHost.children).forEach((c) => { - if (c.classList.contains('alert-message')) c.remove(); - }); - if (!document.getElementById('view')) { - const v = document.createElement('div'); - v.id = 'view'; - contentHost.appendChild(v); - } - /* SAY THAT SOMETHING IS LOADING, on a route whose module has never been fetched. - * - * The chrome switches instantly — title, URL, body[data-page], the menu highlight — but the - * sweep above deliberately does not touch the children of #view, and LuCI's own spinner is - * written by `View.__init__`, i.e. only once the view module has ARRIVED. So between the click - * and the last round-trip of the module chain the user reads the PREVIOUS page's content under - * the new page's title, with nothing moving. Measured on the router at 600 ms latency: at 150 ms - * and 400 ms #view still held the System page while everything else said Processes; the - * "Loading view…" spinner appeared at 900 ms and the content at 1800 ms. A full load would have - * shown the browser's own progress for that whole window. - * - * Only for a COLD route: `_seen` means the class has already been through require(), where - * View.__init__ paints its spinner synchronously and there is no gap to fill. - * - * Deliberately the SAME markup and the SAME msgid luci-base uses, not a skeleton of our own: - * when View.__init__ replaces it there is nothing to see, and the string arrives already - * translated in the ~40 languages this theme ships no catalogue for (the chrome rule — a - * context-free msgid is how we inherit luci-base's translation). */ - if (!_seen.has(className)) { - const vp = document.getElementById('view'); - if (vp) { - const s = document.createElement('div'); - s.className = 'spinning'; - s.textContent = _('Loading view…'); - vp.replaceChildren(s); - } - } + /* the page being LEFT, captured before L.env is re-pointed a few lines down: the sheet scoping + * spares it until the swap takes it off screen (see there) */ + const leaving = (L.env.dispatchpath || []).slice(); - /* teardown: drop the outgoing view's pollers, then put the poll loop back into the state a FRESH - * LOAD leaves it in. The only non-view poller LuCI adds is the transient apply/reboot - * reachability check, so flushing the queue is safe. - * - * The re-arm matters: LuCI runs one 1 s tick and fires a queue entry only when - * `tick % interval == 0`, so leaving the OUTGOING page's tick running makes the incoming poller - * wait for the next multiple of its interval — up to `pollinterval`, 5 s. Wireless draws its - * station list from the first poll and sat spinning for 4950 ms against ~360 ms on a full load. - * - * stop() alone is NOT the fix: it deletes `tick`, and Poll.add() only auto-starts when - * `tick != null`, so the incoming pollers would never start at all. stop()+start() on an EMPTY - * queue leaves what a fresh document has (`tick = 0`, no timer armed); the view's first - * poll.add() then starts it and steps immediately — upstream's own sequence, since on a full - * load initDOM() runs Poll.start() on an empty queue before the view renders. */ - if (L.Poll && L.Poll.queue) { - L.Poll.queue.length = 0; - L.Poll.stop(); - L.Poll.start(); - } - /* kill the outgoing view's plain setInterval pollers too (podkop's log tailer) — a full load - * would have. L.Poll's own tick survives. */ - clearViewIntervals(); - /* and drop uci's document-scoped config cache, which a full load would not have carried into the - * incoming page either (see flushUciCache). What it hands back is the refill of the packages - * network.js will never load again — awaited below, before the view renders. */ - const uciWarm = flushUciCache(); /* the outgoing page's links are about to become a detached tree — do not hold one of them */ _lastHovered = null; /* run every registered navigation callback — today the search palette's recent-pages record and @@ -769,21 +956,6 @@ function navigate(pathname, push, kbd) { L.env.nodespec = { satisfied: true, action: node.action, title: node.title, depends: node.depends, readonly: tree.readonlyForSegs(rsegs) }; - /* Keep <body data-page> in sync with the route: the server stamps the dispatch path - * (`ctx.path`) on every full load, and page-scoped CSS keys off it. `rsegs` is the RESOLVED - * leaf, so a firstchild URL like /admin/status yields the same "admin-status-overview" whether - * it arrives as a full load or a client nav. Without the re-stamp the incoming page keeps the - * previous page's data-page and its scoped styles silently do not apply. */ - document.body.setAttribute('data-page', rsegs.join('-')); - - /* …and immediately hand the new page to fs-sheets, which darkens every foreign sheet that - * belongs to a DIFFERENT page and re-lights the ones that belong to this one. This is what lets - * an invasive sheet stay in the document without spending it — the alternative was a full load - * on the way out of any page carrying one, which stock LuCI's five realtime views all do (see - * the page-ownership block in fs-sheets.js). It must run AFTER the stamp above and BEFORE the - * view renders, so nothing paints through a sheet that no longer owns the page. */ - sheets.scopeToCurrentPage(rsegs); - /* Re-navigating to the page already on screen must REPLACE its history entry, not push a * second one. Clicking the active menu item is ordinary, and a duplicate entry makes Back do * nothing: popstate fires, `location.pathname === _curPath`, and the fragment guard below @@ -870,60 +1042,134 @@ function navigate(pathname, push, kbd) { * and the wait introduces a window in which we may never get there. Marking it up front would * make the NEXT navigation take the cached branch — `new view.constructor()` on a class whose * require() is what renders it — i.e. two renders and two pollers for one page. */ - /* `uciWarm` rides alongside the prefetch wait rather than after it: both are in flight already, and - * a view must not be constructed until the uci cache it reads is back (see flushUciCache). It never - * rejects — the refill catches its own failure — so it cannot cost the navigation a full reload. */ - Promise.all([ warmedThen(className), uciWarm ]).then(() => { + /* THE PREVIOUS RENDER IS WAITED FOR, not raced. Every LuCI view chain resolves `#view` at PAINT + * time, so a chain still running from an older navigation would paint into whatever stage is + * first when it finishes — i.e. into this one's. Waiting is what lets the stale chain land in + * its own stage, which is then dropped unswapped, and it is what retired the three repair + * mechanisms this file used to carry. The wait rides alongside the prefetch wait rather than + * after it: both are already in flight. */ + const previous = _inflight; + let release; + _inflight = new Promise((r) => { release = r; }); + progressStart(); + + Promise.all([ warmedThen(className), previous.catch(() => {}) ]).then(() => { /* superseded while waiting: never start the require. On a first visit the require IS the - * render, so starting it here would paint a page the user has already left and hand - * repairStaleRender() a mess that only exists because a require in flight cannot be stopped. */ + * render, so starting it here would spend a module fetch and a round of RPCs on a page the + * user has already left. */ if (gen !== _navGen) return null; + + /* ---- teardown, now that the previous render is finished and cannot re-register ---- + * + * Drop the outgoing view's pollers, then put the poll loop back into the state a FRESH LOAD + * leaves it in. The only non-view poller LuCI adds is the transient apply/reboot + * reachability check, so flushing the queue is safe. + * + * The re-arm matters: LuCI runs one 1 s tick and fires a queue entry only when + * `tick % interval == 0`, so leaving the OUTGOING page's tick running makes the incoming + * poller wait for the next multiple of its interval — up to `pollinterval`, 5 s. Wireless + * draws its station list from the first poll and sat spinning for 4950 ms against ~360 ms on + * a full load. + * + * stop() alone is NOT the fix: it deletes `tick`, and Poll.add() only auto-starts when + * `tick != null`, so the incoming pollers would never start at all. stop()+start() on an + * EMPTY queue leaves what a fresh document has (`tick = 0`, no timer armed); the view's first + * poll.add() then starts it and steps immediately — upstream's own sequence, since on a full + * load initDOM() runs Poll.start() on an empty queue before the view renders. */ + if (L.Poll && L.Poll.queue) { + L.Poll.queue.length = 0; + L.Poll.stop(); + L.Poll.start(); + } + /* kill the outgoing view's plain setInterval pollers too (podkop's log tailer) — a full load + * would have. L.Poll's own tick survives. */ + clearViewIntervals(); + /* and drop uci's document-scoped config cache, which a full load would not have carried into + * the incoming page either (see flushUciCache). What it hands back is the refill of the + * packages network.js will never load again — awaited below, before the view renders. */ + const uciWarm = flushUciCache(); + + /* Keep <body data-page> in sync with the route: the server stamps the dispatch path + * (`ctx.path`) on every full load, and page-scoped CSS keys off it. `rsegs` is the RESOLVED + * leaf, so a firstchild URL like /admin/status yields the same "admin-status-overview" + * whether it arrives as a full load or a client nav. Without the re-stamp the incoming page + * keeps the previous page's data-page and its scoped styles silently do not apply. + * + * WHERE THIS SITS, AND WHAT IT COSTS. It has to be before the staged render: page-scoped CSS + * is keyed on `body[data-page]`, so a view that renders under the wrong value measures itself + * through the wrong rules — and the fitters run inside the stage. It cannot be moved to the + * swap for the same reason. What that buys is a correct incoming page; what it costs is that + * the OUTGOING page, still on screen until the swap, wears the incoming page's name for the + * staging window. The one artifact that is visible today is the Overview's own + * `<h2 name="content">Status</h2>`, hidden by a `body[data-page='admin-status-overview']` + * rule and therefore un-hidden while leaving that page — the same stray heading the sweep at + * the swap removes. Moving the stamp later would trade that for a wrongly measured incoming + * page, which is worse and lasts longer. Reported in review; stated here rather than left as + * a claim the placement does not have. */ + document.body.setAttribute('data-page', rsegs.join('-')); + + /* …and hand the new page to fs-sheets, which darkens every foreign sheet that belongs to a + * DIFFERENT page and re-lights the ones that belong to this one. This is what lets an + * invasive sheet stay in the document without spending it — the alternative was a full load + * on the way out of any page carrying one, which stock LuCI's five realtime views all do (see + * the page-ownership block in fs-sheets.js). It must run AFTER the stamp above and BEFORE the + * view renders, so nothing paints through a sheet that no longer owns the page. + * + * IN TWO HALVES, because unlike `data-page` this one can be split. Enabling the incoming + * page's sheets is what the staged render needs; DISABLING the outgoing page's is what would + * strip an app's own stylesheet off the content the user is still reading — for the whole + * staging window, which on a cold route is the 600-1800 ms this design exists to fill. So the + * page being left is spared here and swept at the swap (see commitStage). Reported in + * review. */ + sheets.scopeToCurrentPage(rsegs, leaving); + + const stage = stageView(contentHost); + const painted = renderedIn(stage.view); _seen.add(className); /* NAME THE OWNER for the length of this require, AND ONLY WHEN THE MODULE HAS YET TO BE * EVALUATED. On a first visit the require IS the render, so any <style> the module injects - * belongs to THIS page — even if a newer navigation has stamped data-page by the time it - * lands, which is exactly the case repairStaleRender() below exists for. Without it fs-sheets - * credited such a sheet to the page that superseded this one and bound it there for the life - * of the document (measured: luci-app-filemanager's `.cbi-button-save { display: none - * !important }` disabled on its own page and live on System -> System, across return visits). - * - * `!cached` is what makes the hint survive long enough to be read, and its absence is why the - * measured case stopped being covered. A CACHED require injects nothing — the module was - * evaluated on the first visit and `require()` hands back the singleton — but it still ran - * this line, and its `.finally` fires within a microtask, so the navigation that superseded a - * cold require would set the hint to itself and clear it to null while that require was still - * in flight. The sheet then landed with no hint at all, i.e. credited to the superseding page, - * which is the exact bug. A require that cannot inject has no business naming an owner. */ + * belongs to THIS page. Without it fs-sheets credited such a sheet to whichever page was + * stamped when it landed and bound it there for the life of the document (measured: + * luci-app-filemanager's `.cbi-button-save { display: none !important }` disabled on its own + * page and live on System -> System, across return visits). A CACHED require injects nothing + * — the module was evaluated on the first visit and `require()` hands back the singleton — so + * it has no business naming an owner. */ if (!cached) sheets.attributeTo(rsegs, gen); - return RT.require(className).finally(() => { if (!cached) sheets.attributeTo(null, gen); }); - }).then((view) => { - if (view == null) return; - if (!(view instanceof RT.view)) - throw new TypeError('Loaded class ' + className + ' is not a view'); - if (gen !== _navGen) { - /* A newer navigation superseded this one. On the CACHED path nothing has happened - * yet — skipping the constructor below is the whole cancellation. On the FIRST-visit - * path the require() has ALREADY rendered into the live page and registered its - * pollers, with nothing to cancel: undo it. See repairStaleRender(). */ - if (!cached) - repairStaleRender(className); - return; - } - if (cached) { - /* singleton: its __init__ already ran, re-run it. Arm the paint-time guard BEFORE the - * construct (__init__ binds this.render as it builds its chain) and stamp the - * generation right after it (the first load() is a microtask, so this lands first) — - * this navigation can still be superseded while that render awaits its RPC. */ - const cls = view.constructor; - armRenderGuard(cls); - const inst = new cls(); - inst.__fsGen = gen; - } + + /* `uciWarm` is awaited before the construct, never after: a cached module resolves within a + * microtask, well before the refill lands, and the view would read the cache we just emptied. + * It never rejects — the refill catches its own failure — so it cannot cost a full reload. */ + return Promise.resolve(uciWarm) + .then(() => RT.require(className)) + .finally(() => { if (!cached) sheets.attributeTo(null, gen); }) + .then((view) => { + if (!(view instanceof RT.view)) + throw new TypeError('Loaded class ' + className + ' is not a view'); + /* require() does not hand back a class — it caches an INSTANCE, so requiring a class + * not seen before CONSTRUCTS it, and a view's __init__ IS its render. On a first + * visit the require has therefore already painted (into the stage); only on a REVISIT + * is there a singleton whose __init__ has to be re-run. `cached` was read before the + * waits above, since the require is what fills LuCI's cache. */ + if (cached) new view.constructor(); + return painted; + }) + .then(() => { + /* superseded while rendering: the chain painted into ITS OWN stage, so there is + * nothing to repair — drop it and leave the live page to the newer navigation. */ + if (gen !== _navGen) { dropStage(stage); return; } + commitStage(stage, contentHost); + /* now, and only now, is there one height to read: the incoming page's */ + if (restoreTo) restoreScroll(restoreTo, gen); + }) + .catch((e) => { dropStage(stage); throw e; }); }).catch((e) => { /* the full reload is a correct fallback, but swallowing the reason made every SPA-router * regression look like "the page is just slow to load". Log, then fall back. */ console.error('footstrap: SPA nav to ' + className + ' failed, falling back to a full load', e); if (gen === _navGen) window.location = pathname; + }).then(() => { + progressEnd(); + release(); }); return true; @@ -960,10 +1206,39 @@ function prefetchFrom(ev) { * lasts until the pointer happens to cross some other link. */ let _lastHovered = null; +/* ---- a document the router could not have rendered is not one it may navigate AWAY from ---- + * + * A `call`, `cbi` or `function` node — and a `template` other than the one Status→Overview node we + * serve — is a page this theme did not build and cannot rebuild. What it leaves behind is the + * problem: such a page may carry inline scripts and timers of its own, set before this module was + * even evaluated, so the interval hook at the top of this file never saw them and no teardown of + * ours can retire them. Only the document's death does. So the first click away from one is a full + * load, which is what a user got before the router existed. + * + * NARROWER THAN "did the current path resolve", deliberately. A path that resolves to nothing is + * not evidence of a hostile document — a wildcard URL (`admin/network/wireless/radio0.network1`) + * simply is not in the tree, since nodeForSegs() stops at the first unknown segment, and refusing to + * wire there would turn the router off for the whole document on some of the most-used pages in + * LuCI. Only a node we CAN see and CANNOT serve disables it. + * + * On the stands this is a no-op today and is written for the case it is not: of 243 menu nodes, + * the 110 `call` and 8 `function` ones answer with JSON or a redirect and never render this theme + * at all (a probe on those URLs finds no `L` in the document), and the single `template` node is + * the Overview, which viewClassFor() maps to `view.status.index`. */ +function bootDocumentIsOurs() { + const node = tree.currentNode(); + if (!node || !node.action) + return true; /* unknown to the tree: a wildcard page, and today's behaviour is right */ + return tree.viewClassFor(node) != null; +} + function wireRouter() { if (_wired) return; _wired = true; + if (!bootDocumentIsOurs()) + return; + document.addEventListener('click', (ev) => { if (ev.defaultPrevented || ev.button !== 0 || ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.altKey) @@ -1029,11 +1304,18 @@ function wireRouter() { * adopt the entry we arrived on and look up what IT recorded when it was left */ saveScroll(); adoptEntry(); - const target = _scrollMem.get(_curId); - if (!navigate(window.location.pathname, false)) + /* Handed to navigate() rather than started here, and that is not tidiness — it is a bug the + * staged swap introduced and this is where it is fixed. restoreScroll() writes as soon as the + * scroller is TALL ENOUGH for the saved offset, and while the incoming page renders off + * screen the OUTGOING one is still on it, so the height that satisfies the test can be the + * old page's. Measured in the top layout: parked at 386, restored at 386 while Processes was + * still up, then the swap replaced it with a shorter page and the browser clamped to 197. + * Started after the commit instead, there is only one height it can be reading. */ + _pendingRestore = _scrollMem.get(_curId) || null; + if (!navigate(window.location.pathname, false)) { + _pendingRestore = null; window.location.reload(); - else - restoreScroll(target, _navGen); + } }); } @@ -1054,6 +1336,11 @@ document.addEventListener('poll-stop', () => { } }); +/* At module eval, like the listener above and for the same reason: the session can die during the + * FIRST view's own data calls, i.e. before anything has called wire(), and an interceptor that was + * not registered by then never sees the answer that said so. */ +watchSession(); + /* Pause LuCI's 1s poll loop while the tab is hidden: LuCI has no visibilitychange handler, so an * overview left open in a background tab hammers ubus 24/7 (notably the pricey iwinfo getAssocList) * on a low-power router. stop() only clearInterval()s (the queue survives); start() re-arms and runs @@ -1073,7 +1360,10 @@ function wireVisibility() { wasActive = L.Poll.active(); if (wasActive) L.Poll.stop(); } - else if (wasActive) { + /* …but never resume a poll the session can no longer answer: luci-base stopped it on + * purpose when it put its "Session expired" modal up, and restarting it on tab-show + * would spend a burst of failing calls behind a page the user cannot use anyway. */ + else if (wasActive && !_expired) { L.Poll.start(); } } catch (e) { console.error('footstrap: the poll pause/resume threw', e); } diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-sheets.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-sheets.js index 6d864fe9..451a69f9 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-sheets.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-sheets.js @@ -733,12 +733,24 @@ function setEnabled(el, on) { * OWN are touched: a clean sheet is harmless and an invasive one we could not attribute still * poisons the document, so it keeps the full-load path rather than being silently disabled on its * own page. */ -function scopeToCurrentPage(segs) { +/* `keep` is the page still ON SCREEN, and it exists because a client navigation now has a window in + * which two pages are real: the incoming one renders into a hidden stage while the outgoing one is + * still being read (fs-router's staged swap). Scoping is needed BEFORE the staged render — a view + * must not measure itself through a sheet that does not own its page — but doing both halves then + * strips the outgoing page's own stylesheet off content the user is looking at, for the 600-1800 ms + * the staging window exists to fill. So the router calls this twice: once with `keep` set to the + * page it is leaving, which enables the incoming page's sheets and leaves the departing page's + * alone, and once with nothing at the swap, which is the ordinary sweep. */ +function scopeToCurrentPage(segs, keep) { if (segs) _curKey = appKey(segs); const key = currentKey(); + const spared = (keep && keep.length) ? appKey(keep) : null; document.querySelectorAll(VIEW_SHEETS).forEach((el) => { if (!outlivesPage(el) || !_owner.has(el)) return; - setEnabled(el, _owner.get(el) === key); + const owner = _owner.get(el); + /* the page on screen keeps what it owns until the swap takes it off screen */ + if (spared !== null && owner === spared && owner !== key) return; + setEnabled(el, owner === key); }); } diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-version.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-version.js index d3a3254a..c8d033d8 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-version.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-version.js @@ -27,14 +27,17 @@ const FS_VERSION = '0.0.0-dev'; * `git describe` ('0.9.4-12-gabc1234') and that must keep counting as a real version. */ function isReal() { return ((/^\d+\.\d+/).test(FS_VERSION)) && !((/-dev$/).test(FS_VERSION)); } +/* Two exports, and the two that were dropped are worth a line each so they are not re-added out of + * habit: `VERSION` (the bare string) and `isReal` had no caller anywhere in the theme or the + * templates — `label()` is what every reader actually wants, and it is the one place that decides + * how a dev build names itself. An export nobody imports is not free: it is a promise to keep the + * shape stable. */ return baseclass.extend({ - VERSION: FS_VERSION, - /* the project's page: the link at the foot of the Appearance tab, and the one - * nameThemeInFooter() writes into the footer. It was assembled from a separate FS_REPO - * constant that the retired self-update script needed to build API paths from, and nothing - * has needed the bare `owner/name` since. */ + /* the project's page: the link at the foot of the Appearance tab, and its only reader since + * the footer line was withdrawn. It was assembled from a separate FS_REPO constant that the + * retired self-update script needed to build API paths from, and nothing has needed the bare + * `owner/name` since. */ REPO_URL: 'https://github.com/VizzleTF/luci-theme-footstrap', - isReal, /* what the Appearance tab's version row prints */ label: () => (isReal() ? ('Footstrap v' + FS_VERSION) : 'Footstrap (dev)') }); diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap-common.js b/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap-common.js index dbe76157..01d4427a 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap-common.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap-common.js @@ -58,8 +58,6 @@ return baseclass.extend({ fit.add(chrome.fitChrome); chrome.renderChrome(); - /* once per document — the footer outlives every client navigation */ - chrome.nameThemeInFooter(); /* Both of these ADD to a stock page rather than owning a route: each watches * body[data-page] and does nothing anywhere else. A theme may not register a * dispatcher node — it outlives the theme that registered it. */ diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap.js b/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap.js index f492307e..a77779c7 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/menu-footstrap.js @@ -312,8 +312,18 @@ return baseclass.extend({ /* a clamp computed at the old width is wrong at the new one; coalesced via fit.frame * (the shared coalescer) because resize fires dozens of times a second while a window - * is dragged */ - window.addEventListener('resize', fit.frame(clearClamps)); + * is dragged. + * + * WIDTH ONLY, for the reason fs-fit's observer states at length: every browser on iOS + * fires `resize` continuously while the URL bar slides away, and a clamp computed for a + * width that did not change is work done on a page the user is scrolling. */ + let lastWidth = window.innerWidth; + const reclamp = fit.frame(clearClamps); + window.addEventListener('resize', () => { + if (window.innerWidth === lastWidth) return; + lastWidth = window.innerWidth; + reclamp(); + }); /* Appearance -> Submenus -> auto-collapse. fs-prefs.js owns the stored value and says only * that it changed; applying it is entirely ours, because every piece of the state is — diff --git a/luci-theme-footstrap/po/es/footstrap.po b/luci-theme-footstrap/po/es/footstrap.po index 637a20ab..f59b9e69 100644 --- a/luci-theme-footstrap/po/es/footstrap.po +++ b/luci-theme-footstrap/po/es/footstrap.po @@ -35,7 +35,7 @@ msgctxt "footstrap" msgid "Auto-collapse" msgstr "Colapso automático" -#: htdocs/luci-static/resources/fs-appearance.js:653 +#: htdocs/luci-static/resources/fs-appearance.js:656 msgctxt "footstrap" msgid "Background" msgstr "Fondo" @@ -76,7 +76,7 @@ msgid "Collapse menu" msgstr "Contraer menú" #: htdocs/luci-static/resources/fs-appearance.js:344 -#: htdocs/luci-static/resources/fs-appearance.js:650 +#: htdocs/luci-static/resources/fs-appearance.js:653 msgctxt "footstrap" msgid "Colours" msgstr "Colores" @@ -124,7 +124,7 @@ msgctxt "footstrap" msgid "Dark" msgstr "Oscuro" -#: htdocs/luci-static/resources/fs-appearance.js:654 +#: htdocs/luci-static/resources/fs-appearance.js:657 msgctxt "footstrap" msgid "Defaults" msgstr "Predeterminados" @@ -180,7 +180,7 @@ msgctxt "footstrap" msgid "Hard to read %s — large text only" msgstr "Se lee mal %s: solo texto grande" -#: htdocs/luci-static/resources/fs-appearance.js:649 +#: htdocs/luci-static/resources/fs-appearance.js:652 msgctxt "footstrap" msgid "Interface" msgstr "Interfaz" @@ -213,10 +213,6 @@ msgctxt "footstrap" msgid "Light" msgstr "Claro" -#: htdocs/luci-static/resources/fs-router.js:651 -msgid "Loading view…" -msgstr "Cargando vista…" - #: ucode/template/themes/footstrap/sysauth.ut:142 msgid "Log in" msgstr "Iniciar sesión" @@ -331,7 +327,7 @@ msgctxt "footstrap" msgid "Rounding" msgstr "Redondeo" -#: htdocs/luci-static/resources/fs-appearance.js:569 +#: htdocs/luci-static/resources/fs-appearance.js:572 msgctxt "footstrap" msgid "Router default" msgstr "Configuración predeterminada del enrutador" @@ -402,7 +398,7 @@ msgctxt "footstrap" msgid "Submenus" msgstr "Submenús" -#: htdocs/luci-static/resources/fs-appearance.js:651 +#: htdocs/luci-static/resources/fs-appearance.js:654 msgctxt "footstrap" msgid "Surfaces" msgstr "Superficies" @@ -415,7 +411,7 @@ msgstr "Sistema" msgid "System running in recovery (initramfs) mode." msgstr "El sistema se está ejecutando en modo de recuperación (initramfs)." -#: htdocs/luci-static/resources/fs-select.js:587 +#: htdocs/luci-static/resources/fs-select.js:607 msgid "Table" msgstr "Tabla" @@ -569,6 +565,9 @@ msgid "" "the uploaded file could not be removed either; it is still on the router." msgstr "tampoco se pudo eliminar el archivo subido; sigue en el router." +#~ msgid "Loading view…" +#~ msgstr "Cargando vista…" + #~ msgid "Logout" #~ msgstr "Cerrar sesión" diff --git a/luci-theme-footstrap/po/ru/footstrap.po b/luci-theme-footstrap/po/ru/footstrap.po index baa1ab8b..5b9f95df 100644 --- a/luci-theme-footstrap/po/ru/footstrap.po +++ b/luci-theme-footstrap/po/ru/footstrap.po @@ -31,7 +31,7 @@ msgctxt "footstrap" msgid "Auto-collapse" msgstr "Сворачивать" -#: htdocs/luci-static/resources/fs-appearance.js:653 +#: htdocs/luci-static/resources/fs-appearance.js:656 msgctxt "footstrap" msgid "Background" msgstr "Фон" @@ -72,7 +72,7 @@ msgid "Collapse menu" msgstr "Свернуть меню" #: htdocs/luci-static/resources/fs-appearance.js:344 -#: htdocs/luci-static/resources/fs-appearance.js:650 +#: htdocs/luci-static/resources/fs-appearance.js:653 msgctxt "footstrap" msgid "Colours" msgstr "Цвета" @@ -118,7 +118,7 @@ msgctxt "footstrap" msgid "Dark" msgstr "Тёмная" -#: htdocs/luci-static/resources/fs-appearance.js:654 +#: htdocs/luci-static/resources/fs-appearance.js:657 msgctxt "footstrap" msgid "Defaults" msgstr "Умолчания" @@ -174,7 +174,7 @@ msgctxt "footstrap" msgid "Hard to read %s — large text only" msgstr "Плохо читается %s — только крупный текст" -#: htdocs/luci-static/resources/fs-appearance.js:649 +#: htdocs/luci-static/resources/fs-appearance.js:652 msgctxt "footstrap" msgid "Interface" msgstr "Интерфейс" @@ -207,10 +207,6 @@ msgctxt "footstrap" msgid "Light" msgstr "Светлая" -#: htdocs/luci-static/resources/fs-router.js:651 -msgid "Loading view…" -msgstr "Загрузка представления…" - #: ucode/template/themes/footstrap/sysauth.ut:142 msgid "Log in" msgstr "Войти" @@ -324,7 +320,7 @@ msgctxt "footstrap" msgid "Rounding" msgstr "Скругление" -#: htdocs/luci-static/resources/fs-appearance.js:569 +#: htdocs/luci-static/resources/fs-appearance.js:572 msgctxt "footstrap" msgid "Router default" msgstr "По умолчанию для роутера" @@ -395,7 +391,7 @@ msgctxt "footstrap" msgid "Submenus" msgstr "Подменю" -#: htdocs/luci-static/resources/fs-appearance.js:651 +#: htdocs/luci-static/resources/fs-appearance.js:654 msgctxt "footstrap" msgid "Surfaces" msgstr "Поверхности" @@ -408,7 +404,7 @@ msgstr "Система" msgid "System running in recovery (initramfs) mode." msgstr "Система работает в режиме восстановления (initramfs)." -#: htdocs/luci-static/resources/fs-select.js:587 +#: htdocs/luci-static/resources/fs-select.js:607 msgid "Table" msgstr "Таблица" @@ -562,6 +558,9 @@ msgid "" "the uploaded file could not be removed either; it is still on the router." msgstr "загруженный файл тоже не удалось удалить — он остался на роутере." +#~ msgid "Loading view…" +#~ msgstr "Загрузка представления…" + #~ msgid "Logout" #~ msgstr "Выход" diff --git a/luci-theme-footstrap/po/templates/footstrap.pot b/luci-theme-footstrap/po/templates/footstrap.pot index 56c809b6..6ba1b8a0 100644 --- a/luci-theme-footstrap/po/templates/footstrap.pot +++ b/luci-theme-footstrap/po/templates/footstrap.pot @@ -25,7 +25,7 @@ msgctxt "footstrap" msgid "Auto-collapse" msgstr "" -#: htdocs/luci-static/resources/fs-appearance.js:653 +#: htdocs/luci-static/resources/fs-appearance.js:656 msgctxt "footstrap" msgid "Background" msgstr "" @@ -66,7 +66,7 @@ msgid "Collapse menu" msgstr "" #: htdocs/luci-static/resources/fs-appearance.js:344 -#: htdocs/luci-static/resources/fs-appearance.js:650 +#: htdocs/luci-static/resources/fs-appearance.js:653 msgctxt "footstrap" msgid "Colours" msgstr "" @@ -112,7 +112,7 @@ msgctxt "footstrap" msgid "Dark" msgstr "" -#: htdocs/luci-static/resources/fs-appearance.js:654 +#: htdocs/luci-static/resources/fs-appearance.js:657 msgctxt "footstrap" msgid "Defaults" msgstr "" @@ -166,7 +166,7 @@ msgctxt "footstrap" msgid "Hard to read %s — large text only" msgstr "" -#: htdocs/luci-static/resources/fs-appearance.js:649 +#: htdocs/luci-static/resources/fs-appearance.js:652 msgctxt "footstrap" msgid "Interface" msgstr "" @@ -199,10 +199,6 @@ msgctxt "footstrap" msgid "Light" msgstr "" -#: htdocs/luci-static/resources/fs-router.js:651 -msgid "Loading view…" -msgstr "" - #: ucode/template/themes/footstrap/sysauth.ut:142 msgid "Log in" msgstr "" @@ -314,7 +310,7 @@ msgctxt "footstrap" msgid "Rounding" msgstr "" -#: htdocs/luci-static/resources/fs-appearance.js:569 +#: htdocs/luci-static/resources/fs-appearance.js:572 msgctxt "footstrap" msgid "Router default" msgstr "" @@ -385,7 +381,7 @@ msgctxt "footstrap" msgid "Submenus" msgstr "" -#: htdocs/luci-static/resources/fs-appearance.js:651 +#: htdocs/luci-static/resources/fs-appearance.js:654 msgctxt "footstrap" msgid "Surfaces" msgstr "" @@ -398,7 +394,7 @@ msgstr "" msgid "System running in recovery (initramfs) mode." msgstr "" -#: htdocs/luci-static/resources/fs-select.js:587 +#: htdocs/luci-static/resources/fs-select.js:607 msgid "Table" msgstr "" diff --git a/luci-theme-footstrap/strip-templates.sh b/luci-theme-footstrap/strip-templates.sh index e5628955..b021e6d9 100755 --- a/luci-theme-footstrap/strip-templates.sh +++ b/luci-theme-footstrap/strip-templates.sh @@ -16,11 +16,22 @@ # `{% … %}` code block, so a `{#` that survives in this tree is a comment BY DEFINITION; if one # ever sat inside a <script> string the template would already be broken. Verified before # writing this: 0 of them appear inside a code block, and every opener has exactly one closer. -# * `/* … */` inside `{% … %}` — a ucode CODE comment, 6844 bytes more. NOT touched. Stripping it -# needs a lexer that knows ucode strings, and 17 of the `/*` in this tree sit OUTSIDE any code -# block (they are CSS/JS comments in inline <style>/<script>). That is exactly the shape that -# made the old `sed 's/;}/}/g'` in build-css.sh eat a data-URI: a scanner that cannot see -# strings. Not worth 6.8 KB. +# * `/* … */` STANDING ON ITS OWN LINES — a code comment, wherever it sits: ucode inside +# `{% … %}`, JavaScript inside an inline <script>, CSS inside an inline <style>. 18362 bytes +# across this tree, 8 KB of them in the shipped package after gzip, which is 11% of it. +# +# This used to be left alone with the argument that stripping it "needs a lexer that knows +# ucode strings" — and that argument is right about the general case and wrong about this one. +# The rule here is not "remove /* … */"; it is "remove a comment that OWNS its lines": `/*` is +# the first non-blank thing on its line and `*/` is the last non-blank thing on its (possibly +# later) line. For that to eat live code, a string literal would have to span lines AND contain +# a line that is nothing but a comment — measured across every .ut in this tree: 18362 of 18362 +# comment bytes are whole-line, zero are inline, and no multi-line template literal contains a +# line-leading `/*`. Anything that does not fit the rule is LEFT IN PLACE and counted, so the +# day one appears the build says so instead of quietly changing the meaning of a template. +# +# What this deliberately does NOT do is minify: no joining of lines, no touching of anything +# that is not a comment from column one. The output still reads like the source, minus the prose. # # Whitespace control is EMULATED, not ignored: `{#- …` also eats the whitespace before the comment # and `… -#}` the whitespace after it, which is how ucode itself renders them. Nearly every .ut here @@ -73,6 +84,41 @@ while IFS= read -r f; do } ' "$f" > "$CUR" mv "$CUR" "$f" + + # …and the code comments that own their lines, line by line rather than over the slurped file: + # a rule about what a LINE is cannot be expressed over a byte stream, and going line by line is + # also what makes it impossible to walk into a string literal by accident (see the header). + CUR="$f.tmp$$" + awk -v LEFT=0 ' + function blank(t) { return t ~ /^[ \t\r]*$/ } + { + line = $0 + if (!incomment) { + # a comment that owns this line: nothing but whitespace before /* + if (line ~ /^[ \t]*\/\*/) { + # …and if it closes on the same line, the rest of that line must be blank too + if (line ~ /\*\//) { + rest = line; sub(/^.*\*\//, "", rest) + if (blank(rest)) next + LEFT++; print line; next # code after the closer: leave it whole + } + incomment = 1; next + } + # an inline comment (code before it) is left alone and counted + if (line ~ /\/\*/) LEFT++ + print line; next + } + # inside a block comment: it may only end a line, or we would drop live code + if (line ~ /\*\//) { + rest = line; sub(/^.*\*\//, "", rest) + incomment = 0 + if (!blank(rest)) { LEFT++; print rest } + } + next + } + END { if (LEFT > 0) printf "strip-templates: %d comment(s) not on lines of their own, left in place\n", LEFT | "cat 1>&2" } + ' "$f" > "$CUR" + mv "$CUR" "$f" CUR="" a=$(wc -c < "$f") before=$((before + b)) diff --git a/luci-theme-footstrap/styles/theme/20-shell.css b/luci-theme-footstrap/styles/theme/20-shell.css index 1f48eafa..a945ec8c 100644 --- a/luci-theme-footstrap/styles/theme/20-shell.css +++ b/luci-theme-footstrap/styles/theme/20-shell.css @@ -662,6 +662,59 @@ .fs-indicators { flex-wrap: wrap; } .fs-content { padding: var(--fs-space-5) var(--fs-content-pad); flex: 1 1 auto; width: 100%; max-width: var(--fs-content-max); margin: 0 auto; } + /* ---------- the staging area a client navigation renders into ---------- + * fs-router.js renders the incoming page into a second `#view` inside this wrapper, first in + * tree order, and moves its children into the live one when the render completes — so the page + * on screen is never emptied while the next one loads. + * + * HIDDEN BUT LAID OUT, and the three declarations are not interchangeable. `visibility: hidden` + * takes it off the screen while keeping the box: several views size themselves from the element + * they render into (the realtime graphs read `#view.offsetWidth` inside `render()`), and + * `display: none` would hand them a zero width they keep for the life of the instance. `height: + * 0` is what stops the page under it from moving, and `overflow: clip` keeps the content that + * overflows that zero height from painting anyway — `clip` rather than `hidden` because a + * scroll container would be a new scrollport in the middle of the content column. */ + .fs-staging { visibility: hidden; height: 0; overflow: clip; } + + /* ---------- and the hairline that says a slow navigation is under way ---------- + * Shown only once a navigation outlives 150 ms (fs-router.js), so a warm click never flashes it. + * + * FIXED, AT THE TOP OF THE VIEWPORT, AND A CHILD OF <body> — all three are load-bearing and the + * first draft got two of them wrong. In the content column it is a flex item of `.fs-main`, and + * a column flex container shrank its 2px to ZERO (measured: height 0 in the sidebar layout, + * where `.fs-shell` is 100dvh); with `margin-bottom: -2px` the content painted over what was + * left. And it cannot live inside `.fs-shell` either: that box carries `contain: paint`, which + * makes a fixed descendant position itself against the shell and be clipped by it. At the top of + * the viewport is also where a browser puts its own progress, so it is the least surprising + * place for ours. + * + * `transform` and `opacity` only — both composited, so this cannot cost the render it is + * reporting on. Reduced motion keeps the bar and drops its animation: the information is the + * point, the movement is not. */ + #fs-nav-progress { + position: fixed; inset-inline: 0; top: 0; + height: 2px; + background: var(--fs-accent); + transform: scaleX(0); transform-origin: left center; + opacity: 0; pointer-events: none; + z-index: var(--fs-z-tooltip); + } + :root[dir="rtl"] #fs-nav-progress { transform-origin: right center; } + #fs-nav-progress[data-state="active"] { + opacity: 1; + transform: scaleX(.8); + transition: transform 2s cubic-bezier(.1, .7, .1, 1), opacity 120ms linear; + } + #fs-nav-progress[data-state="done"] { + opacity: 0; + transform: scaleX(1); + transition: transform 120ms ease-out, opacity 300ms linear 100ms; + } + @media (prefers-reduced-motion: reduce) { + #fs-nav-progress[data-state="active"], + #fs-nav-progress[data-state="done"] { transition: none; transform: scaleX(1); } + } + /* ---------- footer ---------- * Bare `footer`, not `footer.fs-footer`: the theme owns footer paint outright (absorbed * from base, which keeps only the flex skeleton), so a third-party view emitting its own diff --git a/luci-theme-footstrap/styles/theme/30-tables.css b/luci-theme-footstrap/styles/theme/30-tables.css index 74b5b48a..8ddd9e50 100644 --- a/luci-theme-footstrap/styles/theme/30-tables.css +++ b/luci-theme-footstrap/styles/theme/30-tables.css @@ -224,6 +224,43 @@ background: var(--fs-panel2); } + /* ---- A MEASUREMENT MUST NOT THROW THE READER ---- + * + * `fitTables()` decides a data table's tier by taking its marks OFF and asking the engine + * (fs-fit rule 1: a stacked table is a pile of flex rows and always "fits", so it has to be + * measured un-stacked). The reading forces layout, so for the duration of that pass the document + * really is laid out with a table that is several screens taller than the one on screen. + * + * Scroll anchoring is what turns that into a visible bug. The browser keeps the node under the + * reader still by adjusting the scroll offset — and it re-picks that node whenever the offset + * changes for any other reason (css-scroll-anchoring: an anchor is invalidated by a scroll, by a + * suppression trigger, or by its own removal). While the user is scrolling, that is every frame, + * so the pick can land inside a table in the un-stacked state the fitter is about to undo; the + * next frame the mark is back, the node is somewhere else entirely, and the engine faithfully + * "corrects" the offset by the difference. Measured on Status → Overview at 390x844 with the poll + * driving real re-renders while the page scrolled: 18 movements nobody asked for in 1500 frames, + * the worst 1877px, always a pair — down a screenful and back on the next frame. That is the + * page jumping up and down under the reader. + * + * So the tables the fitter re-stamps are declared ineligible as anchors. They are the only + * elements in the document whose layout is deliberately falsified and restored inside one pass, + * and every other node stays eligible — including the section headings around them, which is what + * keeps the good half of anchoring working: a lease appearing or a station leaving still shifts + * nothing, because the engine anchors on a heading and compensates for the height change. That + * half was measured too, before and after: 0px of movement under the reader across six poll ticks + * that grew and shrank a section above the viewport. + * + * NOT on the scroll container, which is the answer that suggests itself and is worse: with + * `html, body, #maincontent { overflow-anchor: none }` the same run still moved 12 times, up to + * 788px, because it also throws away the compensation the paragraph above depends on. Correct + * anchoring, minus the one region that lies about its height. + * + * The cost is that a row of a data table can no longer be the anchor. On the page where that + * would matter most — Processes at 390px, which is one long table — inserting a row above the + * reader moves the content 285px with this rule and 285px without it: those rows were never being + * chosen anyway. */ + .table.fs-dt { overflow-anchor: none; } + .cbi-section .table:is([id], .fs-dt) .tr:not(.table-titles):not(.placeholder):hover .td { background: var(--fs-panel2); } .cbi-section .table:is([id], .fs-dt) .tr.table-titles .th { border-bottom-color: var(--fs-border); } /* Contour around the whole data table. A real <table> needs border-collapse:separate or the diff --git a/mihomo-alpha/Makefile b/mihomo-alpha/Makefile index 031dfa29..4c035ced 100644 --- a/mihomo-alpha/Makefile +++ b/mihomo-alpha/Makefile @@ -1,14 +1,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mihomo-alpha -PKG_VERSION:=2026.08.13 -PKG_RELEASE:=19 +PKG_VERSION:=2026.08.16 +PKG_RELEASE:=20 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git -PKG_SOURCE_VERSION:=3cac869656f8ce2793afced148ebd5d4280b3e08 +PKG_SOURCE_VERSION:=ac017cdd246ce8bd547653d927e7bf77d7ee73d5 PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL3.0+ @@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 -PKG_BUILD_VERSION:=alpha-3cac869 +PKG_BUILD_VERSION:=alpha-ac017cd PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) PKG_BUILD_TIME:=$(shell date -u -Iseconds) diff --git a/mihomo-meta/Makefile b/mihomo-meta/Makefile index 8cd8f464..e01f318c 100644 --- a/mihomo-meta/Makefile +++ b/mihomo-meta/Makefile @@ -1,14 +1,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mihomo-meta -PKG_VERSION:=1.19.29 -PKG_RELEASE:=13 +PKG_VERSION:=1.19.30 +PKG_RELEASE:=14 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git -PKG_SOURCE_VERSION:=v1.19.29 +PKG_SOURCE_VERSION:=v1.19.30 PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL3.0+ @@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 -PKG_BUILD_VERSION:=v1.19.29 +PKG_BUILD_VERSION:=v1.19.30 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) PKG_BUILD_TIME:=$(shell date -u -Iseconds) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 0d8ad1e4..cb5a20ce 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=miniupnpd -PKG_VERSION:=2.3.10 -PKG_RELEASE:=7 +PKG_VERSION:=2.3.11 +PKG_RELEASE:=8 PKG_SOURCE_URL:=https://github.com/miniupnp/miniupnp/releases/download/miniupnpd_$(subst .,_,$(PKG_VERSION)) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init index 3489a68f..e6f44a3f 100644 --- a/miniupnpd/files/miniupnpd.init +++ b/miniupnpd/files/miniupnpd.init @@ -51,7 +51,7 @@ stop_service() { else nft flush chain inet fw4 upnp_forward 2>/dev/null nft flush chain inet fw4 upnp_prerouting 2>/dev/null - #nft flush chain inet fw4 upnp_postrouting 2>/dev/null + #nft flush chain inet fw4 upnp_postrouting 2>/dev/null # Not used with nftables fi } @@ -185,7 +185,7 @@ upnpd_generate_config() { echo "upnp_nat_table_name=fw4" echo "upnp_forward_chain=upnp_forward" echo "upnp_nat_chain=upnp_prerouting" - #echo "upnp_nat_postrouting_chain=upnp_postrouting" + #echo "upnp_nat_postrouting_chain=upnp_postrouting" # Not used with nftables fi echo "# External network interface" @@ -197,7 +197,8 @@ upnpd_generate_config() { [ "$ipv6_disable" = "0" ] && echo "ipv6_disable=no" || echo "ipv6_disable=yes" local rejectport for rejectport in $reject_ports; do - is_port_or_range "$rejectport" allowport0 && echo "deny $rejectport 0.0.0.0/0 $rejectport # Reject port $rejectport" || + is_port_or_range "$rejectport" allowport0 && echo "deny 1-65535 0.0.0.0/0 $rejectport # Reject port $rejectport" && + echo "deny $rejectport 0.0.0.0/0 1-65535 # Reject external port $rejectport" || log "Invalid port or port range ($rejectport) in reject_ports ignored" daemon.warn done [ "$check_acl" = "1" ] && echo "# Access control list" && config_foreach upnpd_add_acl_entry acl_entry @@ -252,9 +253,9 @@ upnpd_add_acl_entry() { local cfg="$1" local comment int_addr int_port ext_port descr_filter action config_get comment "$cfg" comment "unspecified" # comment - config_get int_addr "$cfg" int_addr "0.0.0.0/0" # IPv4 or network and subnet mask (internal) - config_get int_port "$cfg" int_port "1-65535" # internal port/range: x or x-y - config_get ext_port "$cfg" ext_port "1-65535" # external port/range: x or x-y + config_get int_addr "$cfg" int_addr "0.0.0.0/0" # IPv4 address or address and netmask (internal) + config_get int_port "$cfg" int_port "1-65535" # internal port or range: x or x-y + config_get ext_port "$cfg" ext_port "1-65535" # external port or range: x or x-y config_get descr_filter "$cfg" descr_filter # description regex filter (must be built in) config_get action "$cfg" action # accept/reject/disabled ! is_port_or_range "$int_port" allowport0 && diff --git a/miniupnpd/files/upnpd-migration.uci-defaults b/miniupnpd/files/upnpd-migration.uci-defaults index 60f80d54..c7000cae 100644 --- a/miniupnpd/files/upnpd-migration.uci-defaults +++ b/miniupnpd/files/upnpd-migration.uci-defaults @@ -11,12 +11,7 @@ log() { log "Check UCI options in /etc/config/upnpd to be migrated to v2.0" cp /etc/config/upnpd /tmp -# Set missing enabled option to fix previously different defaults in LuCI/config (0) and init UCI (1) -if ! uci -q get upnpd.config.enabled >/dev/null; then - uci -q set upnpd.config.enabled="1" -fi - -# Migrate boolean options to only use 0/1 for LuCI support +# Migrate boolean options to only use 0/1 for LuCI flag support for option in enabled ipv6_disable system_uptime; do if uci -q get upnpd.config.$option >/dev/null; then uci get upnpd.config.$option | grep -q -E -x "0|off|false|no|disabled" && uci set upnpd.config.$option="0" @@ -24,6 +19,11 @@ for option in enabled ipv6_disable system_uptime; do fi done +# Set missing enabled option to fix previously different defaults in LuCI/config (0) and init UCI (1) +if ! uci -q get upnpd.config.enabled >/dev/null; then + uci -q set upnpd.config.enabled="1" +fi + # Migrate enable_upnp/enable_natpmp -> enable_protocols: Combined option if uci -q get upnpd.config.enable_upnp >/dev/null || uci -q get upnpd.config.enable_natpmp >/dev/null; then log "enable_upnp/enable_natpmp -> enable_protocols: Combined option" @@ -47,6 +47,20 @@ if uci -q get upnpd.config.use_stun >/dev/null; then uci rename upnpd.config.use_stun="allow_cgnat" fi +# Remove known unsupported (not CGNAT filtering test capable) STUN servers and include stun_port in stun_host +if uci -q get upnpd.config.stun_host | grep -q -E "stun[0-9]?.l.google.com|stun.cloudflare.com"; then + log "stun_host: Unsupported STUN server ($(uci -q get upnpd.config.stun_host)) set, remove to set default" + uci delete upnpd.config.stun_host + uci -q delete upnpd.config.stun_port + # To keep behaviour with daemon <2.3.10 as previously, a false-negative filter result was returned for unsupported servers + uci set upnpd.config.allow_cgnat="allow-filtered" +elif uci -q get upnpd.config.stun_port >/dev/null; then + uci -q get upnpd.config.stun_host >/dev/null && [ "$(uci -q get upnpd.config.stun_port)" != "3478" ] && + log "stun_port: Include stun_port in stun_host, and remove option" && + uci set upnpd.config.stun_host="$(uci -q get upnpd.config.stun_host | cut -d ":" -f 1):$(uci -q get upnpd.config.stun_port)" + uci delete upnpd.config.stun_port +fi + # Migrate force_forwarding=1 (in X-Wrt since 2021) to new similar option allow_cgnat=allow-filtered for cross-upgrades if uci -q get upnpd.config.force_forwarding >/dev/null; then log "force_forwarding=1 -> allow_cgnat=allow-filtered: New option" @@ -55,23 +69,9 @@ if uci -q get upnpd.config.force_forwarding >/dev/null; then uci delete upnpd.config.force_forwarding fi -# Remove known unsupported (not CGNAT filtering test capable) STUN servers and include stun_port in stun_host -if uci -q get upnpd.config.stun_host | grep -q -E "stun[0-9]?.l.google.com|stun.cloudflare.com"; then - log "stun_host: Unsupported STUN server ($(uci -q get upnpd.config.stun_host)) set, remove to set default" - uci delete upnpd.config.stun_host - # Workaround for false negative filtered STUN CGNAT test results for unsupported servers before daemon 2.3.10 - uci set upnpd.config.allow_cgnat="allow-filtered" - uci -q delete upnpd.config.stun_port -elif uci -q get upnpd.config.stun_port >/dev/null; then - uci -q get upnpd.config.stun_host >/dev/null && [ "$(uci -q get upnpd.config.stun_port)" != "3478" ] && - log "stun_port: Include stun_port in stun_host, and remove option" && - uci set upnpd.config.stun_host="$(uci -q get upnpd.config.stun_host | cut -d ":" -f 1):$(uci -q get upnpd.config.stun_port)" - uci delete upnpd.config.stun_port -fi - -# Migrate secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd: Invert and extend to PCP +# Migrate secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd/pcp/1: Invert/extend to PCP if uci -q get upnpd.config.secure_mode >/dev/null; then - log "secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd: Invert and extend to PCP" + log "secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd/pcp/1: Invert/extend to PCP" uci get upnpd.config.secure_mode | grep -q -E -x "0|off|false|no|disabled" && uci set upnpd.config.allow_third_party_mapping="upnp-igd" || uci set upnpd.config.allow_third_party_mapping="0" @@ -87,7 +87,7 @@ if uci -q get upnpd.config.log_output >/dev/null; then uci set upnpd.config.log_output="default" fi -# Rename upnp_lease_file -> lease_file: To original daemon name, and remove if UCI default set +# Rename upnp_lease_file -> lease_file: To daemon option name, and remove if UCI default set if uci -q get upnpd.config.upnp_lease_file >/dev/null; then if [ "$(uci -q get upnpd.config.upnp_lease_file)" = "/var/run/miniupnpd.leases" ]; then log "upnp_lease_file -> lease_file: Remove option as UCI default set" @@ -115,7 +115,7 @@ if uci -q get upnpd.config.download >/dev/null; then download="$(uci -q get upnpd.config.download)" if [ "$download" != "1024" ] && [ "$download" -ge "1" ] 2>/dev/null; then log "download -> download_kbps: Convert to kbit/s" - download_kbps="$((download * 8 * 1000 / 1024))" + download_kbps="$((download * 8 * 1024 / 1000))" uci set upnpd.config.download_kbps="$download_kbps" fi uci delete upnpd.config.download @@ -124,7 +124,7 @@ if uci -q get upnpd.config.upload >/dev/null; then upload="$(uci -q get upnpd.config.upload)" if [ "$upload" != "512" ] && [ "$upload" -ge "1" ] 2>/dev/null; then log "upload -> upload_kbps: Convert to kbit/s" - upload_kbps="$((upload * 8 * 1000 / 1024))" + upload_kbps="$((upload * 8 * 1024 / 1000))" uci set upnpd.config.upload_kbps="$upload_kbps" fi uci delete upnpd.config.upload @@ -234,10 +234,8 @@ if [ "$addtemplateentries" = "1" ]; then fi # Rename UCI section config -> settings (v2.0) -if uci -q get upnpd.config >/dev/null; then - log "Rename UCI section config -> settings (v2.0)" && uci rename upnpd.config="settings" || - log "Error renaming the UCI section" daemon.err -fi +log "Rename UCI section config -> settings (v2.0)" +uci rename upnpd.config="settings" || log "Error renaming the UCI section" daemon.err uci commit upnpd >/dev/null diff --git a/miniupnpd/patches/10-upnp-igdv2-compat.patch b/miniupnpd/patches/10-upnp-igdv2-compat.patch index 2307aeb8..27787bd5 100644 --- a/miniupnpd/patches/10-upnp-igdv2-compat.patch +++ b/miniupnpd/patches/10-upnp-igdv2-compat.patch @@ -1,7 +1,7 @@ -From 38e01919d585b0fd663d2b3249963b336061cbd3 Mon Sep 17 00:00:00 2001 +From f94e5bf7a60a41911af8d7e23cdb4ebe166257e2 Mon Sep 17 00:00:00 2001 From: Self-Hosting-Group <155233284+Self-Hosting-Group@users.noreply.github.com> -Date: Wed, 25 Mar 2026 00:00:00 +0000 +Date: Fri, 14 Aug 2026 00:00:00 +0000 Subject: [PATCH] miniupnpd: UPnP IGDv2 Microsoft/Apple compatibility * Add workaround to list port maps with the Windows IGDv2-incompatible @@ -20,7 +20,7 @@ Link: https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Ove --- a/upnphttp.c +++ b/upnphttp.c -@@ -304,9 +304,22 @@ ParseHttpHeaders(struct upnphttp * h) +@@ -307,9 +307,22 @@ ParseHttpHeaders(struct upnphttp * h) } else if(strncasecmp(line, "user-agent:", 11) == 0) { @@ -48,7 +48,7 @@ Link: https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Ove } --- a/upnpsoap.c +++ b/upnpsoap.c -@@ -854,6 +854,14 @@ GetSpecificPortMappingEntry(struct upnph +@@ -920,6 +920,14 @@ GetSpecificPortMappingEntry(struct upnph #ifdef ENABLE_PCP hide_pcp_nonce(desc); #endif @@ -63,7 +63,7 @@ Link: https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Ove bodylen = snprintf(body, sizeof(body), resp, action, ns/*SERVICE_TYPE_WANIPC*/, (unsigned int)iport, int_ip, desc, leaseduration, -@@ -1124,6 +1132,14 @@ GetGenericPortMappingEntry(struct upnpht +@@ -1208,6 +1216,14 @@ GetGenericPortMappingEntry(struct upnpht #ifdef ENABLE_PCP hide_pcp_nonce(desc); #endif diff --git a/miniupnpd/patches/20-improve-logging.patch b/miniupnpd/patches/20-improve-logging.patch index ee067353..a1b999b0 100644 --- a/miniupnpd/patches/20-improve-logging.patch +++ b/miniupnpd/patches/20-improve-logging.patch @@ -1,40 +1,42 @@ -From 38e01919d585b0fd663d2b3249963b336061cbd3 Mon Sep 17 00:00:00 2001 +From a7cebfc522306295cc1745c637f64d0e7d659795 Mon Sep 17 00:00:00 2001 From: Self-Hosting-Group <155233284+Self-Hosting-Group@users.noreply.github.com> -Date: Tue, 12 May 2026 00:00:00 +0000 +Date: Fri, 14 Aug 2026 00:00:00 +0000 Subject: [PATCH] miniupnpd: Improve logging * Clearer logging of enabled protocols/ports, IPv6 mapping, and UPnP IGD compatibility mode… in start banner * Log warnings with an enabled allow third-party mapping option -* Less verbose logging by changing the log level of many normally - occurring or internal messages, or those not relevant to users, to - debug or info -* Comment out log-filling messages when internal interfaces lose link, - and for e.g. `rule with label '%s' is not a IGD pinhole`, as normally - occurring +* Change the log level (less verbose) of many internal or normally + occurring messages, and some error messages, without functional + restrictions, to DEBUG, client requests/actions and their errors to + INFO, and only daemon-wide messages to NOTICE/WARNING/ERR… +* Comment out some log-filling messages when internal interfaces lose + link, and for e.g. `rule with label '%s' is not a IGD pinhole`, as + normally occurring Fixes: https://redirect.github.com/openwrt/packages/issues/17601 Fixes: https://redirect.github.com/openwrt/packages/issues/26483 Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging --- - asyncsendto.c | 4 +-- - getifaddr.c | 4 +-- - minissdp.c | 24 ++++++------- - miniupnpd.c | 20 +++++------ - natpmp.c | 16 ++++----- - netfilter/iptcrdr.c | 10 +++--- - netfilter/iptpinhole.c | 4 +-- + asyncsendto.c | 4 ++-- + getifaddr.c | 4 ++-- + minissdp.c | 24 ++++++++++++------------ + miniupnpd.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- + natpmp.c | 16 ++++++++-------- + netfilter/iptcrdr.c | 10 +++++----- + netfilter/iptpinhole.c | 4 ++-- netfilter_nft/nftnlrdr.c | 2 +- - netfilter_nft/nftnlrdr_misc.c | 8 ++--- - netfilter_nft/nftpinhole.c | 10 +++--- - pcpserver.c | 18 +++++----- - pf/pfpinhole.c | 8 ++--- - upnphttp.c | 6 ++-- - upnppinhole.c | 48 ++++++++++++------------- - upnpredirect.c | 20 +++++------ - upnpsoap.c | 28 +++++++-------- - 16 files changed, 115 insertions(+), 115 deletions(-) + netfilter_nft/nftnlrdr_misc.c | 8 ++++---- + netfilter_nft/nftpinhole.c | 10 +++++----- + pcpserver.c | 18 +++++++++--------- + pf/obsdrdr.c | 6 +++--- + pf/pfpinhole.c | 12 ++++++------ + upnphttp.c | 6 +++--- + upnppinhole.c | 48 ++++++++++++++++++++++++------------------------ + upnpredirect.c | 20 ++++++++++---------- + upnpsoap.c | 30 +++++++++++++++--------------- + 17 files changed, 171 insertions(+), 143 deletions(-) --- a/asyncsendto.c +++ b/asyncsendto.c @@ -72,7 +74,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } --- a/minissdp.c +++ b/minissdp.c -@@ -741,8 +741,8 @@ SendSSDPNotify(int s, const struct socka +@@ -743,8 +743,8 @@ SendSSDPNotify(int s, const struct socka } n = sendto_or_schedule(s, bufr, l, 0, dest, dest_len); if(n < 0) { @@ -83,7 +85,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } else if(n != l) { syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l); } -@@ -752,8 +752,8 @@ SendSSDPNotify(int s, const struct socka +@@ -754,8 +754,8 @@ SendSSDPNotify(int s, const struct socka * discovery messages SHOULD NOT be sent more than three times. */ n = sendto_schedule(s, bufr, l, 0, dest, dest_len, 250); if(n < 0) { @@ -94,7 +96,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } } -@@ -1058,7 +1058,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1060,7 +1060,7 @@ ProcessSSDPData(int s, const char *bufr, } if(lan_addr == NULL) { @@ -103,7 +105,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging sender_str, source_if); return; } -@@ -1161,7 +1161,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1163,7 +1163,7 @@ ProcessSSDPData(int s, const char *bufr, sender_str );*/ if(st && (st_len > 0)) { @@ -112,7 +114,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging sender_str, st_len, st); /* find in which sub network the client is */ #ifdef ENABLE_IPV6 -@@ -1274,7 +1274,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1276,7 +1276,7 @@ ProcessSSDPData(int s, const char *bufr, else snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); #endif @@ -121,7 +123,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef DELAY_MSEARCH_RESPONSE delay = random() / (1 + RAND_MAX / (1000 * mx_value)); #ifdef DEBUG -@@ -1303,7 +1303,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1305,7 +1305,7 @@ ProcessSSDPData(int s, const char *bufr, #ifdef DELAY_MSEARCH_RESPONSE unsigned int delay_increment = (mx_value * 1000) / 15; #endif @@ -130,7 +132,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging for(i=0; known_service_types[i].s; i++) { #ifdef DELAY_MSEARCH_RESPONSE -@@ -1361,7 +1361,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1363,7 +1363,7 @@ ProcessSSDPData(int s, const char *bufr, #endif if(0 == memcmp(st, uuidvalue_igd, l)) { @@ -139,7 +141,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging SendSSDPResponse(s, sender, st, st_len, "", announced_host, http_port, #ifdef ENABLE_HTTPS -@@ -1371,7 +1371,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1373,7 +1373,7 @@ ProcessSSDPData(int s, const char *bufr, } else if(0 == memcmp(st, uuidvalue_wan, l)) { @@ -148,7 +150,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging SendSSDPResponse(s, sender, st, st_len, "", announced_host, http_port, #ifdef ENABLE_HTTPS -@@ -1381,7 +1381,7 @@ ProcessSSDPData(int s, const char *bufr, +@@ -1383,7 +1383,7 @@ ProcessSSDPData(int s, const char *bufr, } else if(0 == memcmp(st, uuidvalue_wcd, l)) { @@ -157,7 +159,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging SendSSDPResponse(s, sender, st, st_len, "", announced_host, http_port, #ifdef ENABLE_HTTPS -@@ -1442,7 +1442,7 @@ SendSSDPbyebye(int s, const struct socka +@@ -1444,7 +1444,7 @@ SendSSDPbyebye(int s, const struct socka n = sendto_or_schedule(s, bufr, l, 0, dest, destlen); if(n < 0) { @@ -168,7 +170,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging else if(n != l) --- a/miniupnpd.c +++ b/miniupnpd.c -@@ -489,7 +489,7 @@ ProcessIncomingHTTP(int shttpl, const ch +@@ -496,7 +496,7 @@ ProcessIncomingHTTP(int shttpl, const ch if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL) { /* The peer is not a LAN ! */ @@ -177,7 +179,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging "%s peer %s is not from a LAN, closing the connection", protocol, addr_str); close(shttp); -@@ -859,7 +859,7 @@ set_startup_time(void) +@@ -867,7 +867,7 @@ set_startup_time(void) } else { @@ -186,7 +188,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } fclose(f); startup_time -= uptime; -@@ -2109,6 +2109,22 @@ init(int argc, char * * argv, struct run +@@ -2228,6 +2228,22 @@ init(int argc, char * * argv, struct run pidfilename = NULL; #endif @@ -209,7 +211,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef USE_SYSTEMD if (systemd_flag) { int r = sd_notify(0, -@@ -2121,7 +2137,7 @@ init(int argc, char * * argv, struct run +@@ -2240,7 +2256,7 @@ init(int argc, char * * argv, struct run #ifdef ENABLE_LEASEFILE /*remove(lease_file);*/ @@ -218,8 +220,8 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging reload_from_lease_file(); #ifdef ENABLE_UPNPPINHOLE reload_from_lease_file6(); -@@ -2409,21 +2425,9 @@ main(int argc, char * * argv) - return 0; +@@ -2431,21 +2447,9 @@ main(int argc, char * * argv) + goto shutdown; } - syslog(LOG_INFO, "version " MINIUPNPD_VERSION " starting%s%sext if %s BOOTID=%u", @@ -241,25 +243,25 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } #endif -@@ -2467,7 +2471,7 @@ main(int argc, char * * argv) - return 1; - } - v.port = listen_port; +@@ -2494,7 +2498,7 @@ main(int argc, char * * argv) + #ifdef ENABLE_NFQUEUE + nfqueue_data.http_port = listen_port; + #endif /* ENABLE_NFQUEUE */ - syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); + syslog(LOG_NOTICE, "Listening for UPnP IGD (SOAP/HTTP) traffic on port %d/TCP, SSDP 1900/UDP", v.port); #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) if(!GETFLAG(IPV6DISABLEDMASK)) { -@@ -2493,7 +2497,7 @@ main(int argc, char * * argv) - return 1; - } - v.https_port = listen_port; +@@ -2525,7 +2529,7 @@ main(int argc, char * * argv) + #ifdef ENABLE_NFQUEUE + nfqueue_data.https_port = listen_port; + #endif /* ENABLE_NFQUEUE */ - syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port); + syslog(LOG_NOTICE, "Listening for UPnP IGD (SOAP/HTTPS) traffic on port %d/TCP", v.https_port); #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) shttpsl_v4 = OpenAndConfHTTPSocket(&listen_port, 0); if(shttpsl_v4 < 0) -@@ -2507,11 +2511,11 @@ main(int argc, char * * argv) +@@ -2540,11 +2544,11 @@ main(int argc, char * * argv) if(!GETFLAG(IPV6DISABLEDMASK)) { if(find_ipv6_addr(lan_addrs.lh_first ? lan_addrs.lh_first->ifname : NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) { @@ -273,7 +275,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging SETFLAG(IPV6DISABLEDMASK); } } -@@ -2563,7 +2567,7 @@ main(int argc, char * * argv) +@@ -2601,7 +2605,7 @@ main(int argc, char * * argv) if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) #endif { @@ -282,7 +284,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } } #endif /* UPNP_STRICT */ -@@ -2588,16 +2592,16 @@ main(int argc, char * * argv) +@@ -2626,16 +2630,16 @@ main(int argc, char * * argv) if(OpenAndConfNATPMPSockets(snatpmp) < 0) #ifdef ENABLE_PCP { @@ -303,7 +305,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging NATPMP_PORT); } #endif -@@ -2706,6 +2710,30 @@ main(int argc, char * * argv) +@@ -2746,6 +2750,30 @@ main(int argc, char * * argv) } #endif /* HAS_LIBCAP_NG */ @@ -334,7 +336,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef USE_SYSTEMD if (v.systemd_notify) { upnp_update_status(); -@@ -3016,7 +3044,7 @@ main(int argc, char * * argv) +@@ -3056,7 +3084,7 @@ main(int argc, char * * argv) } i = try_sendto(&writeset); if(i < 0) { @@ -343,7 +345,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } #ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) -@@ -3116,7 +3144,7 @@ main(int argc, char * * argv) +@@ -3156,7 +3184,7 @@ main(int argc, char * * argv) if(lan_addr == NULL) { char sender_str[64]; sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str)); @@ -352,7 +354,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging sender_str); continue; } -@@ -3139,7 +3167,7 @@ main(int argc, char * * argv) +@@ -3179,7 +3207,7 @@ main(int argc, char * * argv) if(lan_addr == NULL) { char sender_str[64]; sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str)); @@ -361,7 +363,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging sender_str); continue; } -@@ -3173,7 +3201,7 @@ main(int argc, char * * argv) +@@ -3213,7 +3241,7 @@ main(int argc, char * * argv) /* process SSDP packets */ if(sudp >= 0 && FD_ISSET(sudp, &readset)) { @@ -370,7 +372,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef ENABLE_HTTPS ProcessSSDPRequest(sudp, (unsigned short)v.port, (unsigned short)v.https_port); #else -@@ -3183,7 +3211,7 @@ main(int argc, char * * argv) +@@ -3223,7 +3251,7 @@ main(int argc, char * * argv) #ifdef ENABLE_IPV6 if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset)) { @@ -379,7 +381,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef ENABLE_HTTPS ProcessSSDPRequest(sudpv6, (unsigned short)v.port, (unsigned short)v.https_port); #else -@@ -3285,7 +3313,7 @@ main(int argc, char * * argv) +@@ -3325,7 +3353,7 @@ main(int argc, char * * argv) shutdown: @@ -388,7 +390,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging #ifdef USE_SYSTEMD if (v.systemd_notify) { sd_notify(0, -@@ -3304,7 +3332,7 @@ shutdown: +@@ -3344,7 +3372,7 @@ shutdown: if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) #endif { @@ -473,7 +475,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } --- a/netfilter/iptcrdr.c +++ b/netfilter/iptcrdr.c -@@ -711,7 +711,7 @@ delete_filter_rule(const char * ifname, +@@ -715,7 +715,7 @@ delete_filter_rule(const char * ifname, continue; } index = i; @@ -482,7 +484,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule"); h = NULL; break; -@@ -804,7 +804,7 @@ delete_redirect_and_filter_rules(unsigne +@@ -808,7 +808,7 @@ delete_redirect_and_filter_rules(unsigne #endif if(r == 0) { @@ -491,7 +493,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging /* Now delete both rules */ /* first delete the nat rule */ h = iptc_init("nat"); -@@ -848,7 +848,7 @@ delete_redirect_and_filter_rules(unsigne +@@ -852,7 +852,7 @@ delete_redirect_and_filter_rules(unsigne if(iaddr != e->ip.dst.s_addr) continue; index = i; @@ -500,7 +502,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule"); h = NULL; break; -@@ -906,7 +906,7 @@ delete_redirect_and_filter_rules(unsigne +@@ -910,7 +910,7 @@ delete_redirect_and_filter_rules(unsigne } index = i; @@ -509,7 +511,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging r2 = delete_rule_and_commit(index, h, miniupnpd_nat_postrouting_chain, "delete_peer_rule"); h = NULL; break; -@@ -958,7 +958,7 @@ delete_redirect_and_filter_rules(unsigne +@@ -962,7 +962,7 @@ delete_redirect_and_filter_rules(unsigne if(iaddr != e->ip.src.s_addr) continue; index = i; @@ -550,7 +552,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging --- a/netfilter_nft/nftnlrdr_misc.c +++ b/netfilter_nft/nftnlrdr_misc.c -@@ -104,7 +104,7 @@ nft_mnl_connect(void) +@@ -110,7 +110,7 @@ nft_mnl_connect(void) return -1; } mnl_portid = mnl_socket_get_portid(mnl_sock); @@ -559,7 +561,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging return 0; } -@@ -745,7 +745,7 @@ refresh_nft_cache(struct rule_list *head +@@ -751,7 +751,7 @@ refresh_nft_cache(struct rule_list *head errno = 0; ret = mnl_cb_run(buf, n, mnl_seq, mnl_portid, table_cb, &data); if (ret <= -1 /*== MNL_CB_ERROR*/) { @@ -568,7 +570,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging "refresh_nft_cache", ret); return -1; } -@@ -1279,7 +1279,7 @@ nft_send_rule(struct nftnl_rule * rule, +@@ -1288,7 +1288,7 @@ nft_send_rule(struct nftnl_rule * rule, result = send_batch(batch); if (result < 0) { @@ -577,7 +579,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging "nft_send_rule", rule, (int)cmd, (int)chain_type, result); } } -@@ -1462,7 +1462,7 @@ send_batch(struct mnl_nlmsg_batch *batch +@@ -1474,7 +1474,7 @@ send_batch(struct mnl_nlmsg_batch *batch errno = 0; ret = mnl_cb_run(buf, n, 0, mnl_portid, NULL, NULL); if (ret <= -1 /*== MNL_CB_ERROR*/) { @@ -635,7 +637,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging --- a/pcpserver.c +++ b/pcpserver.c -@@ -1086,7 +1086,7 @@ static void CreatePCPMap(pcp_info_t *pcp +@@ -1094,7 +1094,7 @@ static void CreatePCPMap(pcp_info_t *pcp else r = CreatePCPMap_NAT(pcp_msg_info); pcp_msg_info->result_code = r; @@ -644,7 +646,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging "PCP MAP: %s mapping %s %hu->%s:%hu '%s'", r == PCP_SUCCESS ? "added" : "failed to add", proto_itoa(pcp_msg_info->protocol), -@@ -1128,7 +1128,7 @@ static void DeletePCPMap(pcp_info_t *pcp +@@ -1136,7 +1136,7 @@ static void DeletePCPMap(pcp_info_t *pcp if(0 != strcmp(desc, pcp_msg_info->desc)) { /* nonce does not match */ pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED; @@ -653,7 +655,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging iport, proto_itoa(pcp_msg_info->protocol)); return; } else { -@@ -1146,14 +1146,14 @@ static void DeletePCPMap(pcp_info_t *pcp +@@ -1154,14 +1154,14 @@ static void DeletePCPMap(pcp_info_t *pcp desc, sizeof(desc), NULL /* lifetime */); if (uid < 0) { @@ -670,7 +672,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging iport, proto_itoa(pcp_msg_info->protocol)); return; } else { -@@ -1168,7 +1168,7 @@ static void DeletePCPMap(pcp_info_t *pcp +@@ -1176,7 +1176,7 @@ static void DeletePCPMap(pcp_info_t *pcp syslog(LOG_INFO, "PCP: %s port %hu mapping removed", proto==IPPROTO_TCP?"TCP":"UDP", (pcp_msg_info->is_fw ? iport : eport2)); } else { @@ -679,7 +681,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging pcp_msg_info->mapped_str, iport, proto_itoa(proto)); pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; } -@@ -1391,7 +1391,7 @@ static int processPCPRequest(void * req, +@@ -1399,7 +1399,7 @@ static int processPCPRequest(void * req, CreatePCPMap(pcp_msg_info); } } else { @@ -688,7 +690,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging return pcp_msg_info->result_code; } -@@ -1601,7 +1601,7 @@ int ProcessIncomingPCPPacket(int s, unsi +@@ -1609,7 +1609,7 @@ int ProcessIncomingPCPPacket(int s, unsi if (!GETFLAG(PCP_ALLOWTHIRDPARTYMASK)) { lan_addr = get_lan_for_peer(senderaddr); if(lan_addr == NULL) { @@ -697,7 +699,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging addr_str); return 0; } -@@ -1722,7 +1722,7 @@ void PCPSendUnsolicitedAnnounce(int * so +@@ -1730,7 +1730,7 @@ void PCPSendUnsolicitedAnnounce(int * so } len = sendto_or_schedule(sockets[i], buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); if( len < 0 ) { @@ -706,7 +708,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } } #ifdef ENABLE_IPV6 -@@ -1733,7 +1733,7 @@ void PCPSendUnsolicitedAnnounce(int * so +@@ -1741,7 +1741,7 @@ void PCPSendUnsolicitedAnnounce(int * so addr6.sin6_port = htons(5350); len = sendto_or_schedule(socket6, buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)); if( len < 0 ) { @@ -715,6 +717,35 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging } } #endif /* ENABLE_IPV6 */ +--- a/pf/obsdrdr.c ++++ b/pf/obsdrdr.c +@@ -601,7 +601,7 @@ delete_nat_rule(const char * ifname, uns + pr.nr = i; + if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) + { +- syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); ++ syslog(LOG_DEBUG, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); + r = -1; + } + else +@@ -1290,7 +1290,7 @@ priv_delete_redirect_rule_check_desc(con + pr.nr = i; + if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) + { +- syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); ++ syslog(LOG_DEBUG, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); + r = -1; + break; + } +@@ -1375,7 +1375,7 @@ syslog(LOG_DEBUG, "%2d port=%hu proto=%d + pr.nr = i; + if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) + { +- syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); ++ syslog(LOG_DEBUG, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); + r = -1; + } + else --- a/pf/pfpinhole.c +++ b/pf/pfpinhole.c @@ -246,12 +246,12 @@ int find_pinhole(const char * ifname, @@ -732,6 +763,15 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging continue; } #endif /* USE_LIBPFCTL */ +@@ -360,7 +360,7 @@ int delete_pinhole(unsigned short uid) + pr.action = PF_CHANGE_REMOVE; + pr.nr = i; + if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) { +- syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); ++ syslog(LOG_DEBUG, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); + release_ticket(dev, tnum); + return -1; + } @@ -565,7 +565,7 @@ int clean_pinhole_list(unsigned int * ne return -1; } @@ -750,9 +790,18 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging continue; } #endif /* USE_LIBPFCTL */ +@@ -602,7 +602,7 @@ int clean_pinhole_list(unsigned int * ne + pr.action = PF_CHANGE_REMOVE; + pr.nr = i; + if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) { +- syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); ++ syslog(LOG_DEBUG, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); + release_ticket(dev, tnum); + return -1; + } --- a/upnphttp.c +++ b/upnphttp.c -@@ -514,7 +514,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp +@@ -517,7 +517,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp if(h->req_soapActionOff > 0) { /* we can process the request */ @@ -761,7 +810,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging h->req_soapActionLen, h->req_buf + h->req_soapActionOff); ExecuteSoapAction(h, h->req_buf + h->req_soapActionOff, -@@ -819,7 +819,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt +@@ -822,7 +822,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt for(i = 0; i<15 && *p != '\r'; i++) HttpVer[i] = *(p++); HttpVer[i] = '\0'; @@ -770,7 +819,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging h->clientaddr_str, HttpCommand, HttpUrl, HttpVer); ParseHttpHeaders(h); if(h->req_HostOff > 0 && h->req_HostLen > 0) { -@@ -899,7 +899,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt +@@ -902,7 +902,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt return; } #endif @@ -988,7 +1037,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging return -1; } -@@ -168,7 +168,7 @@ int reload_from_lease_file(void) +@@ -175,7 +175,7 @@ int reload_from_lease_file(void) if(!lease_file) return -1; fd = fopen( lease_file, "r"); if (fd==NULL) { @@ -997,7 +1046,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging return -1; } if(unlink(lease_file) < 0) { -@@ -184,33 +184,33 @@ int reload_from_lease_file(void) +@@ -191,33 +191,33 @@ int reload_from_lease_file(void) proto = line; p = strchr(line, ':'); if(!p) { @@ -1036,7 +1085,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging continue; } *(desc++) = '\0'; -@@ -231,7 +231,7 @@ int reload_from_lease_file(void) +@@ -238,7 +238,7 @@ int reload_from_lease_file(void) timestamp += current_time; /* convert to our time */ #else if(timestamp <= (unsigned int)current_unix_time) { @@ -1045,7 +1094,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging eport, iaddr, iport, proto); continue; } else { -@@ -391,7 +391,7 @@ upnp_redirect(const char * rhost, unsign +@@ -398,7 +398,7 @@ upnp_redirect(const char * rhost, unsign #endif /* CHECK_PORTINUSE */ } else { timestamp = (leaseduration > 0) ? upnp_time() + leaseduration : 0; @@ -1054,7 +1103,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging eport, iaddr, iport, protocol, desc); return upnp_redirect_internal(rhost, eport, iaddr, iport, proto, desc, timestamp); -@@ -641,7 +641,7 @@ get_upnp_rules_state_list(int max_rules_ +@@ -648,7 +648,7 @@ get_upnp_rules_state_list(int max_rules_ { if(tmp->to_remove) { @@ -1065,7 +1114,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging *p = tmp->next; --- a/upnpsoap.c +++ b/upnpsoap.c -@@ -491,7 +491,7 @@ AddPortMapping(struct upnphttp * h, cons +@@ -545,7 +545,7 @@ AddPortMapping(struct upnphttp * h, cons } else { @@ -1074,7 +1123,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); return; -@@ -690,7 +690,7 @@ AddAnyPortMapping(struct upnphttp * h, c +@@ -750,7 +750,7 @@ AddAnyPortMapping(struct upnphttp * h, c } else { @@ -1083,7 +1132,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); return; -@@ -847,7 +847,7 @@ GetSpecificPortMappingEntry(struct upnph +@@ -913,7 +913,7 @@ GetSpecificPortMappingEntry(struct upnph } else { @@ -1092,7 +1141,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging action, r_host ? r_host : "NULL", ext_port, protocol, int_ip, (unsigned int)iport, desc, leaseduration); -@@ -931,7 +931,7 @@ DeletePortMapping(struct upnphttp * h, c +@@ -1003,7 +1003,7 @@ DeletePortMapping(struct upnphttp * h, c return; } @@ -1101,7 +1150,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging action, eport, protocol); /* if in secure mode, check the IP -@@ -1047,7 +1047,7 @@ DeletePortMappingRange(struct upnphttp * +@@ -1125,7 +1125,7 @@ DeletePortMappingRange(struct upnphttp * for(i = 0; i < number; i++) { r = upnp_delete_redirection(port_list[i], protocol); @@ -1110,7 +1159,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging action, port_list[i], protocol, r < 0 ? "failed" : "ok"); } free(port_list); -@@ -1112,7 +1112,7 @@ GetGenericPortMappingEntry(struct upnpht +@@ -1196,7 +1196,7 @@ GetGenericPortMappingEntry(struct upnpht return; } @@ -1119,27 +1168,39 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging rhost[0] = '\0'; r = upnp_get_redirection_infos_by_index((int)index, &eport, protocol, &iport, -@@ -1635,7 +1635,7 @@ PinholeVerification(struct upnphttp * h, - int r; - struct addrinfo hints, *ai, *p; +@@ -1777,7 +1777,7 @@ PinholeVerification(struct upnphttp * h, + struct addrinfo hints, *ai, *p; + int found = 0; -- syslog(LOG_INFO, "%s: InternalClient %s is not an IPv6, assume hostname and convert", -+ syslog(LOG_DEBUG, "%s: InternalClient %s is not an IPv6, assume hostname and convert", - "PinholeVerification", int_ip); +- syslog(LOG_INFO, "%s: InternalClient %s is not an IPv6, assume hostname and convert", ++ syslog(LOG_DEBUG, "%s: InternalClient %s is not an IPv6, assume hostname and convert", + "PinholeVerification", int_ip); - memset(&hints, 0, sizeof(hints)); -@@ -1655,8 +1655,8 @@ PinholeVerification(struct upnphttp * h, - { - result_ip = ((struct sockaddr_in6 *)p->ai_addr)->sin6_addr; - if (inet_ntop(AF_INET6, &result_ip, int_ip, sizeof(struct in6_addr)) == NULL) + memset(&hints, 0, sizeof(hints)); +@@ -1788,7 +1788,7 @@ PinholeVerification(struct upnphttp * h, + r = getaddrinfo(int_ip, NULL, &hints, &ai); + if (r != 0) + { +- syslog(LOG_WARNING, "%s: Failed to convert hostname '%s' to IP address : %s", ++ syslog(LOG_INFO, "%s: Failed to convert hostname '%s' to IP address : %s", + "PinholeVerification", int_ip, gai_strerror(r)); + SoapError(h, 402, "Invalid Args"); + return -1; +@@ -1803,11 +1803,11 @@ PinholeVerification(struct upnphttp * h, + + if (inet_ntop(AF_INET6, &result_ip, int_ip_resolved, INET6_ADDRSTRLEN) == NULL) + { - syslog(LOG_WARNING, "%s: inet_ntop(): %m", "PinholeVerification"); -- syslog(LOG_INFO, "%s: InternalClient resolved as %s", -+ syslog(LOG_DEBUG, "%s: inet_ntop(): %m", "PinholeVerification"); -+ syslog(LOG_DEBUG, "%s: InternalClient resolved as %s", - "PinholeVerification", int_ip); ++ syslog(LOG_INFO, "%s: inet_ntop(): %m", "PinholeVerification"); + SoapError(h, 501, "Action Failed"); + return -1; + } +- syslog(LOG_INFO, "%s: InternalClient \"%s\" resolved as %s", ++ syslog(LOG_DEBUG, "%s: InternalClient \"%s\" resolved as %s", + "PinholeVerification", int_ip, int_ip_resolved); found = 1; } -@@ -1672,7 +1672,7 @@ PinholeVerification(struct upnphttp * h, +@@ -1823,7 +1823,7 @@ PinholeVerification(struct upnphttp * h, freeaddrinfo(ai); if (!found) { @@ -1148,16 +1209,16 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging "PinholeVerification", int_ip); SoapError(h, 402, "Invalid Args"); return -1; -@@ -1680,7 +1680,7 @@ PinholeVerification(struct upnphttp * h, - } - else +@@ -1841,7 +1841,7 @@ PinholeVerification(struct upnphttp * h, + /* no need to copy to int_ip_resolved, but we still need to fill result_ip up */ + if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) { -- syslog(LOG_WARNING, "%s: Failed to convert hostname '%s' to IP address : %s", -+ syslog(LOG_INFO, "%s: Failed to convert hostname '%s' to IP address : %s", - "PinholeVerification", int_ip, gai_strerror(r)); - SoapError(h, 402, "Invalid Args"); +- syslog(LOG_ERR, "inet_pton(%s)", int_ip); ++ syslog(LOG_DEBUG, "inet_pton(%s)", int_ip); + SoapError(h, 501, "Action Failed"); return -1; -@@ -1813,7 +1813,7 @@ AddPinhole(struct upnphttp * h, const ch + } +@@ -1974,7 +1974,7 @@ AddPinhole(struct upnphttp * h, const ch inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), rem_ip, sizeof(rem_ip)); @@ -1166,7 +1227,7 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging rem_host = rem_ip; break; } -@@ -1822,7 +1822,7 @@ AddPinhole(struct upnphttp * h, const ch +@@ -1983,7 +1983,7 @@ AddPinhole(struct upnphttp * h, const ch } else { @@ -1175,12 +1236,12 @@ Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging rem_host, gai_strerror(err)); #if 0 SoapError(h, 402, "Invalid Args"); -@@ -2481,7 +2481,7 @@ SoapError(struct upnphttp * h, int errCo +@@ -2696,7 +2696,7 @@ SoapError(struct upnphttp * h, int errCo char body[2048]; int bodylen; - syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc); + syslog(LOG_DEBUG, "Returning UPnPError %d: %s", errCode, errDesc); bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc); - BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen); - SendRespAndClose_upnphttp(h); + if(bodylen < 0) { + syslog(LOG_ERR, "snprintf() returned %d", bodylen); diff --git a/momo/Makefile b/momo/Makefile index d493ba7a..e38c4924 100644 --- a/momo/Makefile +++ b/momo/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=momo PKG_VERSION:=2026.06.03 -PKG_RELEASE:=11 +PKG_RELEASE:=12 PKG_LICENSE:=GPL-3.0+ PKG_MAINTAINER:=Joseph Mory <morytyann@gmail.com> diff --git a/momo/files/momo.init b/momo/files/momo.init index d94244e6..d5953056 100644 --- a/momo/files/momo.init +++ b/momo/files/momo.init @@ -218,16 +218,25 @@ start_service() { procd_close_instance # cron local reload_cron; reload_cron=0 + ## clear cron + if grep -q "#momo" "/etc/crontabs/root"; then + log "App" "Clear cron." + sed -i "/#momo/d" "/etc/crontabs/root" > /dev/null 2>&1 + reload_cron=1 + fi + ## add restart cron if needed if [ "$scheduled_restart" = 1 ] && [ -n "$scheduled_restart_cron" ]; then log "App" "Set scheduled restart." echo "$scheduled_restart_cron /etc/init.d/momo restart #momo scheduled restart" >> "/etc/crontabs/root" reload_cron=1 fi + ## add log scheduled clear cron if needed if [ "$log_scheduled_clear" = 1 ] && [ -n "$log_scheduled_clear_cron" ]; then log "App" "Set log scheduled clear." echo "$log_scheduled_clear_cron /etc/init.d/momo clear_logs #momo log scheduled clear" >> "/etc/crontabs/root" reload_cron=1 fi + ## reload cron if needed if [ "$reload_cron" = 1 ]; then /etc/init.d/cron restart fi @@ -440,8 +449,10 @@ cleanup() { sysctl -q -w net.bridge.bridge-nf-call-ip6tables=1 fi # delete cron - sed -i "/#momo/d" "/etc/crontabs/root" > /dev/null 2>&1 - /etc/init.d/cron restart + if grep -q "#momo" "/etc/crontabs/root"; then + sed -i "/#momo/d" "/etc/crontabs/root" > /dev/null 2>&1 + /etc/init.d/cron restart + fi } clear_logs() { diff --git a/natflow/Makefile b/natflow/Makefile index f76c7a00..fb8fe87d 100644 --- a/natflow/Makefile +++ b/natflow/Makefile @@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=natflow PKG_VERSION:=20260531 -PKG_RELEASE:=71 +PKG_RELEASE:=72 PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=6472300c8d6b9082112a27a6a7547ea6057577be +PKG_SOURCE_VERSION:=fb8848ba93fa22b264e6351865d7d76c846f656b PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com> PKG_LICENSE:=GPL-2.0 diff --git a/nikki/Makefile b/nikki/Makefile index bf43fdcd..a65be9d1 100644 --- a/nikki/Makefile +++ b/nikki/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nikki PKG_VERSION:=2026.04.08 -PKG_RELEASE:=13 +PKG_RELEASE:=14 PKG_LICENSE:=GPL3.0+ PKG_MAINTAINER:=Joseph Mory <morytyann@gmail.com> diff --git a/nikki/files/nikki.init b/nikki/files/nikki.init index e665ecba..c9067a6b 100644 --- a/nikki/files/nikki.init +++ b/nikki/files/nikki.init @@ -275,16 +275,25 @@ start_service() { procd_close_instance # cron local reload_cron; reload_cron=0 + ## clear cron + if grep -q "#nikki" "/etc/crontabs/root"; then + log "App" "Clear cron." + sed -i "/#nikki/d" "/etc/crontabs/root" > /dev/null 2>&1 + reload_cron=1 + fi + ## add restart cron if needed if [ "$scheduled_restart" = 1 ] && [ -n "$scheduled_restart_cron" ]; then log "App" "Set scheduled restart." echo "$scheduled_restart_cron /etc/init.d/nikki restart #nikki scheduled restart" >> "/etc/crontabs/root" reload_cron=1 fi + ## add log scheduled clear cron if needed if [ "$log_scheduled_clear" = 1 ] && [ -n "$log_scheduled_clear_cron" ]; then log "App" "Set log scheduled clear." echo "$log_scheduled_clear_cron /etc/init.d/nikki clear_logs #nikki log scheduled clear" >> "/etc/crontabs/root" reload_cron=1 fi + ## reload cron if needed if [ "$reload_cron" = 1 ]; then /etc/init.d/cron restart fi @@ -497,8 +506,10 @@ cleanup() { sysctl -q -w net.bridge.bridge-nf-call-ip6tables=1 fi # delete cron - sed -i "/#nikki/d" "/etc/crontabs/root" > /dev/null 2>&1 - /etc/init.d/cron restart + if grep -q "#nikki" "/etc/crontabs/root"; then + sed -i "/#nikki/d" "/etc/crontabs/root" > /dev/null 2>&1 + /etc/init.d/cron restart + fi } clear_logs() { diff --git a/openwrt-alwaysonline/Makefile b/openwrt-alwaysonline/Makefile index 1bd6f0b9..c3213e47 100644 --- a/openwrt-alwaysonline/Makefile +++ b/openwrt-alwaysonline/Makefile @@ -8,12 +8,12 @@ PKG_NAME:=alwaysonline PKG_UPSTREAM_VERSION:=1.2.1 PKG_UPSTREAM_GITHASH:=206292ca68e4d6c81b215163a7bbd0cd2eb36860 PKG_VERSION:=$(PKG_UPSTREAM_VERSION)~$(call version_abbrev,$(PKG_UPSTREAM_GITHASH)) -PKG_RELEASE:=11 +PKG_RELEASE:=12 UCI_VERSION:=0.2025.01.25 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/Jamesits/alwaysonline.git -PKG_SOURCE_VERSION:=df3039364e41a68a11ecd462b5e3491403b6ca9e +PKG_SOURCE_VERSION:=db4a6dede32e564c6d2aa4bf3486fd2ac1b76eb7 PKG_MIRROR_HASH:=skip PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION) diff --git a/sing-box/Makefile b/sing-box/Makefile index f4700c3e..413662c7 100644 --- a/sing-box/Makefile +++ b/sing-box/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=sing-box -PKG_VERSION:=1.13.18 -PKG_RELEASE:=25 +PKG_VERSION:=1.13.19 +PKG_RELEASE:=26 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)? diff --git a/torrserver/Makefile b/torrserver/Makefile index 1ca658ca..d058c4ea 100644 --- a/torrserver/Makefile +++ b/torrserver/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=torrserver -PKG_VERSION:=MatriX.142.2 -PKG_RELEASE:=15 +PKG_VERSION:=MatriX.142.4 +PKG_RELEASE:=16 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/YouROK/TorrServer.git -PKG_SOURCE_VERSION:=5be23f5c816e1a44aee4e435b5b7a5369c707cd8 +PKG_SOURCE_VERSION:=9b611cf7022b60f4385392ce37c83793235fe5c6 PKG_MIRROR_HASH:=skip PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>