From 36bfb084e6fa892af3965e752a901c00b5f2c7e3 Mon Sep 17 00:00:00 2001 From: chodak166 Date: Fri, 27 May 2022 20:07:28 +0200 Subject: [PATCH] Added milligram css; repo cleanup --- components/firmware/CMakeLists.txt | 1 + .../firmware/include/nx/firmware/Buttons.h | 17 +- .../include/nx/firmware/GpioTrigger.h | 10 + .../firmware/include/nx/firmware/Wifi.h | 2 +- components/firmware/src/Buttons.c | 33 +- components/firmware/src/GpioTrigger.c | 66 + components/firmware/src/StatusIndicator.c | 8 +- components/firmware/src/Wifi.c | 9 + components/software/CMakeLists.txt | 1 + .../include/nx/software/AppSettings.h | 1 + .../include/nx/software/CommandParser.h | 10 + components/software/src/AppSettings.c | 7 +- components/software/src/CommandParser.c | 40 + components/software/src/SystemSettings.c | 38 +- main/Main.c | 151 +- main/static/app.html | 6 + main/static/index.css | 2576 +++-------------- main/static/index.html | 38 +- main/static/index.js | 31 +- main/static/min/app.html | 3 +- main/static/min/index.css | 2 +- main/static/min/index.html | 3 +- main/static/min/index.js | 15 +- {case => pcb/case}/CaseBody.scad | 0 {case => pcb/case}/CaseBodyExtended.scad | 0 {case => pcb/case}/CaseRoof.scad | 0 {case => pcb/case}/Cover.scad | 0 {case => pcb/case}/LedHook.scad | 0 {case => pcb/case}/RfBoard.scad | 0 {case => pcb/case}/SnapFit.scad | 0 {case => pcb/case}/TargetPcb.scad | 0 {case => pcb/case}/config.scad | 0 {case => pcb/case}/mqtrigger.stl | Bin {kicad => pcb/kicad}/Regulator_Switching.dcm | 0 {kicad => pcb/kicad}/ap1509.dcm | 0 {kicad => pcb/kicad}/ap1509.lib | 0 {kicad => pcb/kicad}/mqtrigger.kicad_pcb | 0 {kicad => pcb/kicad}/mqtrigger.pro | 0 {kicad => pcb/kicad}/mqtrigger.sch | 0 third-party/milligram/license | 21 + third-party/milligram/src/_Base.sass | 42 + third-party/milligram/src/_Blockquote.sass | 12 + third-party/milligram/src/_Button.sass | 76 + third-party/milligram/src/_Code.sass | 22 + third-party/milligram/src/_Color.sass | 12 + third-party/milligram/src/_Divider.sass | 8 + third-party/milligram/src/_Form.sass | 67 + third-party/milligram/src/_Grid.sass | 164 ++ third-party/milligram/src/_Image.sass | 6 + third-party/milligram/src/_Link.sass | 11 + third-party/milligram/src/_List.sass | 22 + third-party/milligram/src/_Spacing.sass | 27 + third-party/milligram/src/_Table.sass | 27 + third-party/milligram/src/_Typography.sass | 48 + third-party/milligram/src/_Utility.sass | 18 + third-party/milligram/src/milligram.sass | 19 + 56 files changed, 1428 insertions(+), 2242 deletions(-) create mode 100644 components/firmware/include/nx/firmware/GpioTrigger.h create mode 100644 components/firmware/src/GpioTrigger.c create mode 100644 components/software/include/nx/software/CommandParser.h create mode 100644 components/software/src/CommandParser.c rename {case => pcb/case}/CaseBody.scad (100%) rename {case => pcb/case}/CaseBodyExtended.scad (100%) rename {case => pcb/case}/CaseRoof.scad (100%) rename {case => pcb/case}/Cover.scad (100%) rename {case => pcb/case}/LedHook.scad (100%) rename {case => pcb/case}/RfBoard.scad (100%) rename {case => pcb/case}/SnapFit.scad (100%) rename {case => pcb/case}/TargetPcb.scad (100%) rename {case => pcb/case}/config.scad (100%) rename {case => pcb/case}/mqtrigger.stl (100%) rename {kicad => pcb/kicad}/Regulator_Switching.dcm (100%) rename {kicad => pcb/kicad}/ap1509.dcm (100%) rename {kicad => pcb/kicad}/ap1509.lib (100%) rename {kicad => pcb/kicad}/mqtrigger.kicad_pcb (100%) rename {kicad => pcb/kicad}/mqtrigger.pro (100%) rename {kicad => pcb/kicad}/mqtrigger.sch (100%) create mode 100644 third-party/milligram/license create mode 100644 third-party/milligram/src/_Base.sass create mode 100644 third-party/milligram/src/_Blockquote.sass create mode 100644 third-party/milligram/src/_Button.sass create mode 100644 third-party/milligram/src/_Code.sass create mode 100644 third-party/milligram/src/_Color.sass create mode 100644 third-party/milligram/src/_Divider.sass create mode 100644 third-party/milligram/src/_Form.sass create mode 100644 third-party/milligram/src/_Grid.sass create mode 100644 third-party/milligram/src/_Image.sass create mode 100644 third-party/milligram/src/_Link.sass create mode 100644 third-party/milligram/src/_List.sass create mode 100644 third-party/milligram/src/_Spacing.sass create mode 100644 third-party/milligram/src/_Table.sass create mode 100644 third-party/milligram/src/_Typography.sass create mode 100644 third-party/milligram/src/_Utility.sass create mode 100644 third-party/milligram/src/milligram.sass diff --git a/components/firmware/CMakeLists.txt b/components/firmware/CMakeLists.txt index 267aca0..8240060 100644 --- a/components/firmware/CMakeLists.txt +++ b/components/firmware/CMakeLists.txt @@ -9,6 +9,7 @@ idf_component_register( src/SntpClient.c src/StatusIndicator.c src/Restarter.c + src/GpioTrigger.c INCLUDE_DIRS ./include PRIV_INCLUDE_DIRS ./src diff --git a/components/firmware/include/nx/firmware/Buttons.h b/components/firmware/include/nx/firmware/Buttons.h index 742822c..675512a 100644 --- a/components/firmware/include/nx/firmware/Buttons.h +++ b/components/firmware/include/nx/firmware/Buttons.h @@ -3,13 +3,22 @@ #include #include - -#define BUTTON_SERVICE_ID 1 -#define BUTTON_SERVICE_GPIO_NUM 23 +#include typedef void (*ButtonEventHandler)(uint8_t btn); -void nxInitButtons(void); +typedef struct Button +{ + uint8_t id; + uint8_t btnGpio; + uint8_t pullGpio; // disabled when 0 + bool inverted; // triggered by gnd by default + bool isPressed; + bool isBouncing; + uint32_t debounceMs; +} Button; + +void nxInitButtons(Button buttons[], size_t buttonCount); void nxSetOnPressHandler(ButtonEventHandler handler); diff --git a/components/firmware/include/nx/firmware/GpioTrigger.h b/components/firmware/include/nx/firmware/GpioTrigger.h new file mode 100644 index 0000000..306c279 --- /dev/null +++ b/components/firmware/include/nx/firmware/GpioTrigger.h @@ -0,0 +1,10 @@ +#ifndef COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_GPIOTRIGGER_H_ +#define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_GPIOTRIGGER_H_ + +#include + +void nxInitGpioTrigger(const uint8_t* pins, uint8_t count); +void nxTriggerGpio(uint8_t outputIndex, uint32_t durationMs); +void nxUpdateTriggerGpio(uint8_t outputIndex, uint8_t level); + +#endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_GPIOTRIGGER_H_ */ diff --git a/components/firmware/include/nx/firmware/Wifi.h b/components/firmware/include/nx/firmware/Wifi.h index 78ce942..3c55985 100644 --- a/components/firmware/include/nx/firmware/Wifi.h +++ b/components/firmware/include/nx/firmware/Wifi.h @@ -32,6 +32,6 @@ bool nxInitWifi(WifiSettings* wifiSettings); void nxSetWifiConnectedCallback(WifiCallback callback); void nxSetWifiErrorCallback(WifiCallback callback); const char* nxGetWifiDeviceName(void); - +bool nxIsWifiStaConnected(void); #endif // COMPONENTS_FIRMWARE_WIFI_H diff --git a/components/firmware/src/Buttons.c b/components/firmware/src/Buttons.c index d5797e4..8af2062 100644 --- a/components/firmware/src/Buttons.c +++ b/components/firmware/src/Buttons.c @@ -18,30 +18,8 @@ #define RTOS_TASK_STACK_SIZE 4096 // stack overflow when less #define RTOS_TASK_PRIORITY 10 -typedef struct Button -{ - uint8_t id; - uint8_t btnGpio; - uint8_t pullGpio; // disabled when 0 - bool inverted; // triggered by gnd by default - bool isPressed; - bool isBouncing; - uint32_t debounceMs; -} Button; - -static Button buttons[] = { - { - .id = BUTTON_SERVICE_ID, - .btnGpio = BUTTON_SERVICE_GPIO_NUM, - .pullGpio = 0, - .inverted = false, - .isPressed = false, - .isBouncing = false, - .debounceMs = 50 - } -}; - -const size_t buttonCount = sizeof(buttons)/sizeof(buttons[0]); +Button* buttons = NULL; +static size_t buttonCount = 0; static ButtonEventHandler pressHandler = NULL; static ButtonEventHandler releaseHandler = NULL; @@ -85,14 +63,18 @@ static void buttonQueueTask(void* arg) // --------- Public API --------- // -void nxInitButtons(void) +void nxInitButtons(Button* buttonArray, size_t count) { + buttons = buttonArray; + buttonCount = count; + gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); for (size_t i = 0; i < buttonCount; ++i) { Button* button = &buttons[i]; gpio_reset_pin(button->btnGpio); gpio_set_direction(button->btnGpio, GPIO_MODE_INPUT); + if (button->pullGpio) { gpio_reset_pin(button->pullGpio); gpio_set_direction(button->pullGpio, GPIO_MODE_OUTPUT); @@ -139,4 +121,3 @@ bool nxIsButtonPressed(uint8_t btn) } - diff --git a/components/firmware/src/GpioTrigger.c b/components/firmware/src/GpioTrigger.c new file mode 100644 index 0000000..3f37a5f --- /dev/null +++ b/components/firmware/src/GpioTrigger.c @@ -0,0 +1,66 @@ +#include "nx/firmware/GpioTrigger.h" + +#include +#include +#include +#include +#include + +static int MAX_TRIGGER_DURATION_MS = 20000; + +static const char* TAG = "NX_TRIGGER"; + +static const uint8_t* outputs = NULL; +static size_t outputCount = 0; + +void nxInitGpioTrigger(const uint8_t* pins, uint8_t count) +{ + outputs = pins; + outputCount = count; + + for (uint8_t i = 0; i < count; ++i) { + ESP_LOGI(TAG, "Initializing GPIO %i (index %i)", outputs[i], i); + gpio_reset_pin(outputs[i]); + gpio_set_direction(outputs[i], GPIO_MODE_OUTPUT); + gpio_set_level(outputs[i], 0); + } +} + +void nxTriggerGpio(uint8_t outputIndex, uint32_t durationMs) +{ + if (outputs == NULL) { + ESP_LOGE(TAG, "Trigger outputs not set, aborting"); + return; + } + + if (outputIndex >= outputCount) { + ESP_LOGE(TAG, "Trigger output index out of range, aborting"); + return; + } + + if (durationMs > MAX_TRIGGER_DURATION_MS) { + durationMs = MAX_TRIGGER_DURATION_MS; + } + + ESP_LOGI(TAG, "Triggering output %i for %ims", outputs[outputIndex], durationMs); + gpio_set_level(outputs[outputIndex], 1); + vTaskDelay(durationMs / portTICK_PERIOD_MS); + gpio_set_level(outputs[outputIndex], 0); +} + +void nxUpdateTriggerGpio(uint8_t outputIndex, uint8_t level) +{ + if (outputs == NULL) { + ESP_LOGE(TAG, "Trigger outputs not set, aborting"); + return; + } + + if (outputIndex >= outputCount) { + ESP_LOGE(TAG, "Trigger output index out of range, aborting"); + return; + } + + ESP_LOGI(TAG, "Updating output %i to level %i", outputs[outputIndex], level); + gpio_set_level(outputs[outputIndex], level); +} + diff --git a/components/firmware/src/StatusIndicator.c b/components/firmware/src/StatusIndicator.c index b2a11cc..25557e1 100644 --- a/components/firmware/src/StatusIndicator.c +++ b/components/firmware/src/StatusIndicator.c @@ -203,8 +203,12 @@ void nxUpdateStatus(HwStatus newStatus) { // priority filters: if (currentStatus == STATUS_SYSTEM_ERROR - && newStatus == STATUS_APP_ERROR) { - return; + && newStatus == STATUS_APP_ERROR) { + return; + } + if (currentStatus == STATUS_OK_WORKING + && newStatus == STATUS_OK_WORKING) { + return; } prevStatus = currentStatus; currentStatus = newStatus; diff --git a/components/firmware/src/Wifi.c b/components/firmware/src/Wifi.c index fd5100f..a349a12 100644 --- a/components/firmware/src/Wifi.c +++ b/components/firmware/src/Wifi.c @@ -42,6 +42,7 @@ static WifiSettings* settings = NULL; static WifiCallback errorCallback = NULL; static WifiCallback connectedCallback = NULL; +static bool staConnected = false; static char deviceName[DEVICE_NAME_MAX_LEN] = {0}; @@ -94,6 +95,8 @@ static void handleStaEvents(esp_event_base_t event_base, int32_t event_id, void* } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { ESP_LOGE(TAG, "Cannot connect to the AP"); + staConnected = false; + if (errorCallback) { errorCallback(); } @@ -113,6 +116,7 @@ static void handleStaEvents(esp_event_base_t event_base, int32_t event_id, void* else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI(TAG, "IP address acquired: " IPSTR, IP2STR(&event->ip_info.ip)); + staConnected = true; retryCount = 0; if (connectedCallback) { connectedCallback(); @@ -354,3 +358,8 @@ const char* nxGetWifiDeviceName(void) return "unknown"; } +bool nxIsWifiStaConnected(void) +{ + return staConnected; +} + diff --git a/components/software/CMakeLists.txt b/components/software/CMakeLists.txt index 56b3966..71e744a 100644 --- a/components/software/CMakeLists.txt +++ b/components/software/CMakeLists.txt @@ -5,6 +5,7 @@ idf_component_register( src/KeyValueParser.c src/AppSettings.c src/AppSettingsApi.c + src/CommandParser.c INCLUDE_DIRS ./include PRIV_INCLUDE_DIRS ./src diff --git a/components/software/include/nx/software/AppSettings.h b/components/software/include/nx/software/AppSettings.h index 673aa76..7b6676a 100644 --- a/components/software/include/nx/software/AppSettings.h +++ b/components/software/include/nx/software/AppSettings.h @@ -28,6 +28,7 @@ typedef struct AppSettings { bool overrideDevName; char customDevName[DEVICE_NAME_MAX_LEN]; char caCert[CA_CERT_MAX_SIZE]; + uint16_t wdogMaxSec; } AppSettings; diff --git a/components/software/include/nx/software/CommandParser.h b/components/software/include/nx/software/CommandParser.h new file mode 100644 index 0000000..dc3075d --- /dev/null +++ b/components/software/include/nx/software/CommandParser.h @@ -0,0 +1,10 @@ +#ifndef COMPONENTS_SOFTWARE_INCLUDE_NX_SOFTWARE_COMMANDPARSER_H_ +#define COMPONENTS_SOFTWARE_INCLUDE_NX_SOFTWARE_COMMANDPARSER_H_ + +#include + +typedef void (*CommandHandler)(const char* cmd, const char** args, uint8_t argc); + +void nxParseCommandString(const char* commandString, CommandHandler handler); + +#endif /* COMPONENTS_SOFTWARE_INCLUDE_NX_SOFTWARE_COMMANDPARSER_H_ */ diff --git a/components/software/src/AppSettings.c b/components/software/src/AppSettings.c index f5f02ba..35d9531 100644 --- a/components/software/src/AppSettings.c +++ b/components/software/src/AppSettings.c @@ -13,6 +13,7 @@ #define KEY_OVR_DEVNAME "ovdn" #define KEY_CUSTOM_DEVNAME "cdn" #define KEY_CA_CERT "cacert" +#define KEY_WDOG_MAX_SEC "wdogs" #define STORAGE_READ(_KEY, _NAME)\ storageRead(_KEY, &settings._NAME, sizeof(settings._NAME)); @@ -32,6 +33,7 @@ static const char* DEFAULT_MQTT_PASS = ""; static const bool DEFAULT_OV_DEVNAME = false; static const char* DEFAULT_CUSTOM_DEVNAME = "esp-dev"; static const char* DEFAULT_CA_CERT = "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"; +static const uint16_t DEFAULT_WDOG_MAX_SEC = 60 * 15; static StorageWriteFn storageWrite = NULL; @@ -62,6 +64,7 @@ static void loadSettings(void) STORAGE_READ(KEY_OVR_DEVNAME , overrideDevName ); STORAGE_READ(KEY_CUSTOM_DEVNAME , customDevName ); STORAGE_READ(KEY_CA_CERT , caCert ); + STORAGE_READ(KEY_WDOG_MAX_SEC , wdogMaxSec ); } @@ -99,6 +102,7 @@ void nxRestoreAppDefaultSettings(void) settings.mqttHbIntervalSec = DEFAULT_MQTT_HB_SEC; settings.mqttUseTls = DEFAULT_MQTT_TLS; settings.overrideDevName = DEFAULT_OV_DEVNAME; + settings.wdogMaxSec = DEFAULT_WDOG_MAX_SEC; strcpy(settings.mqttHbUri , DEFAULT_MQTT_HB_URI ); strcpy(settings.mqttApiUri , DEFAULT_MQTT_API_URI ); @@ -108,7 +112,6 @@ void nxRestoreAppDefaultSettings(void) strcpy(settings.customDevName , DEFAULT_CUSTOM_DEVNAME); strcpy(settings.caCert , DEFAULT_CA_CERT ); - nxWriteAppSettings(); } @@ -128,6 +131,8 @@ void nxWriteAppSettings(void) STORAGE_WRITE(KEY_CA_CERT , caCert ); STORAGE_WRITE(KEY_CUSTOM_DEVNAME , customDevName ); STORAGE_WRITE(KEY_OVR_DEVNAME , overrideDevName ); + STORAGE_WRITE(KEY_WDOG_MAX_SEC , wdogMaxSec ); + settingsUpdatedCb(); } diff --git a/components/software/src/CommandParser.c b/components/software/src/CommandParser.c new file mode 100644 index 0000000..ee396f4 --- /dev/null +++ b/components/software/src/CommandParser.c @@ -0,0 +1,40 @@ +#include "nx/software/CommandParser.h" + +#include +#include +#include +#include + +static const char CMD_SEPARATOR = ' '; + +void nxParseCommandString(const char* commandString, CommandHandler handler) +{ + char* cmd = malloc(strlen(commandString)+1); + if (!cmd) { + return; + } + + strcpy(cmd, commandString); + uint8_t argc = 0; + const char** args = NULL; + char* arg = cmd; + while ( (arg = strchr(arg, CMD_SEPARATOR)) ) { + arg[0] = '\0'; + ++arg; + argc += 1; + + const char** nArgs = calloc(argc, sizeof(char*)); + for (int i = 0; i < argc-1; ++i) { + nArgs[i] = args[i]; + } + nArgs[argc-1] = arg; + if (args) { + free(args); + } + args = nArgs; + } + + handler(cmd, args, argc); + free(args); + free(cmd); +} diff --git a/components/software/src/SystemSettings.c b/components/software/src/SystemSettings.c index ec4c685..719f6cf 100644 --- a/components/software/src/SystemSettings.c +++ b/components/software/src/SystemSettings.c @@ -54,18 +54,17 @@ static bool firstRun(void) static void loadSystemSettings(void) { printf("Loading system settings\n"); - storageRead(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN); - storageRead(KEY_WIFI_PASS , settings.wifiPassword , WIFI_STRINGS_MAX_LEN); - storageRead(KEY_WIFI_ADDR , settings.ip4addr , IPV4_ADDR_SIZE); - storageRead(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE); - storageRead(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE); - storageRead(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE); - storageRead(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN); - storageRead(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN); - storageRead(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE); - + STORAGE_READ(KEY_WIFI_SSID , wifiSsid ); + STORAGE_READ(KEY_WIFI_PASS , wifiPassword ); STORAGE_READ(KEY_WIFI_POWER_SAVE, wifiPowerSave); STORAGE_READ(KEY_WIFI_USE_STATIC, useStaticAddr); + STORAGE_READ(KEY_WIFI_ADDR , ip4addr ); + STORAGE_READ(KEY_WIFI_GW , ip4gw ); + STORAGE_READ(KEY_WIFI_MASK , ip4mask ); + STORAGE_READ(KEY_DNS_ADDR , dnsAddr ); + STORAGE_READ(KEY_SNTP_ADDR , sntpAddr ); + STORAGE_READ(KEY_TZ_ENV , tzEnv ); + STORAGE_READ(KEY_RS_SCHEDULE , rsSchedule ); } @@ -115,18 +114,17 @@ void nxWriteSystemSettings(void) printf("WRITING SYSTEM SETTINGS\n"); storageWrite(KEY_INIT_FLAG, &INIT_FLAG_VALUE, 1); - storageWrite(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN ); - storageWrite(KEY_WIFI_PASS , settings.wifiPassword , WIFI_STRINGS_MAX_LEN ); - storageWrite(KEY_WIFI_ADDR , settings.ip4addr , IPV4_ADDR_SIZE ); - storageWrite(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE ); - storageWrite(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE ); - storageWrite(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE ); - storageWrite(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN ); - storageWrite(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN ); - storageWrite(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE ); - + STORAGE_WRITE(KEY_WIFI_SSID , wifiSsid ); + STORAGE_WRITE(KEY_WIFI_PASS , wifiPassword ); STORAGE_WRITE(KEY_WIFI_POWER_SAVE, wifiPowerSave ); STORAGE_WRITE(KEY_WIFI_USE_STATIC, useStaticAddr ); + STORAGE_WRITE(KEY_WIFI_ADDR , ip4addr ); + STORAGE_WRITE(KEY_WIFI_GW , ip4gw ); + STORAGE_WRITE(KEY_WIFI_MASK , ip4mask ); + STORAGE_WRITE(KEY_DNS_ADDR , dnsAddr ); + STORAGE_WRITE(KEY_SNTP_ADDR , sntpAddr ); + STORAGE_WRITE(KEY_TZ_ENV , tzEnv ); + STORAGE_WRITE(KEY_RS_SCHEDULE , rsSchedule ); } SystemSettings* nxGetSystemSettings(void) diff --git a/main/Main.c b/main/Main.c index 3df364c..0bf4630 100644 --- a/main/Main.c +++ b/main/Main.c @@ -2,6 +2,7 @@ #include "nx/software/SystemSettingsApi.h" #include "nx/software/AppSettings.h" #include "nx/software/AppSettingsApi.h" +#include "nx/software/CommandParser.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -14,6 +15,8 @@ #include "nx/firmware/SntpClient.h" #include "nx/firmware/StatusIndicator.h" #include "nx/firmware/Restarter.h" +#include "nx/firmware/GpioTrigger.h" +#include "nx/firmware/Buttons.h" #include "HttpHandlers.h" @@ -27,9 +30,16 @@ #define API_QOS 2 #define HB_QOS 1 +#define BUTTON_SERVICE_ID 1 +#define BUTTON_SERVICE_GPIO_NUM 15 +#define SERVICE_BUTTON_DEFAULT_RESET_HOLD_SEC 1500 + static const char* DEVICE_NAME_PREFIX = "mqt-"; +static void restoreDefaultsOnStartupButtonHold(void); static void startWifi(void); +static void onCommandRequest(const uint8_t* content, size_t ctLen, + const char** response, size_t* respLen); static void onWifiConnected(void); static void onWifiError(void); static void onAppSettingsUpdate(void); @@ -39,6 +49,7 @@ static void onMqttError(); static void onMqttMessage(const char* msg); static void hbTask(void*); +static void connWatchdogTask(void*); static SystemSettings* systemSettings = NULL; static AppSettings* appSettings = NULL; @@ -47,6 +58,7 @@ static MqttSettings mqttSettings; static bool wifiStarted = false; static bool mqttStarted = false; +static bool serviceMode = false; static const MqTriggerHttpCallbacks httpCallbacks = { .getRoot = rootHandler, @@ -57,22 +69,37 @@ static const MqTriggerHttpCallbacks httpCallbacks = { .getSysSet = nxApiGetSystemSettings, .postSysSet = nxApiUpdateSystemSettings, .getAppSet = nxApiGetAppSettings, - .postAppSet = nxApiUpdateAppSettings - // .postCmd = nxApiHandleCmd + .postAppSet = nxApiUpdateAppSettings, + .postCmd = onCommandRequest +}; + +static Button buttons[] = { + { + .id = BUTTON_SERVICE_ID, + .btnGpio = BUTTON_SERVICE_GPIO_NUM, + .pullGpio = 0, + .inverted = false, + .isPressed = false, + .isBouncing = false, + .debounceMs = 50 + } }; +static const uint8_t TRIGGER_GPIO[] = {27, 26, 25, 33}; + void app_main(void) { nxInitStatusIndicator(); nxUpdateStatus(STATUS_BOOT); xTaskCreate(&nxStatusIndicatorTask, "status_task", 2048, NULL, 1, NULL); + nxInitButtons(buttons, sizeof(buttons)/sizeof(buttons[0])); nxInitStorage(); // uncomment to force default NVS initialization for development -// uint8_t zero = 0; -// nxStorageWrite("ledinit", &zero, 1); -// nxStorageWrite("sysinit", &zero, 1); + // uint8_t zero = 0; + // nxStorageWrite("ledinit", &zero, 1); + // nxStorageWrite("sysinit", &zero, 1); nxInitSystemSettings(nxStorageWrite, nxStorageRead); nxInitAppSettings(nxStorageWrite, nxStorageRead, onAppSettingsUpdate); @@ -80,20 +107,55 @@ void app_main(void) systemSettings = nxGetSystemSettings(); appSettings = nxGetAppSettings(); + restoreDefaultsOnStartupButtonHold(); + + nxInitGpioTrigger(TRIGGER_GPIO, sizeof(TRIGGER_GPIO)); + // uncomment to force WiFi settings for development -// strcpy(systemSettings->wifiSsid, "androidAp"); -// strcpy(systemSettings->wifiPassword, "password"); -// systemSettings->useStaticAddr = false; + strcpy(systemSettings->wifiSsid, "cintra"); + strcpy(systemSettings->wifiPassword, "fffefdfcfb"); + systemSettings->useStaticAddr = false; nxStartRestarter(systemSettings->rsSchedule, systemSettings->tzEnv); + xTaskCreate(&connWatchdogTask, "conn_watchdog_task", 2048, NULL, 1, NULL); nxSetWifiConnectedCallback(onWifiConnected); nxSetWifiErrorCallback(onWifiError); startWifi(); + } // ----- +static void restoreDefaultsOnStartupButtonHold(void) +{ + vTaskDelay(1000 / portTICK_PERIOD_MS); // possible debouncing capacitor wait + + if (nxIsButtonPressed(BUTTON_SERVICE_ID)) { + ESP_LOGI(TAG, "SERVICE BUTTON IS PRESSED"); + } + else { + ESP_LOGI(TAG, "SERVICE BUTTON IS NOT PRESSED"); + } + + const uint16_t stepMs = 500; + uint16_t steps = (SERVICE_BUTTON_DEFAULT_RESET_HOLD_SEC * 1000) / stepMs; + serviceMode = nxIsButtonPressed(BUTTON_SERVICE_ID); + + while (nxIsButtonPressed(BUTTON_SERVICE_ID)) { + if (steps == 0) { + ESP_LOGW(TAG, "RESTORING DEFAULT SYSTEM AND DISPLAY SETTINGS"); + nxRestoreAppDefaultSettings(); + nxRestoreSystemDefaultSettings(); + vTaskDelay(1000 / portTICK_PERIOD_MS); + esp_restart(); + } + ESP_LOGW(TAG, "HOLDING SERVICE BUTTON [COUNTDOWN: %i]", steps); + vTaskDelay(stepMs / portTICK_PERIOD_MS); + steps -= 1; + } +} + static void startWifi(void) { wifiSettings = (struct WifiSettings){ @@ -108,10 +170,48 @@ static void startWifi(void) .dns = systemSettings->dnsAddr }; + wifiSettings.mode = serviceMode ? NX_WIFI_MODE_AP : NX_WIFI_MODE_STA; + ESP_LOGI(TAG, "Initializing WiFi"); if (!nxInitWifi(&wifiSettings)) { nxUpdateStatus(STATUS_SYSTEM_ERROR); } + + nxEnablePowerSavingStatus(systemSettings->wifiPowerSave); +} + +static void handleCommand(const char* cmd, const char* args[], uint8_t argc) +{ + ESP_LOGI(TAG, "Handling command %s with %i args", cmd, argc); + if (strcmp(cmd, "trigger") == 0 && argc >= 2) { + uint32_t durationMs = atoi(args[1]); + nxTriggerGpio(atoi(args[0]), durationMs); + } + else if (strcmp(cmd, "on") == 0 && argc >= 1) { + nxUpdateTriggerGpio(atoi(args[0]), 1); + } + else if (strcmp(cmd, "off") == 0 && argc >= 1) { + nxUpdateTriggerGpio(atoi(args[0]), 0); + } + else if (strcmp(cmd, "setsys") == 0 && argc >= 1) { + nxApiUpdateSystemSettings((uint8_t*)args[0], strlen(args[0]), NULL, NULL); + } + else if (strcmp(cmd, "setapp") == 0 && argc >= 1) { + nxApiUpdateAppSettings((uint8_t*)args[0], strlen(args[0]), NULL, NULL); + } + else if (strcmp(cmd, "reboot") == 0) { + esp_restart(); + } + else { + ESP_LOGW(TAG, "Unknown command or missing args: %s", cmd); + } +} + +static void onCommandRequest(const uint8_t* content, size_t ctLen, + const char** response, size_t* respLen) +{ + nxUpdateStatus(STATUS_OK_WORKING); + nxParseCommandString((const char*)content, handleCommand); } static void onWifiConnected(void) @@ -135,7 +235,7 @@ static void onWifiConnected(void) strcpy(mqttSettings.password, appSettings->mqttPassword); strcpy(mqttSettings.clientId, appSettings->overrideDevName ? appSettings->customDevName - : systemSettings->deviceName); + : systemSettings->deviceName); mqttSettings.hbIntervalSec = appSettings->mqttHbIntervalSec; mqttSettings.caCrt = appSettings->mqttUseTls ? appSettings->caCert : NULL; @@ -162,6 +262,7 @@ static void onMqttMessage(const char* msg) { ESP_LOGI(TAG, "MQTT MESSAGE RECEIVED: %s", msg); nxUpdateStatus(STATUS_OK_WORKING); + nxParseCommandString(msg, handleCommand); } static void onWifiError() @@ -232,3 +333,35 @@ static void hbTask(void* param) vTaskDelay(appSettings->mqttHbIntervalSec*1000 / portTICK_PERIOD_MS); } } + +static void connWatchdogTask(void* param) +{ + if (appSettings->wdogMaxSec == 0) { + ESP_LOGI(TAG, "Connection watchdog disabled"); + vTaskDelete(NULL); + return; + } + + ESP_LOGI(TAG, "Starting connection watchdog task"); + vTaskDelay(1000 * 20 / portTICK_PERIOD_MS); // wait for initialization + + uint32_t fails = 0; + const uint32_t WD_DELAY_SEC = 10; + const uint32_t MAX_FAILS = appSettings->wdogMaxSec/WD_DELAY_SEC; + + while (1) { + if (!nxMqttIsConnected() || !nxIsWifiStaConnected()) { + ESP_LOGI(TAG, "Connection watchdog: DEVICE NOT CONNECTED TO WIFI/MQTT BROKER"); + fails += 1; + if (fails >= MAX_FAILS) { + ESP_LOGW(TAG, "MAX CONNECTION FAILED CHECKS REACHED, REBOOTING"); + esp_restart(); + } + } + else if (fails > 0){ + fails = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + diff --git a/main/static/app.html b/main/static/app.html index 93df1c8..bf82148 100644 --- a/main/static/app.html +++ b/main/static/app.html @@ -69,6 +69,12 @@

+

+ +

+

diff --git a/main/static/index.css b/main/static/index.css index a158e99..3309ee5 100644 --- a/main/static/index.css +++ b/main/static/index.css @@ -1,2169 +1,495 @@ -@charset "UTF-8"; -/* - Flavor name: Nord (mini-nord) - Author: tphecca (https://github.com/tphecca) - Maintainers: tphecca - mini.css version: v3.0.1 -*/ -/* - Browsers resets and base typography. -*/ -/* Core module CSS variable definitions */ -:root { - --fore-color: #2e3440; - --secondary-fore-color: #3b4252; - --back-color: #eceff4; - --secondary-back-color: #e5e9f0; - --blockquote-color: #d08770; - --pre-color: #b48ead; - --border-color: #d8dee9; - --secondary-border-color: #e5e9f0; - --heading-ratio: 1.19; - --universal-margin: 0.5rem; - --universal-padding: 0.5rem; - --universal-border-radius: 0.125rem; - --a-link-color: #88c0d0; - --a-visited-color: #5e81ac; -} +*, +*:after, +*:before { + box-sizing: inherit; } html { - font-size: 16px; -} - -a, b, del, em, i, ins, q, span, strong, u { - font-size: 1em; -} - -html, * { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, sans-serif; - line-height: 1.5; - -webkit-text-size-adjust: 100%; -} - -* { - font-size: 1rem; -} + box-sizing: border-box; + font-size: 62.5%; } body { - margin: 0; - color: var(--fore-color); - background: var(--back-color); -} - -details { - display: block; -} - -summary { - display: list-item; -} - -abbr[title] { - border-bottom: none; - text-decoration: underline dotted; -} - -input { - overflow: visible; -} - -img { - max-width: 100%; - height: auto; -} - -h1, h2, h3, h4, h5, h6 { - line-height: 1.2; - margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); - font-weight: 500; -} - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { - color: var(--secondary-fore-color); - display: block; - margin-top: -0.25rem; -} - -h1 { - font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); -} - -h2 { - font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); -} - -h3 { - font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio)); -} - -h4 { - font-size: calc(1rem * var(--heading-ratio)); -} - -h5 { - font-size: 1rem; -} - -h6 { - font-size: calc(1rem / var(--heading-ratio)); -} - -p { - margin: var(--universal-margin); -} - -ol, ul { - margin: var(--universal-margin); - padding-left: calc(2 * var(--universal-margin)); -} - -b, strong { - font-weight: 700; -} - -hr { - box-sizing: content-box; - border: 0; - line-height: 1.25em; - margin: var(--universal-margin); - height: 0.0625rem; - background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); -} - -blockquote { - display: block; - position: relative; - font-style: italic; - color: var(--secondary-fore-color); - margin: var(--universal-margin); - padding: calc(3 * var(--universal-padding)); - border: 0.0625rem solid var(--secondary-border-color); - border-left: 0.375rem solid var(--blockquote-color); - border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; -} - -blockquote:before { - position: absolute; - top: calc(0rem - var(--universal-padding)); + color: #351C4D; + background-color: #fafafa; + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; + font-size: 1.6em; + font-weight: 300; + letter-spacing: .01em; + line-height: 1.6; } + +.nav-bar { + background-color: #fafafa; + top: 0; left: 0; - font-family: sans-serif; - font-size: 3rem; - font-weight: 700; - content: "\201c"; - color: var(--blockquote-color); -} + right: 0; + border-bottom: 1px solid #b0b0b0; + height: 3rem; + display: flex; + text-transform: uppercase; + margin-bottom: 2rem !important; } + .nav-bar * { + display: inline; } + .nav-bar li { + margin: 1rem; } + .nav-bar li a { + font-weight: bold; } -blockquote[cite]:after { - font-style: normal; - font-size: 0.75em; +blockquote { + border-left: 0.3rem solid #d1d1d1; + margin-left: 0; + margin-right: 0; + padding: 1rem 1.5rem; } + blockquote *:last-child { + margin-bottom: 0; } + +.button, +button, +input[type='button'], +input[type='reset'], +input[type='submit'] { + background-color: #FF7E5F; + border: 0.1rem solid #FF7E5F; + border-radius: .4rem; + color: #fafafa; + cursor: pointer; + display: inline-block; + font-size: 1.1rem; font-weight: 700; - content: "\a— " attr(cite); - white-space: pre; -} - -code, kbd, pre, samp { - font-family: Menlo, Consolas, monospace; - font-size: 0.85em; -} + height: 3.8rem; + letter-spacing: .1rem; + line-height: 3.8rem; + padding: 0 3.0rem; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; } + .button:focus, .button:hover, + button:focus, + button:hover, + input[type='button']:focus, + input[type='button']:hover, + input[type='reset']:focus, + input[type='reset']:hover, + input[type='submit']:focus, + input[type='submit']:hover { + background-color: #351C4D; + border-color: #351C4D; + color: #fafafa; + outline: 0; } + .button[disabled], + button[disabled], + input[type='button'][disabled], + input[type='reset'][disabled], + input[type='submit'][disabled] { + cursor: default; + opacity: .5; } + .button[disabled]:focus, .button[disabled]:hover, + button[disabled]:focus, + button[disabled]:hover, + input[type='button'][disabled]:focus, + input[type='button'][disabled]:hover, + input[type='reset'][disabled]:focus, + input[type='reset'][disabled]:hover, + input[type='submit'][disabled]:focus, + input[type='submit'][disabled]:hover { + background-color: #FF7E5F; + border-color: #FF7E5F; } + .button.button-outline, + button.button-outline, + input[type='button'].button-outline, + input[type='reset'].button-outline, + input[type='submit'].button-outline { + background-color: transparent; + color: #FF7E5F; } + .button.button-outline:focus, .button.button-outline:hover, + button.button-outline:focus, + button.button-outline:hover, + input[type='button'].button-outline:focus, + input[type='button'].button-outline:hover, + input[type='reset'].button-outline:focus, + input[type='reset'].button-outline:hover, + input[type='submit'].button-outline:focus, + input[type='submit'].button-outline:hover { + background-color: transparent; + border-color: #351C4D; + color: #351C4D; } + .button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover, + button.button-outline[disabled]:focus, + button.button-outline[disabled]:hover, + input[type='button'].button-outline[disabled]:focus, + input[type='button'].button-outline[disabled]:hover, + input[type='reset'].button-outline[disabled]:focus, + input[type='reset'].button-outline[disabled]:hover, + input[type='submit'].button-outline[disabled]:focus, + input[type='submit'].button-outline[disabled]:hover { + border-color: inherit; + color: #FF7E5F; } + .button.button-clear, + button.button-clear, + input[type='button'].button-clear, + input[type='reset'].button-clear, + input[type='submit'].button-clear { + background-color: transparent; + border-color: transparent; + color: #FF7E5F; } + .button.button-clear:focus, .button.button-clear:hover, + button.button-clear:focus, + button.button-clear:hover, + input[type='button'].button-clear:focus, + input[type='button'].button-clear:hover, + input[type='reset'].button-clear:focus, + input[type='reset'].button-clear:hover, + input[type='submit'].button-clear:focus, + input[type='submit'].button-clear:hover { + background-color: transparent; + border-color: transparent; + color: #351C4D; } + .button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover, + button.button-clear[disabled]:focus, + button.button-clear[disabled]:hover, + input[type='button'].button-clear[disabled]:focus, + input[type='button'].button-clear[disabled]:hover, + input[type='reset'].button-clear[disabled]:focus, + input[type='reset'].button-clear[disabled]:hover, + input[type='submit'].button-clear[disabled]:focus, + input[type='submit'].button-clear[disabled]:hover { + color: #FF7E5F; } code { - background: var(--secondary-back-color); - border-radius: var(--universal-border-radius); - padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); -} - -kbd { - background: var(--fore-color); - color: var(--back-color); - border-radius: var(--universal-border-radius); - padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); -} + background: #b0b0b0; + border-radius: .4rem; + font-size: 86%; + margin: 0 .2rem; + padding: .2rem .5rem; + white-space: nowrap; } pre { - overflow: auto; - background: var(--secondary-back-color); - padding: calc(1.5 * var(--universal-padding)); - margin: var(--universal-margin); - border: 0.0625rem solid var(--secondary-border-color); - border-left: 0.25rem solid var(--pre-color); - border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; -} - -sup, sub, code, kbd { - line-height: 0; - position: relative; - vertical-align: baseline; -} - -small, sup, sub, figcaption { - font-size: 0.75em; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -figure { - margin: var(--universal-margin); -} - -figcaption { - color: var(--secondary-fore-color); -} - -a { - text-decoration: none; -} - -a:link { - color: var(--a-link-color); -} - -a:visited { - color: var(--a-visited-color); -} - -a:hover, a:focus { - text-decoration: underline; -} - -/* - Definitions for the grid system, cards and containers. -*/ -.container { - margin: 0 auto; - padding: 0 calc(1.5 * var(--universal-padding)); -} - -.row { - box-sizing: border-box; - display: flex; - flex: 0 1 auto; - flex-flow: row wrap; -} - -.col-sm, -[class^='col-sm-'], -[class^='col-sm-offset-'], -.row[class*='cols-sm-'] > * { - box-sizing: border-box; - flex: 0 0 auto; - padding: 0 calc(var(--universal-padding) / 2); -} - -.col-sm, -.row.cols-sm > * { - max-width: 100%; - flex-grow: 1; - flex-basis: 0; -} - -.col-sm-1, -.row.cols-sm-1 > * { - max-width: 8.33333%; - flex-basis: 8.33333%; -} - -.col-sm-offset-0 { - margin-left: 0; -} - -.col-sm-2, -.row.cols-sm-2 > * { - max-width: 16.66667%; - flex-basis: 16.66667%; -} - -.col-sm-offset-1 { - margin-left: 8.33333%; -} - -.col-sm-3, -.row.cols-sm-3 > * { - max-width: 25%; - flex-basis: 25%; -} - -.col-sm-offset-2 { - margin-left: 16.66667%; -} - -.col-sm-4, -.row.cols-sm-4 > * { - max-width: 33.33333%; - flex-basis: 33.33333%; -} - -.col-sm-offset-3 { - margin-left: 25%; -} - -.col-sm-5, -.row.cols-sm-5 > * { - max-width: 41.66667%; - flex-basis: 41.66667%; -} - -.col-sm-offset-4 { - margin-left: 33.33333%; -} - -.col-sm-6, -.row.cols-sm-6 > * { - max-width: 50%; - flex-basis: 50%; -} - -.col-sm-offset-5 { - margin-left: 41.66667%; -} - -.col-sm-7, -.row.cols-sm-7 > * { - max-width: 58.33333%; - flex-basis: 58.33333%; -} - -.col-sm-offset-6 { - margin-left: 50%; -} - -.col-sm-8, -.row.cols-sm-8 > * { - max-width: 66.66667%; - flex-basis: 66.66667%; -} - -.col-sm-offset-7 { - margin-left: 58.33333%; -} - -.col-sm-9, -.row.cols-sm-9 > * { - max-width: 75%; - flex-basis: 75%; -} - -.col-sm-offset-8 { - margin-left: 66.66667%; -} - -.col-sm-10, -.row.cols-sm-10 > * { - max-width: 83.33333%; - flex-basis: 83.33333%; -} - -.col-sm-offset-9 { - margin-left: 75%; -} - -.col-sm-11, -.row.cols-sm-11 > * { - max-width: 91.66667%; - flex-basis: 91.66667%; -} - -.col-sm-offset-10 { - margin-left: 83.33333%; -} - -.col-sm-12, -.row.cols-sm-12 > * { - max-width: 100%; - flex-basis: 100%; -} - -.col-sm-offset-11 { - margin-left: 91.66667%; -} - -.col-sm-normal { - order: initial; -} - -.col-sm-first { - order: -999; -} - -.col-sm-last { - order: 999; -} - -@media screen and (min-width: 768px) { - .col-md, - [class^='col-md-'], - [class^='col-md-offset-'], - .row[class*='cols-md-'] > * { - box-sizing: border-box; - flex: 0 0 auto; - padding: 0 calc(var(--universal-padding) / 2); - } - .col-md, - .row.cols-md > * { - max-width: 100%; - flex-grow: 1; - flex-basis: 0; - } - .col-md-1, - .row.cols-md-1 > * { - max-width: 8.33333%; - flex-basis: 8.33333%; - } - .col-md-offset-0 { - margin-left: 0; - } - .col-md-2, - .row.cols-md-2 > * { - max-width: 16.66667%; - flex-basis: 16.66667%; - } - .col-md-offset-1 { - margin-left: 8.33333%; - } - .col-md-3, - .row.cols-md-3 > * { - max-width: 25%; - flex-basis: 25%; - } - .col-md-offset-2 { - margin-left: 16.66667%; - } - .col-md-4, - .row.cols-md-4 > * { - max-width: 33.33333%; - flex-basis: 33.33333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-5, - .row.cols-md-5 > * { - max-width: 41.66667%; - flex-basis: 41.66667%; - } - .col-md-offset-4 { - margin-left: 33.33333%; - } - .col-md-6, - .row.cols-md-6 > * { - max-width: 50%; - flex-basis: 50%; - } - .col-md-offset-5 { - margin-left: 41.66667%; - } - .col-md-7, - .row.cols-md-7 > * { - max-width: 58.33333%; - flex-basis: 58.33333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-8, - .row.cols-md-8 > * { - max-width: 66.66667%; - flex-basis: 66.66667%; - } - .col-md-offset-7 { - margin-left: 58.33333%; - } - .col-md-9, - .row.cols-md-9 > * { - max-width: 75%; - flex-basis: 75%; - } - .col-md-offset-8 { - margin-left: 66.66667%; - } - .col-md-10, - .row.cols-md-10 > * { - max-width: 83.33333%; - flex-basis: 83.33333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-11, - .row.cols-md-11 > * { - max-width: 91.66667%; - flex-basis: 91.66667%; - } - .col-md-offset-10 { - margin-left: 83.33333%; - } - .col-md-12, - .row.cols-md-12 > * { - max-width: 100%; - flex-basis: 100%; - } - .col-md-offset-11 { - margin-left: 91.66667%; - } - .col-md-normal { - order: initial; - } - .col-md-first { - order: -999; - } - .col-md-last { - order: 999; - } -} - -@media screen and (min-width: 1280px) { - .col-lg, - [class^='col-lg-'], - [class^='col-lg-offset-'], - .row[class*='cols-lg-'] > * { - box-sizing: border-box; - flex: 0 0 auto; - padding: 0 calc(var(--universal-padding) / 2); - } - .col-lg, - .row.cols-lg > * { - max-width: 100%; - flex-grow: 1; - flex-basis: 0; - } - .col-lg-1, - .row.cols-lg-1 > * { - max-width: 8.33333%; - flex-basis: 8.33333%; - } - .col-lg-offset-0 { - margin-left: 0; - } - .col-lg-2, - .row.cols-lg-2 > * { - max-width: 16.66667%; - flex-basis: 16.66667%; - } - .col-lg-offset-1 { - margin-left: 8.33333%; - } - .col-lg-3, - .row.cols-lg-3 > * { - max-width: 25%; - flex-basis: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66667%; - } - .col-lg-4, - .row.cols-lg-4 > * { - max-width: 33.33333%; - flex-basis: 33.33333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-5, - .row.cols-lg-5 > * { - max-width: 41.66667%; - flex-basis: 41.66667%; - } - .col-lg-offset-4 { - margin-left: 33.33333%; - } - .col-lg-6, - .row.cols-lg-6 > * { - max-width: 50%; - flex-basis: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66667%; - } - .col-lg-7, - .row.cols-lg-7 > * { - max-width: 58.33333%; - flex-basis: 58.33333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-8, - .row.cols-lg-8 > * { - max-width: 66.66667%; - flex-basis: 66.66667%; - } - .col-lg-offset-7 { - margin-left: 58.33333%; - } - .col-lg-9, - .row.cols-lg-9 > * { - max-width: 75%; - flex-basis: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66667%; - } - .col-lg-10, - .row.cols-lg-10 > * { - max-width: 83.33333%; - flex-basis: 83.33333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-11, - .row.cols-lg-11 > * { - max-width: 91.66667%; - flex-basis: 91.66667%; - } - .col-lg-offset-10 { - margin-left: 83.33333%; - } - .col-lg-12, - .row.cols-lg-12 > * { - max-width: 100%; - flex-basis: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66667%; - } - .col-lg-normal { - order: initial; - } - .col-lg-first { - order: -999; - } - .col-lg-last { - order: 999; - } -} - -/* Card component CSS variable definitions */ -:root { - --card-back-color: #eceff4; - --card-fore-color: #2e3440; - --card-border-color: #e5e9f0; -} - -.card { - display: flex; - flex-direction: column; - justify-content: space-between; - align-self: center; - position: relative; - width: 100%; - background: var(--card-back-color); - color: var(--card-fore-color); - border: 0.0625rem solid var(--card-border-color); - border-radius: var(--universal-border-radius); - margin: var(--universal-margin); - overflow: hidden; -} - -@media screen and (min-width: 320px) { - .card { - max-width: 320px; - } -} + background: #b0b0b0; + border-left: 0.3rem solid #FF7E5F; + overflow-y: hidden; } + pre > code { + border-radius: 0; + display: block; + padding: 1rem 1.5rem; + white-space: pre; } -.card > .section { - background: var(--card-back-color); - color: var(--card-fore-color); - box-sizing: border-box; - margin: 0; +hr { border: 0; - border-radius: 0; - border-bottom: 0.0625rem solid var(--card-border-color); - padding: var(--universal-padding); - width: 100%; -} - -.card > .section.media { - height: 200px; - padding: 0; - -o-object-fit: cover; - object-fit: cover; -} - -.card > .section:last-child { - border-bottom: 0; -} - -/* - Custom elements for card elements. -*/ -@media screen and (min-width: 240px) { - .card.small { - max-width: 240px; - } -} - -@media screen and (min-width: 480px) { - .card.large { - max-width: 480px; - } -} - -.card.fluid { - max-width: 100%; - width: auto; -} - -.card.warning { - --card-back-color: #ebcb8b; - --card-border-color: #d08770; -} - -.card.error { - --card-back-color: #bf616a; - --card-border-color: #434c5e; -} - -.card > .section.dark { - --card-back-color: #d8dee9; -} - -.card > .section.double-padded { - padding: calc(1.5 * var(--universal-padding)); -} - -/* - Definitions for forms and input elements. -*/ -/* Input_control module CSS variable definitions */ -:root { - --form-back-color: #e5e9f0; - --form-fore-color: #2e3440; - --form-border-color: #e5e9f0; - --input-back-color: #eceff4; - --input-fore-color: #2e3440; - --input-border-color: #e5e9f0; - --input-focus-color: #88c0d0; - --input-invalid-color: #bf616a; - --button-back-color: #e5e9f0; - --button-hover-back-color: #d8dee9; - --button-fore-color: #2e3440; - --button-border-color: transparent; - --button-hover-border-color: transparent; - --button-group-border-color: rgba(124, 124, 124, 0.54); -} - -form { - background: var(--form-back-color); - color: var(--form-fore-color); - border: 0.0625rem solid var(--form-border-color); - border-radius: var(--universal-border-radius); - margin: var(--universal-margin); - padding: calc(2 * var(--universal-padding)) var(--universal-padding); -} - -fieldset { - border: 0.0625rem solid var(--form-border-color); - border-radius: var(--universal-border-radius); - margin: calc(var(--universal-margin) / 4); - padding: var(--universal-padding); -} - -legend { - box-sizing: border-box; - display: table; - max-width: 100%; - white-space: normal; - font-weight: 700; - padding: calc(var(--universal-padding) / 2); -} - -label { - padding: calc(var(--universal-padding) / 2) var(--universal-padding); -} - -.input-group { - display: inline-block; -} - -.input-group.fluid { - display: flex; - align-items: center; - justify-content: center; -} - -.input-group.fluid > input { - max-width: 100%; - flex-grow: 1; - flex-basis: 0px; -} - -@media screen and (max-width: 767px) { - .input-group.fluid { - align-items: stretch; - flex-direction: column; - } -} - -.input-group.vertical { - display: flex; - align-items: stretch; - flex-direction: column; -} - -.input-group.vertical > input { - max-width: 100%; - flex-grow: 1; - flex-basis: 0px; -} - -[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { - height: auto; -} - -[type="search"] { - -webkit-appearance: textfield; - outline-offset: -2px; -} - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"], -[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select { - box-sizing: border-box; - background: var(--input-back-color); - color: var(--input-fore-color); - border: 0.0625rem solid var(--input-border-color); - border-radius: var(--universal-border-radius); - margin: calc(var(--universal-margin) / 2); - padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); -} - -input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus { - border-color: var(--input-focus-color); - box-shadow: none; -} - -input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid { - border-color: var(--input-invalid-color); - box-shadow: none; -} - -input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] { - background: var(--secondary-back-color); -} - + border-top: 0.1rem solid #b0b0b0; + margin: 3.0rem 0; } + +input[type='color'], +input[type='date'], +input[type='datetime'], +input[type='datetime-local'], +input[type='email'], +input[type='month'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='url'], +input[type='week'], +input:not([type]), +textarea, select { - max-width: 100%; -} - -option { - overflow: hidden; - text-overflow: ellipsis; -} - -[type="checkbox"], [type="radio"] { -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - position: relative; - height: calc(1rem + var(--universal-padding) / 2); - width: calc(1rem + var(--universal-padding) / 2); - vertical-align: text-bottom; - padding: 0; - flex-basis: calc(1rem + var(--universal-padding) / 2) !important; - flex-grow: 0 !important; -} - -[type="checkbox"]:checked:before, [type="radio"]:checked:before { - position: absolute; -} - -[type="checkbox"]:checked:before { - content: '\2713'; - font-family: sans-serif; - font-size: calc(1rem + var(--universal-padding) / 2); - top: calc(0rem - var(--universal-padding)); - left: calc(var(--universal-padding) / 4); -} - -[type="radio"] { - border-radius: 100%; -} - -[type="radio"]:checked:before { - border-radius: 100%; - content: ''; - top: calc(0.0625rem + var(--universal-padding) / 2); - left: calc(0.0625rem + var(--universal-padding) / 2); - background: var(--input-fore-color); - width: 0.5rem; - height: 0.5rem; -} - -:placeholder-shown { - color: var(--input-fore-color); -} - -::-ms-placeholder { - color: var(--input-fore-color); - opacity: 0.54; -} - -button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -button, html [type="button"], [type="reset"], [type="submit"] { - -webkit-appearance: button; -} - -button { - overflow: visible; - text-transform: none; -} - -button, [type="button"], [type="submit"], [type="reset"], -a.button, label.button, .button, -a[role="button"], label[role="button"], [role="button"] { - display: inline-block; - background: var(--button-back-color); - color: var(--button-fore-color); - border: 0.0625rem solid var(--button-border-color); - border-radius: var(--universal-border-radius); - padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); - margin: var(--universal-margin); - text-decoration: none; - cursor: pointer; - transition: background 0.3s; -} - -button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus, -a.button:hover, -a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus, -a[role="button"]:hover, -a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus { - background: var(--button-hover-back-color); - border-color: var(--button-hover-border-color); -} - -input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] { - cursor: not-allowed; - opacity: 0.75; -} - -.button-group { - display: flex; - border: 0.0625rem solid var(--button-group-border-color); - border-radius: var(--universal-border-radius); - margin: var(--universal-margin); -} - -.button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], -.button-group > .button, .button-group > [role="button"] { - margin: 0; - max-width: 100%; - flex: 1 1 auto; - text-align: center; - border: 0; - border-radius: 0; + background-color: transparent; + border: 0.1rem solid #d1d1d1; + border-radius: .4rem; box-shadow: none; -} - -.button-group > :not(:first-child) { - border-left: 0.0625rem solid var(--button-group-border-color); -} - -@media screen and (max-width: 767px) { - .button-group { - flex-direction: column; - } - .button-group > :not(:first-child) { - border: 0; - border-top: 0.0625rem solid var(--button-group-border-color); - } -} - -/* - Custom elements for forms and input elements. -*/ -button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary { - --button-back-color: #5e81ac; - --button-fore-color: #eceff4; -} - -button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus { - --button-hover-back-color: #5e81ac; -} - -button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary { - --button-back-color: #bf616a; - --button-fore-color: #eceff4; -} - -button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus { - --button-hover-back-color: #bf616a; -} - -button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary { - --button-back-color: #a3be8c; - --button-fore-color: #434c5e; -} - -button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus { - --button-hover-back-color: #a3be8c; -} - -button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse { - --button-back-color: #3b4252; - --button-fore-color: #eceff4; -} - -button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus { - --button-hover-back-color: #2e3440; -} - -button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small { - padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding)); - margin: var(--universal-margin); -} - -button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large { - padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding)); - margin: var(--universal-margin); -} - -/* - Definitions for navigation elements. -*/ -/* Navigation module CSS variable definitions */ -:root { - --header-back-color: #eceff4; - --header-hover-back-color: #e5e9f0; - --header-fore-color: #3b4252; - --header-border-color: #e5e9f0; - --nav-back-color: #eceff4; - --nav-hover-back-color: #e5e9f0; - --nav-fore-color: #3b4252; - --nav-border-color: #e5e9f0; - --nav-link-color: #88c0d0; - --footer-fore-color: #3b4252; - --footer-back-color: #eceff4; - --footer-border-color: #e5e9f0; - --footer-link-color: #88c0d0; - --drawer-back-color: #eceff4; - --drawer-hover-back-color: #e5e9f0; - --drawer-border-color: #e5e9f0; - --drawer-close-color: #3b4252; -} - -header { - height: 3.1875rem; - background: var(--header-back-color); - color: var(--header-fore-color); - border-bottom: 0.0625rem solid var(--header-border-color); - padding: calc(var(--universal-padding) / 4) 0; - white-space: nowrap; - overflow-x: auto; - overflow-y: hidden; -} - -header.row { - box-sizing: content-box; -} - -header .logo { - color: var(--header-fore-color); - font-size: 1.75rem; - padding: var(--universal-padding) calc(2 * var(--universal-padding)); - text-decoration: none; -} - -header button, header [type="button"], header .button, header [role="button"] { - box-sizing: border-box; - position: relative; - top: calc(0rem - var(--universal-padding) / 4); - height: calc(3.1875rem + var(--universal-padding) / 2); - background: var(--header-back-color); - line-height: calc(3.1875rem - var(--universal-padding) * 1.5); - text-align: center; - color: var(--header-fore-color); - border: 0; - border-radius: 0; - margin: 0; - text-transform: uppercase; -} - -header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus { - background: var(--header-hover-back-color); -} - -nav { - background: var(--nav-back-color); - color: var(--nav-fore-color); - border: 0.0625rem solid var(--nav-border-color); - border-radius: var(--universal-border-radius); - margin: var(--universal-margin); -} + box-sizing: inherit; + height: 3.8rem; + padding: .6rem 1.0rem .7rem; + width: 100%; } + input[type='color']:focus, + input[type='date']:focus, + input[type='datetime']:focus, + input[type='datetime-local']:focus, + input[type='email']:focus, + input[type='month']:focus, + input[type='number']:focus, + input[type='password']:focus, + input[type='search']:focus, + input[type='tel']:focus, + input[type='text']:focus, + input[type='url']:focus, + input[type='week']:focus, + input:not([type]):focus, + textarea:focus, + select:focus { + border-color: #FF7E5F; + outline: 0; } -nav * { - padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); -} - -nav a, nav a:visited { - display: block; - color: var(--nav-link-color); - border-radius: var(--universal-border-radius); - transition: background 0.3s; -} - -nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus { - text-decoration: none; - background: var(--nav-hover-back-color); -} - -nav .sublink-1 { - position: relative; - margin-left: calc(2 * var(--universal-padding)); -} - -nav .sublink-1:before { - position: absolute; - left: calc(var(--universal-padding) - 1 * var(--universal-padding)); - top: -0.0625rem; - content: ''; - height: 100%; - border: 0.0625rem solid var(--nav-border-color); - border-left: 0; -} - -nav .sublink-2 { - position: relative; - margin-left: calc(4 * var(--universal-padding)); -} - -nav .sublink-2:before { - position: absolute; - left: calc(var(--universal-padding) - 3 * var(--universal-padding)); - top: -0.0625rem; - content: ''; - height: 100%; - border: 0.0625rem solid var(--nav-border-color); - border-left: 0; -} - -footer { - background: var(--footer-back-color); - color: var(--footer-fore-color); - border-top: 0.0625rem solid var(--footer-border-color); - padding: calc(2 * var(--universal-padding)) var(--universal-padding); - font-size: 0.875rem; -} - -footer a, footer a:visited { - color: var(--footer-link-color); -} - -header.sticky { - position: -webkit-sticky; - position: sticky; - z-index: 1101; - top: 0; -} - -footer.sticky { - position: -webkit-sticky; - position: sticky; - z-index: 1101; - bottom: 0; -} - -.drawer-toggle:before { - display: inline-block; - position: relative; - vertical-align: bottom; - content: '\00a0\2261\00a0'; - font-family: sans-serif; - font-size: 1.5em; -} - -@media screen and (min-width: 768px) { - .drawer-toggle:not(.persistent) { - display: none; - } -} - -[type="checkbox"].drawer { - height: 1px; - width: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); -} - -[type="checkbox"].drawer + * { - display: block; - box-sizing: border-box; - position: fixed; - top: 0; - width: 320px; - height: 100vh; - overflow-y: auto; - background: var(--drawer-back-color); - border: 0.0625rem solid var(--drawer-border-color); - border-radius: 0; - margin: 0; - z-index: 1110; - right: -320px; - transition: right 0.3s; -} - -[type="checkbox"].drawer + * .drawer-close { - position: absolute; - top: var(--universal-margin); - right: var(--universal-margin); - z-index: 1111; - width: 2rem; - height: 2rem; - border-radius: var(--universal-border-radius); - padding: var(--universal-padding); - margin: 0; - cursor: pointer; - transition: background 0.3s; -} - -[type="checkbox"].drawer + * .drawer-close:before { +select { + background: url('data:image/svg+xml;utf8,') center right no-repeat; + padding-right: 3.0rem; } + select:focus { + background-image: url('data:image/svg+xml;utf8,'); } + select[multiple] { + background: none; + height: auto; } + +textarea { + min-height: 6.5rem; } + +label, +legend { display: block; - content: '\00D7'; - color: var(--drawer-close-color); - position: relative; - font-family: sans-serif; - font-size: 2rem; - line-height: 1; - text-align: center; -} - -[type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus { - background: var(--drawer-hover-back-color); -} - -@media screen and (max-width: 320px) { - [type="checkbox"].drawer + * { - width: 100%; - } -} - -[type="checkbox"].drawer:checked + * { - right: 0; -} - -@media screen and (min-width: 768px) { - [type="checkbox"].drawer:not(.persistent) + * { - position: static; - height: 100%; - z-index: 1100; - } - [type="checkbox"].drawer:not(.persistent) + * .drawer-close { - display: none; - } -} - -/* - Definitions for the responsive table component. -*/ -/* Table module CSS variable definitions. */ -:root { - --table-border-color: #d8dee9; - --table-border-separator-color: #434c5e; - --table-head-back-color: #e5e9f0; - --table-head-fore-color: #2e3440; - --table-body-back-color: #eceff4; - --table-body-fore-color: #2e3440; - --table-body-alt-back-color: #e5e9f0; -} - -table { - border-collapse: separate; - border-spacing: 0; - margin: 0; - display: flex; - flex: 0 1 auto; - flex-flow: row wrap; - padding: var(--universal-padding); - padding-top: 0; -} - -table caption { - font-size: 1.5rem; - margin: calc(2 * var(--universal-margin)) 0; - max-width: 100%; - flex: 0 0 100%; -} - -table thead, table tbody { - display: flex; - flex-flow: row wrap; - border: 0.0625rem solid var(--table-border-color); -} - -table thead { - z-index: 999; - border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; - border-bottom: 0.0625rem solid var(--table-border-separator-color); -} - -table tbody { - border-top: 0; - margin-top: calc(0 - var(--universal-margin)); - border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); -} - -table tr { - display: flex; - padding: 0; -} - -table th, table td { - padding: calc(2 * var(--universal-padding)); -} - -table th { - text-align: left; - background: var(--table-head-back-color); - color: var(--table-head-fore-color); -} - -table td { - background: var(--table-body-back-color); - color: var(--table-body-fore-color); - border-top: 0.0625rem solid var(--table-border-color); -} - -table:not(.horizontal) { - overflow: auto; - max-height: 400px; -} - -table:not(.horizontal) thead, table:not(.horizontal) tbody { - max-width: 100%; - flex: 0 0 100%; -} - -table:not(.horizontal) tr { - flex-flow: row wrap; - flex: 0 0 100%; -} - -table:not(.horizontal) th, table:not(.horizontal) td { - flex: 1 0 0%; - overflow: hidden; - text-overflow: ellipsis; -} - -table:not(.horizontal) thead { - position: sticky; - top: 0; -} - -table:not(.horizontal) tbody tr:first-child td { - border-top: 0; -} - -table.horizontal { - border: 0; -} - -table.horizontal thead, table.horizontal tbody { - border: 0; - flex: .2 0 0; - flex-flow: row nowrap; -} - -table.horizontal tbody { - overflow: auto; - justify-content: space-between; - flex: .8 0 0; - margin-left: 0; - padding-bottom: calc(var(--universal-padding) / 4); -} - -table.horizontal tr { - flex-direction: column; - flex: 1 0 auto; -} - -table.horizontal th, table.horizontal td { - width: auto; - border: 0; - border-bottom: 0.0625rem solid var(--table-border-color); -} - -table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) { - border-top: 0; -} - -table.horizontal th { - text-align: right; - border-left: 0.0625rem solid var(--table-border-color); - border-right: 0.0625rem solid var(--table-border-separator-color); -} - -table.horizontal thead tr:first-child { - padding-left: 0; -} - -table.horizontal th:first-child, table.horizontal td:first-child { - border-top: 0.0625rem solid var(--table-border-color); -} - -table.horizontal tbody tr:last-child td { - border-right: 0.0625rem solid var(--table-border-color); -} - -table.horizontal tbody tr:last-child td:first-child { - border-top-right-radius: 0.25rem; -} - -table.horizontal tbody tr:last-child td:last-child { - border-bottom-right-radius: 0.25rem; -} - -table.horizontal thead tr:first-child th:first-child { - border-top-left-radius: 0.25rem; -} - -table.horizontal thead tr:first-child th:last-child { - border-bottom-left-radius: 0.25rem; -} - -@media screen and (max-width: 767px) { - table, table.horizontal { - border-collapse: collapse; - border: 0; - width: 100%; - display: table; - } - table thead, table th, table.horizontal thead, table.horizontal th { - border: 0; - height: 1px; - width: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); - } - table tbody, table.horizontal tbody { - border: 0; - display: table-row-group; - } - table tr, table.horizontal tr { - display: block; - border: 0.0625rem solid var(--table-border-color); - border-radius: var(--universal-border-radius); - background: #fafafa; - padding: var(--universal-padding); - margin: var(--universal-margin); - margin-bottom: calc(2 * var(--universal-margin)); - } - table th, table td, table.horizontal th, table.horizontal td { - width: auto; - } - table td, table.horizontal td { - display: block; - border: 0; - text-align: right; - } - table td:before, table.horizontal td:before { - content: attr(data-label); - float: left; - font-weight: 600; - } - table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child { - border-top: 0; - } - table tbody tr:last-child td, table.horizontal tbody tr:last-child td { - border-right: 0; - } -} - -:root { - --table-body-alt-back-color: #e5e9f0; -} - -table.striped tr:nth-of-type(2n) > td { - background: var(--table-body-alt-back-color); -} - -@media screen and (max-width: 768px) { - table.striped tr:nth-of-type(2n) { - background: var(--table-body-alt-back-color); - } -} - -:root { - --table-body-hover-back-color: #88c0d0; -} - -table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { - background: var(--table-body-hover-back-color); -} - -@media screen and (max-width: 768px) { - table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { - background: var(--table-body-hover-back-color); - } -} - -/* - Definitions for contextual background elements, toasts and tooltips. -*/ -/* Contextual module CSS variable definitions */ -:root { - --mark-back-color: #5e81ac; - --mark-fore-color: #fafafa; -} - -mark { - background: var(--mark-back-color); - color: var(--mark-fore-color); - font-size: 0.95em; - line-height: 1em; - border-radius: var(--universal-border-radius); - padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); -} - -mark.inline-block { - display: inline-block; - font-size: 1em; - line-height: 1.5; - padding: calc(var(--universal-padding) / 2) var(--universal-padding); -} - -:root { - --toast-back-color: #2e3440; - --toast-fore-color: #eceff4; -} + font-size: 1.6rem; + font-weight: 700; + margin-bottom: .5rem; } -.toast { - position: fixed; - bottom: calc(var(--universal-margin) * 3); - left: 50%; - transform: translate(-50%, -50%); - z-index: 1111; - color: var(--toast-fore-color); - background: var(--toast-back-color); - border-radius: calc(var(--universal-border-radius) * 16); - padding: var(--universal-padding) calc(var(--universal-padding) * 3); -} +fieldset { + border-width: 0; + padding: 0; } -:root { - --tooltip-back-color: #2e3440; - --tooltip-fore-color: #eceff4; -} +input[type='checkbox'], +input[type='radio'] { + display: inline; } -.tooltip { - position: relative; +.label-inline { display: inline-block; -} - -.tooltip:before, .tooltip:after { - position: absolute; - opacity: 0; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); - transition: all 0.3s; - z-index: 1010; - left: 50%; -} - -.tooltip:not(.bottom):before, .tooltip:not(.bottom):after { - bottom: 75%; -} - -.tooltip.bottom:before, .tooltip.bottom:after { - top: 75%; -} - -.tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after { - opacity: 1; - clip: auto; - -webkit-clip-path: inset(0%); - clip-path: inset(0%); -} - -.tooltip:before { - content: ''; - background: transparent; - border: var(--universal-margin) solid transparent; - left: calc(50% - var(--universal-margin)); -} - -.tooltip:not(.bottom):before { - border-top-color: #2e3440; -} - -.tooltip.bottom:before { - border-bottom-color: #2e3440; -} - -.tooltip:after { - content: attr(aria-label); - color: var(--tooltip-fore-color); - background: var(--tooltip-back-color); - border-radius: var(--universal-border-radius); - padding: var(--universal-padding); - white-space: nowrap; - transform: translateX(-50%); -} - -.tooltip:not(.bottom):after { - margin-bottom: calc(2 * var(--universal-margin)); -} - -.tooltip.bottom:after { - margin-top: calc(2 * var(--universal-margin)); -} + font-weight: normal; + margin-left: .5rem; } -:root { - --modal-overlay-color: rgba(0, 0, 0, 0.45); - --modal-close-color: #3b4252; - --modal-close-hover-color: #e5e9f0; -} - -[type="checkbox"].modal { - height: 1px; - width: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); -} - -[type="checkbox"].modal + div { - position: fixed; - top: 0; - left: 0; - display: none; - width: 100vw; - height: 100vh; - background: var(--modal-overlay-color); -} - -[type="checkbox"].modal + div .card { +.container { margin: 0 auto; - max-height: 50vh; - overflow: auto; -} - -[type="checkbox"].modal + div .card .modal-close { - position: absolute; - top: 0; - right: 0; - width: 1.75rem; - height: 1.75rem; - border-radius: var(--universal-border-radius); - padding: var(--universal-padding); - margin: 0; - cursor: pointer; - transition: background 0.3s; -} - -[type="checkbox"].modal + div .card .modal-close:before { - display: block; - content: '\00D7'; - color: var(--modal-close-color); + max-width: 112.0rem; + padding: 0 2.0rem; position: relative; - font-family: sans-serif; - font-size: 1.75rem; - line-height: 1; - text-align: center; -} - -[type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus { - background: var(--modal-close-hover-color); -} + width: 100%; } -[type="checkbox"].modal:checked + div { - display: flex; - flex: 0 1 auto; - z-index: 1200; -} - -[type="checkbox"].modal:checked + div .card .modal-close { - z-index: 1211; -} - -:root { - --collapse-label-back-color: #e5e9f0; - --collapse-label-fore-color: #2e3440; - --collapse-label-hover-back-color: #e5e9f0; - --collapse-selected-label-back-color: #e5e9f0; - --collapse-border-color: #e5e9f0; - --collapse-content-back-color: #fafafa; - --collapse-selected-label-border-color: #88c0d0; -} - -.collapse { - width: calc(100% - 2 * var(--universal-margin)); - opacity: 1; +.row { display: flex; flex-direction: column; - margin: var(--universal-margin); - border-radius: var(--universal-border-radius); -} - -.collapse > [type="radio"], .collapse > [type="checkbox"] { - height: 1px; - width: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); -} - -.collapse > label { - flex-grow: 1; - display: inline-block; - height: 1.5rem; - cursor: pointer; - transition: background 0.3s; - color: var(--collapse-label-fore-color); - background: var(--collapse-label-back-color); - border: 0.0625rem solid var(--collapse-border-color); - padding: calc(1.5 * var(--universal-padding)); -} - -.collapse > label:hover, .collapse > label:focus { - background: var(--collapse-label-hover-back-color); -} - -.collapse > label + div { - flex-basis: auto; - height: 1px; - width: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - clip: rect(0 0 0 0); - -webkit-clip-path: inset(100%); - clip-path: inset(100%); - transition: max-height 0.3s; - max-height: 1px; -} - -.collapse > :checked + label { - background: var(--collapse-selected-label-back-color); - border-bottom-color: var(--collapse-selected-label-border-color); -} - -.collapse > :checked + label + div { - box-sizing: border-box; - position: relative; - width: 100%; - height: auto; - overflow: auto; - margin: 0; - background: var(--collapse-content-back-color); - border: 0.0625rem solid var(--collapse-border-color); - border-top: 0; - padding: var(--universal-padding); - clip: auto; - -webkit-clip-path: inset(0%); - clip-path: inset(0%); - max-height: 400px; -} - -.collapse > label:not(:first-of-type) { - border-top: 0; -} - -.collapse > label:first-of-type { - border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; -} - -.collapse > label:last-of-type:not(:first-of-type) { - border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); -} - -.collapse > label:last-of-type:first-of-type { - border-radius: var(--universal-border-radius); -} - -.collapse > :checked:last-of-type:not(:first-of-type) + label { - border-radius: 0; -} - -.collapse > :checked:last-of-type + label + div { - border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); -} - -/* - Custom elements for contextual background elements, toasts and tooltips. -*/ -mark.secondary { - --mark-back-color: #bf616a; -} - -mark.tertiary { - --mark-back-color: #a3be8c; -} - -mark.tag { - padding: calc(var(--universal-padding)/2) var(--universal-padding); - border-radius: 1em; -} + padding: 0; + width: 100%; } + .row.row-no-padding { + padding: 0; } + .row.row-no-padding > .column { + padding: 0; } + .row.row-wrap { + flex-wrap: wrap; } + .row.row-top { + align-items: flex-start; } + .row.row-bottom { + align-items: flex-end; } + .row.row-center { + align-items: center; } + .row.row-stretch { + align-items: stretch; } + .row.row-baseline { + align-items: baseline; } + .row .column { + display: block; + flex: 1 1 auto; + margin-left: 0; + max-width: 100%; + width: 100%; } + .row .column.column-offset-10 { + margin-left: 10%; } + .row .column.column-offset-20 { + margin-left: 20%; } + .row .column.column-offset-25 { + margin-left: 25%; } + .row .column.column-offset-33, .row .column.column-offset-34 { + margin-left: 33.3333%; } + .row .column.column-offset-40 { + margin-left: 40%; } + .row .column.column-offset-50 { + margin-left: 50%; } + .row .column.column-offset-60 { + margin-left: 60%; } + .row .column.column-offset-66, .row .column.column-offset-67 { + margin-left: 66.6666%; } + .row .column.column-offset-75 { + margin-left: 75%; } + .row .column.column-offset-80 { + margin-left: 80%; } + .row .column.column-offset-90 { + margin-left: 90%; } + .row .column.column-10 { + flex: 0 0 10%; + max-width: 10%; } + .row .column.column-20 { + flex: 0 0 20%; + max-width: 20%; } + .row .column.column-25 { + flex: 0 0 25%; + max-width: 25%; } + .row .column.column-33, .row .column.column-34 { + flex: 0 0 33.3333%; + max-width: 33.3333%; } + .row .column.column-40 { + flex: 0 0 40%; + max-width: 40%; } + .row .column.column-50 { + flex: 0 0 50%; + max-width: 50%; } + .row .column.column-60 { + flex: 0 0 60%; + max-width: 60%; } + .row .column.column-66, .row .column.column-67 { + flex: 0 0 66.6666%; + max-width: 66.6666%; } + .row .column.column-75 { + flex: 0 0 75%; + max-width: 75%; } + .row .column.column-80 { + flex: 0 0 80%; + max-width: 80%; } + .row .column.column-90 { + flex: 0 0 90%; + max-width: 90%; } + .row .column .column-top { + align-self: flex-start; } + .row .column .column-bottom { + align-self: flex-end; } + .row .column .column-center { + align-self: center; } + +@media (min-width: 40rem) { + .row { + flex-direction: row; + margin-left: -1.0rem; + width: calc(100% + 2.0rem); } + .row .column { + margin-bottom: inherit; + padding: 0 1.0rem; } } -/* - Definitions for progress elements and spinners. -*/ -/* Progess module CSS variable definitions */ -:root { - --progress-back-color: #e5e9f0; - --progress-fore-color: #434c5e; -} +a { + color: #FF7E5F; + text-decoration: none; } + a:focus, a:hover { + color: #351C4D; } + +dl, +ol, +ul { + list-style: none; + margin-top: 0; + padding-left: 0; } + dl dl, + dl ol, + dl ul, + ol dl, + ol ol, + ol ul, + ul dl, + ul ol, + ul ul { + font-size: 90%; + margin: 1.5rem 0 1.5rem 3.0rem; } + +ol { + list-style: decimal inside; } + +ul { + list-style: circle inside; } + +.button, +button, +dd, +dt, +li { + margin-bottom: 1.0rem; } + +fieldset, +input, +select, +textarea { + margin-bottom: 1.5rem; } + +blockquote, +dl, +figure, +form, +ol, +p, +pre, +table, +ul { + margin-bottom: 2.5rem; } -progress { +table { + border-spacing: 0; display: block; - vertical-align: baseline; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - height: 0.75rem; - width: calc(100% - 2 * var(--universal-margin)); - margin: var(--universal-margin); - border: 0; - border-radius: calc(2 * var(--universal-border-radius)); - background: var(--progress-back-color); - color: var(--progress-fore-color); -} - -progress::-webkit-progress-value { - background: var(--progress-fore-color); - border-top-left-radius: calc(2 * var(--universal-border-radius)); - border-bottom-left-radius: calc(2 * var(--universal-border-radius)); -} - -progress::-webkit-progress-bar { - background: var(--progress-back-color); -} - -progress::-moz-progress-bar { - background: var(--progress-fore-color); - border-top-left-radius: calc(2 * var(--universal-border-radius)); - border-bottom-left-radius: calc(2 * var(--universal-border-radius)); -} - -progress[value="1000"]::-webkit-progress-value { - border-radius: calc(2 * var(--universal-border-radius)); -} - -progress[value="1000"]::-moz-progress-bar { - border-radius: calc(2 * var(--universal-border-radius)); -} - -progress.inline { - display: inline-block; - vertical-align: middle; - width: 60%; -} - -:root { - --spinner-back-color: #d8dee9; - --spinner-fore-color: #434c5e; -} - -@keyframes spinner-donut-anim { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -.spinner { - display: inline-block; - margin: var(--universal-margin); - border: 0.25rem solid var(--spinner-back-color); - border-left: 0.25rem solid var(--spinner-fore-color); - border-radius: 50%; - width: 1.25rem; - height: 1.25rem; - animation: spinner-donut-anim 1.2s linear infinite; -} - -/* - Custom elements for progress bars and spinners. -*/ -progress.primary { - --progress-fore-color: #5e81ac; -} - -progress.secondary { - --progress-fore-color: #bf616a; -} - -progress.tertiary { - --progress-fore-color: #a3be8c; -} - -.spinner.primary { - --spinner-fore-color: #5e81ac; -} - -.spinner.secondary { - --spinner-fore-color: #bf616a; -} - -.spinner.tertiary { - --spinner-fore-color: #a3be8c; -} - -/* - Definitions for icons - powered by Feather (https://feathericons.com/). -*/ -span[class^='icon-'] { - display: inline-block; - height: 1em; - width: 1em; - vertical-align: -0.125em; - background-size: contain; - margin: 0 calc(var(--universal-margin) / 4); -} - -span[class^='icon-'].secondary { - -webkit-filter: invert(25%); - filter: invert(25%); -} - -span[class^='icon-'].inverse { - -webkit-filter: invert(100%); - filter: invert(100%); -} - -span.icon-alert { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-bookmark { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); -} - -span.icon-calendar { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-credit { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-edit { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); -} - -span.icon-link { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-help { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-home { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); -} - -span.icon-info { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-lock { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); -} - -span.icon-mail { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); -} - -span.icon-location { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); -} - -span.icon-phone { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); -} - -span.icon-rss { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); -} - -span.icon-search { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-settings { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); -} - -span.icon-share { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-cart { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); -} - -span.icon-upload { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); -} - -span.icon-user { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); -} - -/* - Definitions for utilities and helper classes. -*/ -/* Utility module CSS variable definitions */ -:root { - --generic-border-color: rgba(0, 0, 0, 0.3); - --generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.125); -} - -.hidden { - display: none !important; -} - -.visually-hidden { - position: absolute !important; - width: 1px !important; - height: 1px !important; - margin: -1px !important; - border: 0 !important; - padding: 0 !important; - clip: rect(0 0 0 0) !important; - -webkit-clip-path: inset(100%) !important; - clip-path: inset(100%) !important; - overflow: hidden !important; -} - -.bordered { - border: 0.0625rem solid var(--generic-border-color) !important; -} - -.rounded { - border-radius: var(--universal-border-radius) !important; -} - -.circular { - border-radius: 50% !important; -} + overflow-x: auto; + text-align: left; + width: 100%; } + +td, +th { + border-bottom: 0.1rem solid #e1e1e1; + padding: 1.2rem 1.5rem; } + td:first-child, + th:first-child { + padding-left: 0; } + td:last-child, + th:last-child { + padding-right: 0; } + +@media (min-width: 40rem) { + table { + display: table; + overflow-x: initial; } } -.shadowed { - box-shadow: var(--generic-box-shadow) !important; -} +b, +strong { + font-weight: bold; } -.responsive-margin { - margin: calc(var(--universal-margin) / 4) !important; -} +p { + margin-top: 0; } -@media screen and (min-width: 768px) { - .responsive-margin { - margin: calc(var(--universal-margin) / 2) !important; - } -} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 300; + letter-spacing: -.1rem; + margin-bottom: 2.0rem; + margin-top: 0; } -@media screen and (min-width: 1280px) { - .responsive-margin { - margin: var(--universal-margin) !important; - } -} +h1 { + font-size: 4.6rem; + line-height: 1.2; } -.responsive-padding { - padding: calc(var(--universal-padding) / 4) !important; -} +h2 { + font-size: 3.6rem; + line-height: 1.25; } -@media screen and (min-width: 768px) { - .responsive-padding { - padding: calc(var(--universal-padding) / 2) !important; - } -} +h3 { + font-size: 2.8rem; + line-height: 1.3; } -@media screen and (min-width: 1280px) { - .responsive-padding { - padding: var(--universal-padding) !important; - } -} +h4 { + font-size: 2.2rem; + letter-spacing: -.08rem; + line-height: 1.35; } -@media screen and (max-width: 767px) { - .hidden-sm { - display: none !important; - } -} +h5 { + font-size: 1.8rem; + letter-spacing: -.05rem; + line-height: 1.5; } -@media screen and (min-width: 768px) and (max-width: 1279px) { - .hidden-md { - display: none !important; - } -} +h6 { + font-size: 1.6rem; + letter-spacing: 0; + line-height: 1.4; } -@media screen and (min-width: 1280px) { - .hidden-lg { - display: none !important; - } -} +img { + max-width: 100%; } -@media screen and (max-width: 767px) { - .visually-hidden-sm { - position: absolute !important; - width: 1px !important; - height: 1px !important; - margin: -1px !important; - border: 0 !important; - padding: 0 !important; - clip: rect(0 0 0 0) !important; - -webkit-clip-path: inset(100%) !important; - clip-path: inset(100%) !important; - overflow: hidden !important; - } -} +.clearfix:after { + clear: both; + content: ' '; + display: table; } -@media screen and (min-width: 768px) and (max-width: 1279px) { - .visually-hidden-md { - position: absolute !important; - width: 1px !important; - height: 1px !important; - margin: -1px !important; - border: 0 !important; - padding: 0 !important; - clip: rect(0 0 0 0) !important; - -webkit-clip-path: inset(100%) !important; - clip-path: inset(100%) !important; - overflow: hidden !important; - } -} +.float-left { + float: left; } -@media screen and (min-width: 1280px) { - .visually-hidden-lg { - position: absolute !important; - width: 1px !important; - height: 1px !important; - margin: -1px !important; - border: 0 !important; - padding: 0 !important; - clip: rect(0 0 0 0) !important; - -webkit-clip-path: inset(100%) !important; - clip-path: inset(100%) !important; - overflow: hidden !important; - } -} \ No newline at end of file +.float-right { + float: right; } diff --git a/main/static/index.html b/main/static/index.html index 5aa4192..ce640a6 100644 --- a/main/static/index.html +++ b/main/static/index.html @@ -6,34 +6,42 @@ + + - +
+ MqTrigger v1.1 +
-
- App - System - + +
-
- -
-

Loading

-

Loading content... Please make sure that JavaScript is enabled.

-
- -

+
+

Loading

+

Loading content... Please make sure that JavaScript is enabled.

+
+
-
+

- MqTrigger v1.1 2022 + Copyright© nixlab.in 2022

diff --git a/main/static/index.js b/main/static/index.js index 6b10200..b95d156 100644 --- a/main/static/index.js +++ b/main/static/index.js @@ -5,23 +5,16 @@ function ip2int(ip) { } function sendClickHandler(event) { - console.log("Sending form..."); - //console.debug(event); let form = event.srcElement.form; console.debug(form); let params = ''; Array.from(form.elements).forEach(element => { - console.log(element); - console.log(element.name); - console.log(element.value); - if (element.value) { //TODO: checkbox/radio if (!element.hasAttribute('data-ignore')) { params += params ? '&' : ''; if (element.hasAttribute('data-ip32')) { - console.log("IPv4 32"); params += element.name + '=' + ip2int(element.value); } else { @@ -31,16 +24,9 @@ function sendClickHandler(event) { else { console.log("Ignoring " + element.name); } - } - - }); - - console.log("params: " + params); - postParams(form.getAttribute('action'), params); - console.log("Form sent"); } function initFormSendButtons(form) { @@ -62,7 +48,6 @@ function loadContent(url) { http.onreadystatechange = function () {//Call a function when the state changes. if (http.readyState == 4 && http.status == 200) { - console.log("Content received"); element.innerHTML = http.responseText; loadValues(element); initFormSendButtons(element); @@ -71,11 +56,10 @@ function loadContent(url) { http.send(); } -function fillInputs(element, jsonString) { +function fillInputs(jsonString) { let obj = JSON.parse(jsonString); if (obj) { for (var key of Object.keys(obj)) { - console.log(key + " -> " + obj[key]) let input = element.querySelector("[name='" + key + "'"); if (input) { //TODO: checkbox/radio input.value = obj[key]; @@ -98,13 +82,10 @@ function loadValues(element) { } if (valuesCache[srcUrl]) { - console.log("Source values already cached: " + valuesCache[srcUrl]); - fillInputs(element, valuesCache[srcUrl]); + fillInputs(valuesCache[srcUrl]); continue; } - console.log("Getting values from " + srcUrl); - let http = new XMLHttpRequest(); http.open('GET', srcUrl, false); @@ -113,9 +94,8 @@ function loadValues(element) { http.onreadystatechange = function () {//Call a function when the state changes. if (http.readyState == 4 && http.status == 200) { - console.log("Values received: " + http.responseText); valuesCache[srcUrl] = http.responseText; - fillInputs(element, http.responseText); + fillInputs(http.responseText); } } http.send(); @@ -138,8 +118,6 @@ function postParams(url, params) { } function navClickHandler(event) { - console.log('Button Clicked'); - console.log('Destination: ' + this.getAttribute('data-dst')); loadContent(this.getAttribute('data-dst')); } @@ -179,5 +157,4 @@ function rschSet() { document.getElementById("rsd_" + i.toString()).checked = true; } } - -} \ No newline at end of file +} diff --git a/main/static/min/app.html b/main/static/min/app.html index a90a715..5ce0114 100644 --- a/main/static/min/app.html +++ b/main/static/min/app.html @@ -11,4 +11,5 @@

NOTE: device reboot is required

Restore defaults


Reboot

\ No newline at end of file +

NOTE: device reboot is required

Restore defaults


Reboot

\ No newline at end of file diff --git a/main/static/min/index.css b/main/static/min/index.css index 3a8c646..c107600 100644 --- a/main/static/min/index.css +++ b/main/static/min/index.css @@ -1 +1 @@ -@charset "UTF-8";:root{--fore-color: #2e3440;--secondary-fore-color: #3b4252;--back-color: #eceff4;--secondary-back-color: #e5e9f0;--blockquote-color: #d08770;--pre-color: #b48ead;--border-color: #d8dee9;--secondary-border-color: #e5e9f0;--heading-ratio: 1.19;--universal-margin: 0.5rem;--universal-padding: 0.5rem;--universal-border-radius: 0.125rem;--a-link-color: #88c0d0;--a-visited-color: #5e81ac}html{font-size:16px}a,b,del,em,i,ins,q,span,strong,u{font-size:1em}html,*{font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Ubuntu,helvetica neue,Helvetica,sans-serif;line-height:1.5;-webkit-text-size-adjust:100%}*{font-size:1rem}body{margin:0;color:var(--fore-color);background:var(--back-color)}details{display:block}summary{display:list-item}abbr[title]{border-bottom:none;text-decoration:underline dotted}input{overflow:visible}img{max-width:100%;height:auto}h1,h2,h3,h4,h5,h6{line-height:1.2;margin:calc(1.5 * var(--universal-margin))var(--universal-margin);font-weight:500}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:var(--secondary-fore-color);display:block;margin-top:-.25rem}h1{font-size:calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio))}h2{font-size:calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio))}h3{font-size:calc(1rem * var(--heading-ratio) * var(--heading-ratio))}h4{font-size:calc(1rem * var(--heading-ratio))}h5{font-size:1rem}h6{font-size:calc(1rem/var(--heading-ratio))}p{margin:var(--universal-margin)}ol,ul{margin:var(--universal-margin);padding-left:calc(2 * var(--universal-margin))}b,strong{font-weight:700}hr{box-sizing:content-box;border:0;line-height:1.25em;margin:var(--universal-margin);height:.0625rem;background:linear-gradient(to right,transparent,var(--border-color) 20%,var(--border-color) 80%,transparent)}blockquote{display:block;position:relative;font-style:italic;color:var(--secondary-fore-color);margin:var(--universal-margin);padding:calc(3 * var(--universal-padding));border:.0625rem solid var(--secondary-border-color);border-left:.375rem solid var(--blockquote-color);border-radius:0 var(--universal-border-radius)var(--universal-border-radius)0}blockquote:before{position:absolute;top:calc(0 - var(--universal-padding));left:0;font-family:sans-serif;font-size:3rem;font-weight:700;content:"\201c";color:var(--blockquote-color)}blockquote[cite]:after{font-style:normal;font-size:.75em;font-weight:700;content:"\a— " attr(cite);white-space:pre}code,kbd,pre,samp{font-family:Menlo,Consolas,monospace;font-size:.85em}code{background:var(--secondary-back-color);border-radius:var(--universal-border-radius);padding:calc(var(--universal-padding)/4)calc(var(--universal-padding)/2)}kbd{background:var(--fore-color);color:var(--back-color);border-radius:var(--universal-border-radius);padding:calc(var(--universal-padding)/4)calc(var(--universal-padding)/2)}pre{overflow:auto;background:var(--secondary-back-color);padding:calc(1.5 * var(--universal-padding));margin:var(--universal-margin);border:.0625rem solid var(--secondary-border-color);border-left:.25rem solid var(--pre-color);border-radius:0 var(--universal-border-radius)var(--universal-border-radius)0}sup,sub,code,kbd{line-height:0;position:relative;vertical-align:baseline}small,sup,sub,figcaption{font-size:.75em}sup{top:-.5em}sub{bottom:-.25em}figure{margin:var(--universal-margin)}figcaption{color:var(--secondary-fore-color)}a{text-decoration:none}a:link{color:var(--a-link-color)}a:visited{color:var(--a-visited-color)}a:hover,a:focus{text-decoration:underline}.container{margin:0 auto;padding:0 calc(1.5 * var(--universal-padding))}.row{box-sizing:border-box;display:flex;flex:0 1;flex-flow:row wrap}.col-sm,[class^=col-sm-],[class^=col-sm-offset-],.row[class*=cols-sm-]>*{box-sizing:border-box;flex:0 0;padding:0 calc(var(--universal-padding)/2)}.col-sm,.row.cols-sm>*{max-width:100%;flex-grow:1;flex-basis:0}.col-sm-1,.row.cols-sm-1>*{max-width:8.33333%;flex-basis:8.33333%}.col-sm-offset-0{margin-left:0}.col-sm-2,.row.cols-sm-2>*{max-width:16.66667%;flex-basis:16.66667%}.col-sm-offset-1{margin-left:8.33333%}.col-sm-3,.row.cols-sm-3>*{max-width:25%;flex-basis:25%}.col-sm-offset-2{margin-left:16.66667%}.col-sm-4,.row.cols-sm-4>*{max-width:33.33333%;flex-basis:33.33333%}.col-sm-offset-3{margin-left:25%}.col-sm-5,.row.cols-sm-5>*{max-width:41.66667%;flex-basis:41.66667%}.col-sm-offset-4{margin-left:33.33333%}.col-sm-6,.row.cols-sm-6>*{max-width:50%;flex-basis:50%}.col-sm-offset-5{margin-left:41.66667%}.col-sm-7,.row.cols-sm-7>*{max-width:58.33333%;flex-basis:58.33333%}.col-sm-offset-6{margin-left:50%}.col-sm-8,.row.cols-sm-8>*{max-width:66.66667%;flex-basis:66.66667%}.col-sm-offset-7{margin-left:58.33333%}.col-sm-9,.row.cols-sm-9>*{max-width:75%;flex-basis:75%}.col-sm-offset-8{margin-left:66.66667%}.col-sm-10,.row.cols-sm-10>*{max-width:83.33333%;flex-basis:83.33333%}.col-sm-offset-9{margin-left:75%}.col-sm-11,.row.cols-sm-11>*{max-width:91.66667%;flex-basis:91.66667%}.col-sm-offset-10{margin-left:83.33333%}.col-sm-12,.row.cols-sm-12>*{max-width:100%;flex-basis:100%}.col-sm-offset-11{margin-left:91.66667%}.col-sm-normal{order:0}.col-sm-first{order:-999}.col-sm-last{order:999}@media screen and (min-width:768px){.col-md,[class^=col-md-],[class^=col-md-offset-],.row[class*=cols-md-]>*{box-sizing:border-box;flex:0 0;padding:0 calc(var(--universal-padding)/2)}.col-md,.row.cols-md>*{max-width:100%;flex-grow:1;flex-basis:0}.col-md-1,.row.cols-md-1>*{max-width:8.33333%;flex-basis:8.33333%}.col-md-offset-0{margin-left:0}.col-md-2,.row.cols-md-2>*{max-width:16.66667%;flex-basis:16.66667%}.col-md-offset-1{margin-left:8.33333%}.col-md-3,.row.cols-md-3>*{max-width:25%;flex-basis:25%}.col-md-offset-2{margin-left:16.66667%}.col-md-4,.row.cols-md-4>*{max-width:33.33333%;flex-basis:33.33333%}.col-md-offset-3{margin-left:25%}.col-md-5,.row.cols-md-5>*{max-width:41.66667%;flex-basis:41.66667%}.col-md-offset-4{margin-left:33.33333%}.col-md-6,.row.cols-md-6>*{max-width:50%;flex-basis:50%}.col-md-offset-5{margin-left:41.66667%}.col-md-7,.row.cols-md-7>*{max-width:58.33333%;flex-basis:58.33333%}.col-md-offset-6{margin-left:50%}.col-md-8,.row.cols-md-8>*{max-width:66.66667%;flex-basis:66.66667%}.col-md-offset-7{margin-left:58.33333%}.col-md-9,.row.cols-md-9>*{max-width:75%;flex-basis:75%}.col-md-offset-8{margin-left:66.66667%}.col-md-10,.row.cols-md-10>*{max-width:83.33333%;flex-basis:83.33333%}.col-md-offset-9{margin-left:75%}.col-md-11,.row.cols-md-11>*{max-width:91.66667%;flex-basis:91.66667%}.col-md-offset-10{margin-left:83.33333%}.col-md-12,.row.cols-md-12>*{max-width:100%;flex-basis:100%}.col-md-offset-11{margin-left:91.66667%}.col-md-normal{order:0}.col-md-first{order:-999}.col-md-last{order:999}}@media screen and (min-width:1280px){.col-lg,[class^=col-lg-],[class^=col-lg-offset-],.row[class*=cols-lg-]>*{box-sizing:border-box;flex:0 0;padding:0 calc(var(--universal-padding)/2)}.col-lg,.row.cols-lg>*{max-width:100%;flex-grow:1;flex-basis:0}.col-lg-1,.row.cols-lg-1>*{max-width:8.33333%;flex-basis:8.33333%}.col-lg-offset-0{margin-left:0}.col-lg-2,.row.cols-lg-2>*{max-width:16.66667%;flex-basis:16.66667%}.col-lg-offset-1{margin-left:8.33333%}.col-lg-3,.row.cols-lg-3>*{max-width:25%;flex-basis:25%}.col-lg-offset-2{margin-left:16.66667%}.col-lg-4,.row.cols-lg-4>*{max-width:33.33333%;flex-basis:33.33333%}.col-lg-offset-3{margin-left:25%}.col-lg-5,.row.cols-lg-5>*{max-width:41.66667%;flex-basis:41.66667%}.col-lg-offset-4{margin-left:33.33333%}.col-lg-6,.row.cols-lg-6>*{max-width:50%;flex-basis:50%}.col-lg-offset-5{margin-left:41.66667%}.col-lg-7,.row.cols-lg-7>*{max-width:58.33333%;flex-basis:58.33333%}.col-lg-offset-6{margin-left:50%}.col-lg-8,.row.cols-lg-8>*{max-width:66.66667%;flex-basis:66.66667%}.col-lg-offset-7{margin-left:58.33333%}.col-lg-9,.row.cols-lg-9>*{max-width:75%;flex-basis:75%}.col-lg-offset-8{margin-left:66.66667%}.col-lg-10,.row.cols-lg-10>*{max-width:83.33333%;flex-basis:83.33333%}.col-lg-offset-9{margin-left:75%}.col-lg-11,.row.cols-lg-11>*{max-width:91.66667%;flex-basis:91.66667%}.col-lg-offset-10{margin-left:83.33333%}.col-lg-12,.row.cols-lg-12>*{max-width:100%;flex-basis:100%}.col-lg-offset-11{margin-left:91.66667%}.col-lg-normal{order:0}.col-lg-first{order:-999}.col-lg-last{order:999}}:root{--card-back-color: #eceff4;--card-fore-color: #2e3440;--card-border-color: #e5e9f0}.card{display:flex;flex-direction:column;justify-content:space-between;align-self:center;position:relative;width:100%;background:var(--card-back-color);color:var(--card-fore-color);border:.0625rem solid var(--card-border-color);border-radius:var(--universal-border-radius);margin:var(--universal-margin);overflow:hidden}@media screen and (min-width:320px){.card{max-width:320px}}.card>.section{background:var(--card-back-color);color:var(--card-fore-color);box-sizing:border-box;margin:0;border:0;border-radius:0;border-bottom:.0625rem solid var(--card-border-color);padding:var(--universal-padding);width:100%}.card>.section.media{height:200px;padding:0;-o-object-fit:cover;object-fit:cover}.card>.section:last-child{border-bottom:0}@media screen and (min-width:240px){.card.small{max-width:240px}}@media screen and (min-width:480px){.card.large{max-width:480px}}.card.fluid{max-width:100%;width:auto}.card.warning{--card-back-color: #ebcb8b;--card-border-color: #d08770}.card.error{--card-back-color: #bf616a;--card-border-color: #434c5e}.card>.section.dark{--card-back-color: #d8dee9}.card>.section.double-padded{padding:calc(1.5 * var(--universal-padding))}:root{--form-back-color: #e5e9f0;--form-fore-color: #2e3440;--form-border-color: #e5e9f0;--input-back-color: #eceff4;--input-fore-color: #2e3440;--input-border-color: #e5e9f0;--input-focus-color: #88c0d0;--input-invalid-color: #bf616a;--button-back-color: #e5e9f0;--button-hover-back-color: #d8dee9;--button-fore-color: #2e3440;--button-border-color: transparent;--button-hover-border-color: transparent;--button-group-border-color: rgba(124, 124, 124, 0.54)}form{background:var(--form-back-color);color:var(--form-fore-color);border:.0625rem solid var(--form-border-color);border-radius:var(--universal-border-radius);margin:var(--universal-margin);padding:calc(2 * var(--universal-padding))var(--universal-padding)}fieldset{border:.0625rem solid var(--form-border-color);border-radius:var(--universal-border-radius);margin:calc(var(--universal-margin)/4);padding:var(--universal-padding)}legend{box-sizing:border-box;display:table;max-width:100%;white-space:normal;font-weight:700;padding:calc(var(--universal-padding)/2)}label{padding:calc(var(--universal-padding)/2)var(--universal-padding)}.input-group{display:inline-block}.input-group.fluid{display:flex;align-items:center;justify-content:center}.input-group.fluid>input{max-width:100%;flex-grow:1;flex-basis:0}@media screen and (max-width:767px){.input-group.fluid{align-items:stretch;flex-direction:column}}.input-group.vertical{display:flex;align-items:stretch;flex-direction:column}.input-group.vertical>input{max-width:100%;flex-grow:1;flex-basis:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}input:not([type]),[type=text],[type=email],[type=number],[type=search],[type=password],[type=url],[type=tel],[type=checkbox],[type=radio],textarea,select{box-sizing:border-box;background:var(--input-back-color);color:var(--input-fore-color);border:.0625rem solid var(--input-border-color);border-radius:var(--universal-border-radius);margin:calc(var(--universal-margin)/2);padding:var(--universal-padding)calc(1.5 * var(--universal-padding))}input:not([type=button]):not([type=submit]):not([type=reset]):hover,input:not([type=button]):not([type=submit]):not([type=reset]):focus,textarea:hover,textarea:focus,select:hover,select:focus{border-color:var(--input-focus-color);box-shadow:0 0}input:not([type=button]):not([type=submit]):not([type=reset]):invalid,input:not([type=button]):not([type=submit]):not([type=reset]):focus:invalid,textarea:invalid,textarea:focus:invalid,select:invalid,select:focus:invalid{border-color:var(--input-invalid-color);box-shadow:0 0}input:not([type=button]):not([type=submit]):not([type=reset])[readonly],textarea[readonly],select[readonly]{background:var(--secondary-back-color)}select{max-width:100%}option{overflow:hidden;text-overflow:ellipsis}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;position:relative;height:calc(1rem + var(--universal-padding)/2);width:calc(1rem + var(--universal-padding)/2);vertical-align:text-bottom;padding:0;flex-basis:calc(1rem + var(--universal-padding)/2)!important;flex-grow:0!important}[type=checkbox]:checked:before,[type=radio]:checked:before{position:absolute}[type=checkbox]:checked:before{content:'\2713';font-family:sans-serif;font-size:calc(1rem + var(--universal-padding)/2);top:calc(0 - var(--universal-padding));left:calc(var(--universal-padding)/4)}[type=radio]{border-radius:100%}[type=radio]:checked:before{border-radius:100%;content:'';top:calc(.0625rem + var(--universal-padding)/2);left:calc(.0625rem + var(--universal-padding)/2);background:var(--input-fore-color);width:.5rem;height:.5rem}:placeholder-shown{color:var(--input-fore-color)}::-ms-placeholder{color:var(--input-fore-color);opacity:.54}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button{overflow:visible;text-transform:none}button,[type=button],[type=submit],[type=reset],a.button,label.button,.button,a[role=button],label[role=button],[role=button]{display:inline-block;background:var(--button-back-color);color:var(--button-fore-color);border:.0625rem solid var(--button-border-color);border-radius:var(--universal-border-radius);padding:var(--universal-padding)calc(1.5 * var(--universal-padding));margin:var(--universal-margin);text-decoration:none;cursor:pointer;transition:background .3s}button:hover,button:focus,[type=button]:hover,[type=button]:focus,[type=submit]:hover,[type=submit]:focus,[type=reset]:hover,[type=reset]:focus,a.button:hover,a.button:focus,label.button:hover,label.button:focus,.button:hover,.button:focus,a[role=button]:hover,a[role=button]:focus,label[role=button]:hover,label[role=button]:focus,[role=button]:hover,[role=button]:focus{background:var(--button-hover-back-color);border-color:var(--button-hover-border-color)}input:disabled,input[disabled],textarea:disabled,textarea[disabled],select:disabled,select[disabled],button:disabled,button[disabled],.button:disabled,.button[disabled],[role=button]:disabled,[role=button][disabled]{cursor:not-allowed;opacity:.75}.button-group{display:flex;border:.0625rem solid var(--button-group-border-color);border-radius:var(--universal-border-radius);margin:var(--universal-margin)}.button-group>button,.button-group [type=button],.button-group>[type=submit],.button-group>[type=reset],.button-group>.button,.button-group>[role=button]{margin:0;max-width:100%;flex:1 1;text-align:center;border:0;border-radius:0;box-shadow:0 0}.button-group>:not(:first-child){border-left:.0625rem solid var(--button-group-border-color)}@media screen and (max-width:767px){.button-group{flex-direction:column}.button-group>:not(:first-child){border:0;border-top:.0625rem solid var(--button-group-border-color)}}button.primary,[type=button].primary,[type=submit].primary,[type=reset].primary,.button.primary,[role=button].primary{--button-back-color: #5e81ac;--button-fore-color: #eceff4}button.primary:hover,button.primary:focus,[type=button].primary:hover,[type=button].primary:focus,[type=submit].primary:hover,[type=submit].primary:focus,[type=reset].primary:hover,[type=reset].primary:focus,.button.primary:hover,.button.primary:focus,[role=button].primary:hover,[role=button].primary:focus{--button-hover-back-color: #5e81ac}button.secondary,[type=button].secondary,[type=submit].secondary,[type=reset].secondary,.button.secondary,[role=button].secondary{--button-back-color: #bf616a;--button-fore-color: #eceff4}button.secondary:hover,button.secondary:focus,[type=button].secondary:hover,[type=button].secondary:focus,[type=submit].secondary:hover,[type=submit].secondary:focus,[type=reset].secondary:hover,[type=reset].secondary:focus,.button.secondary:hover,.button.secondary:focus,[role=button].secondary:hover,[role=button].secondary:focus{--button-hover-back-color: #bf616a}button.tertiary,[type=button].tertiary,[type=submit].tertiary,[type=reset].tertiary,.button.tertiary,[role=button].tertiary{--button-back-color: #a3be8c;--button-fore-color: #434c5e}button.tertiary:hover,button.tertiary:focus,[type=button].tertiary:hover,[type=button].tertiary:focus,[type=submit].tertiary:hover,[type=submit].tertiary:focus,[type=reset].tertiary:hover,[type=reset].tertiary:focus,.button.tertiary:hover,.button.tertiary:focus,[role=button].tertiary:hover,[role=button].tertiary:focus{--button-hover-back-color: #a3be8c}button.inverse,[type=button].inverse,[type=submit].inverse,[type=reset].inverse,.button.inverse,[role=button].inverse{--button-back-color: #3b4252;--button-fore-color: #eceff4}button.inverse:hover,button.inverse:focus,[type=button].inverse:hover,[type=button].inverse:focus,[type=submit].inverse:hover,[type=submit].inverse:focus,[type=reset].inverse:hover,[type=reset].inverse:focus,.button.inverse:hover,.button.inverse:focus,[role=button].inverse:hover,[role=button].inverse:focus{--button-hover-back-color: #2e3440}button.small,[type=button].small,[type=submit].small,[type=reset].small,.button.small,[role=button].small{padding:calc(.5 * var(--universal-padding))calc(.75 * var(--universal-padding));margin:var(--universal-margin)}button.large,[type=button].large,[type=submit].large,[type=reset].large,.button.large,[role=button].large{padding:calc(1.5 * var(--universal-padding))calc(2 * var(--universal-padding));margin:var(--universal-margin)}:root{--header-back-color: #eceff4;--header-hover-back-color: #e5e9f0;--header-fore-color: #3b4252;--header-border-color: #e5e9f0;--nav-back-color: #eceff4;--nav-hover-back-color: #e5e9f0;--nav-fore-color: #3b4252;--nav-border-color: #e5e9f0;--nav-link-color: #88c0d0;--footer-fore-color: #3b4252;--footer-back-color: #eceff4;--footer-border-color: #e5e9f0;--footer-link-color: #88c0d0;--drawer-back-color: #eceff4;--drawer-hover-back-color: #e5e9f0;--drawer-border-color: #e5e9f0;--drawer-close-color: #3b4252}header{height:3.1875rem;background:var(--header-back-color);color:var(--header-fore-color);border-bottom:.0625rem solid var(--header-border-color);padding:calc(var(--universal-padding)/4)0;white-space:nowrap;overflow-x:auto;overflow-y:hidden}header.row{box-sizing:content-box}header .logo{color:var(--header-fore-color);font-size:1.75rem;padding:var(--universal-padding)calc(2 * var(--universal-padding));text-decoration:none}header button,header [type=button],header .button,header [role=button]{box-sizing:border-box;position:relative;top:calc(0 - var(--universal-padding)/4);height:calc(3.1875rem + var(--universal-padding)/2);background:var(--header-back-color);line-height:calc(3.1875rem - var(--universal-padding) * 1.5);text-align:center;color:var(--header-fore-color);border:0;border-radius:0;margin:0;text-transform:uppercase}header button:hover,header button:focus,header [type=button]:hover,header [type=button]:focus,header .button:hover,header .button:focus,header [role=button]:hover,header [role=button]:focus{background:var(--header-hover-back-color)}nav{background:var(--nav-back-color);color:var(--nav-fore-color);border:.0625rem solid var(--nav-border-color);border-radius:var(--universal-border-radius);margin:var(--universal-margin)}nav *{padding:var(--universal-padding)calc(1.5 * var(--universal-padding))}nav a,nav a:visited{display:block;color:var(--nav-link-color);border-radius:var(--universal-border-radius);transition:background .3s}nav a:hover,nav a:focus,nav a:visited:hover,nav a:visited:focus{text-decoration:none;background:var(--nav-hover-back-color)}nav .sublink-1{position:relative;margin-left:calc(2 * var(--universal-padding))}nav .sublink-1:before{position:absolute;left:calc(var(--universal-padding) - 1 * var(--universal-padding));top:-.0625rem;content:'';height:100%;border:.0625rem solid var(--nav-border-color);border-left:0}nav .sublink-2{position:relative;margin-left:calc(4 * var(--universal-padding))}nav .sublink-2:before{position:absolute;left:calc(var(--universal-padding) - 3 * var(--universal-padding));top:-.0625rem;content:'';height:100%;border:.0625rem solid var(--nav-border-color);border-left:0}footer{background:var(--footer-back-color);color:var(--footer-fore-color);border-top:.0625rem solid var(--footer-border-color);padding:calc(2 * var(--universal-padding))var(--universal-padding);font-size:.875rem}footer a,footer a:visited{color:var(--footer-link-color)}header.sticky{position:-webkit-sticky;position:sticky;z-index:1101;top:0}footer.sticky{position:-webkit-sticky;position:sticky;z-index:1101;bottom:0}.drawer-toggle:before{display:inline-block;position:relative;vertical-align:bottom;content:'\00a0\2261\00a0';font-family:sans-serif;font-size:1.5em}@media screen and (min-width:768px){.drawer-toggle:not(.persistent){display:none}}[type=checkbox].drawer{height:1px;width:1px;margin:-1px;overflow:hidden;position:absolute;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%)}[type=checkbox].drawer+*{display:block;box-sizing:border-box;position:fixed;top:0;width:320px;height:100vh;overflow-y:auto;background:var(--drawer-back-color);border:.0625rem solid var(--drawer-border-color);border-radius:0;margin:0;z-index:1110;right:-320px;transition:right .3s}[type=checkbox].drawer+* .drawer-close{position:absolute;top:var(--universal-margin);right:var(--universal-margin);z-index:1111;width:2rem;height:2rem;border-radius:var(--universal-border-radius);padding:var(--universal-padding);margin:0;cursor:pointer;transition:background .3s}[type=checkbox].drawer+* .drawer-close:before{display:block;content:'\00D7';color:var(--drawer-close-color);position:relative;font-family:sans-serif;font-size:2rem;line-height:1;text-align:center}[type=checkbox].drawer+* .drawer-close:hover,[type=checkbox].drawer+* .drawer-close:focus{background:var(--drawer-hover-back-color)}@media screen and (max-width:320px){[type=checkbox].drawer+*{width:100%}}[type=checkbox].drawer:checked+*{right:0}@media screen and (min-width:768px){[type=checkbox].drawer:not(.persistent)+*{position:static;height:100%;z-index:1100}[type=checkbox].drawer:not(.persistent)+* .drawer-close{display:none}}:root{--table-border-color: #d8dee9;--table-border-separator-color: #434c5e;--table-head-back-color: #e5e9f0;--table-head-fore-color: #2e3440;--table-body-back-color: #eceff4;--table-body-fore-color: #2e3440;--table-body-alt-back-color: #e5e9f0}table{border-collapse:separate;border-spacing:0;margin:0;display:flex;flex:0 1;flex-flow:row wrap;padding:var(--universal-padding);padding-top:0}table caption{font-size:1.5rem;margin:calc(2 * var(--universal-margin))0;max-width:100%;flex:0 0 100%}table thead,table tbody{display:flex;flex-flow:row wrap;border:.0625rem solid var(--table-border-color)}table thead{z-index:999;border-radius:var(--universal-border-radius)var(--universal-border-radius)0 0;border-bottom:.0625rem solid var(--table-border-separator-color)}table tbody{border-top:0;margin-top:calc(0 - var(--universal-margin));border-radius:0 0 var(--universal-border-radius)var(--universal-border-radius)}table tr{display:flex;padding:0}table th,table td{padding:calc(2 * var(--universal-padding))}table th{text-align:left;background:var(--table-head-back-color);color:var(--table-head-fore-color)}table td{background:var(--table-body-back-color);color:var(--table-body-fore-color);border-top:.0625rem solid var(--table-border-color)}table:not(.horizontal){overflow:auto;max-height:400px}table:not(.horizontal) thead,table:not(.horizontal) tbody{max-width:100%;flex:0 0 100%}table:not(.horizontal) tr{flex-flow:row wrap;flex:0 0 100%}table:not(.horizontal) th,table:not(.horizontal) td{flex:1 0 0;overflow:hidden;text-overflow:ellipsis}table:not(.horizontal) thead{position:sticky;top:0}table:not(.horizontal) tbody tr:first-child td{border-top:0}table.horizontal{border:0}table.horizontal thead,table.horizontal tbody{border:0;flex:.2 0 0;flex-flow:row nowrap}table.horizontal tbody{overflow:auto;justify-content:space-between;flex:.8 0 0;margin-left:0;padding-bottom:calc(var(--universal-padding)/4)}table.horizontal tr{flex-direction:column;flex:1 0}table.horizontal th,table.horizontal td{width:auto;border:0;border-bottom:.0625rem solid var(--table-border-color)}table.horizontal th:not(:first-child),table.horizontal td:not(:first-child){border-top:0}table.horizontal th{text-align:right;border-left:.0625rem solid var(--table-border-color);border-right:.0625rem solid var(--table-border-separator-color)}table.horizontal thead tr:first-child{padding-left:0}table.horizontal th:first-child,table.horizontal td:first-child{border-top:.0625rem solid var(--table-border-color)}table.horizontal tbody tr:last-child td{border-right:.0625rem solid var(--table-border-color)}table.horizontal tbody tr:last-child td:first-child{border-top-right-radius:.25rem}table.horizontal tbody tr:last-child td:last-child{border-bottom-right-radius:.25rem}table.horizontal thead tr:first-child th:first-child{border-top-left-radius:.25rem}table.horizontal thead tr:first-child th:last-child{border-bottom-left-radius:.25rem}@media screen and (max-width:767px){table,table.horizontal{border-collapse:collapse;border:0;width:100%;display:table}table thead,table th,table.horizontal thead,table.horizontal th{border:0;height:1px;width:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%)}table tbody,table.horizontal tbody{border:0;display:table-row-group}table tr,table.horizontal tr{display:block;border:.0625rem solid var(--table-border-color);border-radius:var(--universal-border-radius);background:#fafafa;padding:var(--universal-padding);margin:var(--universal-margin);margin-bottom:calc(2 * var(--universal-margin))}table th,table td,table.horizontal th,table.horizontal td{width:auto}table td,table.horizontal td{display:block;border:0;text-align:right}table td:before,table.horizontal td:before{content:attr(data-label);float:left;font-weight:600}table th:first-child,table td:first-child,table.horizontal th:first-child,table.horizontal td:first-child{border-top:0}table tbody tr:last-child td,table.horizontal tbody tr:last-child td{border-right:0}}:root{--table-body-alt-back-color: #e5e9f0}table.striped tr:nth-of-type(2n)>td{background:var(--table-body-alt-back-color)}@media screen and (max-width:768px){table.striped tr:nth-of-type(2n){background:var(--table-body-alt-back-color)}}:root{--table-body-hover-back-color: #88c0d0}table.hoverable tr:hover,table.hoverable tr:hover>td,table.hoverable tr:focus,table.hoverable tr:focus>td{background:var(--table-body-hover-back-color)}@media screen and (max-width:768px){table.hoverable tr:hover,table.hoverable tr:hover>td,table.hoverable tr:focus,table.hoverable tr:focus>td{background:var(--table-body-hover-back-color)}}:root{--mark-back-color: #5e81ac;--mark-fore-color: #fafafa}mark{background:var(--mark-back-color);color:var(--mark-fore-color);font-size:.95em;line-height:1em;border-radius:var(--universal-border-radius);padding:calc(var(--universal-padding)/4)calc(var(--universal-padding)/2)}mark.inline-block{display:inline-block;font-size:1em;line-height:1.5;padding:calc(var(--universal-padding)/2)var(--universal-padding)}:root{--toast-back-color: #2e3440;--toast-fore-color: #eceff4}.toast{position:fixed;bottom:calc(var(--universal-margin) * 3);left:50%;transform:translate(-50%,-50%);z-index:1111;color:var(--toast-fore-color);background:var(--toast-back-color);border-radius:calc(var(--universal-border-radius) * 16);padding:var(--universal-padding)calc(var(--universal-padding) * 3)}:root{--tooltip-back-color: #2e3440;--tooltip-fore-color: #eceff4}.tooltip{position:relative;display:inline-block}.tooltip:before,.tooltip:after{position:absolute;opacity:0;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%);transition:all .3s;z-index:1010;left:50%}.tooltip:not(.bottom):before,.tooltip:not(.bottom):after{bottom:75%}.tooltip.bottom:before,.tooltip.bottom:after{top:75%}.tooltip:hover:before,.tooltip:hover:after,.tooltip:focus:before,.tooltip:focus:after{opacity:1;clip:auto;-webkit-clip-path:inset(0%);clip-path:inset(0%)}.tooltip:before{content:'';background:0 0;border:var(--universal-margin)solid transparent;left:calc(50% - var(--universal-margin))}.tooltip:not(.bottom):before{border-top-color:#2e3440}.tooltip.bottom:before{border-bottom-color:#2e3440}.tooltip:after{content:attr(aria-label);color:var(--tooltip-fore-color);background:var(--tooltip-back-color);border-radius:var(--universal-border-radius);padding:var(--universal-padding);white-space:nowrap;transform:translateX(-50%)}.tooltip:not(.bottom):after{margin-bottom:calc(2 * var(--universal-margin))}.tooltip.bottom:after{margin-top:calc(2 * var(--universal-margin))}:root{--modal-overlay-color: rgba(0, 0, 0, 0.45);--modal-close-color: #3b4252;--modal-close-hover-color: #e5e9f0}[type=checkbox].modal{height:1px;width:1px;margin:-1px;overflow:hidden;position:absolute;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%)}[type=checkbox].modal+div{position:fixed;top:0;left:0;display:none;width:100vw;height:100vh;background:var(--modal-overlay-color)}[type=checkbox].modal+div .card{margin:0 auto;max-height:50vh;overflow:auto}[type=checkbox].modal+div .card .modal-close{position:absolute;top:0;right:0;width:1.75rem;height:1.75rem;border-radius:var(--universal-border-radius);padding:var(--universal-padding);margin:0;cursor:pointer;transition:background .3s}[type=checkbox].modal+div .card .modal-close:before{display:block;content:'\00D7';color:var(--modal-close-color);position:relative;font-family:sans-serif;font-size:1.75rem;line-height:1;text-align:center}[type=checkbox].modal+div .card .modal-close:hover,[type=checkbox].modal+div .card .modal-close:focus{background:var(--modal-close-hover-color)}[type=checkbox].modal:checked+div{display:flex;flex:0 1;z-index:1200}[type=checkbox].modal:checked+div .card .modal-close{z-index:1211}:root{--collapse-label-back-color: #e5e9f0;--collapse-label-fore-color: #2e3440;--collapse-label-hover-back-color: #e5e9f0;--collapse-selected-label-back-color: #e5e9f0;--collapse-border-color: #e5e9f0;--collapse-content-back-color: #fafafa;--collapse-selected-label-border-color: #88c0d0}.collapse{width:calc(100% - 2 * var(--universal-margin));opacity:1;display:flex;flex-direction:column;margin:var(--universal-margin);border-radius:var(--universal-border-radius)}.collapse>[type=radio],.collapse>[type=checkbox]{height:1px;width:1px;margin:-1px;overflow:hidden;position:absolute;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%)}.collapse>label{flex-grow:1;display:inline-block;height:1.5rem;cursor:pointer;transition:background .3s;color:var(--collapse-label-fore-color);background:var(--collapse-label-back-color);border:.0625rem solid var(--collapse-border-color);padding:calc(1.5 * var(--universal-padding))}.collapse>label:hover,.collapse>label:focus{background:var(--collapse-label-hover-back-color)}.collapse>label+div{flex-basis:auto;height:1px;width:1px;margin:-1px;overflow:hidden;position:absolute;clip:rect(0 0 0 0);-webkit-clip-path:inset(100%);clip-path:inset(100%);transition:max-height .3s;max-height:1px}.collapse>:checked+label{background:var(--collapse-selected-label-back-color);border-bottom-color:var(--collapse-selected-label-border-color)}.collapse>:checked+label+div{box-sizing:border-box;position:relative;width:100%;height:auto;overflow:auto;margin:0;background:var(--collapse-content-back-color);border:.0625rem solid var(--collapse-border-color);border-top:0;padding:var(--universal-padding);clip:auto;-webkit-clip-path:inset(0%);clip-path:inset(0%);max-height:400px}.collapse>label:not(:first-of-type){border-top:0}.collapse>label:first-of-type{border-radius:var(--universal-border-radius)var(--universal-border-radius)0 0}.collapse>label:last-of-type:not(:first-of-type){border-radius:0 0 var(--universal-border-radius)var(--universal-border-radius)}.collapse>label:last-of-type:first-of-type{border-radius:var(--universal-border-radius)}.collapse>:checked:last-of-type:not(:first-of-type)+label{border-radius:0}.collapse>:checked:last-of-type+label+div{border-radius:0 0 var(--universal-border-radius)var(--universal-border-radius)}mark.secondary{--mark-back-color: #bf616a}mark.tertiary{--mark-back-color: #a3be8c}mark.tag{padding:calc(var(--universal-padding)/2)var(--universal-padding);border-radius:1em}:root{--progress-back-color: #e5e9f0;--progress-fore-color: #434c5e}progress{display:block;vertical-align:baseline;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:.75rem;width:calc(100% - 2 * var(--universal-margin));margin:var(--universal-margin);border:0;border-radius:calc(2 * var(--universal-border-radius));background:var(--progress-back-color);color:var(--progress-fore-color)}progress::-webkit-progress-value{background:var(--progress-fore-color);border-top-left-radius:calc(2 * var(--universal-border-radius));border-bottom-left-radius:calc(2 * var(--universal-border-radius))}progress::-webkit-progress-bar{background:var(--progress-back-color)}progress::-moz-progress-bar{background:var(--progress-fore-color);border-top-left-radius:calc(2 * var(--universal-border-radius));border-bottom-left-radius:calc(2 * var(--universal-border-radius))}progress[value="1000"]::-webkit-progress-value{border-radius:calc(2 * var(--universal-border-radius))}progress[value="1000"]::-moz-progress-bar{border-radius:calc(2 * var(--universal-border-radius))}progress.inline{display:inline-block;vertical-align:middle;width:60%}:root{--spinner-back-color: #d8dee9;--spinner-fore-color: #434c5e}@keyframes spinner-donut-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.spinner{display:inline-block;margin:var(--universal-margin);border:.25rem solid var(--spinner-back-color);border-left:.25rem solid var(--spinner-fore-color);border-radius:50%;width:1.25rem;height:1.25rem;animation:spinner-donut-anim 1.2s linear infinite}progress.primary{--progress-fore-color: #5e81ac}progress.secondary{--progress-fore-color: #bf616a}progress.tertiary{--progress-fore-color: #a3be8c}.spinner.primary{--spinner-fore-color: #5e81ac}.spinner.secondary{--spinner-fore-color: #bf616a}.spinner.tertiary{--spinner-fore-color: #a3be8c}span[class^=icon-]{display:inline-block;height:1em;width:1em;vertical-align:-.125em;background-size:contain;margin:0 calc(var(--universal-margin)/4)}span[class^=icon-].secondary{-webkit-filter:invert(25%);filter:invert(25%)}span[class^=icon-].inverse{-webkit-filter:invert(100%);filter:invert(100%)}span.icon-alert{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E")}span.icon-bookmark{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E")}span.icon-calendar{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E")}span.icon-credit{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E")}span.icon-edit{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E")}span.icon-link{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E")}span.icon-help{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E")}span.icon-home{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E")}span.icon-info{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E")}span.icon-lock{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E")}span.icon-mail{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E")}span.icon-location{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E")}span.icon-phone{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E")}span.icon-rss{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E")}span.icon-search{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E")}span.icon-settings{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E")}span.icon-share{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E")}span.icon-cart{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E")}span.icon-upload{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E")}span.icon-user{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232e3440' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E")}:root{--generic-border-color: rgba(0, 0, 0, 0.3);--generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.125)}.hidden{display:none!important}.visually-hidden{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;border:0!important;padding:0!important;clip:rect(0 0 0 0)!important;-webkit-clip-path:inset(100%)!important;clip-path:inset(100%)!important;overflow:hidden!important}.bordered{border:.0625rem solid var(--generic-border-color)!important}.rounded{border-radius:var(--universal-border-radius)!important}.circular{border-radius:50%!important}.shadowed{box-shadow:var(--generic-box-shadow)!important}.responsive-margin{margin:calc(var(--universal-margin)/4)!important}@media screen and (min-width:768px){.responsive-margin{margin:calc(var(--universal-margin)/2)!important}}@media screen and (min-width:1280px){.responsive-margin{margin:var(--universal-margin)!important}}.responsive-padding{padding:calc(var(--universal-padding)/4)!important}@media screen and (min-width:768px){.responsive-padding{padding:calc(var(--universal-padding)/2)!important}}@media screen and (min-width:1280px){.responsive-padding{padding:var(--universal-padding)!important}}@media screen and (max-width:767px){.hidden-sm{display:none!important}}@media screen and (min-width:768px) and (max-width:1279px){.hidden-md{display:none!important}}@media screen and (min-width:1280px){.hidden-lg{display:none!important}}@media screen and (max-width:767px){.visually-hidden-sm{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;border:0!important;padding:0!important;clip:rect(0 0 0 0)!important;-webkit-clip-path:inset(100%)!important;clip-path:inset(100%)!important;overflow:hidden!important}}@media screen and (min-width:768px) and (max-width:1279px){.visually-hidden-md{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;border:0!important;padding:0!important;clip:rect(0 0 0 0)!important;-webkit-clip-path:inset(100%)!important;clip-path:inset(100%)!important;overflow:hidden!important}}@media screen and (min-width:1280px){.visually-hidden-lg{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;border:0!important;padding:0!important;clip:rect(0 0 0 0)!important;-webkit-clip-path:inset(100%)!important;clip-path:inset(100%)!important;overflow:hidden!important}} \ No newline at end of file +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#351c4d;background-color:#fafafa;font-family:roboto,helvetica neue,helvetica,arial,sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}.nav-bar{background-color:#fafafa;top:0;left:0;right:0;border-bottom:1px solid #b0b0b0;height:3rem;display:flex;text-transform:uppercase;margin-bottom:2rem!important}.nav-bar *{display:inline}.nav-bar li{margin:1rem}.nav-bar li a{font-weight:700}blockquote{border-left:.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type=button],input[type=reset],input[type=submit]{background-color:#ff7e5f;border:.1rem solid #ff7e5f;border-radius:.4rem;color:#fafafa;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{background-color:#351c4d;border-color:#351c4d;color:#fafafa;outline:0}.button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type=button][disabled]:focus,input[type=button][disabled]:hover,input[type=reset][disabled]:focus,input[type=reset][disabled]:hover,input[type=submit][disabled]:focus,input[type=submit][disabled]:hover{background-color:#ff7e5f;border-color:#ff7e5f}.button.button-outline,button.button-outline,input[type=button].button-outline,input[type=reset].button-outline,input[type=submit].button-outline{background-color:initial;color:#ff7e5f}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type=button].button-outline:focus,input[type=button].button-outline:hover,input[type=reset].button-outline:focus,input[type=reset].button-outline:hover,input[type=submit].button-outline:focus,input[type=submit].button-outline:hover{background-color:initial;border-color:#351c4d;color:#351c4d}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type=button].button-outline[disabled]:focus,input[type=button].button-outline[disabled]:hover,input[type=reset].button-outline[disabled]:focus,input[type=reset].button-outline[disabled]:hover,input[type=submit].button-outline[disabled]:focus,input[type=submit].button-outline[disabled]:hover{border-color:inherit;color:#ff7e5f}.button.button-clear,button.button-clear,input[type=button].button-clear,input[type=reset].button-clear,input[type=submit].button-clear{background-color:initial;border-color:transparent;color:#ff7e5f}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type=button].button-clear:focus,input[type=button].button-clear:hover,input[type=reset].button-clear:focus,input[type=reset].button-clear:hover,input[type=submit].button-clear:focus,input[type=submit].button-clear:hover{background-color:initial;border-color:transparent;color:#351c4d}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type=button].button-clear[disabled]:focus,input[type=button].button-clear[disabled]:hover,input[type=reset].button-clear[disabled]:focus,input[type=reset].button-clear[disabled]:hover,input[type=submit].button-clear[disabled]:focus,input[type=submit].button-clear[disabled]:hover{color:#ff7e5f}code{background:#b0b0b0;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#b0b0b0;border-left:.3rem solid #ff7e5f;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:.1rem solid #b0b0b0;margin:3rem 0}input[type=color],input[type=date],input[type=datetime],input[type=datetime-local],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=url],input[type=week],input:not([type]),textarea,select{-webkit-appearance:none;background-color:initial;border:.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:0 0;box-sizing:inherit;height:3.8rem;padding:.6rem 1rem .7rem;width:100%}input[type=color]:focus,input[type=date]:focus,input[type=datetime]:focus,input[type=datetime-local]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,input[type=week]:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#ff7e5f;outline:0}select{background:url('data:image/svg+xml;utf8,')50% 100% no-repeat;padding-right:3rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:0 0;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type=checkbox],input[type=radio]{display:inline}.label-inline{display:inline-block;font-weight:400;margin-left:.5rem}.container{margin:0 auto;max-width:112rem;padding:0 2rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media(min-width:40rem){.row{flex-direction:row;margin-left:-1rem;width:calc(100% + 2rem)}.row .column{margin-bottom:inherit;padding:0 1rem}}a{color:#ff7e5f;text-decoration:none}a:focus,a:hover{color:#351c4d}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media(min-width:40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:700}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} \ No newline at end of file diff --git a/main/static/min/index.html b/main/static/min/index.html index 57938bc..a11af66 100644 --- a/main/static/min/index.html +++ b/main/static/min/index.html @@ -1,2 +1 @@ -

Loading

Loading content... Please make sure that JavaScript is enabled.


MqTrigger v1.1 2022

\ No newline at end of file +
MqTrigger v1.1

Loading

Loading content... Please make sure that JavaScript is enabled.


Copyright© nixlab.in 2022

\ No newline at end of file diff --git a/main/static/min/index.js b/main/static/min/index.js index 8ecbd33..b878f8f 100644 --- a/main/static/min/index.js +++ b/main/static/min/index.js @@ -1,19 +1,18 @@ var valuesCache={};function ip2int(ip){return ip.split('.').reduce(function(ipInt,octet){return(ipInt<<8)+parseInt(octet,10)},0)>>>0;} -function sendClickHandler(event){console.log("Sending form...");let form=event.srcElement.form;console.debug(form);let params='';Array.from(form.elements).forEach(element=>{console.log(element);console.log(element.name);console.log(element.value);if(element.value){if(!element.hasAttribute('data-ignore')){params+=params?'&':'';if(element.hasAttribute('data-ip32')){console.log("IPv4 32");params+=element.name+'='+ip2int(element.value);} +function sendClickHandler(event){let form=event.srcElement.form;console.debug(form);let params='';Array.from(form.elements).forEach(element=>{if(element.value){if(!element.hasAttribute('data-ignore')){params+=params?'&':'';if(element.hasAttribute('data-ip32')){params+=element.name+'='+ip2int(element.value);} else{params+=element.name+'='+element.value;}} -else{console.log("Ignoring "+element.name);}}});console.log("params: "+params);postParams(form.getAttribute('action'),params);console.log("Form sent");} +else{console.log("Ignoring "+element.name);}}});postParams(form.getAttribute('action'),params);} function initFormSendButtons(form){const btns=form.querySelectorAll('.send');for(i=0;i "+obj[key]) -let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}} +function fillInputs(jsonString){let obj=JSON.parse(jsonString);if(obj){for(var key of Object.keys(obj)){let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}} function loadValues(element){valuesCache={};const forms=element.querySelectorAll('form');for(i=0;i + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third-party/milligram/src/_Base.sass b/third-party/milligram/src/_Base.sass new file mode 100644 index 0000000..65cc417 --- /dev/null +++ b/third-party/milligram/src/_Base.sass @@ -0,0 +1,42 @@ + +// Base +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// Set box-sizing globally to handle padding and border widths +*, +*:after, +*:before + box-sizing: inherit + +// The base font-size is set at 62.5% for having the convenience +// of sizing rems in a way that is similar to using px: 1.6rem = 16px +html + box-sizing: border-box + font-size: 62.5% + +// Default body styles +body + color: $color-secondary + background-color: $color-background + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif + font-size: 1.6em // Currently ems cause chrome bug misinterpreting rems on body element + font-weight: 300 + letter-spacing: .01em + line-height: 1.6 + +.nav-bar + background-color: $color-initial + top: 0 + left: 0 + right: 0 + border-bottom: 1px solid $color-tertiary; + height: 3rem + display: flex + text-transform: uppercase + margin-bottom: 2rem !important + * + display: inline + li + margin: 1rem + a + font-weight: bold diff --git a/third-party/milligram/src/_Blockquote.sass b/third-party/milligram/src/_Blockquote.sass new file mode 100644 index 0000000..9bfce59 --- /dev/null +++ b/third-party/milligram/src/_Blockquote.sass @@ -0,0 +1,12 @@ + +// Blockquote +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +blockquote + border-left: .3rem solid $color-quaternary + margin-left: 0 + margin-right: 0 + padding: 1rem 1.5rem + + *:last-child + margin-bottom: 0 diff --git a/third-party/milligram/src/_Button.sass b/third-party/milligram/src/_Button.sass new file mode 100644 index 0000000..6697c05 --- /dev/null +++ b/third-party/milligram/src/_Button.sass @@ -0,0 +1,76 @@ + +// Button +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +.button, +button, +input[type='button'], +input[type='reset'], +input[type='submit'] + background-color: $color-primary + border: .1rem solid $color-primary + border-radius: .4rem + color: $color-initial + cursor: pointer + display: inline-block + font-size: 1.1rem + font-weight: 700 + height: 3.8rem + letter-spacing: .1rem + line-height: 3.8rem + padding: 0 3.0rem + text-align: center + text-decoration: none + text-transform: uppercase + white-space: nowrap + + &:focus, + &:hover + background-color: $color-secondary + border-color: $color-secondary + color: $color-initial + outline: 0 + + &[disabled] + cursor: default + opacity: .5 + + &:focus, + &:hover + background-color: $color-primary + border-color: $color-primary + + &.button-outline + background-color: transparent + color: $color-primary + + &:focus, + &:hover + background-color: transparent + border-color: $color-secondary + color: $color-secondary + + &[disabled] + + &:focus, + &:hover + border-color: inherit + color: $color-primary + + &.button-clear + background-color: transparent + border-color: transparent + color: $color-primary + + &:focus, + &:hover + background-color: transparent + border-color: transparent + color: $color-secondary + + &[disabled] + + &:focus, + &:hover + color: $color-primary + diff --git a/third-party/milligram/src/_Code.sass b/third-party/milligram/src/_Code.sass new file mode 100644 index 0000000..12749ef --- /dev/null +++ b/third-party/milligram/src/_Code.sass @@ -0,0 +1,22 @@ + +// Code +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +code + background: $color-tertiary + border-radius: .4rem + font-size: 86% + margin: 0 .2rem + padding: .2rem .5rem + white-space: nowrap + +pre + background: $color-tertiary + border-left: .3rem solid $color-primary + overflow-y: hidden + + & > code + border-radius: 0 + display: block + padding: 1rem 1.5rem + white-space: pre diff --git a/third-party/milligram/src/_Color.sass b/third-party/milligram/src/_Color.sass new file mode 100644 index 0000000..174cb15 --- /dev/null +++ b/third-party/milligram/src/_Color.sass @@ -0,0 +1,12 @@ + +// Color +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +$color-initial: #fafafa !default +$color-primary: #FF7E5F!default +$color-secondary: #351C4D !default +$color-tertiary: #b0b0b0 !default +$color-quaternary: #d1d1d1 !default +$color-quinary: #e1e1e1 !default +$color-background: #fafafa !default + diff --git a/third-party/milligram/src/_Divider.sass b/third-party/milligram/src/_Divider.sass new file mode 100644 index 0000000..d8dceed --- /dev/null +++ b/third-party/milligram/src/_Divider.sass @@ -0,0 +1,8 @@ + +// Divider +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +hr + border: 0 + border-top: .1rem solid $color-tertiary + margin: 3.0rem 0 diff --git a/third-party/milligram/src/_Form.sass b/third-party/milligram/src/_Form.sass new file mode 100644 index 0000000..fd4c6da --- /dev/null +++ b/third-party/milligram/src/_Form.sass @@ -0,0 +1,67 @@ + +// Form +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +input[type='color'], +input[type='date'], +input[type='datetime'], +input[type='datetime-local'], +input[type='email'], +input[type='month'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='url'], +input[type='week'], +input:not([type]), +textarea, +select + -webkit-appearance: none // sass-lint:disable-line no-vendor-prefixes + background-color: transparent + border: .1rem solid $color-quaternary + border-radius: .4rem + box-shadow: none + box-sizing: inherit // Forced to replace inherit values of the normalize.css + height: 3.8rem + padding: .6rem 1.0rem .7rem // This vertically centers text on FF, ignored by Webkit + width: 100% + + &:focus + border-color: $color-primary + outline: 0 + +select + background: url('data:image/svg+xml;utf8,') center right no-repeat + padding-right: 3.0rem + + &:focus + background-image: url('data:image/svg+xml;utf8,') + + &[multiple] + background: none + height: auto + +textarea + min-height: 6.5rem + +label, +legend + display: block + font-size: 1.6rem + font-weight: 700 + margin-bottom: .5rem + +fieldset + border-width: 0 + padding: 0 + +input[type='checkbox'], +input[type='radio'] + display: inline + +.label-inline + display: inline-block + font-weight: normal + margin-left: .5rem diff --git a/third-party/milligram/src/_Grid.sass b/third-party/milligram/src/_Grid.sass new file mode 100644 index 0000000..8c05b8c --- /dev/null +++ b/third-party/milligram/src/_Grid.sass @@ -0,0 +1,164 @@ + +// Grid +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// .container is main centered wrapper with a max width of 112.0rem (1120px) +.container + margin: 0 auto + max-width: 112.0rem + padding: 0 2.0rem + position: relative + width: 100% + +// Using flexbox for the grid, inspired by Philip Walton: +// http://philipwalton.github.io/solved-by-flexbox/demos/grids/ +// By default each .column within a .row will evenly take up +// available width, and the height of each .column with take +// up the height of the tallest .column in the same .row +.row + display: flex + flex-direction: column + padding: 0 + width: 100% + + &.row-no-padding + padding: 0 + + &> .column + padding: 0 + + &.row-wrap + flex-wrap: wrap + + // Vertically Align Columns + // .row-* vertically aligns every .col in the .row + &.row-top + align-items: flex-start + + &.row-bottom + align-items: flex-end + + &.row-center + align-items: center + + &.row-stretch + align-items: stretch + + &.row-baseline + align-items: baseline + + .column + display: block + // IE 11 required specifying the flex-basis otherwise it breaks mobile + flex: 1 1 auto + margin-left: 0 + max-width: 100% + width: 100% + + // Column Offsets + &.column-offset-10 + margin-left: 10% + + &.column-offset-20 + margin-left: 20% + + &.column-offset-25 + margin-left: 25% + + &.column-offset-33, + &.column-offset-34 + margin-left: 33.3333% + + &.column-offset-40 + margin-left: 40% + + &.column-offset-50 + margin-left: 50% + + &.column-offset-60 + margin-left: 60% + + &.column-offset-66, + &.column-offset-67 + margin-left: 66.6666% + + &.column-offset-75 + margin-left: 75% + + &.column-offset-80 + margin-left: 80% + + &.column-offset-90 + margin-left: 90% + + // Explicit Column Percent Sizes + // By default each grid column will evenly distribute + // across the grid. However, you can specify individual + // columns to take up a certain size of the available area + &.column-10 + flex: 0 0 10% + max-width: 10% + + &.column-20 + flex: 0 0 20% + max-width: 20% + + &.column-25 + flex: 0 0 25% + max-width: 25% + + &.column-33, + &.column-34 + flex: 0 0 33.3333% + max-width: 33.3333% + + &.column-40 + flex: 0 0 40% + max-width: 40% + + &.column-50 + flex: 0 0 50% + max-width: 50% + + &.column-60 + flex: 0 0 60% + max-width: 60% + + &.column-66, + &.column-67 + flex: 0 0 66.6666% + max-width: 66.6666% + + &.column-75 + flex: 0 0 75% + max-width: 75% + + &.column-80 + flex: 0 0 80% + max-width: 80% + + &.column-90 + flex: 0 0 90% + max-width: 90% + + // .column-* vertically aligns an individual .column + .column-top + align-self: flex-start + + .column-bottom + align-self: flex-end + + .column-center + align-self: center + +// Larger than mobile screen +@media (min-width: 40.0rem) // Safari desktop has a bug using `rem`, but Safari mobile works + + .row + flex-direction: row + margin-left: -1.0rem + width: calc(100% + 2.0rem) + + .column + margin-bottom: inherit + padding: 0 1.0rem diff --git a/third-party/milligram/src/_Image.sass b/third-party/milligram/src/_Image.sass new file mode 100644 index 0000000..8e1c8da --- /dev/null +++ b/third-party/milligram/src/_Image.sass @@ -0,0 +1,6 @@ + +// Image +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +img + max-width: 100% diff --git a/third-party/milligram/src/_Link.sass b/third-party/milligram/src/_Link.sass new file mode 100644 index 0000000..f026b5c --- /dev/null +++ b/third-party/milligram/src/_Link.sass @@ -0,0 +1,11 @@ + +// Link +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +a + color: $color-primary + text-decoration: none + + &:focus, + &:hover + color: $color-secondary diff --git a/third-party/milligram/src/_List.sass b/third-party/milligram/src/_List.sass new file mode 100644 index 0000000..5671b02 --- /dev/null +++ b/third-party/milligram/src/_List.sass @@ -0,0 +1,22 @@ + +// List +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +dl, +ol, +ul + list-style: none + margin-top: 0 + padding-left: 0 + + dl, + ol, + ul + font-size: 90% + margin: 1.5rem 0 1.5rem 3.0rem + +ol + list-style: decimal inside + +ul + list-style: circle inside diff --git a/third-party/milligram/src/_Spacing.sass b/third-party/milligram/src/_Spacing.sass new file mode 100644 index 0000000..8912da1 --- /dev/null +++ b/third-party/milligram/src/_Spacing.sass @@ -0,0 +1,27 @@ + +// Spacing +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +.button, +button, +dd, +dt, +li + margin-bottom: 1.0rem + +fieldset, +input, +select, +textarea + margin-bottom: 1.5rem + +blockquote, +dl, +figure, +form, +ol, +p, +pre, +table, +ul + margin-bottom: 2.5rem diff --git a/third-party/milligram/src/_Table.sass b/third-party/milligram/src/_Table.sass new file mode 100644 index 0000000..37afe7e --- /dev/null +++ b/third-party/milligram/src/_Table.sass @@ -0,0 +1,27 @@ + +// Table +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +table + border-spacing: 0 + display: block + overflow-x: auto + text-align: left + width: 100% + +td, +th + border-bottom: .1rem solid $color-quinary + padding: 1.2rem 1.5rem + + &:first-child + padding-left: 0 + + &:last-child + padding-right: 0 + +@media (min-width: 40.0rem) + + table + display: table + overflow-x: initial diff --git a/third-party/milligram/src/_Typography.sass b/third-party/milligram/src/_Typography.sass new file mode 100644 index 0000000..27e8e18 --- /dev/null +++ b/third-party/milligram/src/_Typography.sass @@ -0,0 +1,48 @@ + +// Typography +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +b, +strong + font-weight: bold + +p + margin-top: 0 + +h1, +h2, +h3, +h4, +h5, +h6 + font-weight: 300 + letter-spacing: -.1rem + margin-bottom: 2.0rem + margin-top: 0 + +h1 + font-size: 4.6rem + line-height: 1.2 + +h2 + font-size: 3.6rem + line-height: 1.25 + +h3 + font-size: 2.8rem + line-height: 1.3 + +h4 + font-size: 2.2rem + letter-spacing: -.08rem + line-height: 1.35 + +h5 + font-size: 1.8rem + letter-spacing: -.05rem + line-height: 1.5 + +h6 + font-size: 1.6rem + letter-spacing: 0 + line-height: 1.4 diff --git a/third-party/milligram/src/_Utility.sass b/third-party/milligram/src/_Utility.sass new file mode 100644 index 0000000..9c3ea73 --- /dev/null +++ b/third-party/milligram/src/_Utility.sass @@ -0,0 +1,18 @@ + +// Utility +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// Clear a float with .clearfix +.clearfix + + &:after + clear: both + content: ' ' // The space content is one way to avoid an Opera bug. + display: table + +// Float either direction +.float-left + float: left + +.float-right + float: right diff --git a/third-party/milligram/src/milligram.sass b/third-party/milligram/src/milligram.sass new file mode 100644 index 0000000..cf5e57d --- /dev/null +++ b/third-party/milligram/src/milligram.sass @@ -0,0 +1,19 @@ + +// Modules +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +@import _Color +@import _Base +@import _Blockquote +@import _Button +@import _Code +@import _Divider +@import _Form +@import _Grid +@import _Link +@import _List +@import _Spacing +@import _Table +@import _Typography +@import _Image +@import _Utility