+
+
+
+
+
+ 
+ {{app_name}}
+
+ |
+
+
+
diff --git a/tests/.DS_Store b/tests/.DS_Store
deleted file mode 100644
index ea19a3e..0000000
Binary files a/tests/.DS_Store and /dev/null differ
diff --git a/tests/Http/ApiAuthTest.php b/tests/Http/ApiAuthTest.php
new file mode 100644
index 0000000..4b6f8d0
--- /dev/null
+++ b/tests/Http/ApiAuthTest.php
@@ -0,0 +1,69 @@
+serverBackup = $_SERVER;
+ }
+
+ protected function tearDown(): void
+ {
+ $_SERVER = $this->serverBackup;
+ }
+
+ public function testExtractsValidBearerToken(): void
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Bearer abc123def456';
+ unset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('abc123def456', ApiAuth::extractBearerToken());
+ }
+
+ public function testReturnsEmptyStringWhenNoHeader(): void
+ {
+ unset($_SERVER['HTTP_AUTHORIZATION'], $_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('', ApiAuth::extractBearerToken());
+ }
+
+ public function testReturnsEmptyStringForNonBearerScheme(): void
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Basic dXNlcjpwYXNz';
+ unset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('', ApiAuth::extractBearerToken());
+ }
+
+ public function testReturnsEmptyStringForBearerWithNoToken(): void
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Bearer ';
+ unset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('', ApiAuth::extractBearerToken());
+ }
+
+ public function testFallsBackToRedirectHeader(): void
+ {
+ unset($_SERVER['HTTP_AUTHORIZATION']);
+ $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'Bearer fallback_token';
+ $this->assertSame('fallback_token', ApiAuth::extractBearerToken());
+ }
+
+ public function testIsCaseInsensitiveForBearerScheme(): void
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'bearer lowercase_token';
+ unset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('lowercase_token', ApiAuth::extractBearerToken());
+ }
+
+ public function testTrimsWhitespaceFromToken(): void
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Bearer token_with_spaces ';
+ unset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
+ $this->assertSame('token_with_spaces', ApiAuth::extractBearerToken());
+ }
+}
diff --git a/tests/Repository/RepoQueryTest.php b/tests/Repository/RepoQueryTest.php
index df1dae3..8640c6f 100644
--- a/tests/Repository/RepoQueryTest.php
+++ b/tests/Repository/RepoQueryTest.php
@@ -45,7 +45,7 @@ class RepoQueryTest extends TestCase
$this->assertSame([], $params);
RepoQuery::addLikeFilter($where, $params, ['a', 'b'], 'foo');
- $this->assertSame(['(a like ? or b like ?)'], $where);
+ $this->assertSame(["(a like ? escape '\\\\' or b like ? escape '\\\\')"], $where);
$this->assertSame(['%foo%', '%foo%'], $params);
}
diff --git a/tests/Service/UserServicePasswordTest.php b/tests/Service/UserServicePasswordTest.php
index c38925c..0046b37 100644
--- a/tests/Service/UserServicePasswordTest.php
+++ b/tests/Service/UserServicePasswordTest.php
@@ -1,49 +1,33 @@
invoke(null, $password, $password2, $required, $email);
- }
-
public function testRequiresPasswordWhenRequired(): void
{
- $errors = $this->validate('', '', true, 'test@example.com');
+ $errors = UserService::validatePassword('', '', true, 'test@example.com');
$this->assertNotEmpty($errors);
}
public function testRejectsMismatch(): void
{
- $errors = $this->validate('Abcd1234$efg', 'Abcd1234$xxx', true, 'test@example.com');
+ $errors = UserService::validatePassword('Abcd1234$efg', 'Abcd1234$xxx', true, 'test@example.com');
$this->assertNotEmpty($errors);
}
public function testAcceptsStrongPassword(): void
{
- $errors = $this->validate('StrongPass1!', 'StrongPass1!', true, 'test@example.com');
+ $errors = UserService::validatePassword('StrongPass1!', 'StrongPass1!', true, 'test@example.com');
$this->assertSame([], $errors);
}
public function testRejectsPasswordContainingEmail(): void
{
- $errors = $this->validate('test@example.comA1!', 'test@example.comA1!', true, 'test@example.com');
+ $errors = UserService::validatePassword('test@example.comA1!', 'test@example.comA1!', true, 'test@example.com');
$this->assertNotEmpty($errors);
}
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..48316b6
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,4 @@
+ highest priority):
+ * - tokens: design tokens and theme variables
+ * - vendor: third-party styles
+ * - layout: shell, header, sidebar and app structure
+ * - vendor-overrides: project overrides for third-party CSS
+ * - components: reusable UI building blocks
+ * - pages: page-specific styles
+ * - utilities: last-resort helpers/overrides
+ */
+@layer tokens, vendor, layout, vendor-overrides, components, pages, utilities;
+
+/* Load third-party styles into the vendor layer so app layers can override them predictably. */
+@import url("../vendor/bootstrap-icons/bootstrap-icons.css") layer(vendor);
+@import url("../vendor/gridjs/mermaid.min.css") layer(vendor);
+@import url("../vendor/multi-select/MultiSelect.css") layer(vendor);
diff --git a/web/css/base/variables.base.css b/web/css/base/variables.base.css
index a4d864f..f8a9e4b 100644
--- a/web/css/base/variables.base.css
+++ b/web/css/base/variables.base.css
@@ -1,5 +1,6 @@
@charset "UTF-8";
+@layer tokens {
:host,
:root {
--app-font-family-emoji:
@@ -795,3 +796,4 @@
:root {
--app-scrollbar-width: 0px;
}
+}
diff --git a/web/css/base/variables.contrast.css b/web/css/base/variables.contrast.css
index a4f4ed4..8928070 100644
--- a/web/css/base/variables.contrast.css
+++ b/web/css/base/variables.contrast.css
@@ -1,5 +1,6 @@
@charset "UTF-8";
+@layer tokens {
/* High contrast overrides */
html[data-contrast="high"][data-theme="light"],
[data-contrast="high"][data-theme="light"] {
@@ -42,3 +43,4 @@ html[data-contrast="high"][data-theme^="dark"],
--app-tooltip-background-color: #fff;
--app-tooltip-color: #0b0f14;
}
+}
diff --git a/web/css/base/variables.theme-dark-green.css b/web/css/base/variables.theme-dark-green.css
index 8edaa79..6aa9101 100644
--- a/web/css/base/variables.theme-dark-green.css
+++ b/web/css/base/variables.theme-dark-green.css
@@ -1,5 +1,6 @@
@charset "UTF-8";
+@layer tokens {
[data-theme="dark-green"] {
--app-background-color: #0f1713;
--app-sidebar-background-color: #0d1511;
@@ -40,3 +41,4 @@
--app-tile-bg: rgb(20 28 24);
--app-blockquote-background-color: rgb(20 28 24);
}
+}
diff --git a/web/css/components/app-badges.css b/web/css/components/app-badges.css
index 5a2ada6..84e3d94 100644
--- a/web/css/components/app-badges.css
+++ b/web/css/components/app-badges.css
@@ -1,3 +1,4 @@
+@layer components {
.badge[role="button"],
.badge {
display: inline-flex;
@@ -68,6 +69,18 @@
border-color: var(--badge-info-border);
}
+.badge[data-variant="primary"] {
+ background: var(--badge-info-bg);
+ color: var(--badge-info-color);
+ border-color: var(--badge-info-border);
+}
+
+.badge[data-variant="secondary"] {
+ background: var(--badge-neutral-bg);
+ color: var(--badge-neutral-color);
+ border-color: var(--badge-neutral-border);
+}
+
.badge[data-variant="warn"] {
background: var(--badge-warn-bg);
color: var(--badge-warn-color);
@@ -105,3 +118,4 @@
display: flex;
gap: 0.35rem;
}
+}
diff --git a/web/css/components/app-blockquote.css b/web/css/components/app-blockquote.css
index 480fbfd..13ce337 100644
--- a/web/css/components/app-blockquote.css
+++ b/web/css/components/app-blockquote.css
@@ -1,60 +1,66 @@
-blockquote {
- --blockquote-bg: var(--app-blockquote-background-color);
- --blockquote-color: inherit;
- --blockquote-border: var(--app-blockquote-border-color);
- --blockquote-footer-color: var(--app-blockquote-footer-color);
+@layer components {
+ blockquote {
+ --blockquote-bg: var(--app-blockquote-background-color);
+ --blockquote-color: inherit;
+ --blockquote-border: var(--app-blockquote-border-color);
+ --blockquote-footer-color: var(--app-blockquote-footer-color);
- display: block;
- margin: var(--app-typography-spacing-vertical) 0;
- padding: var(--app-spacing);
- border-right: none;
- border-left: 0.25rem solid var(--app-blockquote-border-color);
- border-inline-start: 0.25rem solid var(--app-blockquote-border-color);
- border-inline-end: none;
- background-color: var(--blockquote-bg);
- color: var(--blockquote-color);
- border-left-color: var(--blockquote-border);
- border-inline-start-color: var(--blockquote-border);
- border-radius: var(--app-border-radius);
-}
+ display: block;
+ margin: var(--app-typography-spacing-vertical) 0;
+ padding: var(--app-spacing);
+ border-right: none;
+ border-left: 0.25rem solid var(--app-blockquote-border-color);
+ border-inline-start: 0.25rem solid var(--app-blockquote-border-color);
+ border-inline-end: none;
+ background-color: var(--blockquote-bg);
+ color: var(--blockquote-color);
+ border-left-color: var(--blockquote-border);
+ border-inline-start-color: var(--blockquote-border);
+ border-radius: var(--app-border-radius);
+ }
+ blockquote p:last-child {
+ margin: 0;
+ }
-blockquote footer {
- margin-top: calc(var(--app-typography-spacing-vertical) * 0.5);
- color: var(--blockquote-footer-color);
-}
+ blockquote footer {
+ margin-top: calc(var(--app-typography-spacing-vertical) * 0.5);
+ color: var(--blockquote-footer-color);
+ }
-blockquote[data-variant="success"] {
- --blockquote-bg: var(--badge-success-bg);
- --blockquote-color: var(--badge-success-color);
- --blockquote-border: var(--badge-success-border);
- --blockquote-footer-color: var(--badge-success-color);
-}
+ blockquote[data-variant="success"] {
+ --blockquote-bg: var(--badge-success-bg);
+ --blockquote-color: var(--badge-success-color);
+ --blockquote-border: var(--badge-success-border);
+ --blockquote-footer-color: var(--badge-success-color);
+ }
-blockquote[data-variant="danger"] {
- --blockquote-bg: var(--badge-danger-bg);
- --blockquote-color: var(--badge-danger-color);
- --blockquote-border: var(--badge-danger-border);
- --blockquote-footer-color: var(--badge-danger-color);
-}
+ blockquote[data-variant="error"],
+ blockquote[data-variant="danger"] {
+ --blockquote-bg: var(--badge-danger-bg);
+ --blockquote-color: var(--badge-danger-color);
+ --blockquote-border: var(--badge-danger-border);
+ --blockquote-footer-color: var(--badge-danger-color);
+ }
-blockquote[data-variant="info"] {
- --blockquote-bg: var(--badge-info-bg);
- --blockquote-color: var(--badge-info-color);
- --blockquote-border: var(--badge-info-border);
- --blockquote-footer-color: var(--badge-info-color);
-}
+ blockquote[data-variant="info"] {
+ --blockquote-bg: var(--badge-info-bg);
+ --blockquote-color: var(--badge-info-color);
+ --blockquote-border: var(--badge-info-border);
+ --blockquote-footer-color: var(--badge-info-color);
+ }
-blockquote[data-variant="warn"],
-blockquote[data-variant="warning"] {
- --blockquote-bg: var(--badge-warn-bg);
- --blockquote-color: var(--badge-warn-color);
- --blockquote-border: var(--badge-warn-border);
- --blockquote-footer-color: var(--badge-warn-color);
-}
+ blockquote[data-variant="warn"],
+ blockquote[data-variant="warning"] {
+ --blockquote-bg: var(--badge-warn-bg);
+ --blockquote-color: var(--badge-warn-color);
+ --blockquote-border: var(--badge-warn-border);
+ --blockquote-footer-color: var(--badge-warn-color);
+ }
-blockquote[data-variant="neutral"] {
- --blockquote-bg: var(--badge-neutral-bg);
- --blockquote-color: var(--badge-neutral-color);
- --blockquote-border: var(--badge-neutral-border);
- --blockquote-footer-color: var(--badge-neutral-color);
+ blockquote[data-variant="neutral"] {
+ --blockquote-bg: var(--badge-neutral-bg);
+ --blockquote-color: var(--badge-neutral-color);
+ --blockquote-border: var(--badge-neutral-border);
+ --blockquote-footer-color: var(--badge-neutral-color);
+ }
}
diff --git a/web/css/components/app-brand.css b/web/css/components/app-brand.css
index 0d54441..22d61f2 100644
--- a/web/css/components/app-brand.css
+++ b/web/css/components/app-brand.css
@@ -1,3 +1,4 @@
+@layer components {
.brand {
display: flex;
align-items: center;
@@ -28,4 +29,5 @@ img.brand-logo {
.badge:empty {
padding: 0;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-breadcrumb.css b/web/css/components/app-breadcrumb.css
index 913296c..3d367a1 100644
--- a/web/css/components/app-breadcrumb.css
+++ b/web/css/components/app-breadcrumb.css
@@ -1,3 +1,4 @@
+@layer components {
.app-breadcrumb {
margin-bottom: 5px;
display: flex;
@@ -9,4 +10,5 @@
.app-breadcrumb a {
color: inherit;
text-decoration: none;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-buttons.css b/web/css/components/app-buttons.css
index d8f3d3d..78c36db 100644
--- a/web/css/components/app-buttons.css
+++ b/web/css/components/app-buttons.css
@@ -1,3 +1,4 @@
+@layer components {
.danger:is(button, [type="submit"], [type="button"], [role="button"]) {
--app-background-color: var(--app-notice-error-border-color);
--app-border-color: var(--app-notice-error-border-color);
@@ -42,3 +43,4 @@
var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
0 0 0 var(--app-outline-width) var(--app-form-element-invalid-focus-color);
}
+}
diff --git a/web/css/components/app-dashboard-titlebar.css b/web/css/components/app-dashboard-titlebar.css
index b33ada9..399a8c8 100644
--- a/web/css/components/app-dashboard-titlebar.css
+++ b/web/css/components/app-dashboard-titlebar.css
@@ -1,3 +1,4 @@
+@layer components {
.app-dashboard-titlebar {
display: flex;
align-items: center;
@@ -52,4 +53,5 @@
.app-dashboard-titlebar h1 a:hover i {
background: var(--app-border);
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-details-titlebar.css b/web/css/components/app-details-titlebar.css
index 203d643..4037cf4 100644
--- a/web/css/components/app-details-titlebar.css
+++ b/web/css/components/app-details-titlebar.css
@@ -1,4 +1,5 @@
-.app-details-titlebar {
+@layer components {
+ .app-details-titlebar {
display: flex;
align-items: center;
justify-content: space-between;
@@ -7,33 +8,38 @@
border-bottom: 1px solid var(--app-border);
padding-block-end: var(--app-spacing);
margin-bottom: calc(var(--app-spacing) * 2);
-}
+ }
-.app-details-titlebar h1,
-.app-details-titlebar h2,
-.app-details-titlebar h3,
-.app-details-titlebar h4,
-.app-details-titlebar h5,
-.app-details-titlebar h6 {
- margin: 0;
-}
+ .app-details-titlebar h1,
+ .app-details-titlebar h2,
+ .app-details-titlebar h3,
+ .app-details-titlebar h4,
+ .app-details-titlebar h5,
+ .app-details-titlebar h6 {
+ margin: 0;
+ }
-.app-details-titlebar button,
-.app-details-titlebar [role="button"] {
- --app-button-padding-horizontal: 10px;
- --app-button-padding-vertical: 6px;
- font-size: 13px;
- margin: 0;
-}
+ .app-details-titlebar button,
+ .app-details-titlebar [role="button"] {
+ --app-button-padding-horizontal: 10px;
+ --app-button-padding-vertical: 6px;
+ font-size: 13px;
+ margin: 0;
+ }
-.app-details-titlebar-actions {
- display: flex;
- align-items: center;
- gap: 10px;
- white-space: nowrap;
-}
+ .app-details-titlebar button i,
+ .app-details-titlebar [role="button"] i {
+ font-size: 10px;
+ }
-.app-details-titlebar h1 i {
+ .app-details-titlebar-actions {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ white-space: nowrap;
+ }
+
+ .app-details-titlebar h1 i {
background: var(--app-background-color);
width: 35px;
height: 29px;
@@ -46,42 +52,43 @@
border: 1px solid var(--app-border);
color: var(--app-muted-color);
box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;
-}
+ }
-.app-details-titlebar h1:has(i) {
+ .app-details-titlebar h1:has(i) {
display: flex;
align-items: center;
gap: 7px;
line-height: 1;
-}
-.app-details-titlebar details.dropdown {
- margin-bottom: 0;
-}
+ }
+ .app-details-titlebar details.dropdown {
+ margin-bottom: 0;
+ }
-.app-details-titlebar details.dropdown summary:after {
+ .app-details-titlebar details.dropdown summary:after {
display: none;
-}
+ }
-.app-details-titlebar details.dropdown li {
- padding: 0!important;
- margin: 0!important;
+ .app-details-titlebar details.dropdown li {
+ padding: 0 !important;
+ margin: 0 !important;
border-bottom: 1px solid var(--app-border);
-}
+ }
-.app-details-titlebar details.dropdown li:last-child {
+ .app-details-titlebar details.dropdown li:last-child {
border-bottom: none;
-}
+ }
-.app-details-titlebar details.dropdown ul {
- padding: 0!important;
- margin: 0!important;
-}
+ .app-details-titlebar details.dropdown ul {
+ padding: 0 !important;
+ margin: 0 !important;
+ }
-.app-details-titlebar details.dropdown li button,
-.app-details-titlebar details.dropdown li [role=button] {
- margin: 0!important;
+ .app-details-titlebar details.dropdown li button,
+ .app-details-titlebar details.dropdown li [role="button"] {
+ margin: 0 !important;
border: none;
border-radius: 0;
width: 100%;
text-align: left;
-}
\ No newline at end of file
+ }
+}
diff --git a/web/css/components/app-details.css b/web/css/components/app-details.css
index e253aee..8c655c8 100644
--- a/web/css/components/app-details.css
+++ b/web/css/components/app-details.css
@@ -1,7 +1,22 @@
+@layer components {
.app-details-container aside {
padding-top: var(--app-spacing);
}
+.app-details-aside-actions {
+ display: grid;
+ gap: calc(var(--app-spacing) * 0.5);
+}
+
+.app-details-aside-actions form {
+ margin: 0;
+}
+
+.app-details-aside-actions a[role="button"],
+.app-details-aside-actions button {
+ width: 100%;
+}
+
.user-avatar-block,
.entity-avatar-block {
--avatar-size: 96px;
@@ -54,7 +69,7 @@
.avatar-square .user-avatar-placeholder,
.avatar-square .entity-avatar-image,
.avatar-square .entity-avatar-placeholder {
- border-radius: var(--app-radius);
+ border-radius: var(--app-border-radius);
}
.avatar-ratio-1-1 {
@@ -102,13 +117,15 @@
.app-details-container .app-breadcrumb {
padding-top: calc(var(--app-spacing) * 2);
position: sticky;
- top: 20px;
+ top: 16px;
+ z-index: 10;
background: var(--app-background-color);
}
.app-details-container .app-details-titlebar {
position: sticky;
- top: 69px;
+ top: 64px;
+ z-index: 10;
background: var(--app-background-color);
}
@@ -146,5 +163,4 @@
min-height: 100vh;
}
}
-
-
+}
diff --git a/web/css/components/app-flash.css b/web/css/components/app-flash.css
index cf22919..6c7790a 100644
--- a/web/css/components/app-flash.css
+++ b/web/css/components/app-flash.css
@@ -1,3 +1,4 @@
+@layer components {
.notice {
--app-notice-border-color: var(--app-muted-border-color);
--app-notice-background-color: var(--app-card-background-color);
@@ -127,4 +128,5 @@
.notice li {
list-style: none;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-forms.css b/web/css/components/app-forms.css
index 4d7a5a2..dd1fae5 100644
--- a/web/css/components/app-forms.css
+++ b/web/css/components/app-forms.css
@@ -1,62 +1,103 @@
-.form-hint {
- font-size: small;
-}
+@layer components {
+ .form-hint {
+ font-size: small;
+ }
-ul.form-hint-list {
- margin: 0;
- padding-left: var(--app-spacing);
-}
+ ul.form-hint-list {
+ margin: 0;
+ padding-left: var(--app-spacing);
+ }
-ul.form-hint-list li {
- margin: 0;
-}
+ ul.form-hint-list li {
+ margin: 0;
+ }
-ul.form-hint-list li.is-valid {
- color: var(--app-form-element-valid-border-color);
-}
+ ul.form-hint-list li.is-valid {
+ color: var(--app-form-element-valid-border-color);
+ }
-ul.form-hint-list li.is-invalid {
- color: var(--app-form-element-invalid-border-color);
-}
+ ul.form-hint-list li.is-invalid {
+ color: var(--app-form-element-invalid-border-color);
+ }
-ul.form-hint-list li.is-valid:after {
- content: "\F26B";
- font-family: "Bootstrap-icons";
- margin-left: 4px;
- font-size: 10px;
-}
+ ul.form-hint-list li.is-valid:after {
+ content: "\F26B";
+ font-family: "Bootstrap-icons";
+ margin-left: 4px;
+ font-size: 10px;
+ }
-ul.form-hint-list li.is-invalid:after {
- content: "\F33A";
- font-family: "Bootstrap-icons";
- margin-left: 4px;
- font-size: 10px;
-}
+ ul.form-hint-list li.is-invalid:after {
+ content: "\F33A";
+ font-family: "Bootstrap-icons";
+ margin-left: 4px;
+ font-size: 10px;
+ }
-label:has([type="checkbox"], [type="radio"]) {
- display: flex;
- line-height: 1;
- align-items: center;
-}
+ label:has([type="checkbox"], [type="radio"]) {
+ display: flex;
+ line-height: 1;
+ align-items: center;
+ }
-input[type="color"] {
+ input[type="color"] {
padding: 0;
width: 42px;
border: 0;
margin: 0;
height: 42px;
flex-shrink: 0;
-}
+ }
-label:has(input[type="color"]) {
- display: flex;
- align-items: center;
- gap: 10px;
-}
+ label:has(input[type="color"]) {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
-small.muted {
+ small.muted {
display: block;
width: 100%;
color: var(--app-muted-color);
-}
+ }
+ a.muted {
+ color: var(--app-muted-color);
+ }
+ label.app-field:has(input[type="checkbox"][disabled]),
+ label.app-field:has(input[type="radio"][disabled]) {
+ cursor: not-allowed;
+ opacity: 0.8;
+ }
+
+ label.app-field:has(input[type="checkbox"][disabled]) > span,
+ label.app-field:has(input[type="radio"][disabled]) > span {
+ color: var(--app-muted-color);
+ }
+
+ input[type="checkbox"][disabled],
+ input[type="radio"][disabled] {
+ --app-border-color: var(--app-muted-border-color);
+ --app-background-color: var(--app-form-element-background-color);
+ cursor: not-allowed;
+ }
+
+ input[type="checkbox"][disabled]:checked,
+ input[type="checkbox"][disabled]:indeterminate,
+ input[type="radio"][disabled]:checked {
+ --app-border-color: var(--app-muted-border-color);
+ --app-background-color: var(--app-muted-border-color);
+ }
+
+ fieldset[aria-disabled="true"] {
+ border-color: var(--app-muted-border-color);
+ }
+
+ fieldset[aria-disabled="true"] .muted,
+ fieldset[aria-disabled="true"] legend small {
+ color: var(--app-muted-color);
+ }
+ label:has(.badge) > span {
+ margin-bottom: 5px;
+ }
+}
diff --git a/web/css/components/app-list-table.css b/web/css/components/app-list-table.css
index 3ff8ae8..a9f8d36 100644
--- a/web/css/components/app-list-table.css
+++ b/web/css/components/app-list-table.css
@@ -1,7 +1,9 @@
+@layer components {
.app-list-table table {
margin: 0;
}
.app-list-table {
white-space: nowrap;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-list-tabs.css b/web/css/components/app-list-tabs.css
index c45b318..0850858 100644
--- a/web/css/components/app-list-tabs.css
+++ b/web/css/components/app-list-tabs.css
@@ -1,3 +1,4 @@
+@layer components {
.app-list-tabs {
display: flex;
flex-wrap: wrap;
@@ -29,3 +30,4 @@
color: var(--app-color);
border-color: var(--list-tabs-active);
}
+}
diff --git a/web/css/components/app-list-titlebar.css b/web/css/components/app-list-titlebar.css
index 0c86fad..0bb0439 100644
--- a/web/css/components/app-list-titlebar.css
+++ b/web/css/components/app-list-titlebar.css
@@ -1,36 +1,38 @@
-.app-list-titlebar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: 10px;
- margin-bottom: calc(var(--app-spacing) * 1);
-}
+@layer components {
+ .app-list-titlebar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: calc(var(--app-spacing) * 1);
+ }
-.app-list-titlebar h1,
-.app-list-titlebar h2,
-.app-list-titlebar h3,
-.app-list-titlebar h4,
-.app-list-titlebar h5,
-.app-list-titlebar h6 {
- margin: 0;
-}
+ .app-list-titlebar h1,
+ .app-list-titlebar h2,
+ .app-list-titlebar h3,
+ .app-list-titlebar h4,
+ .app-list-titlebar h5,
+ .app-list-titlebar h6 {
+ margin: 0;
+ }
-.app-list-titlebar button,
-.app-list-titlebar [role="button"] {
- --app-button-padding-horizontal: 10px;
- --app-button-padding-vertical: 6px;
- font-size: 13px;
- margin: 0;
-}
+ .app-list-titlebar button,
+ .app-list-titlebar [role="button"] {
+ --app-button-padding-horizontal: 10px;
+ --app-button-padding-vertical: 6px;
+ font-size: 13px;
+ margin: 0;
+ }
-.app-list-titlebar-actions {
- display: flex;
- align-items: center;
- gap: 10px;
-}
+ .app-list-titlebar-actions {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ white-space: nowrap;
+ }
-.app-list-titlebar h1 i {
+ .app-list-titlebar h1 i {
background: var(--app-muted-border-color);
width: 35px;
height: 35px;
@@ -39,41 +41,43 @@
display: inline-flex;
align-items: center;
justify-content: center;
-}
+ }
-.app-list-titlebar h1:has(i) {
+ .app-list-titlebar h1:has(i) {
display: flex;
align-items: center;
gap: 7px;
-}
+ }
-.app-list-titlebar details.dropdown {
- margin-bottom: 0;
-}
+ .app-list-titlebar details.dropdown {
+ margin-bottom: 0;
+ }
-.app-list-titlebar details.dropdown summary:after {
+ .app-list-titlebar details.dropdown summary:after {
display: none;
-}
+ }
-.app-list-titlebar details.dropdown li {
- padding: 0!important;
- margin: 0!important;
+ .app-list-titlebar details.dropdown li {
+ padding: 0 !important;
+ margin: 0 !important;
border-bottom: 1px solid var(--app-border);
-}
+ }
-.app-list-titlebar details.dropdown li:last-child {
+ .app-list-titlebar details.dropdown li:last-child {
border-bottom: none;
-}
+ }
-.app-list-titlebar details.dropdown ul {
- padding: 0!important;
- margin: 0!important;
-}
+ .app-list-titlebar details.dropdown ul {
+ padding: 0 !important;
+ margin: 0 !important;
+ }
-.app-list-titlebar details.dropdown li button, .app-list-titlebar details.dropdown li [role=button] {
+ .app-list-titlebar details.dropdown li button,
+ .app-list-titlebar details.dropdown li [role="button"] {
margin: 0 !important;
border: none;
border-radius: 0;
width: 100%;
text-align: left;
-}
\ No newline at end of file
+ }
+}
diff --git a/web/css/components/app-list-toolbar.css b/web/css/components/app-list-toolbar.css
index d7d5909..b3dd9dd 100644
--- a/web/css/components/app-list-toolbar.css
+++ b/web/css/components/app-list-toolbar.css
@@ -1,3 +1,4 @@
+@layer components {
.app-list-toolbar {
display: flex;
align-items: flex-end;
@@ -74,4 +75,5 @@
padding: 0 !important;
padding-left: 3px !important;
font-size: 11px !important;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-page-copy.css b/web/css/components/app-page-copy.css
index c06755e..3c44d53 100644
--- a/web/css/components/app-page-copy.css
+++ b/web/css/components/app-page-copy.css
@@ -1,3 +1,4 @@
+@layer components {
.app-page-copy .app-field {
@@ -7,4 +8,5 @@
.app-page-copy .app-field [role="group"] {
margin-bottom: 0;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-page-editor.css b/web/css/components/app-page-editor.css
index b3c4798..2297be9 100644
--- a/web/css/components/app-page-editor.css
+++ b/web/css/components/app-page-editor.css
@@ -1,3 +1,4 @@
+@layer components {
.app-page-header {
display: flex;
align-items: center;
@@ -71,4 +72,5 @@ label.app-field > small {
.app-details-aside-section button {
margin-bottom: 0;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/components/app-search.css b/web/css/components/app-search.css
index c88e3ac..19f345d 100644
--- a/web/css/components/app-search.css
+++ b/web/css/components/app-search.css
@@ -1,5 +1,49 @@
+@layer components {
.app-search {
- padding: 0 var(--app-spacing);
+ position: relative;
+ padding: 0 var(--app-spacing);
+ margin-bottom: var(--app-spacing);
+}
+
+.app-search-shortcut {
+ position: absolute;
+ right: calc(var(--app-spacing) + 0.5rem);
+ top: 50%;
+ transform: translateY(-50%);
+ border: 1px solid var(--app-border);
+ border-radius: 6px;
+ background: var(--app-card-background-color);
+ color: var(--app-muted-color);
+ font-size: 0.75rem;
+ line-height: 1;
+ padding: 0.2rem 0.4rem;
+ pointer-events: none;
+}
+
+.app-search-empty-state {
+ margin: var(--app-spacing);
+ padding: 1rem;
+ border: 1px dashed var(--app-border);
+ border-radius: var(--app-border-radius);
+ text-align: center;
+ color: var(--app-muted-color);
+ font-size: 0.9rem;
+ cursor: text;
+}
+
+.app-search-empty-state .bi-search {
+ display: inline-block;
+ font-size: 1.25rem;
+ margin-bottom: 0.5rem;
+ color: var(--app-color);
+}
+
+.app-search-empty-state p {
+ margin: 0 0 0.25rem;
+}
+
+.app-search-empty-state small {
+ display: block;
}
ul.app-search-results {
@@ -14,21 +58,23 @@ ul.app-search-results > li > a {
ul.app-search-results .badge {
font-size: 10px;
padding: 1px;
- min-width: 20px;
+ min-width: 18px;
text-align: center;
border-radius: 999px;
background: var(--app-accordion-border-color);
display: inline-flex;
justify-content: center;
align-items: center;
- height: 20px;
+ height: 18px;
+ position: relative;
+ top: -1px;
}
ul.app-search-preview {
position: relative;
font-size: 11px;
- padding: 0 0 0 20px;
- margin: 6px 0 1.5rem 10px;
+ padding: 0 0 0 0;
+ margin: 0;
opacity: 0.75;
list-style: none;
}
@@ -86,6 +132,8 @@ input#side-search {
--app-form-element-spacing-vertical: 6px;
height: auto;
font-size: 13px;
+ padding-right: 3rem;
+ margin-bottom:0;
}
ul.app-search-preview:has(li) {
@@ -137,3 +185,4 @@ ul.app-search-preview:has(li) {
color: var(--app-muted-color);
font-weight: 600;
}
+}
diff --git a/web/css/components/app-tabs.css b/web/css/components/app-tabs.css
index d1012f1..acec9aa 100644
--- a/web/css/components/app-tabs.css
+++ b/web/css/components/app-tabs.css
@@ -1,9 +1,24 @@
+@layer components {
.app-tabs {
display: flex;
flex-direction: column;
gap: var(--app-spacing);
}
+/* No-JS fallback: show only first tab panel. */
+html.no-js [data-tabs] [data-tab-panel] {
+ display: none;
+}
+
+html.no-js [data-tabs] [data-tab-panel]:first-of-type {
+ display: block;
+}
+
+/* JS mode: keep panels hidden until tab init completed (prevents flash). */
+html.js [data-tabs]:not([data-tabs-ready="1"]) [data-tab-panel] {
+ display: none !important;
+}
+
.app-tabs-nav {
display: flex;
border-bottom: 1px solid var(--tabs-border);
@@ -42,6 +57,21 @@
border-color: var(--tabs-active);
}
+.app-tabs-nav button.has-invalid,
+.app-tabs-nav a.has-invalid {
+ color: var(--app-danger, #dc3545) !important;
+}
+
[data-tab-panel][hidden] {
display: none;
}
+
+html.js [data-tabs][data-tabs-ready="1"] [data-tab-panel]:not([hidden]) {
+ display: block;
+}
+
+/* Safety fallback when JS is available but the ready marker is missing. */
+html:not(.no-js) [data-tabs] [data-tab-panel]:not([hidden]) {
+ display: block;
+}
+}
diff --git a/web/css/components/app-tile.css b/web/css/components/app-tile.css
index f4a664f..560ceb0 100644
--- a/web/css/components/app-tile.css
+++ b/web/css/components/app-tile.css
@@ -1,74 +1,83 @@
-.app-tiles {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
- gap: calc(var(--app-spacing) * 1);
- margin-bottom: calc(var(--app-spacing) * 2);
-}
+@layer components {
+ .app-tiles {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ gap: calc(var(--app-spacing) * 1);
+ margin-bottom: calc(var(--app-spacing) * 2);
+ }
-.app-stats-table {
- overflow: auto;
- border: 1px solid var(--app-border);
- border-radius: var(--app-border-radius);
- margin-bottom: calc(var(--app-spacing) * 1);
-}
+ .app-stats-table {
+ overflow: auto;
+ border: 1px solid var(--app-border);
+ border-radius: var(--app-border-radius);
+ margin-bottom: calc(var(--app-spacing) * 1);
+ }
-.app-stats-table th {
- border-top: 0;
-}
+ .app-stats-table th {
+ border-top: 0;
+ }
-.app-stats-table table {
- margin: 0;
-}
+ .app-stats-table table {
+ margin: 0;
+ }
-.app-stats-table table tr:last-child td {
- border-bottom: 0;
-}
+ .app-stats-table table tr:last-child td {
+ border-bottom: 0;
+ }
-.app-tile {
- --tile-icon-bg: var(--app-tile-icon-bg);
- --tile-icon-color: var(--app-tile-icon-color);
- --tile-count-color: var(--app-tile-count-color);
- --tile-label-color: var(--app-tile-label-color);
- --tile-link-color: var(--app-tile-link-color);
- position: relative;
- display: block;
- padding: calc(var(--app-spacing) * 1);
- border: 1px solid var(--app-tile-border);
- border-radius: calc(var(--app-border-radius) * 1.1);
- background: var(--app-tile-bg);
- color: var(--app-tile-label-color);
- text-decoration: none;
- transition:
- transform var(--app-transition),
- box-shadow var(--app-transition),
- border-color var(--app-transition);
-}
+ .app-stats-table-empty {
+ padding: var(--app-spacing);
+ }
-.app-tile:hover {
- box-shadow: 0 12px 30px rgba(0, 0, 0, 0.08);
-}
+ .app-stats-table-explanation {
+ padding: var(--app-spacing);
+ }
-.app-tile-icon {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 36px;
- height: 36px;
- border-radius: 10px;
- background: var(--tile-icon-bg);
- color: var(--tile-icon-color);
- font-size: 1.1rem;
-}
+ .app-tile {
+ --tile-icon-bg: var(--app-tile-icon-bg);
+ --tile-icon-color: var(--app-tile-icon-color);
+ --tile-count-color: var(--app-tile-count-color);
+ --tile-label-color: var(--app-tile-label-color);
+ --tile-link-color: var(--app-tile-link-color);
+ position: relative;
+ display: block;
+ padding: calc(var(--app-spacing) * 1);
+ border: 1px solid var(--app-tile-border);
+ border-radius: calc(var(--app-border-radius) * 1.1);
+ background: var(--app-tile-bg);
+ color: var(--app-tile-label-color);
+ text-decoration: none;
+ transition:
+ transform var(--app-transition),
+ box-shadow var(--app-transition),
+ border-color var(--app-transition);
+ }
-.app-tile-count {
- position: absolute;
- top: calc(var(--app-spacing) * 1);
- right: calc(var(--app-spacing) * 1);
- font-weight: 700;
- color: var(--tile-count-color);
-}
+ .app-tile:hover {
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.08);
+ }
-.app-tile-label {
+ .app-tile-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 36px;
+ height: 36px;
+ border-radius: 10px;
+ background: var(--tile-icon-bg);
+ color: var(--tile-icon-color);
+ font-size: 1.1rem;
+ }
+
+ .app-tile-count {
+ position: absolute;
+ top: calc(var(--app-spacing) * 1);
+ right: calc(var(--app-spacing) * 1);
+ font-weight: 700;
+ color: var(--tile-count-color);
+ }
+
+ .app-tile-label {
display: block;
margin-top: calc(var(--app-spacing) * 1);
color: var(--tile-label-color);
@@ -76,55 +85,56 @@
overflow: hidden;
white-space: nowrap;
max-width: 191px;
-}
+ }
-.app-tile-link {
- position: absolute;
- right: calc(var(--app-spacing) * 1);
- bottom: calc(var(--app-spacing) * 1);
- color: var(--tile-link-color);
- font-size: 0.9rem;
-}
+ .app-tile-link {
+ position: absolute;
+ right: calc(var(--app-spacing) * 1);
+ bottom: calc(var(--app-spacing) * 1);
+ color: var(--tile-link-color);
+ font-size: 0.9rem;
+ }
-.app-tile.is-small {
- padding: 10px;
- display: flex;
- align-items: center;
- min-height: 50px;
-}
-.app-tile.is-small span.app-tile-icon {
- width: 25px;
- height: 25px;
- border-radius: 6px;
- font-size: 12px;
- margin-right: 10px;
-}
+ .app-tile.is-small {
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ min-height: 50px;
+ }
+ .app-tile.is-small span.app-tile-icon {
+ width: 25px;
+ height: 25px;
+ border-radius: 6px;
+ font-size: 12px;
+ margin-right: 10px;
+ }
-.app-tile.is-small .app-tile-link {
+ .app-tile.is-small .app-tile-link {
bottom: 14px;
-}
+ }
-.app-tile.is-small .app-tile-count {
+ .app-tile.is-small .app-tile-count {
position: static;
margin-right: 5px;
display: block;
-}
-.app-tile.is-small .app-tile-label {
- margin-top: 0;
- font-weight: 400;
-}
+ }
+ .app-tile.is-small .app-tile-label {
+ margin-top: 0;
+ font-weight: 400;
+ }
-.app-stats-table-header {
- border-bottom: 1px solid var(--app-border);
- padding: 4px 10px 4px 10px;
- text-transform: uppercase;
- font-size: 13px;
- letter-spacing: 0.4px;
- background: var(--app-blockquote-background-color);
-}
+ .app-stats-table-header {
+ border-bottom: 1px solid var(--app-border);
+ padding: 4px 10px 4px 10px;
+ text-transform: uppercase;
+ font-size: 13px;
+ letter-spacing: 0.4px;
+ background: var(--app-blockquote-background-color);
+ }
-@media (max-width: 640px) {
- .app-tiles {
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ @media (max-width: 640px) {
+ .app-tiles {
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ }
}
}
diff --git a/web/css/components/app-tooltips.css b/web/css/components/app-tooltips.css
index 0f64695..155c664 100644
--- a/web/css/components/app-tooltips.css
+++ b/web/css/components/app-tooltips.css
@@ -1,3 +1,4 @@
+@layer components {
[data-tooltip] {
--app-card-background-color: inherit;
position: relative;
@@ -97,3 +98,4 @@
left: auto;
transform: translate(calc(-1 * (var(--tooltip-offset) - 2px)), -50%) rotate(45deg);
}
+}
diff --git a/web/css/components/vendor-gridjs.css b/web/css/components/vendor-gridjs.css
deleted file mode 100644
index 31d4733..0000000
--- a/web/css/components/vendor-gridjs.css
+++ /dev/null
@@ -1,212 +0,0 @@
-.gridjs-container {
- color: var(--app-color);
- width: 100%;
- padding: 0;
-}
-
-.gridjs-wrapper {
- border: 0;
- border-radius: 0;
- box-shadow: none;
- background-color: var(--app-background-color);
- border-top: var(--app-border-width) solid var(--app-table-border-color);
- padding-block-end: 1rem;
- min-height: 515px;
-}
-
-.gridjs-footer {
- background-color: var(--app-background-color);
- border: 0;
- border-top: 0;
- box-shadow: none;
- color: var(--app-muted-color);
- padding: 1rem 0 0;
-}
-
-.gridjs-table {
- color: var(--app-color);
-}
-
-th.gridjs-th {
- padding: calc(var(--app-spacing) / 2) var(--app-spacing);
- border: none;
- border-bottom: var(--app-border-width) solid var(--app-table-border-color);
- background-color: var(--app-background-color);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- text-align: left;
- text-align: start;
-}
-
-button.gridjs-sort {
- height: 15px;
-}
-
-th.gridjs-th-sort:hover,
-th.gridjs-th-sort:focus {
- background-color: var(--app-table-row-stripped-background-color);
-}
-
-td.gridjs-td {
- background-color: var(--app-background-color);
- border: none;
- border-color: var(--app-table-border-color);
- padding: calc(var(--app-spacing) / 2) var(--app-spacing);
- border-bottom: var(--app-border-width) solid var(--app-table-border-color);
- background-color: var(--app-background-color);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- text-align: left;
- text-align: start;
-}
-
-.gridjs-search {
- float: none;
-}
-
-.gridjs-search-input {
- width: min(320px, 100%);
-}
-
-input.gridjs-input {
- background-color: var(--app-background-color);
- border: var(--app-border-width) solid var(--app-form-element-border-color);
- border-radius: var(--app-border-radius);
- color: var(--app-color);
- font-size: 0.95rem;
- padding: 0.5rem 0.75rem;
-}
-
-input.gridjs-input:focus {
- border-color: var(--app-primary);
- box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
-}
-
-.gridjs-pagination {
- color: var(--app-muted-color);
-}
-
-.gridjs-pagination .gridjs-pages button {
- background-color: var(--app-background-color);
- border: var(--app-border-width) solid var(--app-table-border-color);
- color: var(--app-color);
- padding: 1px 10px;
-}
-
-.gridjs-pagination .gridjs-pages button:hover {
- background-color: var(--app-primary-hover-background);
- border-color: var(--app-primary-hover-border);
- color: var(--app-primary-inverse);
-}
-
-.gridjs-pagination .gridjs-pages button:focus {
- box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
-}
-
-.gridjs-pagination .gridjs-pages button.gridjs-currentPage {
- background-color: var(--app-primary) !important;
- font-weight: 400;
- padding: 2px 10px;
- color: var(--app-secondary-inverse) !important;
-}
-
-.gridjs-pagination .gridjs-pages button:disabled, .gridjs-pagination .gridjs-pages button[disabled] {
- background-color: var(--app-background-color);
- color: var(--app-muted-color);
- cursor: default;
- padding: 2px 10px;
- border: 0;
-}
-
-.gridjs-pagination .gridjs-pages {
- display: inline-flex;
- gap: 5px;
-}
-
-.gridjs-loading-bar {
- background-color: var(--app-background-color);
- opacity: 0.7;
-}
-
-.grid-avatar {
- width: 36px;
- height: 36px;
- border-radius: 999px;
- border: 1px solid var(--app-muted-border-color);
- background: var(--app-card-background-color);
- object-fit: contain;
- display: inline-flex;
-}
-
-.grid-avatar-placeholder {
- align-items: center;
- justify-content: center;
- font-weight: 600;
- color: var(--app-muted-color);
- font-size: 11px;
- background: var(--app-background-color);
-}
-
-.gridjs-loading-bar:after {
- background-image: linear-gradient(
- 90deg,
- transparent,
- var(--app-primary-focus),
- transparent
- );
-}
-
- /* .gridjs-container:not(.gridjs-has-loaded) .gridjs-message.gridjs-notfound {
- display: none;
- } */
-
-.gridjs-container.gridjs-is-updating .gridjs-message.gridjs-notfound {
- display: none;
-}
-
-.gridjs-pages button {
- background: var(--app-form-element-background-color) !important;
- color: var(--app-contrast) !important;
-}
-
-.gridjs-summary {
- font-size: small;
-}
-
-tr.gridjs-tr {
- cursor: pointer;
-}
-
-tr.gridjs-tr:hover td {
- background: var(--app-table-row-stripped-background-color);
-}
-
-html[data-theme=dark] button.gridjs-sort,
-html[data-theme=dark] button.gridjs-sort-neutral {
- filter: invert(1);
-}
-
-html[data-theme=dark-green] button.gridjs-sort,
-html[data-theme=dark-green] button.gridjs-sort-neutral {
- filter: invert(1);
-}
-
-.gridjs-tbody, td.gridjs-td {
- background-color: var(--app-background-color)
-}
-
-.gridjs-table input[data-grid-select-all] {
- width: 1em;
- height: 1em;
- margin: 0;
- border-radius: 4px;
- border-width: .5px;
-}
-
-.gridjs-th-content:has(input[data-grid-select-all]) {
- text-align: center;
-}
-
-.gridjs-pagination .gridjs-pages button:last-child {
- border-right: none;
-}
\ No newline at end of file
diff --git a/web/css/layout/app-aside-icon-bar.css b/web/css/layout/app-aside-icon-bar.css
index cec0d14..97b1674 100644
--- a/web/css/layout/app-aside-icon-bar.css
+++ b/web/css/layout/app-aside-icon-bar.css
@@ -1,3 +1,4 @@
+@layer layout {
aside.aside-icon-bar {
--app-icon-bar-item-padding: 0.5rem;
--app-icon-bar-item-size: 20px;
@@ -104,3 +105,4 @@ aside.aside-icon-bar li button.active {
border-top: var(--app-icon-bar-border-width) solid var(--app-primary);
}
}
+}
diff --git a/web/css/layout/app-page-layout.css b/web/css/layout/app-page-layout.css
new file mode 100644
index 0000000..105b5b5
--- /dev/null
+++ b/web/css/layout/app-page-layout.css
@@ -0,0 +1,34 @@
+.page-layout {
+ display: flex;
+ flex-direction: column;
+ min-height: 100dvh;
+}
+
+.page-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.75rem 1.5rem;
+ border-bottom: 1px solid var(--border);
+}
+
+.page-header .app-brand img {
+ height: 2.5rem;
+ width: auto;
+}
+
+.page-header nav ul {
+ display: flex;
+ gap: 1.5rem;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.page-content {
+ flex: 1;
+ max-width: 60rem;
+ margin: 0 auto;
+ padding: 2rem 1.5rem;
+ width: 100%;
+}
diff --git a/web/css/layout/app-shell.css b/web/css/layout/app-shell.css
index 9ce05de..9a4fbe3 100644
--- a/web/css/layout/app-shell.css
+++ b/web/css/layout/app-shell.css
@@ -1,239 +1,258 @@
@charset "UTF-8";
-a {
- --app-text-decoration: underline;
-}
+@layer layout {
+ a {
+ --app-text-decoration: underline;
+ }
-a.contrast,
-a.secondary {
- --app-text-decoration: underline;
-}
+ a.contrast,
+ a.secondary {
+ --app-text-decoration: underline;
+ }
-small {
- --app-font-size: 0.875em;
-}
+ small {
+ --app-font-size: 0.875em;
+ }
-div#debugger-bar {
- display: none;
-}
+ div#debugger-bar {
+ display: none;
+ }
-.app-container.is-sidebar-hidden .app-sidebar {
- display: none;
-}
+ .app-container.is-sidebar-hidden .app-sidebar {
+ display: none;
+ }
-.sidebar-hidden .app-sidebar {
- display: none;
-}
+ .sidebar-hidden .app-sidebar {
+ display: none;
+ }
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- --app-font-weight: 700;
-}
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ --app-font-weight: 700;
+ }
-h1 {
- --app-font-size: 1.5rem;
- --app-line-height: 1.125;
- --app-typography-spacing-top: 3rem;
-}
+ h1 {
+ --app-font-size: 1.5rem;
+ --app-line-height: 1.125;
+ --app-typography-spacing-top: 3rem;
+ }
-h2 {
- --app-font-size: 1.4rem;
- --app-line-height: 1.15;
- --app-typography-spacing-top: 2.625rem;
-}
+ h2 {
+ --app-font-size: 1.4rem;
+ --app-line-height: 1.15;
+ --app-typography-spacing-top: 2.625rem;
+ }
-h3 {
- --app-font-size: 1.3rem;
- --app-line-height: 1.175;
- --app-typography-spacing-top: 2.25rem;
-}
+ h3 {
+ --app-font-size: 1.3rem;
+ --app-line-height: 1.175;
+ --app-typography-spacing-top: 2.25rem;
+ }
-h4 {
- --app-font-size: 1.2rem;
- --app-line-height: 1.2;
- --app-typography-spacing-top: 1.874rem;
-}
+ h4 {
+ --app-font-size: 1.2rem;
+ --app-line-height: 1.2;
+ --app-typography-spacing-top: 1.874rem;
+ }
-h5 {
- --app-font-size: 1.1rem;
- --app-line-height: 1.225;
- --app-typography-spacing-top: 1.6875rem;
-}
+ h5 {
+ --app-font-size: 1.1rem;
+ --app-line-height: 1.225;
+ --app-typography-spacing-top: 1.6875rem;
+ }
-h6 {
- --app-font-size: 1rem;
- --app-line-height: 1.25;
- --app-typography-spacing-top: 1.5rem;
-}
+ h6 {
+ --app-font-size: 1rem;
+ --app-line-height: 1.25;
+ --app-typography-spacing-top: 1.5rem;
+ }
-tfoot td,
-tfoot th,
-thead td,
-thead th {
- --app-font-weight: 600;
- --app-border-width: 2px;
-}
+ tfoot td,
+ tfoot th,
+ thead td,
+ thead th {
+ --app-font-weight: 600;
+ --app-border-width: 2px;
+ }
-code,
-kbd,
-pre,
-samp {
- --app-font-family: var(--app-font-family-monospace);
-}
+ code,
+ kbd,
+ pre,
+ samp {
+ --app-font-family: var(--app-font-family-monospace);
+ }
-kbd {
- --app-font-weight: bolder;
-}
+ kbd {
+ --app-font-weight: bolder;
+ }
-:where(select, textarea),
-input:not(
- [type="submit"],
- [type="button"],
- [type="reset"],
- [type="checkbox"],
- [type="radio"],
- [type="file"]
-) {
- --app-outline-width: 0.0625rem;
-}
-
-[type="checkbox"],
-[type="radio"] {
- --app-border-width: 0.125rem;
-}
-
-[type="checkbox"][role="switch"] {
- --app-border-width: 0.1875rem;
-}
-
-details.dropdown summary:not([role="button"]) {
- --app-outline-width: 0.0625rem;
-}
-
-nav details.dropdown summary:focus-visible {
- --app-outline-width: 0.125rem;
-}
-
-[role="search"] {
- --app-border-radius: 5rem;
-}
-
-[role="group"]:has(
- button.secondary:focus,
- [type="submit"].secondary:focus,
- [type="button"].secondary:focus,
- [role="button"].secondary:focus
-),
-[role="search"]:has(
- button.secondary:focus,
- [type="submit"].secondary:focus,
- [type="button"].secondary:focus,
- [role="button"].secondary:focus
-) {
- --app-group-box-shadow-focus-with-button: 0 0 0 var(--app-outline-width)
- var(--app-secondary-focus);
-}
-
-[role="group"]:has(
- button.contrast:focus,
- [type="submit"].contrast:focus,
- [type="button"].contrast:focus,
- [role="button"].contrast:focus
-),
-[role="search"]:has(
- button.contrast:focus,
- [type="submit"].contrast:focus,
- [type="button"].contrast:focus,
- [role="button"].contrast:focus
-) {
- --app-group-box-shadow-focus-with-button: 0 0 0 var(--app-outline-width)
- var(--app-contrast-focus);
-}
-
-[role="group"] [role="button"],
-[role="group"] [type="button"],
-[role="group"] [type="submit"],
-[role="group"] button,
-[role="search"] [role="button"],
-[role="search"] [type="button"],
-[role="search"] [type="submit"],
-[role="search"] button {
- --app-form-element-spacing-horizontal: 2rem;
-}
-
-[role="group"] form:last-child button {
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
-}
-
-table td [role="group"] {
- margin: 0;
-}
-
-th {
- text-transform: uppercase;
- font-size: 11px;
- letter-spacing: 0.4px;
- border-top: 1px solid var(--app-border);
-}
-
-table td .grid-actions button,
-table td .grid-actions [role="button"] {
- padding: 4px 10px;
- color: var(--app-muted-color);
- border: 1px solid var(--app-border);
- font-size: small;
- background: var(--app-form-element-background-color);
- box-shadow: var(--app-group-box-shadow);
-}
-
-table td .grid-actions button:has(i),
-table td .grid-actions [role="button"]:has(i) {
- max-width: 42px;
-}
-
-table td .grid-actions button:hover,
-table td .grid-actions [role="button"]:hover {
- color: var(--app-contrast);
-}
-
-details summary[role="button"]:not(.outline)::after {
- filter: brightness(0) invert(1);
-}
-
-[aria-busy="true"]:not(input, select, textarea):is(
- button,
+ :where(select, textarea),
+ input:not(
[type="submit"],
[type="button"],
[type="reset"],
- [role="button"]
- ):not(.outline)::before {
- filter: brightness(0) invert(1);
-}
-
-@media only screen and (prefers-color-scheme: dark) {
- :host(:not([data-theme]))
- details
- summary[role="button"].contrast:not(.outline)::after,
- :root:not([data-theme])
- details
- summary[role="button"].contrast:not(.outline)::after {
- filter: brightness(0);
+ [type="checkbox"],
+ [type="radio"],
+ [type="file"]
+ ) {
+ --app-outline-width: 0.0625rem;
}
- :host(:not([data-theme]))
- [aria-busy="true"]:not(input, select, textarea).contrast:is(
+ [type="checkbox"],
+ [type="radio"] {
+ --app-border-width: 0.125rem;
+ }
+
+ [type="checkbox"][role="switch"] {
+ --app-border-width: 0.1875rem;
+ }
+
+ details.dropdown summary:not([role="button"]) {
+ --app-outline-width: 0.0625rem;
+ }
+
+ nav details.dropdown summary:focus-visible {
+ --app-outline-width: 0.125rem;
+ }
+
+ [role="search"] {
+ --app-border-radius: 5rem;
+ }
+
+ [role="group"]:has(
+ button.secondary:focus,
+ [type="submit"].secondary:focus,
+ [type="button"].secondary:focus,
+ [role="button"].secondary:focus
+ ),
+ [role="search"]:has(
+ button.secondary:focus,
+ [type="submit"].secondary:focus,
+ [type="button"].secondary:focus,
+ [role="button"].secondary:focus
+ ) {
+ --app-group-box-shadow-focus-with-button: 0 0 0 var(--app-outline-width)
+ var(--app-secondary-focus);
+ }
+
+ [role="group"]:has(
+ button.contrast:focus,
+ [type="submit"].contrast:focus,
+ [type="button"].contrast:focus,
+ [role="button"].contrast:focus
+ ),
+ [role="search"]:has(
+ button.contrast:focus,
+ [type="submit"].contrast:focus,
+ [type="button"].contrast:focus,
+ [role="button"].contrast:focus
+ ) {
+ --app-group-box-shadow-focus-with-button: 0 0 0 var(--app-outline-width)
+ var(--app-contrast-focus);
+ }
+
+ [role="group"] [role="button"],
+ [role="group"] [type="button"],
+ [role="group"] [type="submit"],
+ [role="group"] button,
+ [role="search"] [role="button"],
+ [role="search"] [type="button"],
+ [role="search"] [type="submit"],
+ [role="search"] button {
+ --app-form-element-spacing-horizontal: 2rem;
+ }
+
+ [role="group"] form:last-child button {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+
+ table td [role="group"] {
+ margin: 0;
+ }
+
+ th {
+ text-transform: uppercase;
+ font-size: 11px;
+ letter-spacing: 0.4px;
+ border-top: 1px solid var(--app-border);
+ }
+
+ table td .grid-actions button,
+ table td .grid-actions [role="button"] {
+ padding: 4px 10px;
+ color: var(--app-muted-color);
+ border: 1px solid var(--app-border);
+ font-size: small;
+ background: var(--app-form-element-background-color);
+ box-shadow: var(--app-group-box-shadow);
+ }
+
+ table td .grid-actions button:has(i),
+ table td .grid-actions [role="button"]:has(i) {
+ max-width: 42px;
+ }
+
+ table td .grid-actions button:hover,
+ table td .grid-actions [role="button"]:hover {
+ color: var(--app-contrast);
+ }
+
+ details summary[role="button"]:not(.outline)::after {
+ filter: brightness(0) invert(1);
+ }
+
+ [aria-busy="true"]:not(input, select, textarea):is(
button,
[type="submit"],
[type="button"],
[type="reset"],
[role="button"]
- ):not(.outline)::before,
- :root:not([data-theme])
+ ):not(.outline)::before {
+ filter: brightness(0) invert(1);
+ }
+
+ @media only screen and (prefers-color-scheme: dark) {
+ :host(:not([data-theme]))
+ details
+ summary[role="button"].contrast:not(.outline)::after,
+ :root:not([data-theme])
+ details
+ summary[role="button"].contrast:not(.outline)::after {
+ filter: brightness(0);
+ }
+
+ :host(:not([data-theme]))
+ [aria-busy="true"]:not(input, select, textarea).contrast:is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [role="button"]
+ ):not(.outline)::before,
+ :root:not([data-theme])
+ [aria-busy="true"]:not(input, select, textarea).contrast:is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [role="button"]
+ ):not(.outline)::before {
+ filter: brightness(0);
+ }
+ }
+
+ [data-theme="dark"]
+ details
+ summary[role="button"].contrast:not(.outline)::after {
+ filter: brightness(0);
+ }
+
+ [data-theme="dark"]
[aria-busy="true"]:not(input, select, textarea).contrast:is(
button,
[type="submit"],
@@ -243,2787 +262,2800 @@ details summary[role="button"]:not(.outline)::after {
):not(.outline)::before {
filter: brightness(0);
}
-}
-[data-theme="dark"]
- details
- summary[role="button"].contrast:not(.outline)::after {
- filter: brightness(0);
-}
-
-[data-theme="dark"]
- [aria-busy="true"]:not(input, select, textarea).contrast:is(
- button,
- [type="submit"],
- [type="button"],
- [type="reset"],
- [role="button"]
- ):not(.outline)::before {
- filter: brightness(0);
-}
-
-[type="checkbox"],
-[type="radio"],
-[type="range"],
-progress {
- accent-color: var(--app-primary);
-}
-
-*,
-::after,
-::before {
- box-sizing: border-box;
- background-repeat: no-repeat;
-}
-
-::after,
-::before {
- text-decoration: inherit;
- vertical-align: inherit;
-}
-
-:where(:host),
-:where(:root) {
- -webkit-tap-highlight-color: transparent;
- -webkit-text-size-adjust: 100%;
- -moz-text-size-adjust: 100%;
- text-size-adjust: 100%;
- background-color: var(--app-background-color);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- font-size: var(--app-font-size);
- line-height: var(--app-line-height);
- font-family: var(--app-font-family);
- text-underline-offset: var(--app-text-underline-offset);
- text-rendering: optimizeLegibility;
- overflow-wrap: break-word;
- -moz-tab-size: 4;
- -o-tab-size: 4;
- tab-size: 4;
-}
-
-body {
- width: 100%;
- margin: 0;
-}
-
-main {
- display: block;
-}
-
-body > footer,
-body > main {
- padding-block: var(--app-block-spacing-vertical);
-}
-
-body > footer {
- padding-inline: calc(var(--app-spacing) * 2);
-}
-
-footer.site-footer {
- padding-inline: calc(var(--app-spacing) * 2);
- border-top: 1px solid var(--app-border);
-}
-
-footer.site-footer a {
- color: inherit;
-}
-
-body > footer a {
- color: inherit;
-}
-header[data-align="center"],
-hgroup[data-align="center"] > h1,
-hgroup[data-align="center"] > h2,
-hgroup[data-align="center"] > h3,
-hgroup[data-align="center"] > p,
-hgroup[data-align="center"] > *,
-hgroup[data-align="center"] {
- text-align: center;
- justify-content: center;
-}
-
-section {
- margin-bottom: var(--app-block-spacing-vertical);
-}
-
-.container-small {
- max-width: 420px;
- margin-right: auto;
- margin-left: auto;
-}
-
-.container,
-.container-fluid {
- width: 100%;
- margin-right: auto;
- margin-left: auto;
- padding-right: var(--app-spacing);
- padding-left: var(--app-spacing);
-}
-
-.app-main-content {
- padding-inline: calc(var(--app-spacing) * 1);
-}
-
-@media (min-width: 576px) {
- .container {
- max-width: 510px;
- padding-right: 0;
- padding-left: 0;
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ progress {
+ accent-color: var(--app-primary);
}
- h1 {
- --app-font-size: 1.7rem;
-
+ *,
+ ::after,
+ ::before {
+ box-sizing: border-box;
+ background-repeat: no-repeat;
}
- h2 {
- --app-font-size: 1.6rem;
-
+ ::after,
+ ::before {
+ text-decoration: inherit;
+ vertical-align: inherit;
}
- h3 {
- --app-font-size: 1.3rem;
-
+ :where(:host),
+ :where(:root) {
+ -webkit-tap-highlight-color: transparent;
+ -webkit-text-size-adjust: 100%;
+ -moz-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+ background-color: var(--app-background-color);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ font-size: var(--app-font-size);
+ line-height: var(--app-line-height);
+ font-family: var(--app-font-family);
+ text-underline-offset: var(--app-text-underline-offset);
+ text-rendering: optimizeLegibility;
+ overflow-wrap: break-word;
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
}
- h4 {
- --app-font-size: 1.2rem;
-
+ body {
+ width: 100%;
+ margin: 0;
}
- h5 {
- --app-font-size: 1.1rem;
-
+ main {
+ display: block;
}
- h6 {
- --app-font-size: 1rem;
-
- }
-}
-
-@media (min-width: 768px) {
- .container {
- max-width: 700px;
- }
- .app-container.is-sidebar-hidden:has(.aside-icon-bar):has(.app-sidebar) {
- display: grid;
- min-height: 100dvh;
- align-items: flex-start;
- grid-template-columns: minmax(0, 60px) minmax(0, 1fr);
- }
- .sidebar-hidden .app-container:has(.aside-icon-bar):has(.app-sidebar) {
- grid-template-columns: minmax(0, 60px) minmax(0, 1fr);
- }
- .app-container:has(.aside-icon-bar):has(.app-sidebar) {
- display: grid;
- min-height: 100dvh;
- align-items: flex-start;
- grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
- }
- .app-container.is-sidebar-collapsed:has(.aside-icon-bar):has(.app-sidebar) {
- display: grid;
- min-height: 100dvh;
- align-items: flex-start;
- grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ body > footer,
+ body > main {
+ padding-block: var(--app-block-spacing-vertical);
}
- .app-container.is-sidebar-collapsed {
- grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ body > footer {
+ padding-inline: calc(var(--app-spacing) * 2);
}
- .sidebar-collapsed .app-container {
- grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ footer.site-footer {
+ padding-inline: calc(var(--app-spacing) * 2);
+ border-top: 1px solid var(--app-border);
}
- .app-main {
- border-left: 1px solid var(--app-border);
- min-height: 100dvh;
- background: var(--app-background-color);
+ footer.site-footer a {
+ color: inherit;
+ }
+
+ body > footer a {
+ color: inherit;
+ }
+ header[data-align="center"],
+ hgroup[data-align="center"] > h1,
+ hgroup[data-align="center"] > h2,
+ hgroup[data-align="center"] > h3,
+ hgroup[data-align="center"] > p,
+ hgroup[data-align="center"] > *,
+ hgroup[data-align="center"] {
+ text-align: center;
+ justify-content: center;
+ }
+
+ section {
+ margin-bottom: var(--app-block-spacing-vertical);
+ }
+
+ .container-small {
+ max-width: 420px;
+ margin-right: auto;
+ margin-left: auto;
+ }
+
+ .container,
+ .container-fluid {
+ width: 100%;
+ margin-right: auto;
+ margin-left: auto;
+ padding-right: var(--app-spacing);
+ padding-left: var(--app-spacing);
}
.app-main-content {
- padding-inline: calc(var(--app-spacing) * 2);
- margin-bottom: calc(var(--app-spacing) * 2);
+ padding-inline: calc(var(--app-spacing) * 1);
}
- .app-main-content:has(.app-details-container) {
+
+ @media (min-width: 576px) {
+ .container {
+ max-width: 510px;
+ padding-right: 0;
+ padding-left: 0;
+ }
+
+ h1 {
+ --app-font-size: 1.7rem;
+ }
+
+ h2 {
+ --app-font-size: 1.6rem;
+ }
+
+ h3 {
+ --app-font-size: 1.3rem;
+ }
+
+ h4 {
+ --app-font-size: 1.2rem;
+ }
+
+ h5 {
+ --app-font-size: 1.1rem;
+ }
+
+ h6 {
+ --app-font-size: 1rem;
+ }
+ }
+
+ @media (min-width: 768px) {
+ .container {
+ max-width: 700px;
+ }
+ .app-container.is-sidebar-hidden:has(.aside-icon-bar):has(.app-sidebar) {
+ display: grid;
+ min-height: 100dvh;
+ align-items: flex-start;
+ grid-template-columns: minmax(0, 60px) minmax(0, 1fr);
+ }
+ .sidebar-hidden .app-container:has(.aside-icon-bar):has(.app-sidebar) {
+ grid-template-columns: minmax(0, 60px) minmax(0, 1fr);
+ }
+ .app-container:has(.aside-icon-bar):has(.app-sidebar) {
+ display: grid;
+ min-height: 100dvh;
+ align-items: flex-start;
+ grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ }
+ .app-container.is-sidebar-collapsed:has(.aside-icon-bar):has(.app-sidebar) {
+ display: grid;
+ min-height: 100dvh;
+ align-items: flex-start;
+ grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ }
+
+ .app-container.is-sidebar-collapsed {
+ grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ }
+
+ .sidebar-collapsed .app-container {
+ grid-template-columns: minmax(0, 60px) minmax(0, 220px) minmax(0, 1fr);
+ }
+
+ .app-main {
+ border-left: 1px solid var(--app-border);
+ min-height: 100dvh;
+ background: var(--app-background-color);
+ }
+
+ .app-main-content {
+ padding-inline: calc(var(--app-spacing) * 2);
+ margin-bottom: calc(var(--app-spacing) * 2);
+ }
+ .app-main-content:has(.app-details-container) {
+ margin-bottom: 0;
+ padding: 0;
+ position: relative;
+ z-index: 1;
+ }
+ }
+
+ @media (min-width: 1024px) {
+ .container {
+ max-width: 950px;
+ }
+ }
+
+ @media (min-width: 1280px) {
+ .container {
+ max-width: 1200px;
+ }
+ }
+
+ @media (min-width: 1536px) {
+ .container {
+ max-width: 1450px;
+ }
+ }
+
+ .grid {
+ grid-column-gap: var(--app-grid-column-gap);
+ grid-row-gap: var(--app-grid-row-gap);
+ display: grid;
+ --app-grid-template-columns: 1fr;
+ grid-template-columns: var(--app-grid-template-columns);
+ }
+
+ .flex {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--app-flex-gap);
+ }
+
+ .flex h1,
+ .flex h2,
+ .flex h3,
+ .flex h4,
+ .flex h5,
+ .flex h6 {
margin-bottom: 0;
- padding: 0;
+ }
+
+ .align-center {
+ align-items: center;
+ }
+
+ .align-flex-start {
+ align-items: flex-start;
+ }
+
+ .justify-space-between {
+ justify-content: space-between;
+ }
+
+ @media (min-width: 768px) {
+ .grid {
+ --app-grid-template-columns: repeat(auto-fit, minmax(0%, 1fr));
+ }
+
+ .grid.grid-2,
+ .grid.grid-1-1 {
+ --app-grid-template-columns: repeat(2, minmax(0%, 1fr));
+ }
+
+ .grid.grid-3 {
+ --app-grid-template-columns: repeat(3, minmax(0%, 1fr));
+ }
+
+ .grid.grid-4 {
+ --app-grid-template-columns: repeat(4, minmax(0%, 1fr));
+ }
+
+ .grid.grid-5 {
+ --app-grid-template-columns: repeat(5, minmax(0%, 1fr));
+ }
+
+ .grid.grid-6 {
+ --app-grid-template-columns: repeat(6, minmax(0%, 1fr));
+ }
+
+ .grid.grid-1-2 {
+ --app-grid-template-columns: minmax(0%, 1fr) minmax(0%, 2fr);
+ }
+
+ .grid.grid-2-1 {
+ --app-grid-template-columns: minmax(0%, 2fr) minmax(0%, 1fr);
+ }
+
+ .grid.grid-1-3 {
+ --app-grid-template-columns: minmax(0%, 1fr) minmax(0%, 3fr);
+ }
+
+ .grid.grid-3-1 {
+ --app-grid-template-columns: minmax(0%, 3fr) minmax(0%, 1fr);
+ }
+ }
+
+ .grid > * {
+ min-width: 0;
+ }
+
+ .overflow-auto {
+ overflow: auto;
+ }
+
+ b,
+ strong {
+ font-weight: bolder;
+ }
+
+ sub,
+ sup {
position: relative;
+ font-size: 0.75em;
+ line-height: 0;
+ vertical-align: baseline;
+ }
+
+ sub {
+ bottom: -0.25em;
+ }
+
+ sup {
+ top: -0.5em;
+ }
+
+ address,
+ blockquote,
+ dl,
+ ol,
+ p,
+ pre,
+ table,
+ ul {
+ margin-top: 0;
+ margin-bottom: var(--app-typography-spacing-vertical);
+ color: var(--app-color);
+ font-style: normal;
+ font-weight: var(--app-font-weight);
+ }
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ margin-top: 0;
+ margin-bottom: var(--app-typography-spacing-vertical);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ font-size: var(--app-font-size);
+ line-height: var(--app-line-height);
+ font-family: var(--app-font-family);
+ }
+
+ h1 {
+ --app-color: var(--app-h1-color);
+ }
+
+ h2 {
+ --app-color: var(--app-h2-color);
+ }
+
+ h3 {
+ --app-color: var(--app-h3-color);
+ }
+
+ h4 {
+ --app-color: var(--app-h4-color);
+ }
+
+ h5 {
+ --app-color: var(--app-h5-color);
+ }
+
+ h6 {
+ --app-color: var(--app-h6-color);
+ }
+
+ :where(article, address, blockquote, dl, figure, form, ol, p, pre, table, ul)
+ ~ :is(h1, h2, h3, h4, h5, h6) {
+ margin-top: var(--app-typography-spacing-top);
+ }
+
+ p {
+ margin-bottom: var(--app-typography-spacing-vertical);
+ }
+
+ hgroup {
+ margin-bottom: var(--app-typography-spacing-vertical);
+ }
+
+ .flex hgroup {
+ margin-bottom: 0;
+ }
+
+ hgroup > * {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ hgroup > :not(:first-child):last-child {
+ --app-color: var(--app-muted-color);
+ --app-font-weight: unset;
+ font-size: 1rem;
+ }
+
+ :where(ol, ul) li {
+ margin-bottom: calc(var(--app-typography-spacing-vertical) * 0.25);
+ }
+
+ :where(dl, ol, ul) :where(dl, ol, ul) {
+ margin: 0;
+ margin-top: calc(var(--app-typography-spacing-vertical) * 0.25);
+ }
+
+ ul li {
+ list-style: square;
+ }
+
+ mark {
+ padding: 0.125rem 0.25rem;
+ background-color: var(--app-mark-background-color);
+ color: var(--app-mark-color);
+ vertical-align: baseline;
+ }
+
+ abbr[title] {
+ border-bottom: 1px dotted;
+ text-decoration: none;
+ cursor: help;
+ }
+
+ ins {
+ color: var(--app-ins-color);
+ text-decoration: none;
+ }
+
+ del {
+ color: var(--app-del-color);
+ }
+
+ ::-moz-selection {
+ background-color: var(--app-text-selection-color);
+ }
+
+ ::selection {
+ background-color: var(--app-text-selection-color);
+ }
+
+ :where(a:not([role="button"])),
+ [role="link"] {
+ --app-color: var(--app-primary);
+ --app-background-color: transparent;
+ --app-underline: var(--app-primary-underline);
+ outline: 0;
+ background-color: var(--app-background-color);
+ color: cornflowerblue;
+ -webkit-text-decoration: var(--app-text-decoration);
+ text-decoration: var(--app-text-decoration);
+ text-decoration-color: var(--app-underline);
+ text-underline-offset: 0.125em;
+ transition:
+ background-color var(--app-transition),
+ color var(--app-transition),
+ box-shadow var(--app-transition),
+ -webkit-text-decoration var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ color var(--app-transition),
+ text-decoration var(--app-transition),
+ box-shadow var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ color var(--app-transition),
+ text-decoration var(--app-transition),
+ box-shadow var(--app-transition),
+ -webkit-text-decoration var(--app-transition);
+ }
+
+ :where(a:not([role="button"])):is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [role="link"]:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-color: var(--app-primary-hover);
+ --app-underline: var(--app-primary-hover-underline);
+ --app-text-decoration: underline;
+ }
+
+ :where(a:not([role="button"])):focus-visible,
+ [role="link"]:focus-visible {
+ box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ }
+
+ :where(a:not([role="button"])).secondary,
+ [role="link"].secondary {
+ --app-color: var(--app-secondary);
+ --app-underline: var(--app-secondary-underline);
+ }
+
+ :where(a:not([role="button"])).secondary:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [role="link"].secondary:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-color: var(--app-secondary-hover);
+ --app-underline: var(--app-secondary-hover-underline);
+ }
+
+ :where(a:not([role="button"])).contrast,
+ [role="link"].contrast {
+ --app-color: var(--app-contrast);
+ --app-underline: var(--app-contrast-underline);
+ }
+
+ :where(a:not([role="button"])).contrast:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [role="link"].contrast:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-color: var(--app-contrast-hover);
+ --app-underline: var(--app-contrast-hover-underline);
+ }
+
+ a[role="button"] {
+ display: inline-block;
+ }
+
+ button {
+ margin: 0;
+ overflow: visible;
+ font-family: inherit;
+ text-transform: none;
+ }
+
+ a.transparent[role="button"],
+ button.transparent,
+ .transparent[role="button"] {
+ background: transparent;
+ border: none;
+ box-shadow: none;
+ color: var(--app-muted-color);
+ }
+ a.transparent[role="button"]:hover,
+ button.transparent:hover,
+ .transparent[role="button"]:hover {
+ background: var(--app-muted-border-color);
+ color: var(--app-contrast);
+ }
+
+ [type="button"],
+ [type="reset"],
+ [type="submit"],
+ button {
+ -webkit-appearance: button;
+ }
+
+ [role="button"],
+ [type="button"],
+ [type="file"]::file-selector-button,
+ [type="reset"],
+ [type="submit"],
+ button {
+ --app-background-color: var(--app-primary-background);
+ --app-border-color: var(--app-primary-border);
+ --app-color: var(--app-primary-inverse);
+ --app-box-shadow: var(--app-button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));
+ padding: var(--app-button-padding-vertical)
+ var(--app-button-padding-horizontal);
+ border: var(--app-border-width) solid var(--app-border-color);
+ border-radius: var(--app-border-radius);
+ outline: 0;
+ background-color: var(--app-background-color);
+ box-shadow: var(--app-box-shadow);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ font-size: 1rem;
+ line-height: var(--app-line-height);
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ transition:
+ background-color var(--app-transition),
+ border-color var(--app-transition),
+ color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
+
+ :where(
+ button,
+ [type="submit"],
+ [type="reset"],
+ [type="button"],
+ [role="button"]
+ ).small {
+ --app-button-padding-vertical: var(--app-button-padding-vertical-small);
+ --app-button-padding-horizontal: var(--app-button-padding-horizontal-small);
+ font-size: 13px;
+ }
+
+ [role="button"]:is(:hover, :active, :focus),
+ [role="button"]:is([aria-current]:not([aria-current="false"])),
+ [type="button"]:is(:hover, :active, :focus),
+ [type="button"]:is([aria-current]:not([aria-current="false"])),
+ [type="file"]::file-selector-button:is(:hover, :active, :focus),
+ [type="file"]::file-selector-button:is(
+ [aria-current]:not([aria-current="false"])
+ ),
+ [type="reset"]:is(:hover, :active, :focus),
+ [type="reset"]:is([aria-current]:not([aria-current="false"])),
+ [type="submit"]:is(:hover, :active, :focus),
+ [type="submit"]:is([aria-current]:not([aria-current="false"])),
+ button:is(:hover, :active, :focus),
+ button:is([aria-current]:not([aria-current="false"])) {
+ --app-background-color: var(--app-primary-hover-background);
+ --app-border-color: var(--app-primary-hover-border);
+ --app-box-shadow: var(
+ --app-button-hover-box-shadow,
+ 0 0 0 rgba(0, 0, 0, 0)
+ );
+ --app-color: var(--app-primary-inverse);
+ }
+
+ [role="button"]:focus,
+ [role="button"]:is([aria-current]:not([aria-current="false"])):focus,
+ [type="button"]:focus,
+ [type="button"]:is([aria-current]:not([aria-current="false"])):focus,
+ [type="file"]::file-selector-button:focus,
+ [type="file"]::file-selector-button:is(
+ [aria-current]:not([aria-current="false"])
+ ):focus,
+ [type="reset"]:focus,
+ [type="reset"]:is([aria-current]:not([aria-current="false"])):focus,
+ [type="submit"]:focus,
+ [type="submit"]:is([aria-current]:not([aria-current="false"])):focus,
+ button:focus,
+ button:is([aria-current]:not([aria-current="false"])):focus {
+ --app-box-shadow:
+ var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
+ 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ }
+
+ [type="button"],
+ [type="reset"] {
+ margin-bottom: var(--app-spacing);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).secondary,
+ [type="file"]::file-selector-button,
+ [type="reset"] {
+ --app-background-color: var(--app-secondary-background);
+ --app-border-color: var(--app-secondary-border);
+ --app-color: var(--app-secondary-inverse);
+ cursor: pointer;
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).secondary:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [type="file"]::file-selector-button:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [type="reset"]:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-background-color: var(--app-secondary-hover-background);
+ --app-border-color: var(--app-secondary-hover-border);
+ --app-color: var(--app-secondary-inverse);
+ }
+
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [role="button"]
+ ).secondary:focus,
+ :is(button, [type="submit"], [type="button"], [role="button"]).secondary:is(
+ [aria-current]:not([aria-current="false"])
+ ):focus,
+ [type="file"]::file-selector-button:focus,
+ [type="file"]::file-selector-button:is(
+ [aria-current]:not([aria-current="false"])
+ ):focus,
+ [type="reset"]:focus,
+ [type="reset"]:is([aria-current]:not([aria-current="false"])):focus {
+ --app-box-shadow:
+ var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
+ 0 0 0 var(--app-outline-width) var(--app-secondary-focus);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).contrast {
+ --app-background-color: var(--app-contrast-background);
+ --app-border-color: var(--app-contrast-border);
+ --app-color: var(--app-contrast-inverse);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).contrast:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-background-color: var(--app-contrast-hover-background);
+ --app-border-color: var(--app-contrast-hover-border);
+ --app-color: var(--app-contrast-inverse);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).contrast:focus,
+ :is(button, [type="submit"], [type="button"], [role="button"]).contrast:is(
+ [aria-current]:not([aria-current="false"])
+ ):focus {
+ --app-box-shadow:
+ var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
+ 0 0 0 var(--app-outline-width) var(--app-contrast-focus);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).outline,
+ [type="reset"].outline {
+ --app-background-color: transparent;
+ --app-color: var(--app-primary);
+ --app-border-color: var(--app-primary);
+ }
+
+ :is(button, [type="submit"], [type="button"], [role="button"]).outline:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [type="reset"].outline:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-background-color: transparent;
+ --app-color: var(--app-primary-hover);
+ --app-border-color: var(--app-primary-hover);
+ }
+
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [role="button"]
+ ).outline.secondary,
+ [type="reset"].outline {
+ --app-color: var(--app-secondary);
+ --app-border-color: var(--app-secondary);
+ }
+
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [role="button"]
+ ).outline.secondary:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ [type="reset"].outline:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-color: var(--app-secondary-hover);
+ --app-border-color: var(--app-secondary-hover);
+ }
+
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [role="button"]
+ ).outline.contrast {
+ --app-color: var(--app-contrast);
+ --app-border-color: var(--app-contrast);
+ }
+
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [role="button"]
+ ).outline.contrast:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ --app-color: var(--app-contrast-hover);
+ --app-border-color: var(--app-contrast-hover);
+ }
+
+ :where(
+ button,
+ [type="submit"],
+ [type="reset"],
+ [type="button"],
+ [role="button"]
+ )[disabled],
+ :where(fieldset[disabled])
+ :is(
+ button,
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [role="button"]
+ ) {
+ opacity: 0.5;
+ pointer-events: none;
+ }
+
+ :where(table) {
+ width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+ text-indent: 0;
+ }
+
+ td,
+ th {
+ padding: calc(var(--app-spacing) / 2) var(--app-spacing);
+ border-bottom: var(--app-border-width) solid var(--app-table-border-color);
+ background-color: var(--app-background-color);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ text-align: left;
+ text-align: start;
+ }
+
+ tfoot td,
+ tfoot th {
+ border-top: var(--app-border-width) solid var(--app-table-border-color);
+ border-bottom: 0;
+ }
+
+ table.striped tbody tr:nth-child(odd) td,
+ table.striped tbody tr:nth-child(odd) th {
+ background-color: var(--app-table-row-stripped-background-color);
+ }
+
+ :where(audio, canvas, iframe, img, svg, video) {
+ vertical-align: middle;
+ }
+
+ audio,
+ video {
+ display: inline-block;
+ }
+
+ audio:not([controls]) {
+ display: none;
+ height: 0;
+ }
+
+ :where(iframe) {
+ border-style: none;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ border-style: none;
+ }
+
+ img.rounded {
+ border-radius: 0.5rem;
+ }
+
+ :where(svg:not([fill])) {
+ fill: currentColor;
+ }
+
+ svg:not(:host),
+ svg:not(:root) {
+ overflow: hidden;
+ }
+
+ code,
+ kbd,
+ pre,
+ samp {
+ font-size: 0.875em;
+ font-family: var(--app-font-family);
+ }
+
+ pre code,
+ pre samp {
+ font-size: inherit;
+ font-family: inherit;
+ }
+
+ pre {
+ -ms-overflow-style: scrollbar;
+ overflow: auto;
+ }
+
+ code,
+ kbd,
+ pre,
+ samp {
+ border-radius: var(--app-border-radius);
+ background: var(--app-code-background-color);
+ color: var(--app-code-color);
+ font-weight: var(--app-font-weight);
+ line-height: initial;
+ }
+
+ code,
+ kbd,
+ samp {
+ display: inline-block;
+ padding: 0.375rem;
+ }
+
+ pre {
+ display: block;
+ margin-bottom: var(--app-spacing);
+ overflow-x: auto;
+ }
+
+ pre > code,
+ pre > samp {
+ display: block;
+ padding: var(--app-spacing);
+ background: 0 0;
+ line-height: var(--app-line-height);
+ }
+
+ .code-toolbar {
+ position: relative;
+ margin-block: var(--app-spacing);
+ }
+
+ .code-toolbar > .toolbar {
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
z-index: 1;
}
-}
-@media (min-width: 1024px) {
- .container {
- max-width: 950px;
- }
-}
-
-@media (min-width: 1280px) {
- .container {
- max-width: 1200px;
- }
-}
-
-@media (min-width: 1536px) {
- .container {
- max-width: 1450px;
- }
-}
-
-.grid {
- grid-column-gap: var(--app-grid-column-gap);
- grid-row-gap: var(--app-grid-row-gap);
- display: grid;
- --app-grid-template-columns: 1fr;
- grid-template-columns: var(--app-grid-template-columns);
-}
-
-.flex {
- display: flex;
- flex-wrap: wrap;
- gap: var(--app-flex-gap);
-}
-
-.flex h1,
-.flex h2,
-.flex h3,
-.flex h4,
-.flex h5,
-.flex h6 {
- margin-bottom: 0;
-}
-
-.align-center {
- align-items: center;
-}
-
-.align-flex-start {
- align-items: flex-start;
-}
-
-.justify-space-between {
- justify-content: space-between;
-}
-
-@media (min-width: 768px) {
- .grid {
- --app-grid-template-columns: repeat(auto-fit, minmax(0%, 1fr));
+ .code-toolbar > .toolbar .toolbar-item {
+ display: inline-flex;
}
- .grid.grid-2,
- .grid.grid-1-1 {
- --app-grid-template-columns: repeat(2, minmax(0%, 1fr));
+ .code-toolbar > .toolbar .copy-to-clipboard-button {
+ --app-background-color: transparent;
+ --app-border-color: var(--app-muted-border-color);
+ --app-color: var(--app-muted-color);
+ --app-box-shadow: none;
+ --app-button-padding-vertical: var(--app-button-padding-vertical-small);
+ --app-button-padding-horizontal: var(--app-button-padding-horizontal-small);
+ font-size: 0.75rem;
}
- .grid.grid-3 {
- --app-grid-template-columns: repeat(3, minmax(0%, 1fr));
+ .code-toolbar > .toolbar .copy-to-clipboard-button:is(:hover, :focus) {
+ --app-background-color: var(--app-card-sectioning-background-color);
+ --app-border-color: var(--app-muted-border-color);
}
- .grid.grid-4 {
- --app-grid-template-columns: repeat(4, minmax(0%, 1fr));
+ .code-toolbar > pre > code {
+ padding-top: calc(var(--app-spacing) * 2);
}
- .grid.grid-5 {
- --app-grid-template-columns: repeat(5, minmax(0%, 1fr));
+ kbd {
+ background-color: var(--app-code-kbd-background-color);
+ color: var(--app-code-kbd-color);
+ vertical-align: baseline;
}
- .grid.grid-6 {
- --app-grid-template-columns: repeat(6, minmax(0%, 1fr));
+ figure {
+ display: block;
+ margin: 0;
+ padding: 0;
}
- .grid.grid-1-2 {
- --app-grid-template-columns: minmax(0%, 1fr) minmax(0%, 2fr);
+ figure figcaption {
+ padding: calc(var(--app-spacing) * 0.5) 0;
+ color: var(--app-muted-color);
}
- .grid.grid-2-1 {
- --app-grid-template-columns: minmax(0%, 2fr) minmax(0%, 1fr);
+ hr {
+ height: 0;
+ margin: var(--app-typography-spacing-vertical) 0;
+ border: 0;
+ border-top: 1px solid var(--app-muted-border-color);
+ color: inherit;
}
- .grid.grid-1-3 {
- --app-grid-template-columns: minmax(0%, 1fr) minmax(0%, 3fr);
+ [hidden],
+ template {
+ display: none !important;
}
- .grid.grid-3-1 {
- --app-grid-template-columns: minmax(0%, 3fr) minmax(0%, 1fr);
- }
-}
-
-.grid > * {
- min-width: 0;
-}
-
-.overflow-auto {
- overflow: auto;
-}
-
-b,
-strong {
- font-weight: bolder;
-}
-
-sub,
-sup {
- position: relative;
- font-size: 0.75em;
- line-height: 0;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-address,
-blockquote,
-dl,
-ol,
-p,
-pre,
-table,
-ul {
- margin-top: 0;
- margin-bottom: var(--app-typography-spacing-vertical);
- color: var(--app-color);
- font-style: normal;
- font-weight: var(--app-font-weight);
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin-top: 0;
- margin-bottom: var(--app-typography-spacing-vertical);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- font-size: var(--app-font-size);
- line-height: var(--app-line-height);
- font-family: var(--app-font-family);
-}
-
-h1 {
- --app-color: var(--app-h1-color);
-}
-
-h2 {
- --app-color: var(--app-h2-color);
-}
-
-h3 {
- --app-color: var(--app-h3-color);
-}
-
-h4 {
- --app-color: var(--app-h4-color);
-}
-
-h5 {
- --app-color: var(--app-h5-color);
-}
-
-h6 {
- --app-color: var(--app-h6-color);
-}
-
-:where(article, address, blockquote, dl, figure, form, ol, p, pre, table, ul)
- ~ :is(h1, h2, h3, h4, h5, h6) {
- margin-top: var(--app-typography-spacing-top);
-}
-
-p {
- margin-bottom: var(--app-typography-spacing-vertical);
-}
-
-hgroup {
- margin-bottom: var(--app-typography-spacing-vertical);
-}
-
-.flex hgroup {
- margin-bottom: 0;
-}
-
-hgroup > * {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-hgroup > :not(:first-child):last-child {
- --app-color: var(--app-muted-color);
- --app-font-weight: unset;
- font-size: 1rem;
-}
-
-:where(ol, ul) li {
- margin-bottom: calc(var(--app-typography-spacing-vertical) * 0.25);
-}
-
-:where(dl, ol, ul) :where(dl, ol, ul) {
- margin: 0;
- margin-top: calc(var(--app-typography-spacing-vertical) * 0.25);
-}
-
-ul li {
- list-style: square;
-}
-
-mark {
- padding: 0.125rem 0.25rem;
- background-color: var(--app-mark-background-color);
- color: var(--app-mark-color);
- vertical-align: baseline;
-}
-
-abbr[title] {
- border-bottom: 1px dotted;
- text-decoration: none;
- cursor: help;
-}
-
-ins {
- color: var(--app-ins-color);
- text-decoration: none;
-}
-
-del {
- color: var(--app-del-color);
-}
-
-::-moz-selection {
- background-color: var(--app-text-selection-color);
-}
-
-::selection {
- background-color: var(--app-text-selection-color);
-}
-
-:where(a:not([role="button"])),
-[role="link"] {
- --app-color: var(--app-primary);
- --app-background-color: transparent;
- --app-underline: var(--app-primary-underline);
- outline: 0;
- background-color: var(--app-background-color);
- color: cornflowerblue;
- -webkit-text-decoration: var(--app-text-decoration);
- text-decoration: var(--app-text-decoration);
- text-decoration-color: var(--app-underline);
- text-underline-offset: 0.125em;
- transition:
- background-color var(--app-transition),
- color var(--app-transition),
- box-shadow var(--app-transition),
- -webkit-text-decoration var(--app-transition);
- transition:
- background-color var(--app-transition),
- color var(--app-transition),
- text-decoration var(--app-transition),
- box-shadow var(--app-transition);
- transition:
- background-color var(--app-transition),
- color var(--app-transition),
- text-decoration var(--app-transition),
- box-shadow var(--app-transition),
- -webkit-text-decoration var(--app-transition);
-}
-
-:where(a:not([role="button"])):is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
-),
-[role="link"]:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
-) {
- --app-color: var(--app-primary-hover);
- --app-underline: var(--app-primary-hover-underline);
- --app-text-decoration: underline;
-}
-
-:where(a:not([role="button"])):focus-visible,
-[role="link"]:focus-visible {
- box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
-}
-
-:where(a:not([role="button"])).secondary,
-[role="link"].secondary {
- --app-color: var(--app-secondary);
- --app-underline: var(--app-secondary-underline);
-}
-
-:where(a:not([role="button"])).secondary:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[role="link"].secondary:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-color: var(--app-secondary-hover);
- --app-underline: var(--app-secondary-hover-underline);
-}
-
-:where(a:not([role="button"])).contrast,
-[role="link"].contrast {
- --app-color: var(--app-contrast);
- --app-underline: var(--app-contrast-underline);
-}
-
-:where(a:not([role="button"])).contrast:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[role="link"].contrast:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-color: var(--app-contrast-hover);
- --app-underline: var(--app-contrast-hover-underline);
-}
-
-a[role="button"] {
- display: inline-block;
-}
-
-button {
- margin: 0;
- overflow: visible;
- font-family: inherit;
- text-transform: none;
-}
-
-a.transparent[role="button"],
-button.transparent,
-.transparent[role="button"] {
- background: transparent;
- border: none;
- box-shadow: none;
- color: var(--app-muted-color);
-}
-a.transparent[role="button"]:hover,
-button.transparent:hover,
-.transparent[role="button"]:hover {
- background: var(--app-muted-border-color);
- color: var(--app-contrast);
-}
-
-[type="button"],
-[type="reset"],
-[type="submit"],
-button {
- -webkit-appearance: button;
-}
-
-[role="button"],
-[type="button"],
-[type="file"]::file-selector-button,
-[type="reset"],
-[type="submit"],
-button {
- --app-background-color: var(--app-primary-background);
- --app-border-color: var(--app-primary-border);
- --app-color: var(--app-primary-inverse);
- --app-box-shadow: var(--app-button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));
- padding: var(--app-button-padding-vertical)
- var(--app-button-padding-horizontal);
- border: var(--app-border-width) solid var(--app-border-color);
- border-radius: var(--app-border-radius);
- outline: 0;
- background-color: var(--app-background-color);
- box-shadow: var(--app-box-shadow);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- font-size: 1rem;
- line-height: var(--app-line-height);
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- transition:
- background-color var(--app-transition),
- border-color var(--app-transition),
- color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-:where(
- button,
- [type="submit"],
- [type="reset"],
- [type="button"],
- [role="button"]
-).small {
- --app-button-padding-vertical: var(--app-button-padding-vertical-small);
- --app-button-padding-horizontal: var(--app-button-padding-horizontal-small);
-}
-
-[role="button"]:is(:hover, :active, :focus),
-[role="button"]:is([aria-current]:not([aria-current="false"])),
-[type="button"]:is(:hover, :active, :focus),
-[type="button"]:is([aria-current]:not([aria-current="false"])),
-[type="file"]::file-selector-button:is(:hover, :active, :focus),
-[type="file"]::file-selector-button:is(
- [aria-current]:not([aria-current="false"])
- ),
-[type="reset"]:is(:hover, :active, :focus),
-[type="reset"]:is([aria-current]:not([aria-current="false"])),
-[type="submit"]:is(:hover, :active, :focus),
-[type="submit"]:is([aria-current]:not([aria-current="false"])),
-button:is(:hover, :active, :focus),
-button:is([aria-current]:not([aria-current="false"])) {
- --app-background-color: var(--app-primary-hover-background);
- --app-border-color: var(--app-primary-hover-border);
- --app-box-shadow: var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));
- --app-color: var(--app-primary-inverse);
-}
-
-[role="button"]:focus,
-[role="button"]:is([aria-current]:not([aria-current="false"])):focus,
-[type="button"]:focus,
-[type="button"]:is([aria-current]:not([aria-current="false"])):focus,
-[type="file"]::file-selector-button:focus,
-[type="file"]::file-selector-button:is(
- [aria-current]:not([aria-current="false"])
- ):focus,
-[type="reset"]:focus,
-[type="reset"]:is([aria-current]:not([aria-current="false"])):focus,
-[type="submit"]:focus,
-[type="submit"]:is([aria-current]:not([aria-current="false"])):focus,
-button:focus,
-button:is([aria-current]:not([aria-current="false"])):focus {
- --app-box-shadow:
- var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
- 0 0 0 var(--app-outline-width) var(--app-primary-focus);
-}
-
-[type="button"],
-[type="reset"] {
- margin-bottom: var(--app-spacing);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).secondary,
-[type="file"]::file-selector-button,
-[type="reset"] {
- --app-background-color: var(--app-secondary-background);
- --app-border-color: var(--app-secondary-border);
- --app-color: var(--app-secondary-inverse);
- cursor: pointer;
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).secondary:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[type="file"]::file-selector-button:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[type="reset"]:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
-) {
- --app-background-color: var(--app-secondary-hover-background);
- --app-border-color: var(--app-secondary-hover-border);
- --app-color: var(--app-secondary-inverse);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).secondary:focus,
-:is(button, [type="submit"], [type="button"], [role="button"]).secondary:is(
- [aria-current]:not([aria-current="false"])
- ):focus,
-[type="file"]::file-selector-button:focus,
-[type="file"]::file-selector-button:is(
- [aria-current]:not([aria-current="false"])
- ):focus,
-[type="reset"]:focus,
-[type="reset"]:is([aria-current]:not([aria-current="false"])):focus {
- --app-box-shadow:
- var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
- 0 0 0 var(--app-outline-width) var(--app-secondary-focus);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).contrast {
- --app-background-color: var(--app-contrast-background);
- --app-border-color: var(--app-contrast-border);
- --app-color: var(--app-contrast-inverse);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).contrast:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-background-color: var(--app-contrast-hover-background);
- --app-border-color: var(--app-contrast-hover-border);
- --app-color: var(--app-contrast-inverse);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).contrast:focus,
-:is(button, [type="submit"], [type="button"], [role="button"]).contrast:is(
- [aria-current]:not([aria-current="false"])
- ):focus {
- --app-box-shadow:
- var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
- 0 0 0 var(--app-outline-width) var(--app-contrast-focus);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).outline,
-[type="reset"].outline {
- --app-background-color: transparent;
- --app-color: var(--app-primary);
- --app-border-color: var(--app-primary);
-}
-
-:is(button, [type="submit"], [type="button"], [role="button"]).outline:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[type="reset"].outline:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-background-color: transparent;
- --app-color: var(--app-primary-hover);
- --app-border-color: var(--app-primary-hover);
-}
-
-:is(
- button,
- [type="submit"],
- [type="button"],
- [role="button"]
- ).outline.secondary,
-[type="reset"].outline {
- --app-color: var(--app-secondary);
- --app-border-color: var(--app-secondary);
-}
-
-:is(
- button,
- [type="submit"],
- [type="button"],
- [role="button"]
- ).outline.secondary:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-[type="reset"].outline:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-color: var(--app-secondary-hover);
- --app-border-color: var(--app-secondary-hover);
-}
-
-:is(
- button,
- [type="submit"],
- [type="button"],
- [role="button"]
- ).outline.contrast {
- --app-color: var(--app-contrast);
- --app-border-color: var(--app-contrast);
-}
-
-:is(
- button,
- [type="submit"],
- [type="button"],
- [role="button"]
- ).outline.contrast:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- --app-color: var(--app-contrast-hover);
- --app-border-color: var(--app-contrast-hover);
-}
-
-:where(
- button,
- [type="submit"],
- [type="reset"],
- [type="button"],
- [role="button"]
-)[disabled],
-:where(fieldset[disabled])
- :is(
- button,
- [type="submit"],
- [type="button"],
- [type="reset"],
- [role="button"]
- ) {
- opacity: 0.5;
- pointer-events: none;
-}
-
-:where(table) {
- width: 100%;
- border-collapse: collapse;
- border-spacing: 0;
- text-indent: 0;
-}
-
-td,
-th {
- padding: calc(var(--app-spacing) / 2) var(--app-spacing);
- border-bottom: var(--app-border-width) solid var(--app-table-border-color);
- background-color: var(--app-background-color);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- text-align: left;
- text-align: start;
-}
-
-tfoot td,
-tfoot th {
- border-top: var(--app-border-width) solid var(--app-table-border-color);
- border-bottom: 0;
-}
-
-table.striped tbody tr:nth-child(odd) td,
-table.striped tbody tr:nth-child(odd) th {
- background-color: var(--app-table-row-stripped-background-color);
-}
-
-:where(audio, canvas, iframe, img, svg, video) {
- vertical-align: middle;
-}
-
-audio,
-video {
- display: inline-block;
-}
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-:where(iframe) {
- border-style: none;
-}
-
-img {
- max-width: 100%;
- height: auto;
- border-style: none;
-}
-
-img.rounded {
- border-radius: 0.5rem;
-}
-
-:where(svg:not([fill])) {
- fill: currentColor;
-}
-
-svg:not(:host),
-svg:not(:root) {
- overflow: hidden;
-}
-
-code,
-kbd,
-pre,
-samp {
- font-size: 0.875em;
- font-family: var(--app-font-family);
-}
-
-pre code,
-pre samp {
- font-size: inherit;
- font-family: inherit;
-}
-
-pre {
- -ms-overflow-style: scrollbar;
- overflow: auto;
-}
-
-code,
-kbd,
-pre,
-samp {
- border-radius: var(--app-border-radius);
- background: var(--app-code-background-color);
- color: var(--app-code-color);
- font-weight: var(--app-font-weight);
- line-height: initial;
-}
-
-code,
-kbd,
-samp {
- display: inline-block;
- padding: 0.375rem;
-}
-
-pre {
- display: block;
- margin-bottom: var(--app-spacing);
- overflow-x: auto;
-}
-
-pre > code,
-pre > samp {
- display: block;
- padding: var(--app-spacing);
- background: 0 0;
- line-height: var(--app-line-height);
-}
-
-.code-toolbar {
- position: relative;
- margin-block: var(--app-spacing);
-}
-
-.code-toolbar > .toolbar {
- position: absolute;
- top: 0.5rem;
- right: 0.5rem;
- z-index: 1;
-}
-
-.code-toolbar > .toolbar .toolbar-item {
- display: inline-flex;
-}
-
-.code-toolbar > .toolbar .copy-to-clipboard-button {
- --app-background-color: transparent;
- --app-border-color: var(--app-muted-border-color);
- --app-color: var(--app-muted-color);
- --app-box-shadow: none;
- --app-button-padding-vertical: var(--app-button-padding-vertical-small);
- --app-button-padding-horizontal: var(--app-button-padding-horizontal-small);
- font-size: 0.75rem;
-}
-
-.code-toolbar > .toolbar .copy-to-clipboard-button:is(:hover, :focus) {
- --app-background-color: var(--app-card-sectioning-background-color);
- --app-border-color: var(--app-muted-border-color);
-}
-
-.code-toolbar > pre > code {
- padding-top: calc(var(--app-spacing) * 2);
-}
-
-kbd {
- background-color: var(--app-code-kbd-background-color);
- color: var(--app-code-kbd-color);
- vertical-align: baseline;
-}
-
-figure {
- display: block;
- margin: 0;
- padding: 0;
-}
-
-figure figcaption {
- padding: calc(var(--app-spacing) * 0.5) 0;
- color: var(--app-muted-color);
-}
-
-hr {
- height: 0;
- margin: var(--app-typography-spacing-vertical) 0;
- border: 0;
- border-top: 1px solid var(--app-muted-border-color);
- color: inherit;
-}
-
-[hidden],
-template {
- display: none !important;
-}
-
-canvas {
- display: inline-block;
-}
-
-input,
-optgroup,
-select,
-textarea {
- margin: 0;
- font-size: 1rem;
- line-height: var(--app-line-height);
- font-family: inherit;
- letter-spacing: inherit;
-}
-
-input {
- overflow: visible;
-}
-
-select {
- text-transform: none;
-}
-
-legend {
- max-width: 100%;
- white-space: normal;
- margin: 0;
- display: block;
- color: var(--app-color);
- font-weight: var(--app-form-label-font-weight, var(--app-font-weight));
-}
-
-textarea {
- overflow: auto;
-}
-
-[type="checkbox"],
-[type="radio"] {
- padding: 0;
-}
-
-::-webkit-inner-spin-button,
-::-webkit-outer-spin-button {
- height: auto;
-}
-
-[type="search"] {
- -webkit-appearance: textfield;
- outline-offset: -2px;
-}
-
-[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- font: inherit;
-}
-
-::-moz-focus-inner {
- padding: 0;
- border-style: none;
-}
-
-:-moz-focusring {
- outline: 0;
-}
-
-:-moz-ui-invalid {
- box-shadow: none;
-}
-
-::-ms-expand {
- display: none;
-}
-
-[type="file"],
-[type="range"] {
- padding: 0;
- border-width: 0;
-}
-
-input:not([type="checkbox"], [type="radio"], [type="range"]) {
- height: calc(
- 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
- 2 + var(--app-border-width) * 2
- );
-}
-
-fieldset {
- width: 100%;
- margin-bottom: var(--app-spacing);
- border: 1px solid var(--app-form-element-border-color);
- padding: var(--app-spacing);
- border-radius: var(--app-border-radius);
-}
-
-fieldset[role="group"] {
- padding: 0;
- border: 0;
- border-radius: 0;
-}
-
-label {
- display: block;
- margin-bottom: calc(var(--app-spacing) * 0.375);
- color: var(--app-color);
- font-weight: var(--app-form-label-font-weight, var(--app-font-weight));
- font-size: small;
-}
-
-label:has(input[required]) span:after {
- content: " *";
-}
-
-button[type="submit"],
-input:not([type="checkbox"], [type="radio"]),
-select,
-textarea {
- width: 100%;
-}
-
-input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]),
-select,
-textarea {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- padding: var(--app-form-element-spacing-vertical)
- var(--app-form-element-spacing-horizontal);
-}
-
-input,
-select,
-textarea {
- --app-background-color: var(--app-form-element-background-color);
- --app-border-color: var(--app-form-element-border-color);
- --app-color: var(--app-form-element-color);
- --app-box-shadow: none;
- border: var(--app-border-width) solid var(--app-border-color);
- border-radius: var(--app-border-radius);
- outline: 0;
- background-color: var(--app-background-color);
- box-shadow: var(--app-box-shadow);
- color: var(--app-color);
- font-weight: var(--app-font-weight);
- transition:
- background-color var(--app-transition),
- border-color var(--app-transition),
- color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-:where(select, textarea):not([readonly]):is(:active, :focus),
-input:not(
- [type="submit"],
- [type="button"],
- [type="reset"],
- [type="checkbox"],
- [type="radio"],
- [readonly]
- ):is(:active, :focus) {
- --app-background-color: var(--app-form-element-active-background-color);
-}
-
-:where(select, textarea):not([readonly]):is(:active, :focus),
-input:not(
- [type="submit"],
- [type="button"],
- [type="reset"],
- [role="switch"],
- [readonly]
- ):is(:active, :focus) {
- --app-border-color: var(--app-form-element-active-border-color);
-}
-
-:where(select, textarea):not([readonly]):focus,
-input:not(
- [type="submit"],
- [type="button"],
- [type="reset"],
- [type="range"],
- [type="file"],
- [readonly]
- ):focus {
- --app-box-shadow: 0 0 0 var(--app-outline-width)
- var(--app-form-element-focus-color);
-}
-
-:where(fieldset[disabled])
- :is(
- input:not([type="submit"], [type="button"], [type="reset"]),
- select,
- textarea
- ),
-input:not([type="submit"], [type="button"], [type="reset"])[disabled],
-label[aria-disabled="true"],
-select[disabled],
-textarea[disabled] {
- opacity: var(--app-form-element-disabled-opacity);
- pointer-events: none;
-}
-
-label[aria-disabled="true"] input[disabled] {
- opacity: 1;
-}
-
-:where(input, select, textarea):not(
- [type="checkbox"],
- [type="radio"],
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"],
- [type="range"]
- )[aria-invalid] {
- padding-right: calc(
- var(--app-form-element-spacing-horizontal) + 1.5rem
- ) !important;
- padding-left: var(--app-form-element-spacing-horizontal);
- padding-inline-start: var(--app-form-element-spacing-horizontal) !important;
- padding-inline-end: calc(
- var(--app-form-element-spacing-horizontal) + 1.5rem
- ) !important;
- background-position: center right 0.75rem;
- background-size: 1rem auto;
- background-repeat: no-repeat;
-}
-
-:where(input, select, textarea):not(
- [type="checkbox"],
- [type="radio"],
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"],
- [type="range"]
- )[aria-invalid="false"]:not(select) {
- background-image: var(--app-icon-valid);
-}
-
-:where(input, select, textarea):not(
- [type="checkbox"],
- [type="radio"],
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"],
- [type="range"]
- )[aria-invalid="true"]:not(select) {
- background-image: var(--app-icon-invalid);
-}
-
-:where(input, select, textarea)[aria-invalid="false"] {
- --app-border-color: var(--app-form-element-valid-border-color);
-}
-
-:where(input, select, textarea)[aria-invalid="false"]:is(:active, :focus) {
- --app-border-color: var(
- --app-form-element-valid-active-border-color
- ) !important
-;
-}
-
-:where(input, select, textarea)[aria-invalid="false"]:is(:active, :focus):not(
- [type="checkbox"],
- [type="radio"]
- ) {
- --app-box-shadow: 0 0 0 var(--app-outline-width)
- var(--app-form-element-valid-focus-color) !important
-;
-}
-
-:where(input, select, textarea)[aria-invalid="true"] {
- --app-border-color: var(--app-form-element-invalid-border-color);
-}
-
-:where(input, select, textarea)[aria-invalid="true"]:is(:active, :focus) {
- --app-border-color: var(
- --app-form-element-invalid-active-border-color
- ) !important
-;
-}
-
-:where(input, select, textarea)[aria-invalid="true"]:is(:active, :focus):not(
- [type="checkbox"],
- [type="radio"]
- ) {
- --app-box-shadow: 0 0 0 var(--app-outline-width)
- var(--app-form-element-invalid-focus-color) !important
-;
-}
-
-[dir="rtl"]
- :where(input, select, textarea):not([type="checkbox"], [type="radio"]):is(
- [aria-invalid],
- [aria-invalid="true"],
- [aria-invalid="false"]
- ) {
- background-position: center left 0.75rem;
-}
-
-input::-webkit-input-placeholder,
-input::placeholder,
-select:invalid,
-textarea::-webkit-input-placeholder,
-textarea::placeholder {
- color: var(--app-form-element-placeholder-color);
- opacity: 1;
-}
-
-input:not([type="checkbox"], [type="radio"]),
-select,
-textarea {
- margin-bottom: var(--app-spacing);
-}
-
-select::-ms-expand {
- border: 0;
- background-color: transparent;
-}
-
-select:not([multiple], [size]) {
- padding-right: calc(var(--app-form-element-spacing-horizontal) + 1.5rem);
- padding-left: var(--app-form-element-spacing-horizontal);
- padding-inline-start: var(--app-form-element-spacing-horizontal);
- padding-inline-end: calc(var(--app-form-element-spacing-horizontal) + 1.5rem);
- background-image: var(--app-icon-chevron);
- background-position: center right 0.75rem;
- background-size: 1rem auto;
- background-repeat: no-repeat;
-}
-
-select[multiple] option:checked {
- background: var(--app-form-element-selected-background-color);
- color: var(--app-form-element-color);
-}
-
-[dir="rtl"] select:not([multiple], [size]) {
- background-position: center left 0.75rem;
-}
-
-textarea {
- display: block;
- resize: vertical;
-}
-
-textarea[aria-invalid] {
- --app-icon-height: calc(
- 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
- 2 + var(--app-border-width) * 2
- );
- background-position: top right 0.75rem !important;
- background-size: 1rem var(--app-icon-height) !important;
-}
-
-:where(input, select, textarea, fieldset, .grid) + small {
- display: block;
- width: 100%;
- margin-top: calc(var(--app-spacing) * -0.75);
- margin-bottom: var(--app-spacing);
- color: var(--app-muted-color);
-}
-
-:where(input, select, textarea, fieldset, .grid)[aria-invalid="false"] + small {
- color: var(--app-ins-color);
-}
-
-:where(input, select, textarea, fieldset, .grid)[aria-invalid="true"] + small {
- color: var(--app-del-color);
-}
-
-label > :where(input, select, textarea) {
- margin-top: calc(var(--app-spacing) * 0.25);
-}
-
-label:has([type="checkbox"], [type="radio"]) {
- width: -moz-fit-content;
- width: fit-content;
- cursor: pointer;
-}
-
-[type="checkbox"],
-[type="radio"] {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- width: 1.25em;
- height: 1.25em;
- margin-top: -0.125em;
- margin-inline-end: 0.5em;
- border-width: var(--app-border-width);
- vertical-align: middle;
- cursor: pointer;
-}
-
-[type="checkbox"]::-ms-check,
-[type="radio"]::-ms-check {
- display: none;
-}
-
-[type="checkbox"]:checked,
-[type="checkbox"]:checked:active,
-[type="checkbox"]:checked:focus,
-[type="radio"]:checked,
-[type="radio"]:checked:active,
-[type="radio"]:checked:focus {
- --app-background-color: var(--app-primary-background);
- --app-border-color: var(--app-primary-border);
- background-image: var(--app-icon-checkbox);
- background-position: center;
- background-size: 0.75em auto;
- background-repeat: no-repeat;
-}
-
-[type="checkbox"] ~ label,
-[type="radio"] ~ label {
- display: inline-block;
- margin-bottom: 0;
- cursor: pointer;
-}
-
-[type="checkbox"] ~ label:not(:last-of-type),
-[type="radio"] ~ label:not(:last-of-type) {
- margin-inline-end: 1em;
-}
-
-[type="checkbox"]:indeterminate {
- --app-background-color: var(--app-primary-background);
- --app-border-color: var(--app-primary-border);
- background-image: var(--app-icon-minus);
- background-position: center;
- background-size: 0.75em auto;
- background-repeat: no-repeat;
-}
-
-[type="radio"] {
- border-radius: 50%;
-}
-
-[type="radio"]:checked,
-[type="radio"]:checked:active,
-[type="radio"]:checked:focus {
- --app-background-color: var(--app-primary-inverse);
- border-width: 0.35em;
- background-image: none;
-}
-
-[type="checkbox"][role="switch"] {
- --app-background-color: var(--app-switch-background-color);
- --app-color: var(--app-switch-color);
- width: 2.25em;
- height: 1.25em;
- border: var(--app-border-width) solid var(--app-border-color);
- border-radius: 1.25em;
- background-color: var(--app-background-color);
- line-height: 1.25em;
-}
-
-[type="checkbox"][role="switch"]:not([aria-invalid]) {
- --app-border-color: var(--app-switch-background-color);
-}
-
-[type="checkbox"][role="switch"]:before {
- display: block;
- aspect-ratio: 1;
- height: 100%;
- border-radius: 50%;
- background-color: var(--app-color);
- box-shadow: var(--app-switch-thumb-box-shadow);
- content: "";
- transition: margin 0.1s ease-in-out;
-}
-
-[type="checkbox"][role="switch"]:focus {
- --app-background-color: var(--app-switch-background-color);
- --app-border-color: var(--app-switch-background-color);
-}
-
-[type="checkbox"][role="switch"]:checked {
- --app-background-color: var(--app-switch-checked-background-color);
- --app-border-color: var(--app-switch-checked-background-color);
- background-image: none;
-}
-
-[type="checkbox"][role="switch"]:checked::before {
- margin-inline-start: calc(2.25em - 1.25em);
-}
-
-[type="checkbox"][role="switch"][disabled] {
- --app-background-color: var(--app-border-color);
-}
-
-[type="checkbox"][aria-invalid="false"]:checked,
-[type="checkbox"][aria-invalid="false"]:checked:active,
-[type="checkbox"][aria-invalid="false"]:checked:focus,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked:active,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked:focus {
- --app-background-color: var(--app-form-element-valid-border-color);
-}
-
-[type="checkbox"]:checked:active[aria-invalid="true"],
-[type="checkbox"]:checked:focus[aria-invalid="true"],
-[type="checkbox"]:checked[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked:active[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked:focus[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked[aria-invalid="true"] {
- --app-background-color: var(--app-form-element-invalid-border-color);
-}
-
-[type="checkbox"][aria-invalid="false"]:checked,
-[type="checkbox"][aria-invalid="false"]:checked:active,
-[type="checkbox"][aria-invalid="false"]:checked:focus,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked:active,
-[type="checkbox"][role="switch"][aria-invalid="false"]:checked:focus,
-[type="radio"][aria-invalid="false"]:checked,
-[type="radio"][aria-invalid="false"]:checked:active,
-[type="radio"][aria-invalid="false"]:checked:focus {
- --app-border-color: var(--app-form-element-valid-border-color);
-}
-
-[type="checkbox"]:checked:active[aria-invalid="true"],
-[type="checkbox"]:checked:focus[aria-invalid="true"],
-[type="checkbox"]:checked[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked:active[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked:focus[aria-invalid="true"],
-[type="checkbox"][role="switch"]:checked[aria-invalid="true"],
-[type="radio"]:checked:active[aria-invalid="true"],
-[type="radio"]:checked:focus[aria-invalid="true"],
-[type="radio"]:checked[aria-invalid="true"] {
- --app-border-color: var(--app-form-element-invalid-border-color);
-}
-
-[type="color"]::-webkit-color-swatch-wrapper {
- padding: 0;
-}
-
-[type="color"]::-moz-focus-inner {
- padding: 0;
-}
-
-[type="color"]::-webkit-color-swatch {
- border: 0;
- border-radius: calc(var(--app-border-radius) * 0.5);
-}
-
-[type="color"]::-moz-color-swatch {
- border: 0;
- border-radius: calc(var(--app-border-radius) * 0.5);
-}
-
-input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]):is(
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"]
- ) {
- --app-icon-position: 0.75rem;
- --app-icon-width: 1rem;
- padding-right: calc(var(--app-icon-width) + var(--app-icon-position));
- background-image: var(--app-icon-date);
- background-position: center right var(--app-icon-position);
- background-size: var(--app-icon-width) auto;
- background-repeat: no-repeat;
-}
-
-input:not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="time"] {
- background-image: var(--app-icon-time);
-}
-
-[type="date"]::-webkit-calendar-picker-indicator,
-[type="datetime-local"]::-webkit-calendar-picker-indicator,
-[type="month"]::-webkit-calendar-picker-indicator,
-[type="time"]::-webkit-calendar-picker-indicator,
-[type="week"]::-webkit-calendar-picker-indicator {
- width: var(--app-icon-width);
- margin-right: calc(var(--app-icon-width) * -1);
- margin-left: var(--app-icon-position);
- opacity: 0;
-}
-
-@-moz-document url-prefix() {
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"] {
- padding-right: var(--app-form-element-spacing-horizontal) !important;
- background-image: none !important;
- }
-}
-
-[dir="rtl"]
- :is(
- [type="date"],
- [type="datetime-local"],
- [type="month"],
- [type="time"],
- [type="week"]
- ) {
- text-align: right;
-}
-
-[type="file"] {
- --app-color: var(--app-muted-color);
- margin-left: calc(var(--app-outline-width) * -1);
- background: 0 0;
- border: 2px dashed var(--app-form-element-border-color);
- padding: 1.5rem;
- height: auto !important;
-}
-
-[type="file"]::file-selector-button {
- margin-right: calc(var(--app-spacing) / 2);
- padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
- var(--app-form-element-spacing-horizontal);
-}
-
-[type="file"]:is(:hover, :active, :focus)::file-selector-button {
- --app-background-color: var(--app-secondary-hover-background);
- --app-border-color: var(--app-secondary-hover-border);
-}
-
-[type="file"]:focus::file-selector-button {
- --app-box-shadow:
- var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
- 0 0 0 var(--app-outline-width) var(--app-secondary-focus);
-}
-
-[type="range"] {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- width: 100%;
- height: 1.25rem;
- background: 0 0;
-}
-
-[type="range"]::-webkit-slider-runnable-track {
- width: 100%;
- height: 0.375rem;
- border-radius: var(--app-border-radius);
- background-color: var(--app-range-border-color);
- -webkit-transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
- transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-[type="range"]::-moz-range-track {
- width: 100%;
- height: 0.375rem;
- border-radius: var(--app-border-radius);
- background-color: var(--app-range-border-color);
- -moz-transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
- transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-[type="range"]::-ms-track {
- width: 100%;
- height: 0.375rem;
- border-radius: var(--app-border-radius);
- background-color: var(--app-range-border-color);
- -ms-transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
- transition:
- background-color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-[type="range"]::-webkit-slider-thumb {
- -webkit-appearance: none;
- width: 1.25rem;
- height: 1.25rem;
- margin-top: -0.4375rem;
- border: 2px solid var(--app-range-thumb-border-color);
- border-radius: 50%;
- background-color: var(--app-range-thumb-color);
- cursor: pointer;
- -webkit-transition:
- background-color var(--app-transition),
- transform var(--app-transition);
- transition:
- background-color var(--app-transition),
- transform var(--app-transition);
-}
-
-[type="range"]::-moz-range-thumb {
- -webkit-appearance: none;
- width: 1.25rem;
- height: 1.25rem;
- margin-top: -0.4375rem;
- border: 2px solid var(--app-range-thumb-border-color);
- border-radius: 50%;
- background-color: var(--app-range-thumb-color);
- cursor: pointer;
- -moz-transition:
- background-color var(--app-transition),
- transform var(--app-transition);
- transition:
- background-color var(--app-transition),
- transform var(--app-transition);
-}
-
-[type="range"]::-ms-thumb {
- -webkit-appearance: none;
- width: 1.25rem;
- height: 1.25rem;
- margin-top: -0.4375rem;
- border: 2px solid var(--app-range-thumb-border-color);
- border-radius: 50%;
- background-color: var(--app-range-thumb-color);
- cursor: pointer;
- -ms-transition:
- background-color var(--app-transition),
- transform var(--app-transition);
- transition:
- background-color var(--app-transition),
- transform var(--app-transition);
-}
-
-[type="range"]:active,
-[type="range"]:focus-within {
- --app-range-border-color: var(--app-range-active-border-color);
- --app-range-thumb-color: var(--app-range-thumb-active-color);
-}
-
-[type="range"]:active::-webkit-slider-thumb {
- transform: scale(1.25);
-}
-
-[type="range"]:active::-moz-range-thumb {
- transform: scale(1.25);
-}
-
-[type="range"]:active::-ms-thumb {
- transform: scale(1.25);
-}
-
-input:not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"] {
- padding-inline-start: calc(
- var(--app-form-element-spacing-horizontal) + 1.75rem
- );
- background-image: var(--app-icon-search);
- background-position: center left
- calc(var(--app-form-element-spacing-horizontal) + 0.125rem);
- background-size: 1rem auto;
- background-repeat: no-repeat;
-}
-
-input:not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"][aria-invalid] {
- padding-inline-start: calc(
- var(--app-form-element-spacing-horizontal) + 1.75rem
- ) !important;
- background-position:
- center left 1.125rem,
- center right 0.75rem;
-}
-
-input:not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"][aria-invalid="false"] {
- background-image: var(--app-icon-search), var(--app-icon-valid);
-}
-
-input:not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"][aria-invalid="true"] {
- background-image: var(--app-icon-search), var(--app-icon-invalid);
-}
-
-[dir="rtl"]
- :where(input):not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"] {
- background-position: center right 1.125rem;
-}
-
-[dir="rtl"]
- :where(input):not(
- [type="checkbox"],
- [type="radio"],
- [type="range"],
- [type="file"]
- )[type="search"][aria-invalid] {
- background-position:
- center right 1.125rem,
- center left 0.75rem;
-}
-
-details {
- display: block;
- margin-bottom: var(--app-spacing);
-}
-
-details summary {
- line-height: 1rem;
- list-style-type: none;
- cursor: pointer;
- transition: color var(--app-transition);
-}
-
-details summary:not([role]) {
- color: var(--app-accordion-close-summary-color);
-}
-
-details summary::-webkit-details-marker {
- display: none;
-}
-
-details summary::marker {
- display: none;
-}
-
-details summary::-moz-list-bullet {
- list-style-type: none;
-}
-
-details summary::after {
- display: block;
- width: 1rem;
- height: 1rem;
- margin-inline-start: calc(var(--app-spacing, 1rem) * 0.5);
- float: right;
- transform: rotate(-90deg);
- background-image: var(--app-icon-chevron);
- background-position: right center;
- background-size: 1rem auto;
- background-repeat: no-repeat;
- content: "";
- transition: transform var(--app-transition);
-}
-
-details summary:focus {
- outline: 0;
-}
-
-details summary:focus:not([role]) {
- color: var(--app-accordion-active-summary-color);
-}
-
-details summary:focus-visible:not([role]) {
- outline: var(--app-outline-width) solid var(--app-primary-focus);
- outline-offset: calc(var(--app-spacing, 1rem) * 0.5);
- color: var(--app-primary);
-}
-
-details summary[role="button"] {
- width: 100%;
- text-align: left;
-}
-
-details summary[role="button"]::after {
- height: calc(1rem * var(--app-line-height, 1.5));
-}
-
-details[open] > summary {
- margin-bottom: calc(var(--app-spacing) * 0.5);
-}
-
-details[open] > summary:not([role]):not(:focus) {
- color: var(--app-accordion-close-summary-color);
-}
-
-details[open] > summary::after {
- transform: rotate(0);
-}
-
-[dir="rtl"] details summary {
- text-align: right;
-}
-
-[dir="rtl"] details summary::after {
- float: left;
- background-position: left center;
-}
-
-article {
- margin-bottom: var(--app-block-spacing-vertical);
- padding: var(--app-block-spacing-vertical) var(--app-block-spacing-horizontal);
- border-radius: var(--app-border-radius);
- background: var(--app-card-background-color);
- box-shadow: var(--app-card-box-shadow);
-}
-
-article:not(:has(footer)) p:last-child {
- margin: 0;
-}
-
-article > footer,
-article > header {
- margin-right: calc(var(--app-block-spacing-horizontal) * -1);
- margin-left: calc(var(--app-block-spacing-horizontal) * -1);
- padding: calc(var(--app-block-spacing-vertical) * 1)
- var(--app-block-spacing-horizontal);
- background-color: var(--app-card-sectioning-background-color);
-}
-
-article > header {
- margin-top: calc(var(--app-block-spacing-vertical) * -1);
- margin-bottom: var(--app-block-spacing-vertical);
- border-bottom: var(--app-border-width) solid var(--app-card-border-color);
- border-top-right-radius: var(--app-border-radius);
- border-top-left-radius: var(--app-border-radius);
-}
-
-article > header > hgroup {
- margin: 0;
-}
-
-article > footer {
- margin-top: var(--app-block-spacing-vertical);
- margin-bottom: calc(var(--app-block-spacing-vertical) * -1);
- border-top: var(--app-border-width) solid var(--app-card-border-color);
- border-bottom-right-radius: var(--app-border-radius);
- border-bottom-left-radius: var(--app-border-radius);
-}
-
-details.dropdown {
- position: relative;
- border-bottom: none;
-}
-
-details.dropdown > a::after,
-details.dropdown > button::after,
-details.dropdown > summary::after {
- display: block;
- width: 1rem;
- height: calc(1rem * var(--app-line-height, 1.5));
- margin-inline-start: 0.25rem;
- float: right;
- transform: rotate(0) translateX(0.2rem);
- background-image: var(--app-icon-chevron);
- background-position: right center;
- background-size: 1rem auto;
- background-repeat: no-repeat;
- content: "";
-}
-
-nav details.dropdown {
- margin-bottom: 0;
-}
-
-details.dropdown > summary:not([role]) {
- height: calc(
- 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
- 2 + var(--app-border-width) * 2
- );
- padding: var(--app-form-element-spacing-vertical)
- var(--app-form-element-spacing-horizontal);
- border: var(--app-border-width) solid var(--app-form-element-border-color);
- border-radius: var(--app-border-radius);
- background-color: var(--app-form-element-background-color);
- color: var(--app-form-element-placeholder-color);
- line-height: inherit;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- transition:
- background-color var(--app-transition),
- border-color var(--app-transition),
- color var(--app-transition),
- box-shadow var(--app-transition);
-}
-
-details.dropdown > summary:not([role]):active,
-details.dropdown > summary:not([role]):focus {
- border-color: var(--app-form-element-active-border-color);
- background-color: var(--app-form-element-active-background-color);
-}
-
-details.dropdown > summary:not([role]):focus {
- box-shadow: 0 0 0 var(--app-outline-width) var(--app-form-element-focus-color);
-}
-
-details.dropdown > summary:not([role]):focus-visible {
- outline: 0;
-}
-
-details.dropdown > summary:not([role])[aria-invalid="false"] {
- --app-form-element-border-color: var(--app-form-element-valid-border-color);
- --app-form-element-active-border-color: var(
- --app-form-element-valid-focus-color
- );
- --app-form-element-focus-color: var(--app-form-element-valid-focus-color);
-}
-
-details.dropdown > summary:not([role])[aria-invalid="true"] {
- --app-form-element-border-color: var(--app-form-element-invalid-border-color);
- --app-form-element-active-border-color: var(
- --app-form-element-invalid-focus-color
- );
- --app-form-element-focus-color: var(--app-form-element-invalid-focus-color);
-}
-
-nav details.dropdown {
- display: inline;
- margin: calc(var(--app-nav-element-spacing-vertical) * -1) 0;
-}
-
-nav details.dropdown > summary::after {
- transform: rotate(0) translateX(0);
-}
-
-nav details.dropdown > summary:not([role]) {
- height: calc(
- 1rem * var(--app-line-height) + var(--app-nav-link-spacing-vertical) * 2
- );
- padding: calc(
- var(--app-nav-link-spacing-vertical) - var(--app-border-width) * 2
- )
- var(--app-nav-link-spacing-horizontal);
-}
-
-nav details.dropdown > summary:not([role]):focus-visible {
- box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
-}
-
-details.dropdown > summary + ul {
- display: flex;
- z-index: 99;
- position: absolute;
- left: 0;
- flex-direction: column;
- width: 100%;
- min-width: -moz-fit-content;
- min-width: fit-content;
- margin: 0;
- margin-top: var(--app-outline-width);
- padding: 0;
- border: var(--app-border-width) solid var(--app-dropdown-border-color);
- border-radius: var(--app-border-radius);
- background-color: var(--app-dropdown-background-color);
- box-shadow: var(--app-dropdown-box-shadow);
- color: var(--app-dropdown-color);
- white-space: nowrap;
- opacity: 0;
- transition:
- opacity var(--app-transition),
- transform 0s ease-in-out 1s;
-}
-
-details.dropdown > summary + ul[dir="rtl"] {
- right: 0;
- left: auto;
-}
-
-details.dropdown > summary + ul li {
- width: 100%;
- margin-bottom: 0;
- padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
- var(--app-form-element-spacing-horizontal);
- list-style: none;
- text-align: left;
- border-bottom: 1px solid var(--app-accordion-border-color);
-}
-
-details.dropdown > summary + ul li:first-of-type {
- margin-top: calc(var(--app-form-element-spacing-vertical) * 0.5);
-}
-
-details.dropdown > summary + ul li:last-of-type {
- margin-bottom: calc(var(--app-form-element-spacing-vertical) * 0.5);
- border-bottom: 0;
-}
-
-details.dropdown > summary + ul li a {
- display: block;
- margin: calc(var(--app-form-element-spacing-vertical) * -0.5)
- calc(var(--app-form-element-spacing-horizontal) * -1);
- padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
- var(--app-form-element-spacing-horizontal);
- overflow: hidden;
- border-radius: 0;
- color: var(--app-dropdown-color);
- text-decoration: none;
- text-overflow: ellipsis;
-}
-
-details.dropdown > summary + ul li a:active,
-details.dropdown > summary + ul li a:focus,
-details.dropdown > summary + ul li a:focus-visible,
-details.dropdown > summary + ul li a:hover,
-details.dropdown > summary + ul li a[aria-current]:not([aria-current="false"]) {
- background-color: var(--app-dropdown-hover-background-color);
-}
-
-details.dropdown > summary + ul li label {
- width: 100%;
-}
-
-details.dropdown > summary + ul li:has(label):hover {
- background-color: var(--app-dropdown-hover-background-color);
-}
-
-details.dropdown[open] > summary {
- margin-bottom: 0;
-}
-
-details.dropdown[open] > summary + ul {
- transform: scaleY(1);
- opacity: 1;
- transition:
- opacity var(--app-transition),
- transform 0s ease-in-out 0s;
-}
-
-details.dropdown[open] > summary::before {
- display: block;
- z-index: 1;
- position: fixed;
- width: 100vw;
- height: 100vh;
- inset: 0;
- background: 0 0;
- content: "";
- cursor: default;
-}
-
-label > details.dropdown {
- margin-top: calc(var(--app-spacing) * 0.25);
-}
-
-[role="group"],
-[role="search"] {
- display: inline-flex;
- position: relative;
- width: 100%;
- margin-bottom: var(--app-spacing);
- border-radius: var(--app-border-radius);
- box-shadow: var(--app-group-box-shadow, 0 0 0 transparent);
- vertical-align: middle;
- transition: box-shadow var(--app-transition);
-}
-
-[role="group"] input:not([type="checkbox"], [type="radio"]),
-[role="group"] select,
-[role="group"] > *,
-[role="search"] input:not([type="checkbox"], [type="radio"]),
-[role="search"] select,
-[role="search"] > * {
- position: relative;
- flex: 1 1 auto;
- margin-bottom: 0;
-}
-
-[role="group"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
-[role="group"] select:not(:first-child),
-[role="group"] > :not(:first-child),
-[role="search"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
-[role="search"] select:not(:first-child),
-[role="search"] > :not(:first-child) {
- margin-left: 0;
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
-}
-
-[role="group"] input:not([type="checkbox"], [type="radio"]):not(:last-child),
-[role="group"] select:not(:last-child),
-[role="group"] > :not(:last-child),
-[role="search"] input:not([type="checkbox"], [type="radio"]):not(:last-child),
-[role="search"] select:not(:last-child),
-[role="search"] > :not(:last-child) {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
-}
-
-[role="group"] input:not([type="checkbox"], [type="radio"]):focus,
-[role="group"] select:focus,
-[role="group"] > :focus,
-[role="search"] input:not([type="checkbox"], [type="radio"]):focus,
-[role="search"] select:focus,
-[role="search"] > :focus {
- z-index: 2;
-}
-
-[role="group"] [role="button"]:not(:first-child),
-[role="group"] [type="button"]:not(:first-child),
-[role="group"] [type="reset"]:not(:first-child),
-[role="group"] [type="submit"]:not(:first-child),
-[role="group"] button:not(:first-child),
-[role="group"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
-[role="group"] select:not(:first-child),
-[role="search"] [role="button"]:not(:first-child),
-[role="search"] [type="button"]:not(:first-child),
-[role="search"] [type="reset"]:not(:first-child),
-[role="search"] [type="submit"]:not(:first-child),
-[role="search"] button:not(:first-child),
-[role="search"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
-[role="search"] select:not(:first-child) {
- margin-left: calc(var(--app-border-width) * -1);
-}
-
-[role="group"] [role="button"],
-[role="group"] [type="button"],
-[role="group"] [type="reset"],
-[role="group"] [type="submit"],
-[role="group"] button,
-[role="search"] [role="button"],
-[role="search"] [type="button"],
-[role="search"] [type="reset"],
-[role="search"] [type="submit"],
-[role="search"] button {
- width: auto;
-}
-
-@supports selector(:has(*)) {
- [role="group"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- ),
- [role="search"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- ) {
- --app-group-box-shadow: var(--app-group-box-shadow-focus-with-button);
+ canvas {
+ display: inline-block;
}
- [role="group"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- )
- input:not([type="checkbox"], [type="radio"]),
- [role="group"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- )
- select,
- [role="search"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- )
- input:not([type="checkbox"], [type="radio"]),
- [role="search"]:has(
- button:focus,
- [type="submit"]:focus,
- [type="button"]:focus,
- [role="button"]:focus
- )
- select {
- border-color: transparent;
+ input,
+ optgroup,
+ select,
+ textarea {
+ margin: 0;
+ font-size: 1rem;
+ line-height: var(--app-line-height);
+ font-family: inherit;
+ letter-spacing: inherit;
}
- [role="group"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- ),
- [role="search"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- ) {
- --app-group-box-shadow: var(--app-group-box-shadow-focus-with-input);
+ input {
+ overflow: visible;
}
- [role="group"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [role="button"],
- [role="group"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [type="button"],
- [role="group"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [type="submit"],
- [role="group"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- button,
- [role="search"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [role="button"],
- [role="search"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [type="button"],
- [role="search"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- [type="submit"],
- [role="search"]:has(
- input:not([type="submit"], [type="button"]):focus,
- select:focus
- )
- button {
- --app-button-box-shadow: 0 0 0 var(--app-border-width)
- var(--app-primary-border);
- --app-button-hover-box-shadow: 0 0 0 var(--app-border-width)
- var(--app-primary-hover-border);
+ select {
+ text-transform: none;
}
- [role="group"] [role="button"]:focus,
- [role="group"] [type="button"]:focus,
- [role="group"] [type="reset"]:focus,
- [role="group"] [type="submit"]:focus,
- [role="group"] button:focus,
- [role="search"] [role="button"]:focus,
- [role="search"] [type="button"]:focus,
- [role="search"] [type="reset"]:focus,
- [role="search"] [type="submit"]:focus,
- [role="search"] button:focus {
+ legend {
+ max-width: 100%;
+ white-space: normal;
+ margin: 0;
+ display: block;
+ color: var(--app-color);
+ font-weight: var(--app-form-label-font-weight, var(--app-font-weight));
+ }
+
+ textarea {
+ overflow: auto;
+ }
+
+ [type="checkbox"],
+ [type="radio"] {
+ padding: 0;
+ }
+
+ ::-webkit-inner-spin-button,
+ ::-webkit-outer-spin-button {
+ height: auto;
+ }
+
+ [type="search"] {
+ -webkit-appearance: textfield;
+ outline-offset: -2px;
+ }
+
+ [type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+ }
+
+ ::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ font: inherit;
+ }
+
+ ::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+ }
+
+ :-moz-focusring {
+ outline: 0;
+ }
+
+ :-moz-ui-invalid {
box-shadow: none;
}
-}
-[role="search"] > :first-child {
- border-top-left-radius: 5rem;
- border-bottom-left-radius: 5rem;
-}
-
-[role="search"] > :last-child {
- border-top-right-radius: 5rem;
- border-bottom-right-radius: 5rem;
-}
-
-html {
- scroll-behavior: smooth;
- background: var(--app-sidebar-background-color);
-}
-
-.white-space-nowrap {
- white-space: nowrap;
-}
-
-[aria-busy="true"]:not(input, select, textarea, html, form) {
- white-space: nowrap;
-}
-
-[aria-busy="true"]:not(input, select, textarea, html, form)::before {
- display: inline-block;
- width: 1em;
- height: 1em;
- background-image: var(--app-icon-loading);
- background-size: 1em auto;
- background-repeat: no-repeat;
- content: "";
- vertical-align: -0.125em;
-}
-
-[aria-busy="true"]:not(input, select, textarea, html, form):not(
- :empty
- )::before {
- margin-inline-end: calc(var(--app-spacing) * 0.5);
-}
-
-[aria-busy="true"]:not(input, select, textarea, html, form):empty {
- text-align: center;
-}
-
-[role="button"][aria-busy="true"],
-[type="button"][aria-busy="true"],
-[type="reset"][aria-busy="true"],
-[type="submit"][aria-busy="true"],
-a[aria-busy="true"],
-button[aria-busy="true"] {
- pointer-events: none;
-}
-
-dialog {
- display: flex;
- z-index: 999;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- align-items: center;
- justify-content: center;
- width: inherit;
- min-width: 100%;
- height: inherit;
- min-height: 100%;
- padding: 0;
- border: 0;
- -webkit-backdrop-filter: var(--app-modal-overlay-backdrop-filter);
- backdrop-filter: var(--app-modal-overlay-backdrop-filter);
- background-color: var(--app-modal-overlay-background-color);
- color: var(--app-color);
-}
-
-dialog > article {
- width: 100%;
- max-height: calc(100vh - var(--app-spacing) * 2);
- margin: var(--app-spacing);
- overflow: auto;
-}
-
-@media (min-width: 576px) {
- dialog > article {
- max-width: 510px;
+ ::-ms-expand {
+ display: none;
}
-}
-@media (min-width: 768px) {
- dialog > article {
- max-width: 700px;
+ [type="file"],
+ [type="range"] {
+ padding: 0;
+ border-width: 0;
}
-}
-dialog > article > header > * {
- margin-bottom: 0;
-}
+ input:not([type="checkbox"], [type="radio"], [type="range"]) {
+ height: calc(
+ 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
+ 2 + var(--app-border-width) * 2
+ );
+ }
-dialog > article > header .close,
-dialog > article > header :is(a, button)[rel="prev"] {
- margin: 0;
- margin-left: var(--app-spacing);
- padding: 0;
- float: right;
-}
+ fieldset {
+ width: 100%;
+ margin-bottom: var(--app-spacing);
+ border: 1px solid var(--app-form-element-border-color);
+ padding: var(--app-spacing);
+ border-radius: var(--app-border-radius);
+ }
-dialog > article > footer {
- text-align: right;
-}
+ fieldset[role="group"] {
+ padding: 0;
+ border: 0;
+ border-radius: 0;
+ }
-dialog > article > footer [role="button"],
-dialog > article > footer button {
- margin-bottom: 0;
-}
+ label {
+ display: block;
+ margin-bottom: calc(var(--app-spacing) * 0.375);
+ color: var(--app-color);
+ font-weight: var(--app-form-label-font-weight, var(--app-font-weight));
+ font-size: small;
+ }
-dialog > article > footer [role="button"]:not(:first-of-type),
-dialog > article > footer button:not(:first-of-type) {
- margin-left: calc(var(--app-spacing) * 0.5);
-}
+ label:has(input[required]) span:after {
+ content: " *";
+ }
-dialog > article .close,
-dialog > article :is(a, button)[rel="prev"] {
- display: block;
- width: 1rem;
- height: 1rem;
- margin-top: calc(var(--app-spacing) * -1);
- margin-bottom: var(--app-spacing);
- margin-left: auto;
- border: none;
- background-image: var(--app-icon-close);
- background-position: center;
- background-size: auto 1rem;
- background-repeat: no-repeat;
- background-color: transparent;
- opacity: 0.5;
- transition: opacity var(--app-transition);
-}
+ button[type="submit"],
+ input:not([type="checkbox"], [type="radio"]),
+ select,
+ textarea {
+ width: 100%;
+ }
-dialog
- > article
- .close:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ),
-dialog
- > article
- :is(a, button)[rel="prev"]:is(
- [aria-current]:not([aria-current="false"]),
- :hover,
- :active,
- :focus
- ) {
- opacity: 1;
-}
+ input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]),
+ select,
+ textarea {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ padding: var(--app-form-element-spacing-vertical)
+ var(--app-form-element-spacing-horizontal);
+ }
-dialog:not([open]),
-dialog[open="false"] {
- display: none;
-}
+ input,
+ select,
+ textarea {
+ --app-background-color: var(--app-form-element-background-color);
+ --app-border-color: var(--app-form-element-border-color);
+ --app-color: var(--app-form-element-color);
+ --app-box-shadow: none;
+ border: var(--app-border-width) solid var(--app-border-color);
+ border-radius: var(--app-border-radius);
+ outline: 0;
+ background-color: var(--app-background-color);
+ box-shadow: var(--app-box-shadow);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ transition:
+ background-color var(--app-transition),
+ border-color var(--app-transition),
+ color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
-.modal-is-open {
- padding-right: var(--app-scrollbar-width, 0);
- overflow: hidden;
- pointer-events: none;
- touch-action: none;
-}
+ :where(select, textarea):not([readonly]):is(:active, :focus),
+ input:not(
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [type="checkbox"],
+ [type="radio"],
+ [readonly]
+ ):is(:active, :focus) {
+ --app-background-color: var(--app-form-element-active-background-color);
+ }
-.modal-is-open dialog {
- pointer-events: auto;
- touch-action: auto;
-}
+ :where(select, textarea):not([readonly]):is(:active, :focus),
+ input:not(
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [role="switch"],
+ [readonly]
+ ):is(:active, :focus) {
+ --app-border-color: var(--app-form-element-active-border-color);
+ }
-:where(.modal-is-opening, .modal-is-closing) dialog,
-:where(.modal-is-opening, .modal-is-closing) dialog > article {
- animation-duration: 0.2s;
- animation-timing-function: ease-in-out;
- animation-fill-mode: both;
-}
+ :where(select, textarea):not([readonly]):focus,
+ input:not(
+ [type="submit"],
+ [type="button"],
+ [type="reset"],
+ [type="range"],
+ [type="file"],
+ [readonly]
+ ):focus {
+ --app-box-shadow: 0 0 0 var(--app-outline-width)
+ var(--app-form-element-focus-color);
+ }
-:where(.modal-is-opening, .modal-is-closing) dialog {
- animation-duration: 0.8s;
- animation-name: modal-overlay;
-}
+ :where(fieldset[disabled])
+ :is(
+ input:not([type="submit"], [type="button"], [type="reset"]),
+ select,
+ textarea
+ ),
+ input:not([type="submit"], [type="button"], [type="reset"])[disabled],
+ label[aria-disabled="true"],
+ select[disabled],
+ textarea[disabled] {
+ opacity: var(--app-form-element-disabled-opacity);
+ pointer-events: none;
+ }
-:where(.modal-is-opening, .modal-is-closing) dialog > article {
- animation-delay: 0.2s;
- animation-name: modal;
-}
+ label[aria-disabled="true"] input[disabled] {
+ opacity: 1;
+ }
-.modal-is-closing dialog,
-.modal-is-closing dialog > article {
- animation-delay: 0s;
- animation-direction: reverse;
-}
+ :where(input, select, textarea):not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"],
+ [type="range"]
+ )[aria-invalid] {
+ padding-right: calc(
+ var(--app-form-element-spacing-horizontal) + 1.5rem
+ ) !important;
+ padding-left: var(--app-form-element-spacing-horizontal);
+ padding-inline-start: var(--app-form-element-spacing-horizontal) !important;
+ padding-inline-end: calc(
+ var(--app-form-element-spacing-horizontal) + 1.5rem
+ ) !important;
+ background-position: center right 0.75rem;
+ background-size: 1rem auto;
+ background-repeat: no-repeat;
+ }
-@keyframes modal-overlay {
- from {
- -webkit-backdrop-filter: none;
- backdrop-filter: none;
+ :where(input, select, textarea):not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"],
+ [type="range"]
+ )[aria-invalid="false"]:not(select) {
+ background-image: var(--app-icon-valid);
+ }
+
+ :where(input, select, textarea):not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"],
+ [type="range"]
+ )[aria-invalid="true"]:not(select) {
+ background-image: var(--app-icon-invalid);
+ }
+
+ :where(input, select, textarea)[aria-invalid="false"] {
+ --app-border-color: var(--app-form-element-valid-border-color);
+ }
+
+ :where(input, select, textarea)[aria-invalid="false"]:is(:active, :focus) {
+ --app-border-color: var(
+ --app-form-element-valid-active-border-color
+ ) !important
+;
+ }
+
+ :where(input, select, textarea)[aria-invalid="false"]:is(:active, :focus):not(
+ [type="checkbox"],
+ [type="radio"]
+ ) {
+ --app-box-shadow: 0 0 0 var(--app-outline-width)
+ var(--app-form-element-valid-focus-color) !important
+;
+ }
+
+ :where(input, select, textarea)[aria-invalid="true"] {
+ --app-border-color: var(--app-form-element-invalid-border-color);
+ }
+
+ :where(input, select, textarea)[aria-invalid="true"]:is(:active, :focus) {
+ --app-border-color: var(
+ --app-form-element-invalid-active-border-color
+ ) !important
+;
+ }
+
+ :where(input, select, textarea)[aria-invalid="true"]:is(:active, :focus):not(
+ [type="checkbox"],
+ [type="radio"]
+ ) {
+ --app-box-shadow: 0 0 0 var(--app-outline-width)
+ var(--app-form-element-invalid-focus-color) !important
+;
+ }
+
+ [dir="rtl"]
+ :where(input, select, textarea):not([type="checkbox"], [type="radio"]):is(
+ [aria-invalid],
+ [aria-invalid="true"],
+ [aria-invalid="false"]
+ ) {
+ background-position: center left 0.75rem;
+ }
+
+ input::-webkit-input-placeholder,
+ input::placeholder,
+ select:invalid,
+ textarea::-webkit-input-placeholder,
+ textarea::placeholder {
+ color: var(--app-form-element-placeholder-color);
+ opacity: 1;
+ }
+
+ input:not([type="checkbox"], [type="radio"]),
+ select,
+ textarea {
+ margin-bottom: var(--app-spacing);
+ }
+
+ select::-ms-expand {
+ border: 0;
background-color: transparent;
}
-}
-@keyframes modal {
- from {
- transform: translateY(-100%);
+ select:not([multiple], [size]) {
+ padding-right: calc(var(--app-form-element-spacing-horizontal) + 1.5rem);
+ padding-left: var(--app-form-element-spacing-horizontal);
+ padding-inline-start: var(--app-form-element-spacing-horizontal);
+ padding-inline-end: calc(
+ var(--app-form-element-spacing-horizontal) + 1.5rem
+ );
+ background-image: var(--app-icon-chevron);
+ background-position: center right 0.75rem;
+ background-size: 1rem auto;
+ background-repeat: no-repeat;
+ }
+
+ select[multiple] option:checked {
+ background: var(--app-form-element-selected-background-color);
+ color: var(--app-form-element-color);
+ }
+
+ [dir="rtl"] select:not([multiple], [size]) {
+ background-position: center left 0.75rem;
+ }
+
+ textarea {
+ display: block;
+ resize: vertical;
+ }
+
+ textarea[aria-invalid] {
+ --app-icon-height: calc(
+ 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
+ 2 + var(--app-border-width) * 2
+ );
+ background-position: top right 0.75rem !important;
+ background-size: 1rem var(--app-icon-height) !important;
+ }
+
+ :where(input, select, textarea, fieldset, .grid) + small {
+ display: block;
+ width: 100%;
+ margin-top: calc(var(--app-spacing) * -0.75);
+ margin-bottom: var(--app-spacing);
+ color: var(--app-muted-color);
+ }
+
+ :where(input, select, textarea, fieldset, .grid)[aria-invalid="false"]
+ + small {
+ color: var(--app-ins-color);
+ }
+
+ :where(input, select, textarea, fieldset, .grid)[aria-invalid="true"]
+ + small {
+ color: var(--app-del-color);
+ }
+
+ label > :where(input, select, textarea) {
+ margin-top: calc(var(--app-spacing) * 0.25);
+ }
+
+ label:has([type="checkbox"], [type="radio"]) {
+ width: -moz-fit-content;
+ width: fit-content;
+ cursor: pointer;
+ }
+
+ [type="checkbox"],
+ [type="radio"] {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ width: 1.25em;
+ height: 1.25em;
+ margin-top: -0.125em;
+ margin-inline-end: 0.5em;
+ border-width: var(--app-border-width);
+ vertical-align: middle;
+ cursor: pointer;
+ flex-shrink: 0;
+ }
+
+ [type="checkbox"]::-ms-check,
+ [type="radio"]::-ms-check {
+ display: none;
+ }
+
+ [type="checkbox"]:checked,
+ [type="checkbox"]:checked:active,
+ [type="checkbox"]:checked:focus,
+ [type="radio"]:checked,
+ [type="radio"]:checked:active,
+ [type="radio"]:checked:focus {
+ --app-background-color: var(--app-primary-background);
+ --app-border-color: var(--app-primary-border);
+ background-image: var(--app-icon-checkbox);
+ background-position: center;
+ background-size: 0.75em auto;
+ background-repeat: no-repeat;
+ }
+
+ [type="checkbox"] ~ label,
+ [type="radio"] ~ label {
+ display: inline-block;
+ margin-bottom: 0;
+ cursor: pointer;
+ }
+
+ [type="checkbox"] ~ label:not(:last-of-type),
+ [type="radio"] ~ label:not(:last-of-type) {
+ margin-inline-end: 1em;
+ }
+
+ [type="checkbox"]:indeterminate {
+ --app-background-color: var(--app-primary-background);
+ --app-border-color: var(--app-primary-border);
+ background-image: var(--app-icon-minus);
+ background-position: center;
+ background-size: 0.75em auto;
+ background-repeat: no-repeat;
+ }
+
+ [type="radio"] {
+ border-radius: 50%;
+ }
+
+ [type="radio"]:checked,
+ [type="radio"]:checked:active,
+ [type="radio"]:checked:focus {
+ --app-background-color: var(--app-primary-inverse);
+ border-width: 0.35em;
+ background-image: none;
+ }
+
+ [type="checkbox"][role="switch"] {
+ --app-background-color: var(--app-switch-background-color);
+ --app-color: var(--app-switch-color);
+ width: 2.25em;
+ height: 1.25em;
+ border: var(--app-border-width) solid var(--app-border-color);
+ border-radius: 1.25em;
+ background-color: var(--app-background-color);
+ line-height: 1.25em;
+ }
+
+ [type="checkbox"][role="switch"]:not([aria-invalid]) {
+ --app-border-color: var(--app-switch-background-color);
+ }
+
+ [type="checkbox"][role="switch"]:before {
+ display: block;
+ aspect-ratio: 1;
+ height: 100%;
+ border-radius: 50%;
+ background-color: var(--app-color);
+ box-shadow: var(--app-switch-thumb-box-shadow);
+ content: "";
+ transition: margin 0.1s ease-in-out;
+ }
+
+ [type="checkbox"][role="switch"]:focus {
+ --app-background-color: var(--app-switch-background-color);
+ --app-border-color: var(--app-switch-background-color);
+ }
+
+ [type="checkbox"][role="switch"]:checked {
+ --app-background-color: var(--app-switch-checked-background-color);
+ --app-border-color: var(--app-switch-checked-background-color);
+ background-image: none;
+ }
+
+ [type="checkbox"][role="switch"]:checked::before {
+ margin-inline-start: calc(2.25em - 1.25em);
+ }
+
+ [type="checkbox"][role="switch"][disabled] {
+ --app-background-color: var(--app-border-color);
+ }
+
+ [type="checkbox"][aria-invalid="false"]:checked,
+ [type="checkbox"][aria-invalid="false"]:checked:active,
+ [type="checkbox"][aria-invalid="false"]:checked:focus,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked:active,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked:focus {
+ --app-background-color: var(--app-form-element-valid-border-color);
+ }
+
+ [type="checkbox"]:checked:active[aria-invalid="true"],
+ [type="checkbox"]:checked:focus[aria-invalid="true"],
+ [type="checkbox"]:checked[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked:active[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked:focus[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked[aria-invalid="true"] {
+ --app-background-color: var(--app-form-element-invalid-border-color);
+ }
+
+ [type="checkbox"][aria-invalid="false"]:checked,
+ [type="checkbox"][aria-invalid="false"]:checked:active,
+ [type="checkbox"][aria-invalid="false"]:checked:focus,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked:active,
+ [type="checkbox"][role="switch"][aria-invalid="false"]:checked:focus,
+ [type="radio"][aria-invalid="false"]:checked,
+ [type="radio"][aria-invalid="false"]:checked:active,
+ [type="radio"][aria-invalid="false"]:checked:focus {
+ --app-border-color: var(--app-form-element-valid-border-color);
+ }
+
+ [type="checkbox"]:checked:active[aria-invalid="true"],
+ [type="checkbox"]:checked:focus[aria-invalid="true"],
+ [type="checkbox"]:checked[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked:active[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked:focus[aria-invalid="true"],
+ [type="checkbox"][role="switch"]:checked[aria-invalid="true"],
+ [type="radio"]:checked:active[aria-invalid="true"],
+ [type="radio"]:checked:focus[aria-invalid="true"],
+ [type="radio"]:checked[aria-invalid="true"] {
+ --app-border-color: var(--app-form-element-invalid-border-color);
+ }
+
+ [type="color"]::-webkit-color-swatch-wrapper {
+ padding: 0;
+ }
+
+ [type="color"]::-moz-focus-inner {
+ padding: 0;
+ }
+
+ [type="color"]::-webkit-color-swatch {
+ border: 0;
+ border-radius: calc(var(--app-border-radius) * 0.5);
+ }
+
+ [type="color"]::-moz-color-swatch {
+ border: 0;
+ border-radius: calc(var(--app-border-radius) * 0.5);
+ }
+
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ ):is(
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"]
+ ) {
+ --app-icon-position: 0.75rem;
+ --app-icon-width: 1rem;
+ padding-right: calc(var(--app-icon-width) + var(--app-icon-position));
+ background-image: var(--app-icon-date);
+ background-position: center right var(--app-icon-position);
+ background-size: var(--app-icon-width) auto;
+ background-repeat: no-repeat;
+ }
+
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="time"] {
+ background-image: var(--app-icon-time);
+ }
+
+ [type="date"]::-webkit-calendar-picker-indicator,
+ [type="datetime-local"]::-webkit-calendar-picker-indicator,
+ [type="month"]::-webkit-calendar-picker-indicator,
+ [type="time"]::-webkit-calendar-picker-indicator,
+ [type="week"]::-webkit-calendar-picker-indicator {
+ width: var(--app-icon-width);
+ margin-right: calc(var(--app-icon-width) * -1);
+ margin-left: var(--app-icon-position);
opacity: 0;
}
-}
-:where(nav li)::before {
- float: left;
- content: "";
-}
+ @-moz-document url-prefix() {
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"] {
+ padding-right: var(--app-form-element-spacing-horizontal) !important;
+ background-image: none !important;
+ }
+ }
-nav,
-nav ul {
- display: flex;
-}
+ [dir="rtl"]
+ :is(
+ [type="date"],
+ [type="datetime-local"],
+ [type="month"],
+ [type="time"],
+ [type="week"]
+ ) {
+ text-align: right;
+ }
-nav {
- justify-content: space-between;
- overflow: visible;
-}
+ [type="file"] {
+ --app-color: var(--app-muted-color);
+ margin-left: calc(var(--app-outline-width) * -1);
+ background: 0 0;
+ border: 2px dashed var(--app-form-element-border-color);
+ padding: 1.5rem;
+ height: auto !important;
+ }
-nav ol,
-nav ul {
- align-items: center;
- margin-bottom: 0;
- padding: 0;
- list-style: none;
-}
+ [type="file"]::file-selector-button {
+ margin-right: calc(var(--app-spacing) / 2);
+ padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
+ var(--app-form-element-spacing-horizontal);
+ }
-nav ol:first-of-type,
-nav ul:first-of-type {
- margin-left: calc(var(--app-nav-element-spacing-horizontal) * -1);
-}
+ [type="file"]:is(:hover, :active, :focus)::file-selector-button {
+ --app-background-color: var(--app-secondary-hover-background);
+ --app-border-color: var(--app-secondary-hover-border);
+ }
-nav ol:last-of-type,
-nav ul:last-of-type {
- margin-right: calc(var(--app-nav-element-spacing-horizontal) * -1);
-}
+ [type="file"]:focus::file-selector-button {
+ --app-box-shadow:
+ var(--app-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),
+ 0 0 0 var(--app-outline-width) var(--app-secondary-focus);
+ }
-nav li {
- display: inline-block;
- margin: 0;
- padding: var(--app-nav-element-spacing-vertical)
- var(--app-nav-element-spacing-horizontal);
-}
+ [type="range"] {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 1.25rem;
+ background: 0 0;
+ }
-nav li :where(a, [role="link"]) {
- display: inline-block;
- margin: calc(var(--app-nav-link-spacing-vertical) * -1)
- calc(var(--app-nav-link-spacing-horizontal) * -1);
- padding: var(--app-nav-link-spacing-vertical)
- var(--app-nav-link-spacing-horizontal);
- border-radius: var(--app-border-radius);
-}
+ [type="range"]::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 0.375rem;
+ border-radius: var(--app-border-radius);
+ background-color: var(--app-range-border-color);
+ -webkit-transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
-nav li :where(a, [role="link"]):not(:hover) {
- text-decoration: none;
-}
+ [type="range"]::-moz-range-track {
+ width: 100%;
+ height: 0.375rem;
+ border-radius: var(--app-border-radius);
+ background-color: var(--app-range-border-color);
+ -moz-transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
-nav li [role="button"],
-nav li [type="button"],
-nav li button,
-nav
- li
- input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]),
-nav li select {
- height: auto;
- margin-right: inherit;
- margin-bottom: 0;
- margin-left: inherit;
- padding: calc(
- var(--app-nav-link-spacing-vertical) - var(--app-border-width) * 2
- )
- var(--app-nav-link-spacing-horizontal);
-}
+ [type="range"]::-ms-track {
+ width: 100%;
+ height: 0.375rem;
+ border-radius: var(--app-border-radius);
+ background-color: var(--app-range-border-color);
+ -ms-transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
-nav[aria-label="breadcrumb"] {
- --app-breadcrumb-separator-size: 0.75rem;
- --app-nav-element-spacing-vertical: 0.25rem;
- --app-nav-element-spacing-horizontal: 0.25rem;
- --app-nav-link-spacing-vertical: 0.25rem;
- --app-nav-link-spacing-horizontal: 0.25rem;
- align-items: center;
- justify-content: start;
- font-size: 0.875em;
-}
+ [type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ width: 1.25rem;
+ height: 1.25rem;
+ margin-top: -0.4375rem;
+ border: 2px solid var(--app-range-thumb-border-color);
+ border-radius: 50%;
+ background-color: var(--app-range-thumb-color);
+ cursor: pointer;
+ -webkit-transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ }
-nav[aria-label="breadcrumb"] ol,
-nav[aria-label="breadcrumb"] ul {
- margin: 0;
-}
+ [type="range"]::-moz-range-thumb {
+ -webkit-appearance: none;
+ width: 1.25rem;
+ height: 1.25rem;
+ margin-top: -0.4375rem;
+ border: 2px solid var(--app-range-thumb-border-color);
+ border-radius: 50%;
+ background-color: var(--app-range-thumb-color);
+ cursor: pointer;
+ -moz-transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ }
-nav[aria-label="breadcrumb"] :is(ol, ul) li {
- padding: 0;
-}
+ [type="range"]::-ms-thumb {
+ -webkit-appearance: none;
+ width: 1.25rem;
+ height: 1.25rem;
+ margin-top: -0.4375rem;
+ border: 2px solid var(--app-range-thumb-border-color);
+ border-radius: 50%;
+ background-color: var(--app-range-thumb-color);
+ cursor: pointer;
+ -ms-transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ transition:
+ background-color var(--app-transition),
+ transform var(--app-transition);
+ }
-nav[aria-label="breadcrumb"] :is(ol, ul) li:not(:first-child) {
- margin-inline-start: 0;
-}
+ [type="range"]:active,
+ [type="range"]:focus-within {
+ --app-range-border-color: var(--app-range-active-border-color);
+ --app-range-thumb-color: var(--app-range-thumb-active-color);
+ }
-nav[aria-label="breadcrumb"] :is(ol, ul) li a {
- margin: calc(var(--app-nav-link-spacing-vertical) * -1) 0;
- margin-inline-start: calc(var(--app-nav-link-spacing-horizontal) * -1);
-}
+ [type="range"]:active::-webkit-slider-thumb {
+ transform: scale(1.25);
+ }
-nav[aria-label="breadcrumb"] :is(ol, ul) li:not(:last-child)::after {
- display: inline-block;
- width: var(--app-breadcrumb-separator-size);
- height: var(--app-breadcrumb-separator-size);
- margin-inline: calc(var(--app-nav-link-spacing-horizontal) * 0.75);
- content: "";
- background-image: var(--app-icon-chevron);
- background-size: var(--app-breadcrumb-separator-size) auto;
- background-repeat: no-repeat;
- opacity: 0.7;
- transform: rotate(-90deg);
-}
+ [type="range"]:active::-moz-range-thumb {
+ transform: scale(1.25);
+ }
-nav[aria-label="breadcrumb"] a[aria-current]:not([aria-current="false"]) {
- background-color: transparent;
- color: inherit;
- text-decoration: none;
- pointer-events: none;
-}
+ [type="range"]:active::-ms-thumb {
+ transform: scale(1.25);
+ }
-aside li,
-aside nav,
-aside ol,
-aside ul {
- display: block;
-}
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"] {
+ padding-inline-start: calc(
+ var(--app-form-element-spacing-horizontal) + 1.75rem
+ );
+ background-image: var(--app-icon-search);
+ background-position: center left
+ calc(var(--app-form-element-spacing-horizontal) + 0.125rem);
+ background-size: 1rem auto;
+ background-repeat: no-repeat;
+ }
-aside li {
- padding: calc(var(--app-nav-element-spacing-vertical) * 0.5)
- var(--app-nav-element-spacing-horizontal);
-}
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"][aria-invalid] {
+ padding-inline-start: calc(
+ var(--app-form-element-spacing-horizontal) + 1.75rem
+ ) !important;
+ background-position:
+ center left 1.125rem,
+ center right 0.75rem;
+ }
-aside li a {
- display: block;
-}
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"][aria-invalid="false"] {
+ background-image: var(--app-icon-search), var(--app-icon-valid);
+ }
-aside li [role="button"] {
- margin: inherit;
-}
+ input:not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"][aria-invalid="true"] {
+ background-image: var(--app-icon-search), var(--app-icon-invalid);
+ }
-.text-align-center {
- text-align: center;
-}
+ [dir="rtl"]
+ :where(input):not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"] {
+ background-position: center right 1.125rem;
+ }
-.primary {
- box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;
-}
+ [dir="rtl"]
+ :where(input):not(
+ [type="checkbox"],
+ [type="radio"],
+ [type="range"],
+ [type="file"]
+ )[type="search"][aria-invalid] {
+ background-position:
+ center right 1.125rem,
+ center left 0.75rem;
+ }
-.secondary {
- border: 1px solid var(--app-border);
- color: var(--app-muted-color);
- box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;
-}
-.secondary:hover {
- border: 1px solid var(--app-contrast);
- color: var(--app-contrast);
-}
+ details {
+ display: block;
+ margin-bottom: var(--app-spacing);
+ }
-/* Loading state - global cursor and interaction blocking */
-body.is-loading {
- cursor: wait;
-}
+ details summary {
+ line-height: 1rem;
+ list-style-type: none;
+ cursor: pointer;
+ transition: color var(--app-transition);
+ }
-body.is-loading * {
- cursor: wait !important;
-}
+ details summary:not([role]) {
+ color: var(--app-accordion-close-summary-color);
+ }
-body.is-loading button,
-body.is-loading a,
-body.is-loading input,
-body.is-loading select,
-body.is-loading textarea {
- pointer-events: none;
+ details summary::-webkit-details-marker {
+ display: none;
+ }
+
+ details summary::marker {
+ display: none;
+ }
+
+ details summary::-moz-list-bullet {
+ list-style-type: none;
+ }
+
+ details summary::after {
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ margin-inline-start: calc(var(--app-spacing, 1rem) * 0.5);
+ float: right;
+ transform: rotate(-90deg);
+ background-image: var(--app-icon-chevron);
+ background-position: right center;
+ background-size: 1rem auto;
+ background-repeat: no-repeat;
+ content: "";
+ transition: transform var(--app-transition);
+ }
+
+ details summary:focus {
+ outline: 0;
+ }
+
+ details summary:focus:not([role]) {
+ color: var(--app-accordion-active-summary-color);
+ }
+
+ details summary:focus-visible:not([role]) {
+ outline: var(--app-outline-width) solid var(--app-primary-focus);
+ outline-offset: calc(var(--app-spacing, 1rem) * 0.5);
+ color: var(--app-primary);
+ }
+
+ details summary[role="button"] {
+ width: 100%;
+ text-align: left;
+ }
+
+ details summary[role="button"]::after {
+ height: calc(1rem * var(--app-line-height, 1.5));
+ }
+
+ details[open] > summary {
+ margin-bottom: calc(var(--app-spacing) * 0.5);
+ }
+
+ details[open] > summary:not([role]):not(:focus) {
+ color: var(--app-accordion-close-summary-color);
+ }
+
+ details[open] > summary::after {
+ transform: rotate(0);
+ }
+
+ [dir="rtl"] details summary {
+ text-align: right;
+ }
+
+ [dir="rtl"] details summary::after {
+ float: left;
+ background-position: left center;
+ }
+
+ article {
+ margin-bottom: var(--app-block-spacing-vertical);
+ padding: var(--app-block-spacing-vertical)
+ var(--app-block-spacing-horizontal);
+ border-radius: var(--app-border-radius);
+ background: var(--app-card-background-color);
+ box-shadow: var(--app-card-box-shadow);
+ }
+
+ article:not(:has(footer)) p:last-child {
+ margin: 0;
+ }
+
+ article > footer,
+ article > header {
+ margin-right: calc(var(--app-block-spacing-horizontal) * -1);
+ margin-left: calc(var(--app-block-spacing-horizontal) * -1);
+ padding: calc(var(--app-block-spacing-vertical) * 1)
+ var(--app-block-spacing-horizontal);
+ background-color: var(--app-card-sectioning-background-color);
+ }
+
+ article > header {
+ margin-top: calc(var(--app-block-spacing-vertical) * -1);
+ margin-bottom: var(--app-block-spacing-vertical);
+ border-bottom: var(--app-border-width) solid var(--app-card-border-color);
+ border-top-right-radius: var(--app-border-radius);
+ border-top-left-radius: var(--app-border-radius);
+ }
+
+ article > header > hgroup {
+ margin: 0;
+ }
+
+ article > footer {
+ margin-top: var(--app-block-spacing-vertical);
+ margin-bottom: calc(var(--app-block-spacing-vertical) * -1);
+ border-top: var(--app-border-width) solid var(--app-card-border-color);
+ border-bottom-right-radius: var(--app-border-radius);
+ border-bottom-left-radius: var(--app-border-radius);
+ }
+
+ details.dropdown {
+ position: relative;
+ border-bottom: none;
+ }
+
+ details.dropdown > a::after,
+ details.dropdown > button::after,
+ details.dropdown > summary::after {
+ display: block;
+ width: 1rem;
+ height: calc(1rem * var(--app-line-height, 1.5));
+ margin-inline-start: 0.25rem;
+ float: right;
+ transform: rotate(0) translateX(0.2rem);
+ background-image: var(--app-icon-chevron);
+ background-position: right center;
+ background-size: 1rem auto;
+ background-repeat: no-repeat;
+ content: "";
+ }
+
+ nav details.dropdown {
+ margin-bottom: 0;
+ }
+
+ details.dropdown > summary:not([role]) {
+ height: calc(
+ 1rem * var(--app-line-height) + var(--app-form-element-spacing-vertical) *
+ 2 + var(--app-border-width) * 2
+ );
+ padding: var(--app-form-element-spacing-vertical)
+ var(--app-form-element-spacing-horizontal);
+ border: var(--app-border-width) solid var(--app-form-element-border-color);
+ border-radius: var(--app-border-radius);
+ background-color: var(--app-form-element-background-color);
+ color: var(--app-form-element-placeholder-color);
+ line-height: inherit;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ transition:
+ background-color var(--app-transition),
+ border-color var(--app-transition),
+ color var(--app-transition),
+ box-shadow var(--app-transition);
+ }
+
+ details.dropdown > summary:not([role]):active,
+ details.dropdown > summary:not([role]):focus {
+ border-color: var(--app-form-element-active-border-color);
+ background-color: var(--app-form-element-active-background-color);
+ }
+
+ details.dropdown > summary:not([role]):focus {
+ box-shadow: 0 0 0 var(--app-outline-width)
+ var(--app-form-element-focus-color);
+ }
+
+ details.dropdown > summary:not([role]):focus-visible {
+ outline: 0;
+ }
+
+ details.dropdown > summary:not([role])[aria-invalid="false"] {
+ --app-form-element-border-color: var(--app-form-element-valid-border-color);
+ --app-form-element-active-border-color: var(
+ --app-form-element-valid-focus-color
+ );
+ --app-form-element-focus-color: var(--app-form-element-valid-focus-color);
+ }
+
+ details.dropdown > summary:not([role])[aria-invalid="true"] {
+ --app-form-element-border-color: var(
+ --app-form-element-invalid-border-color
+ );
+ --app-form-element-active-border-color: var(
+ --app-form-element-invalid-focus-color
+ );
+ --app-form-element-focus-color: var(--app-form-element-invalid-focus-color);
+ }
+
+ nav details.dropdown {
+ display: inline;
+ margin: calc(var(--app-nav-element-spacing-vertical) * -1) 0;
+ }
+
+ nav details.dropdown > summary::after {
+ transform: rotate(0) translateX(0);
+ }
+
+ nav details.dropdown > summary:not([role]) {
+ height: calc(
+ 1rem * var(--app-line-height) + var(--app-nav-link-spacing-vertical) * 2
+ );
+ padding: calc(
+ var(--app-nav-link-spacing-vertical) - var(--app-border-width) * 2
+ )
+ var(--app-nav-link-spacing-horizontal);
+ }
+
+ nav details.dropdown > summary:not([role]):focus-visible {
+ box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ }
+
+ details.dropdown > summary + ul {
+ display: flex;
+ z-index: 99;
+ position: absolute;
+ left: 0;
+ flex-direction: column;
+ width: 100%;
+ min-width: -moz-fit-content;
+ min-width: fit-content;
+ margin: 0;
+ margin-top: var(--app-outline-width);
+ padding: 0;
+ border: var(--app-border-width) solid var(--app-dropdown-border-color);
+ border-radius: var(--app-border-radius);
+ background-color: var(--app-dropdown-background-color);
+ box-shadow: var(--app-dropdown-box-shadow);
+ color: var(--app-dropdown-color);
+ white-space: nowrap;
+ opacity: 0;
+ transition:
+ opacity var(--app-transition),
+ transform 0s ease-in-out 1s;
+ }
+
+ details.dropdown > summary + ul[dir="rtl"] {
+ right: 0;
+ left: auto;
+ }
+
+ details.dropdown > summary + ul li {
+ width: 100%;
+ margin-bottom: 0;
+ padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
+ var(--app-form-element-spacing-horizontal);
+ list-style: none;
+ text-align: left;
+ border-bottom: 1px solid var(--app-accordion-border-color);
+ }
+
+ details.dropdown > summary + ul li:first-of-type {
+ margin-top: calc(var(--app-form-element-spacing-vertical) * 0.5);
+ }
+
+ details.dropdown > summary + ul li:last-of-type {
+ margin-bottom: calc(var(--app-form-element-spacing-vertical) * 0.5);
+ border-bottom: 0;
+ }
+
+ details.dropdown > summary + ul li a {
+ display: block;
+ margin: calc(var(--app-form-element-spacing-vertical) * -0.5)
+ calc(var(--app-form-element-spacing-horizontal) * -1);
+ padding: calc(var(--app-form-element-spacing-vertical) * 0.5)
+ var(--app-form-element-spacing-horizontal);
+ overflow: hidden;
+ border-radius: 0;
+ color: var(--app-dropdown-color);
+ text-decoration: none;
+ text-overflow: ellipsis;
+ }
+
+ details.dropdown > summary + ul li a:active,
+ details.dropdown > summary + ul li a:focus,
+ details.dropdown > summary + ul li a:focus-visible,
+ details.dropdown > summary + ul li a:hover,
+ details.dropdown
+ > summary
+ + ul
+ li
+ a[aria-current]:not([aria-current="false"]) {
+ background-color: var(--app-dropdown-hover-background-color);
+ }
+
+ details.dropdown > summary + ul li label {
+ width: 100%;
+ }
+
+ details.dropdown > summary + ul li:has(label):hover {
+ background-color: var(--app-dropdown-hover-background-color);
+ }
+
+ details.dropdown[open] > summary {
+ margin-bottom: 0;
+ }
+
+ details.dropdown[open] > summary + ul {
+ transform: scaleY(1);
+ opacity: 1;
+ transition:
+ opacity var(--app-transition),
+ transform 0s ease-in-out 0s;
+ }
+
+ details.dropdown[open] > summary::before {
+ display: block;
+ z-index: 1;
+ position: fixed;
+ width: 100vw;
+ height: 100vh;
+ inset: 0;
+ background: 0 0;
+ content: "";
+ cursor: default;
+ }
+
+ label > details.dropdown {
+ margin-top: calc(var(--app-spacing) * 0.25);
+ }
+
+ [role="group"],
+ [role="search"] {
+ display: inline-flex;
+ position: relative;
+ width: 100%;
+ margin-bottom: var(--app-spacing);
+ border-radius: var(--app-border-radius);
+ box-shadow: var(--app-group-box-shadow, 0 0 0 transparent);
+ vertical-align: middle;
+ transition: box-shadow var(--app-transition);
+ }
+
+ [role="group"] input:not([type="checkbox"], [type="radio"]),
+ [role="group"] select,
+ [role="group"] > *,
+ [role="search"] input:not([type="checkbox"], [type="radio"]),
+ [role="search"] select,
+ [role="search"] > * {
+ position: relative;
+ flex: 1 1 auto;
+ margin-bottom: 0;
+ }
+
+ [role="group"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
+ [role="group"] select:not(:first-child),
+ [role="group"] > :not(:first-child),
+ [role="search"]
+ input:not([type="checkbox"], [type="radio"]):not(:first-child),
+ [role="search"] select:not(:first-child),
+ [role="search"] > :not(:first-child) {
+ margin-left: 0;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+
+ [role="group"] input:not([type="checkbox"], [type="radio"]):not(:last-child),
+ [role="group"] select:not(:last-child),
+ [role="group"] > :not(:last-child),
+ [role="search"] input:not([type="checkbox"], [type="radio"]):not(:last-child),
+ [role="search"] select:not(:last-child),
+ [role="search"] > :not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+
+ [role="group"] input:not([type="checkbox"], [type="radio"]):focus,
+ [role="group"] select:focus,
+ [role="group"] > :focus,
+ [role="search"] input:not([type="checkbox"], [type="radio"]):focus,
+ [role="search"] select:focus,
+ [role="search"] > :focus {
+ z-index: 2;
+ }
+
+ [role="group"] [role="button"]:not(:first-child),
+ [role="group"] [type="button"]:not(:first-child),
+ [role="group"] [type="reset"]:not(:first-child),
+ [role="group"] [type="submit"]:not(:first-child),
+ [role="group"] button:not(:first-child),
+ [role="group"] input:not([type="checkbox"], [type="radio"]):not(:first-child),
+ [role="group"] select:not(:first-child),
+ [role="search"] [role="button"]:not(:first-child),
+ [role="search"] [type="button"]:not(:first-child),
+ [role="search"] [type="reset"]:not(:first-child),
+ [role="search"] [type="submit"]:not(:first-child),
+ [role="search"] button:not(:first-child),
+ [role="search"]
+ input:not([type="checkbox"], [type="radio"]):not(:first-child),
+ [role="search"] select:not(:first-child) {
+ margin-left: calc(var(--app-border-width) * -1);
+ }
+
+ [role="group"] [role="button"],
+ [role="group"] [type="button"],
+ [role="group"] [type="reset"],
+ [role="group"] [type="submit"],
+ [role="group"] button,
+ [role="search"] [role="button"],
+ [role="search"] [type="button"],
+ [role="search"] [type="reset"],
+ [role="search"] [type="submit"],
+ [role="search"] button {
+ width: auto;
+ }
+
+ @supports selector(:has(*)) {
+ [role="group"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ ),
+ [role="search"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ ) {
+ --app-group-box-shadow: var(--app-group-box-shadow-focus-with-button);
+ }
+
+ [role="group"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ )
+ input:not([type="checkbox"], [type="radio"]),
+ [role="group"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ )
+ select,
+ [role="search"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ )
+ input:not([type="checkbox"], [type="radio"]),
+ [role="search"]:has(
+ button:focus,
+ [type="submit"]:focus,
+ [type="button"]:focus,
+ [role="button"]:focus
+ )
+ select {
+ border-color: transparent;
+ }
+
+ [role="group"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ ),
+ [role="search"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ ) {
+ --app-group-box-shadow: var(--app-group-box-shadow-focus-with-input);
+ }
+
+ [role="group"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [role="button"],
+ [role="group"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [type="button"],
+ [role="group"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [type="submit"],
+ [role="group"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ button,
+ [role="search"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [role="button"],
+ [role="search"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [type="button"],
+ [role="search"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ [type="submit"],
+ [role="search"]:has(
+ input:not([type="submit"], [type="button"]):focus,
+ select:focus
+ )
+ button {
+ --app-button-box-shadow: 0 0 0 var(--app-border-width)
+ var(--app-primary-border);
+ --app-button-hover-box-shadow: 0 0 0 var(--app-border-width)
+ var(--app-primary-hover-border);
+ }
+
+ [role="group"] [role="button"]:focus,
+ [role="group"] [type="button"]:focus,
+ [role="group"] [type="reset"]:focus,
+ [role="group"] [type="submit"]:focus,
+ [role="group"] button:focus,
+ [role="search"] [role="button"]:focus,
+ [role="search"] [type="button"]:focus,
+ [role="search"] [type="reset"]:focus,
+ [role="search"] [type="submit"]:focus,
+ [role="search"] button:focus {
+ box-shadow: none;
+ }
+ }
+
+ [role="search"] > :first-child {
+ border-top-left-radius: 5rem;
+ border-bottom-left-radius: 5rem;
+ }
+
+ [role="search"] > :last-child {
+ border-top-right-radius: 5rem;
+ border-bottom-right-radius: 5rem;
+ }
+
+ html {
+ scroll-behavior: smooth;
+ background: var(--app-sidebar-background-color);
+ }
+
+ .white-space-nowrap {
+ white-space: nowrap;
+ }
+
+ [aria-busy="true"]:not(input, select, textarea, html, form) {
+ white-space: nowrap;
+ }
+
+ [aria-busy="true"]:not(input, select, textarea, html, form)::before {
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ background-image: var(--app-icon-loading);
+ background-size: 1em auto;
+ background-repeat: no-repeat;
+ content: "";
+ vertical-align: -0.125em;
+ }
+
+ [aria-busy="true"]:not(input, select, textarea, html, form):not(
+ :empty
+ )::before {
+ margin-inline-end: calc(var(--app-spacing) * 0.5);
+ }
+
+ [aria-busy="true"]:not(input, select, textarea, html, form):empty {
+ text-align: center;
+ }
+
+ [role="button"][aria-busy="true"],
+ [type="button"][aria-busy="true"],
+ [type="reset"][aria-busy="true"],
+ [type="submit"][aria-busy="true"],
+ a[aria-busy="true"],
+ button[aria-busy="true"] {
+ pointer-events: none;
+ }
+
+ dialog {
+ display: flex;
+ z-index: 999;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ align-items: center;
+ justify-content: center;
+ width: inherit;
+ min-width: 100%;
+ height: inherit;
+ min-height: 100%;
+ padding: 0;
+ border: 0;
+ -webkit-backdrop-filter: var(--app-modal-overlay-backdrop-filter);
+ backdrop-filter: var(--app-modal-overlay-backdrop-filter);
+ background-color: var(--app-modal-overlay-background-color);
+ color: var(--app-color);
+ }
+
+ dialog > article {
+ width: 100%;
+ max-height: calc(100vh - var(--app-spacing) * 2);
+ margin: var(--app-spacing);
+ overflow: auto;
+ }
+
+ .bi::before,
+ [class^="bi-"]::before,
+ [class*=" bi-"]::before {
+ vertical-align: -0.125em;
+ }
+
+ @media (min-width: 576px) {
+ dialog > article {
+ max-width: 510px;
+ }
+ }
+
+ @media (min-width: 768px) {
+ dialog > article {
+ max-width: 700px;
+ }
+ }
+
+ dialog > article > header > * {
+ margin-bottom: 0;
+ }
+
+ dialog > article > header .close,
+ dialog > article > header :is(a, button)[rel="prev"] {
+ margin: 0;
+ margin-left: var(--app-spacing);
+ padding: 0;
+ float: right;
+ }
+
+ dialog > article > footer {
+ text-align: right;
+ }
+
+ dialog > article > footer [role="button"],
+ dialog > article > footer button {
+ margin-bottom: 0;
+ }
+
+ dialog > article > footer [role="button"]:not(:first-of-type),
+ dialog > article > footer button:not(:first-of-type) {
+ margin-left: calc(var(--app-spacing) * 0.5);
+ }
+
+ dialog > article .close,
+ dialog > article :is(a, button)[rel="prev"] {
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ margin-top: calc(var(--app-spacing) * -1);
+ margin-bottom: var(--app-spacing);
+ margin-left: auto;
+ border: none;
+ background-image: var(--app-icon-close);
+ background-position: center;
+ background-size: auto 1rem;
+ background-repeat: no-repeat;
+ background-color: transparent;
+ opacity: 0.5;
+ transition: opacity var(--app-transition);
+ }
+
+ dialog
+ > article
+ .close:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ),
+ dialog
+ > article
+ :is(a, button)[rel="prev"]:is(
+ [aria-current]:not([aria-current="false"]),
+ :hover,
+ :active,
+ :focus
+ ) {
+ opacity: 1;
+ }
+
+ dialog:not([open]),
+ dialog[open="false"] {
+ display: none;
+ }
+
+ .modal-is-open {
+ padding-right: var(--app-scrollbar-width, 0);
+ overflow: hidden;
+ pointer-events: none;
+ touch-action: none;
+ }
+
+ .modal-is-open dialog {
+ pointer-events: auto;
+ touch-action: auto;
+ }
+
+ :where(.modal-is-opening, .modal-is-closing) dialog,
+ :where(.modal-is-opening, .modal-is-closing) dialog > article {
+ animation-duration: 0.2s;
+ animation-timing-function: ease-in-out;
+ animation-fill-mode: both;
+ }
+
+ :where(.modal-is-opening, .modal-is-closing) dialog {
+ animation-duration: 0.8s;
+ animation-name: modal-overlay;
+ }
+
+ :where(.modal-is-opening, .modal-is-closing) dialog > article {
+ animation-delay: 0.2s;
+ animation-name: modal;
+ }
+
+ .modal-is-closing dialog,
+ .modal-is-closing dialog > article {
+ animation-delay: 0s;
+ animation-direction: reverse;
+ }
+
+ @keyframes modal-overlay {
+ from {
+ -webkit-backdrop-filter: none;
+ backdrop-filter: none;
+ background-color: transparent;
+ }
+ }
+
+ @keyframes modal {
+ from {
+ transform: translateY(-100%);
+ opacity: 0;
+ }
+ }
+
+ :where(nav li)::before {
+ float: left;
+ content: "";
+ }
+
+ nav,
+ nav ul {
+ display: flex;
+ }
+
+ nav {
+ justify-content: space-between;
+ overflow: visible;
+ }
+
+ nav ol,
+ nav ul {
+ align-items: center;
+ margin-bottom: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ nav ol:first-of-type,
+ nav ul:first-of-type {
+ margin-left: calc(var(--app-nav-element-spacing-horizontal) * -1);
+ }
+
+ nav ol:last-of-type,
+ nav ul:last-of-type {
+ margin-right: calc(var(--app-nav-element-spacing-horizontal) * -1);
+ }
+
+ nav li {
+ display: inline-block;
+ margin: 0;
+ padding: var(--app-nav-element-spacing-vertical)
+ var(--app-nav-element-spacing-horizontal);
+ }
+
+ nav li :where(a, [role="link"]) {
+ display: inline-block;
+ margin: calc(var(--app-nav-link-spacing-vertical) * -1)
+ calc(var(--app-nav-link-spacing-horizontal) * -1);
+ padding: var(--app-nav-link-spacing-vertical)
+ var(--app-nav-link-spacing-horizontal);
+ border-radius: var(--app-border-radius);
+ }
+
+ nav li :where(a, [role="link"]):not(:hover) {
+ text-decoration: none;
+ }
+
+ nav li [role="button"],
+ nav li [type="button"],
+ nav li button,
+ nav
+ li
+ input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]),
+ nav li select {
+ height: auto;
+ margin-right: inherit;
+ margin-bottom: 0;
+ margin-left: inherit;
+ padding: calc(
+ var(--app-nav-link-spacing-vertical) - var(--app-border-width) * 2
+ )
+ var(--app-nav-link-spacing-horizontal);
+ }
+
+ nav[aria-label="breadcrumb"] {
+ --app-breadcrumb-separator-size: 0.75rem;
+ --app-nav-element-spacing-vertical: 0.25rem;
+ --app-nav-element-spacing-horizontal: 0.25rem;
+ --app-nav-link-spacing-vertical: 0.25rem;
+ --app-nav-link-spacing-horizontal: 0.25rem;
+ align-items: center;
+ justify-content: start;
+ font-size: 0.875em;
+ }
+
+ nav[aria-label="breadcrumb"] ol,
+ nav[aria-label="breadcrumb"] ul {
+ margin: 0;
+ }
+
+ nav[aria-label="breadcrumb"] :is(ol, ul) li {
+ padding: 0;
+ }
+
+ nav[aria-label="breadcrumb"] :is(ol, ul) li:not(:first-child) {
+ margin-inline-start: 0;
+ }
+
+ nav[aria-label="breadcrumb"] :is(ol, ul) li a {
+ margin: calc(var(--app-nav-link-spacing-vertical) * -1) 0;
+ margin-inline-start: calc(var(--app-nav-link-spacing-horizontal) * -1);
+ }
+
+ nav[aria-label="breadcrumb"] :is(ol, ul) li:not(:last-child)::after {
+ display: inline-block;
+ width: var(--app-breadcrumb-separator-size);
+ height: var(--app-breadcrumb-separator-size);
+ margin-inline: calc(var(--app-nav-link-spacing-horizontal) * 0.75);
+ content: "";
+ background-image: var(--app-icon-chevron);
+ background-size: var(--app-breadcrumb-separator-size) auto;
+ background-repeat: no-repeat;
+ opacity: 0.7;
+ transform: rotate(-90deg);
+ }
+
+ nav[aria-label="breadcrumb"] a[aria-current]:not([aria-current="false"]) {
+ background-color: transparent;
+ color: inherit;
+ text-decoration: none;
+ pointer-events: none;
+ }
+
+ aside li,
+ aside nav,
+ aside ol,
+ aside ul {
+ display: block;
+ }
+
+ aside li {
+ padding: calc(var(--app-nav-element-spacing-vertical) * 0.5)
+ var(--app-nav-element-spacing-horizontal);
+ }
+
+ aside li a {
+ display: block;
+ text-decoration: none;
+ }
+
+ aside li [role="button"] {
+ margin: inherit;
+ }
+
+ .text-align-center {
+ text-align: center;
+ }
+
+ .primary {
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;
+ }
+
+ .secondary {
+ border: 1px solid var(--app-border);
+ color: var(--app-muted-color);
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 2px;
+ }
+ .secondary:hover {
+ border: 1px solid var(--app-contrast);
+ color: var(--app-contrast);
+ }
+
+ /* Loading state - global cursor and interaction blocking */
+ body.is-loading {
+ cursor: wait;
+ }
+
+ body.is-loading * {
+ cursor: wait !important;
+ }
+
+ body.is-loading button,
+ body.is-loading a,
+ body.is-loading input,
+ body.is-loading select,
+ body.is-loading textarea {
+ pointer-events: none;
+ }
}
diff --git a/web/css/layout/app-sidebar.css b/web/css/layout/app-sidebar.css
index 4d2bf67..4a36316 100644
--- a/web/css/layout/app-sidebar.css
+++ b/web/css/layout/app-sidebar.css
@@ -1,238 +1,297 @@
-.app-sidebar {
- background: var(--app-sidebar-background-color);
- --app-sidebar-gap: 0.5rem;
- --app-sidebar-item-gap: 10px;
- --app-sidebar-title-size: 10px;
- --app-sidebar-summary-size: 12px;
- --app-sidebar-tenant-size: 14px;
- --app-sidebar-titlebar-height: 30px;
- --app-sidebar-border-width: 2px;
- --app-sidebar-summary-max-width: 157px;
- --app-sidebar-section-gap: 2rem;
- --app-sidebar-section-space: 5px;
- --app-sidebar-hover-bg: transparent;
-}
-
-.app-sidebar .brand {
- padding: var(--app-spacing);
-}
-
-.app-sidebar-titlebar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: var(--app-sidebar-gap);
- padding: 0 var(--app-spacing);
- margin-bottom: 0;
- min-height: var(--app-sidebar-titlebar-height);
-}
-
-.aside-pending .app-sidebar-titlebar {
- visibility: hidden;
-}
-
-.app-sidebar .app-sidebar-panel {
- display: block;
-}
-
-.app-sidebar .app-sidebar-panel[hidden] {
- display: none !important;
-}
-
-.app-sidebar.is-collapsed .app-sidebar-panels,
-.app-sidebar.is-collapsed .app-sidebar-titlebar,
-.sidebar-collapsed .app-sidebar .app-sidebar-titlebar,
-.sidebar-collapsed .app-sidebar .app-sidebar-panels {
- display: none;
-}
-
-.app-sidebar-tenant-logo {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: var(--app-sidebar-gap);
- padding: var(--app-spacing);
-}
-
-.app-sidebar .app-sidebar-tenant-logo a:hover {
- background: transparent;
- border: 0;
-}
-
-.app-sidebar .app-sidebar-tenant-logo > a {
- padding: 0;
- flex: 1;
- border: 0;
-}
-
-.app-sidebar-tenant-toggle {
- display: none;
- border: 1px solid var(--app-border);
- background: transparent;
- margin: 0;
-}
-
-.app-sidebar-tenant-toggle:hover {
- color: var(--app-contrast);
- border-color: var(--app-contrast);
-}
-
-.app-sidebar-tenant-name {
- flex: 1;
- font-weight: 600;
- font-size: var(--app-sidebar-tenant-size);
- color: var(--app-contrast);
- padding: 8px 12px;
- border-radius: var(--app-border-radius);
- text-align: left;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- border: 1px solid var(--app-border);
-}
-
-.app-sidebar-title {
- text-transform: uppercase;
- font-size: var(--app-sidebar-title-size);
- color: var(--app-muted-color);
-}
-
-.app-sidebar-tools {
- display: flex;
- align-items: center;
- gap: 0.35rem;
-}
-
-.app-sidebar-tools .icon-button {
- border: 0;
- background: transparent;
- color: var(--app-muted-color);
- padding: 0.25rem;
- font-size: 0.9rem;
- cursor: pointer;
- margin-bottom: 0;
-}
-
-.app-sidebar-tools .icon-button:hover {
- color: var(--app-contrast);
-}
-
-@media (min-width: 768px) {
- .app-sidebar .brand {
- margin-bottom: 1rem;
- padding-block-start: 0.5rem;
+@layer layout {
+ .app-sidebar {
+ background: var(--app-sidebar-background-color);
+ --app-sidebar-gap: 0.5rem;
+ --app-sidebar-item-gap: 10px;
+ --app-sidebar-title-size: 10px;
+ --app-sidebar-summary-size: 12px;
+ --app-sidebar-tenant-size: 14px;
+ --app-sidebar-titlebar-height: 30px;
+ --app-sidebar-border-width: 2px;
+ --app-sidebar-summary-max-width: 157px;
+ --app-sidebar-section-gap: 2rem;
+ --app-sidebar-section-space: 5px;
+ --app-sidebar-hover-bg: transparent;
}
- .app-sidebar-title {
+ .app-sidebar .brand {
+ padding: var(--app-spacing);
+ }
+
+ .app-sidebar-titlebar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--app-sidebar-gap);
+ padding: 0 var(--app-spacing);
+ margin-bottom: 0;
+ min-height: var(--app-sidebar-titlebar-height);
+ }
+
+ .aside-pending .app-sidebar-titlebar {
+ visibility: hidden;
+ }
+
+ .app-sidebar .app-sidebar-panel {
display: block;
}
- .app-sidebar {
- position: sticky;
- top: 0;
- z-index: 1;
+ .app-sidebar .app-sidebar-panel[hidden] {
+ display: none !important;
}
-}
-@media (max-width: 767px) {
- .app-sidebar-tenant-toggle {
- display: inline-flex;
+ .app-sidebar.is-collapsed .app-sidebar-panels,
+ .app-sidebar.is-collapsed .app-sidebar-titlebar,
+ .sidebar-collapsed .app-sidebar .app-sidebar-titlebar,
+ .sidebar-collapsed .app-sidebar .app-sidebar-panels {
+ display: none;
+ }
+
+ .app-sidebar-tenant-logo {
+ display: flex;
align-items: center;
- justify-content: center;
- }
- .app-sidebar-tenant-logo img {
- max-width: 120px;
- flex-shrink: 0;
- }
- .app-sidebar {
- border-bottom: 1px solid var(--app-border);
+ justify-content: space-between;
+ gap: var(--app-sidebar-gap);
+ padding: var(--app-spacing);
}
- .app-sidebar-panels {
- padding-block-end: var(--app-spacing);
+ .app-sidebar .app-sidebar-tenant-logo a:hover {
+ background: transparent;
+ border: 0;
+ }
+
+ .app-sidebar .app-sidebar-tenant-logo > a {
+ padding: 0;
+ flex: 1;
+ border: 0;
+ }
+
+ .app-sidebar-tenant-toggle {
+ display: none;
+ border: 1px solid var(--app-border);
+ background: transparent;
+ margin: 0;
+ }
+
+ .app-sidebar-tenant-toggle:hover {
+ color: var(--app-contrast);
+ border-color: var(--app-contrast);
+ }
+
+ .app-sidebar-tenant-name {
+ flex: 1;
+ font-weight: 600;
+ font-size: var(--app-sidebar-tenant-size);
+ color: var(--app-contrast);
+ padding: 8px 12px;
+ border-radius: var(--app-border-radius);
+ text-align: left;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ border: 1px solid var(--app-border);
+ }
+
+ .app-sidebar-title {
+ text-transform: uppercase;
+ font-size: var(--app-sidebar-title-size);
+ color: var(--app-muted-color);
+ }
+
+ .app-sidebar-tools {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ }
+
+ .app-sidebar-tools .icon-button {
+ border: 0;
+ background: transparent;
+ color: var(--app-muted-color);
+ padding: 0.25rem;
+ font-size: 0.9rem;
+ cursor: pointer;
+ margin-bottom: 0;
+ }
+
+ .app-sidebar-tools .icon-button:hover {
+ color: var(--app-contrast);
+ }
+
+ @media (min-width: 768px) {
+ .app-sidebar .brand {
+ margin-bottom: 1rem;
+ padding-block-start: 0.5rem;
+ }
+
+ .app-sidebar-title {
+ display: block;
+ }
+
+ .app-sidebar {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ height: 100vh;
+ overflow-y: auto;
+ }
+ }
+
+ @media (max-width: 767px) {
+ .app-sidebar-tenant-toggle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .app-sidebar-tenant-logo img {
+ max-width: 120px;
+ flex-shrink: 0;
+ }
+ .app-sidebar {
+ border-bottom: 1px solid var(--app-border);
+ }
+
+ .app-sidebar-panels {
+ padding-block-end: var(--app-spacing);
+ }
+ }
+
+ .app-sidebar a {
+ color: inherit;
+ display: block;
+ padding: 5px var(--app-spacing);
+ border-radius: 0;
+ margin: 0;
+ border-left: var(--app-sidebar-border-width) solid transparent;
+ width: 100%;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+
+ .app-sidebar a:hover,
+ .app-sidebar a.active,
+ .app-sidebar .active > a {
+ color: var(--app-primary);
+ background: var(--app-sidebar-hover-bg);
+ border-left: var(--app-sidebar-border-width) solid var(--app-primary);
+ }
+
+ aside.app-sidebar ul,
+ aside.app-sidebar li {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ .app-sidebar small {
+ margin-top: var(--app-sidebar-section-gap);
+ margin-bottom: var(--app-sidebar-section-space);
+ display: block;
+ padding-inline: var(--app-spacing);
+ }
+
+ .app-sidebar .app-sidebar-group small {
+ margin-top: 0;
+ margin-bottom: 0;
+ display: block;
+ padding-inline: 0;
+ opacity: 1;
+ }
+
+ .app-sidebar .app-sidebar-group details {
+ padding: 0;
+ margin: 0;
+ }
+
+ .app-sidebar .app-sidebar-group summary {
+ padding: 0 var(--app-spacing);
+ font-size: var(--app-sidebar-summary-size);
+ color: var(--app-muted-color);
+ line-height: 1;
+ }
+
+ nav#aside-panel-people {
+ margin-top: var(--app-spacing);
+ }
+
+ .app-sidebar .app-sidebar-group summary::-webkit-details-marker {
+ display: none;
+ }
+
+ .app-sidebar .app-sidebar-group details > ul {
+ margin: 0;
+ padding: 0;
+ }
+
+ .app-sidebar .app-sidebar-group summary > span {
+ text-overflow: ellipsis;
+ display: inline-block;
+ max-width: var(--app-sidebar-summary-max-width);
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .app-sidebar .app-sidebar-group details > ul li:first-child {
+ margin-top: 10px;
+ }
+
+ .app-sidebar .app-sidebar-saved-filters {
+ margin-bottom: var(--app-spacing);
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-item:before {
+ content: "";
+ display: none;
+ }
+
+ .app-sidebar .app-sidebar-group.app-sidebar-saved-filters > small {
+ padding: 5px var(--app-spacing);
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-item {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ justify-content: space-between;
+ padding-right: 10px;
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-item > a {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-delete {
+ margin: 0;
+ display: flex;
+ align-items: center;
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-delete button {
+ margin: 0;
+ border: 0;
+ background: transparent;
+ color: var(--app-muted-color);
+ padding: 4px;
+ opacity: 0;
+ visibility: hidden;
+ pointer-events: none;
+ transition: opacity 120ms ease;
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-delete button:hover {
+ color: var(--app-contrast);
+ }
+
+ .app-sidebar .app-sidebar-saved-filter-item:hover .app-sidebar-saved-filter-delete button,
+ .app-sidebar .app-sidebar-saved-filter-item:focus-within .app-sidebar-saved-filter-delete button {
+ opacity: 1;
+ visibility: visible;
+ pointer-events: auto;
+ }
+
+ aside.app-sidebar li.app-sidebar-group {
+ margin-bottom: var(--app-spacing);
}
}
-
-.app-sidebar a {
- color: inherit;
- display: flex;
- align-items: center;
- gap: var(--app-sidebar-item-gap);
- text-decoration: none;
- padding: 5px var(--app-spacing);
- border-radius: 0;
- margin: 0;
- border-left: var(--app-sidebar-border-width) solid transparent;
- width: 100%;
-}
-
-.app-sidebar a:hover,
-.app-sidebar a.active,
-.app-sidebar .active > a {
- color: var(--app-primary);
- background: var(--app-sidebar-hover-bg);
- border-left: var(--app-sidebar-border-width) solid var(--app-primary);
-}
-
-aside.app-sidebar ul,
-aside.app-sidebar li {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.app-sidebar small {
- margin-top: var(--app-sidebar-section-gap);
- margin-bottom: var(--app-sidebar-section-space);
- display: block;
- padding-inline: var(--app-spacing);
-}
-
-.app-sidebar .app-sidebar-group small {
- margin-top: 0;
- margin-bottom: 0;
- display: block;
- padding-inline: 0;
- opacity: 1;
-}
-
-.app-sidebar .app-sidebar-group details {
- padding: 0;
- margin: 0;
-}
-
-.app-sidebar .app-sidebar-group summary {
- padding: 0 var(--app-spacing);
- font-size: var(--app-sidebar-summary-size);
- color: var(--app-muted-color);
- line-height: 1;
-}
-
-nav#aside-panel-people {
- margin-top: var(--app-spacing);
-}
-
-.app-sidebar .app-sidebar-group summary::-webkit-details-marker {
- display: none;
-}
-
-.app-sidebar .app-sidebar-group details > ul {
- margin: 0;
- padding: 0;
-}
-
-.app-sidebar .app-sidebar-group summary > span {
- text-overflow: ellipsis;
- display: inline-block;
- max-width: var(--app-sidebar-summary-max-width);
- overflow: hidden;
- white-space: nowrap;
-}
-
-.app-sidebar .app-sidebar-group details > ul li:first-child {
- margin-top: 10px;
-}
-
-.app-sidebar .app-sidebar-group > small {
- padding-inline: var(--app-spacing);
-}
diff --git a/web/css/layout/app-topbar.css b/web/css/layout/app-topbar.css
index c5765c0..4381c08 100644
--- a/web/css/layout/app-topbar.css
+++ b/web/css/layout/app-topbar.css
@@ -1,3 +1,4 @@
+@layer layout {
.app-header {
--app-topbar-item-padding: 5px;
--app-topbar-list-gap: 8px;
@@ -91,3 +92,4 @@ main:has(#app-details-aside-section) li:has(#toggle-main-content-aside) {
.app-header details.dropdown[open] > summary::before {
display: none;
}
+}
diff --git a/web/css/components/app-profile.css b/web/css/pages/address-book-view.css
similarity index 99%
rename from web/css/components/app-profile.css
rename to web/css/pages/address-book-view.css
index 41a466e..37ac9b4 100644
--- a/web/css/components/app-profile.css
+++ b/web/css/pages/address-book-view.css
@@ -1,3 +1,8 @@
+@layer pages {
+.app-profile-card-container {
+ margin-top: calc(var(--app-spacing) * 2);
+}
+
.app-profile-card {
border: 1px solid var(--app-border);
background: var(--app-card-background-color);
@@ -568,3 +573,4 @@
contain: paint;
height: 160px;
}
+}
diff --git a/web/css/pages/app-docs.css b/web/css/pages/app-docs.css
new file mode 100644
index 0000000..e9f787d
--- /dev/null
+++ b/web/css/pages/app-docs.css
@@ -0,0 +1,366 @@
+@layer components {
+ /* ─── Layout ─────────────────────────────────────────────────── */
+
+ .app-docs-container {
+ display: grid;
+ grid-template-columns: 220px 1fr 200px;
+ grid-template-areas: "nav content toc";
+ align-items: start;
+ gap: 0 2rem;
+ min-height: 100%;
+ }
+
+ .app-docs-nav {
+ grid-area: nav;
+ }
+ .app-docs-content {
+ grid-area: content;
+ }
+ .app-docs-toc {
+ grid-area: toc;
+ }
+
+ /* Stick nav and toc to viewport while scrolling */
+ .app-docs-nav,
+ .app-docs-toc {
+ position: sticky;
+ top: 70px;
+ max-height: calc(100dvh - 6rem);
+ overflow-y: auto;
+ overscroll-behavior: contain;
+ }
+
+ @media (max-width: 1100px) {
+ .app-docs-container {
+ grid-template-columns: 220px 1fr;
+ grid-template-areas: "nav content";
+ }
+
+ .app-docs-toc {
+ display: none;
+ }
+ }
+
+ @media (max-width: 768px) {
+ .app-docs-container {
+ grid-template-columns: 1fr;
+ grid-template-areas:
+ "nav"
+ "content";
+ }
+
+ .app-docs-nav {
+ position: static;
+ max-height: none;
+ overflow-y: visible;
+ border-bottom: 1px solid var(--app-border);
+ padding-bottom: 1rem;
+ margin-bottom: 1rem;
+ }
+ }
+
+ /* ─── Left navigation ─────────────────────────────────────────── */
+
+ .app-docs-nav {
+ --docs-nav-border-width: 2px;
+ padding-block: 0.25rem;
+ }
+
+ .app-docs-nav-group {
+ margin-bottom: 0.25rem;
+ }
+
+ .app-docs-nav-group small {
+ display: block;
+ padding: 1.25rem 0.75rem 0.25rem;
+ font-size: 0.7rem;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+ }
+
+ .app-docs-nav-group:first-child small {
+ padding-top: 0.25rem;
+ }
+
+ .app-docs-nav ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ .app-docs-nav a {
+ display: block;
+ padding: 4px 0.75rem;
+ color: inherit;
+ border-left: var(--docs-nav-border-width) solid transparent;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: 0.875rem;
+ border-radius: 0;
+ text-decoration: none;
+ }
+
+ .app-docs-nav a:hover {
+ color: var(--app-primary);
+ border-left-color: var(--app-muted-border-color);
+ }
+
+ .app-docs-nav a.active {
+ color: var(--app-primary);
+ border-left-color: var(--app-primary);
+ font-weight: 500;
+ }
+
+ /* ─── TOC ─────────────────────────────────────────────────────── */
+
+ .app-docs-toc {
+ padding-block: 0.25rem;
+ }
+
+ .app-docs-toc > small {
+ display: block;
+ padding: 0 0 0.5rem;
+ font-size: 0.7rem;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+ }
+
+ .app-docs-toc ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ .app-docs-toc li {
+ position: relative;
+ }
+
+ .app-docs-toc a {
+ display: block;
+ text-decoration: none;
+ color: inherit;
+ line-height: 1.35;
+ padding-block: 0.12rem;
+ }
+
+ .app-docs-toc a:hover {
+ color: var(--app-primary);
+ }
+
+ .app-docs-toc-level-2 {
+ margin: 0;
+ padding: 0 0 10px 0;
+ }
+
+ .app-docs-toc-level-3 {
+ margin: 0;
+ padding: 0;
+ padding-left: 1rem;
+ }
+
+ .app-docs-toc-level-3 a {
+ font-size: 0.75rem;
+ padding-left: 0.45rem;
+ }
+
+ .app-docs-toc-level-3::before {
+ content: "";
+ position: absolute;
+ left: 0.2rem;
+ top: 2px;
+ width: 13px;
+ height: 0.55rem;
+ background: transparent;
+ border-left: 1px solid var(--app-border);
+ border-bottom: 1px solid var(--app-border);
+ border-bottom-left-radius: 6px;
+ }
+
+ .app-docs-toc-level-3:has(+ .app-docs-toc-level-2) {
+ margin-bottom: 1rem;
+ }
+
+ /* ─── Prose (rendered markdown) ────────────────────────────────── */
+
+ .app-docs-content {
+ max-width: 72ch;
+ min-width: 0;
+ background: transparent;
+ box-shadow: none;
+ }
+
+ .app-docs-content h1,
+ .app-docs-content h2,
+ .app-docs-content h3,
+ .app-docs-content h4,
+ .app-docs-content h5,
+ .app-docs-content h6 {
+ scroll-margin-top: 1.5rem;
+ line-height: 1.3;
+ }
+
+ .app-docs-content h1 {
+ color: var(--app-h1-color);
+ margin-top: 0;
+ font-size: 2.75rem;
+ }
+ .app-docs-content h2 {
+ color: var(--app-h2-color);
+ font-size: 1.375rem;
+ margin-top: 2.5rem;
+ padding-top: 1rem;
+ border-top: 1px solid var(--app-border);
+ }
+ .app-docs-content h3 {
+ color: var(--app-h3-color);
+ font-size: 1.125rem;
+ margin-top: 1.75rem;
+ }
+ .app-docs-content h4 {
+ color: var(--app-h4-color);
+ font-size: 1rem;
+ margin-top: 1.25rem;
+ }
+ .app-docs-content h5,
+ .app-docs-content h6 {
+ color: var(--app-h5-color);
+ font-size: 0.9rem;
+ margin-top: 1rem;
+ }
+
+ .app-docs-content p {
+ margin-block: 0.875rem;
+ line-height: 1.7;
+ }
+
+ .app-docs-content a {
+ color: var(--app-primary);
+ text-decoration: underline;
+ text-underline-offset: 0.15em;
+ }
+
+ .app-docs-content .app-breadcrumb a {
+ text-decoration: none;
+ color: inherit;
+ }
+
+ .app-docs-content a:hover {
+ color: var(--app-primary-hover);
+ }
+
+ .app-docs-content ul,
+ .app-docs-content ol {
+ padding-left: 1.5rem;
+ margin-block: 0.875rem;
+ }
+
+ .app-docs-content li {
+ margin-block: 0.3rem;
+ line-height: 1.6;
+ }
+
+ .app-docs-content li > ul,
+ .app-docs-content li > ol {
+ margin-block: 0.25rem;
+ }
+
+ .app-docs-content ul.contains-task-list,
+ .app-docs-content ol.contains-task-list,
+ .app-docs-content ul:has(> li > input[type="checkbox"]),
+ .app-docs-content ol:has(> li > input[type="checkbox"]) {
+ list-style: none;
+ padding-left: 0;
+ }
+
+ .app-docs-content .task-list-item,
+ .app-docs-content li:has(> input[type="checkbox"]) {
+ list-style: none;
+ position: relative;
+ padding-left: 1.6rem;
+ }
+
+ .app-docs-content .task-list-item .task-list-item-checkbox,
+ .app-docs-content .task-list-item > input[type="checkbox"] {
+ position: absolute;
+ left: 0;
+ top: 0.3rem;
+ width: 1rem;
+ height: 1rem;
+ margin: 0;
+ accent-color: var(--app-primary);
+ }
+
+ .app-docs-content pre {
+ background: var(--app-code-background-color);
+ border: 1px solid var(--app-border);
+ border-radius: var(--app-border-radius);
+ padding: 1rem 1.25rem;
+ overflow-x: auto;
+ margin-block: 1.25rem;
+ }
+
+ .app-docs-content pre code {
+ background: none;
+ padding: 0;
+ font-size: 0.85rem;
+ color: var(--app-color);
+ }
+
+ .app-docs-content blockquote {
+ border-left: 3px solid var(--app-blockquote-border-color);
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0.5rem 1rem;
+ background: var(--app-blockquote-background-color);
+ border-radius: 0 var(--app-border-radius) var(--app-border-radius) 0;
+ color: var(--app-muted-color);
+ }
+
+ .app-docs-content blockquote p {
+ margin: 0;
+ }
+
+ .app-docs-content hr {
+ border: 0;
+ border-top: 1px solid var(--app-border);
+ margin-block: 2rem;
+ }
+
+ .app-docs-content table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.875rem;
+ margin-block: 1.25rem;
+ overflow-x: auto;
+ display: block;
+ }
+
+ .app-docs-content th,
+ .app-docs-content td {
+ text-align: left;
+ padding: 0.5rem 0.75rem;
+ border: 1px solid var(--app-table-border-color);
+ }
+
+ .app-docs-content th {
+ background: var(--app-code-background-color);
+ font-weight: 600;
+ color: var(--app-color);
+ }
+
+ .app-docs-content tbody tr:nth-child(odd) {
+ background: var(--app-table-row-stripped-background-color);
+ }
+
+ .app-docs-content img {
+ max-width: 100%;
+ height: auto;
+ border-radius: var(--app-border-radius);
+ }
+
+ /* HeadingPermalink anchors – keep invisible */
+ .app-docs-content .docs-heading-anchor {
+ display: none;
+ }
+}
diff --git a/web/css/pages/app-error.css b/web/css/pages/app-error.css
new file mode 100644
index 0000000..59e627d
--- /dev/null
+++ b/web/css/pages/app-error.css
@@ -0,0 +1,38 @@
+.error-page {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 100dvh;
+ padding: 2rem;
+ text-align: center;
+}
+
+.error-page__code {
+ font-size: 5rem;
+ font-weight: 700;
+ line-height: 1;
+ color: var(--color-text-muted);
+}
+
+.error-page__message {
+ margin-top: 1rem;
+ font-size: 1.125rem;
+ color: var(--color-text);
+}
+
+.error-page__back {
+ display: inline-block;
+ margin-top: 2rem;
+ padding: 0.5rem 1.25rem;
+ font-size: 0.875rem;
+ text-decoration: none;
+ border: 1px solid var(--color-border);
+ border-radius: 0.375rem;
+ color: var(--color-text);
+ background: var(--color-bg-surface);
+}
+
+.error-page__back:hover {
+ opacity: 0.8;
+}
diff --git a/web/css/pages/app-login.css b/web/css/pages/app-login.css
index ca961f4..059669c 100644
--- a/web/css/pages/app-login.css
+++ b/web/css/pages/app-login.css
@@ -1,10 +1,662 @@
-.back_to_login {
- margin-bottom: 1rem;
-}
+@layer pages {
+ @keyframes ani-gradient {
+ 0% {
+ --s-start-0: 14.489998991212337%;
+ --s-end-0: 72%;
+ --x-0: 93%;
+ --c-0: hsla(212, 0%, 0%, 1);
+ --y-0: 93%;
+ --y-1: 9%;
+ --s-start-1: 0%;
+ --s-end-1: 45%;
+ --c-1: hsla(212, 0%, 0%, 1);
+ --x-1: 26%;
+ --c-2: hsla(257, 91%, 27%, 0.35);
+ --s-start-2: 2.9253667596993065%;
+ --s-end-2: 22.388851682060018%;
+ --x-2: 15%;
+ --y-2: 79%;
+ --c-3: hsla(212, 100%, 50%, 0.5);
+ --x-3: 40%;
+ --s-start-3: 3.985353824694249%;
+ --s-end-3: 47.580278608924694%;
+ --y-3: 104%;
+ --x-4: 0%;
+ --s-start-4: 2.391200382592061%;
+ --s-end-4: 29.307684556768592%;
+ --y-4: 60%;
+ --c-4: hsla(224, 72%, 36%, 1);
+ --c-5: hsla(248, 52%, 24%, 1);
+ --s-start-5: 2.9253667596993065%;
+ --s-end-5: 22.388851682060018%;
+ --x-5: 92%;
+ --y-5: 37%;
+ --c-6: hsla(212, 100%, 50%, 0.19);
+ --y-6: 16%;
+ --x-6: 101%;
+ --s-start-6: 13.173642363290591%;
+ --s-end-6: 31.747336520355095%;
+ --s-start-7: 1%;
+ --s-end-7: 31%;
+ --y-7: 13%;
+ --c-7: hsla(227, 98%, 53%, 1);
+ --x-7: 90%;
+ --y-8: 56%;
+ --x-8: 104%;
+ --c-8: hsla(166, 71%, 60%, 0.32);
+ --s-start-8: 3.985353824694249%;
+ --s-end-8: 13.103042116379756%;
+ --x-9: 97%;
+ --y-9: 19%;
+ --s-start-9: 18.597054544690312%;
+ --s-end-9: 31%;
+ --c-9: hsla(219, 83%, 23%, 0.18);
+ }
-@media (min-width: 600px) {
- main {
- min-height: 90vh;
- place-content: center;
+ 100% {
+ --s-start-0: 2.391200382592061%;
+ --s-end-0: 43.902064173373226%;
+ --x-0: 7%;
+ --c-0: hsla(306, 0%, 0%, 1);
+ --y-0: 9%;
+ --y-1: 93%;
+ --s-start-1: 9%;
+ --s-end-1: 54.805582404585024%;
+ --c-1: hsla(306, 0%, 0%, 1);
+ --x-1: 96%;
+ --c-2: hsla(166, 72%, 60%, 1);
+ --s-start-2: 3%;
+ --s-end-2: 26.722813338714598%;
+ --x-2: -2%;
+ --y-2: 103%;
+ --c-3: hsla(180, 100%, 50%, 0.26);
+ --x-3: 33%;
+ --s-start-3: 2.391200382592061%;
+ --s-end-3: 32.0689540200964%;
+ --y-3: 82%;
+ --x-4: 37%;
+ --s-start-4: 4.40642490323111%;
+ --s-end-4: 37.23528104246256%;
+ --y-4: 81%;
+ --c-4: hsla(212, 88%, 26%, 0.58);
+ --c-5: hsla(271, 98%, 53%, 0.31);
+ --s-start-5: 3%;
+ --s-end-5: 32.537089799783296%;
+ --x-5: 54%;
+ --y-5: 99%;
+ --c-6: hsla(262, 100%, 50%, 0.15);
+ --y-6: 43%;
+ --x-6: 104%;
+ --s-start-6: 6%;
+ --s-end-6: 42.501105312974815%;
+ --s-start-7: 5%;
+ --s-end-7: 13.10107024898374%;
+ --y-7: -16%;
+ --c-7: hsla(298, 36%, 23%, 1);
+ --x-7: 104%;
+ --y-8: 30%;
+ --x-8: 97%;
+ --c-8: hsla(180, 100%, 50%, 0.11);
+ --s-start-8: 2.391200382592061%;
+ --s-end-8: 27.141813016850573%;
+ --x-9: 78%;
+ --y-9: 4%;
+ --s-start-9: 5%;
+ --s-end-9: 21.32164536610654%;
+ --c-9: hsla(219, 83%, 23%, 0.59);
+ }
+ }
+
+ @property --s-start-0 {
+ syntax: "";
+ inherits: false;
+ initial-value: 14.489998991212337%;
+ }
+
+ @property --s-end-0 {
+ syntax: "";
+ inherits: false;
+ initial-value: 72%;
+ }
+
+ @property --x-0 {
+ syntax: "";
+ inherits: false;
+ initial-value: 93%;
+ }
+
+ @property --c-0 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(212, 0%, 0%, 1);
+ }
+
+ @property --y-0 {
+ syntax: "";
+ inherits: false;
+ initial-value: 93%;
+ }
+
+ @property --y-1 {
+ syntax: "";
+ inherits: false;
+ initial-value: 9%;
+ }
+
+ @property --s-start-1 {
+ syntax: "";
+ inherits: false;
+ initial-value: 0%;
+ }
+
+ @property --s-end-1 {
+ syntax: "";
+ inherits: false;
+ initial-value: 45%;
+ }
+
+ @property --c-1 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(212, 0%, 0%, 1);
+ }
+
+ @property --x-1 {
+ syntax: "";
+ inherits: false;
+ initial-value: 26%;
+ }
+
+ @property --c-2 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(257, 91%, 27%, 0.35);
+ }
+
+ @property --s-start-2 {
+ syntax: "";
+ inherits: false;
+ initial-value: 2.9253667596993065%;
+ }
+
+ @property --s-end-2 {
+ syntax: "";
+ inherits: false;
+ initial-value: 22.388851682060018%;
+ }
+
+ @property --x-2 {
+ syntax: "";
+ inherits: false;
+ initial-value: 15%;
+ }
+
+ @property --y-2 {
+ syntax: "";
+ inherits: false;
+ initial-value: 79%;
+ }
+
+ @property --c-3 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(212, 100%, 50%, 0.5);
+ }
+
+ @property --x-3 {
+ syntax: "";
+ inherits: false;
+ initial-value: 40%;
+ }
+
+ @property --s-start-3 {
+ syntax: "";
+ inherits: false;
+ initial-value: 3.985353824694249%;
+ }
+
+ @property --s-end-3 {
+ syntax: "";
+ inherits: false;
+ initial-value: 47.580278608924694%;
+ }
+
+ @property --y-3 {
+ syntax: "";
+ inherits: false;
+ initial-value: 104%;
+ }
+
+ @property --x-4 {
+ syntax: "";
+ inherits: false;
+ initial-value: 0%;
+ }
+
+ @property --s-start-4 {
+ syntax: "";
+ inherits: false;
+ initial-value: 2.391200382592061%;
+ }
+
+ @property --s-end-4 {
+ syntax: "";
+ inherits: false;
+ initial-value: 29.307684556768592%;
+ }
+
+ @property --y-4 {
+ syntax: "";
+ inherits: false;
+ initial-value: 60%;
+ }
+
+ @property --c-4 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(224, 72%, 36%, 1);
+ }
+
+ @property --c-5 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(248, 52%, 24%, 1);
+ }
+
+ @property --s-start-5 {
+ syntax: "";
+ inherits: false;
+ initial-value: 2.9253667596993065%;
+ }
+
+ @property --s-end-5 {
+ syntax: "";
+ inherits: false;
+ initial-value: 22.388851682060018%;
+ }
+
+ @property --x-5 {
+ syntax: "";
+ inherits: false;
+ initial-value: 92%;
+ }
+
+ @property --y-5 {
+ syntax: "";
+ inherits: false;
+ initial-value: 37%;
+ }
+
+ @property --c-6 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(212, 100%, 50%, 0.19);
+ }
+
+ @property --y-6 {
+ syntax: "";
+ inherits: false;
+ initial-value: 16%;
+ }
+
+ @property --x-6 {
+ syntax: "";
+ inherits: false;
+ initial-value: 101%;
+ }
+
+ @property --s-start-6 {
+ syntax: "";
+ inherits: false;
+ initial-value: 13.173642363290591%;
+ }
+
+ @property --s-end-6 {
+ syntax: "";
+ inherits: false;
+ initial-value: 31.747336520355095%;
+ }
+
+ @property --s-start-7 {
+ syntax: "";
+ inherits: false;
+ initial-value: 1%;
+ }
+
+ @property --s-end-7 {
+ syntax: "";
+ inherits: false;
+ initial-value: 31%;
+ }
+
+ @property --y-7 {
+ syntax: "";
+ inherits: false;
+ initial-value: 13%;
+ }
+
+ @property --c-7 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(227, 98%, 53%, 1);
+ }
+
+ @property --x-7 {
+ syntax: "";
+ inherits: false;
+ initial-value: 90%;
+ }
+
+ @property --y-8 {
+ syntax: "";
+ inherits: false;
+ initial-value: 56%;
+ }
+
+ @property --x-8 {
+ syntax: "";
+ inherits: false;
+ initial-value: 104%;
+ }
+
+ @property --c-8 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(166, 71%, 60%, 0.32);
+ }
+
+ @property --s-start-8 {
+ syntax: "";
+ inherits: false;
+ initial-value: 3.985353824694249%;
+ }
+
+ @property --s-end-8 {
+ syntax: "";
+ inherits: false;
+ initial-value: 13.103042116379756%;
+ }
+
+ @property --x-9 {
+ syntax: "";
+ inherits: false;
+ initial-value: 97%;
+ }
+
+ @property --y-9 {
+ syntax: "";
+ inherits: false;
+ initial-value: 19%;
+ }
+
+ @property --s-start-9 {
+ syntax: "";
+ inherits: false;
+ initial-value: 18.597054544690312%;
+ }
+
+ @property --s-end-9 {
+ syntax: "";
+ inherits: false;
+ initial-value: 31%;
+ }
+
+ @property --c-9 {
+ syntax: "";
+ inherits: false;
+ initial-value: hsla(219, 83%, 23%, 0.18);
+ }
+
+ #gradient {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ pointer-events: none;
+ }
+
+ html[data-theme="light"] #gradient {
+ background-color: hsla(333, 0%, 100%, 1);
+ background-image:
+ radial-gradient(
+ circle at 0% 0%,
+ hsla(64, 82%, 77%, 0.35) 3.1210986267166043%,
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 20% 0%,
+ hsla(5, 77%, 74%, 0.35) 3.1210986267166043%,
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 40% 0%,
+ hsla(315, 77%, 74%, 0.35) 3.1210986267166043%,
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 60% 0%,
+ hsla(256, 77%, 74%, 0.35) 3.1210986267166043%,
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 80% 0%,
+ hsla(191, 77%, 74%, 0.35) 3.1210986267166043%,
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 100% 0%,
+ hsla(152, 77%, 74%, 0.35) 3%,
+ transparent 40%
+ );
+ background-blend-mode: normal, normal, normal, normal, normal, normal;
+ }
+
+ html[data-theme="dark"] #gradient {
+ --x-0: 93%;
+ --c-0: hsla(212, 0%, 0%, 1);
+ --y-0: 93%;
+ --y-1: 9%;
+ --c-1: hsla(212, 0%, 0%, 1);
+ --x-1: 26%;
+ --c-2: hsla(257, 91%, 27%, 0.35);
+ --x-2: 15%;
+ --y-2: 79%;
+ --c-3: hsla(212, 100%, 50%, 0.5);
+ --x-3: 40%;
+ --y-3: 104%;
+ --x-4: 0%;
+ --y-4: 60%;
+ --c-4: hsla(224, 72%, 36%, 1);
+ --c-5: hsla(248, 52%, 24%, 1);
+ --x-5: 92%;
+ --y-5: 37%;
+ --c-6: hsla(212, 100%, 50%, 0.19);
+ --y-6: 16%;
+ --x-6: 101%;
+ --y-7: 13%;
+ --c-7: hsla(227, 98%, 53%, 1);
+ --x-7: 90%;
+ --y-8: 56%;
+ --x-8: 104%;
+ --c-8: hsla(166, 71%, 60%, 0.32);
+ --x-9: 97%;
+ --y-9: 19%;
+ --c-9: hsla(219, 83%, 23%, 0.18);
+ background-color: hsla(305, 0%, 0%, 1);
+ background-image:
+ radial-gradient(
+ circle at var(--x-0) var(--y-0),
+ var(--c-0) var(--s-start-0),
+ transparent var(--s-end-0)
+ ),
+ radial-gradient(
+ circle at var(--x-1) var(--y-1),
+ var(--c-1) var(--s-start-1),
+ transparent var(--s-end-1)
+ ),
+ radial-gradient(
+ circle at var(--x-2) var(--y-2),
+ var(--c-2) var(--s-start-2),
+ transparent var(--s-end-2)
+ ),
+ radial-gradient(
+ circle at var(--x-3) var(--y-3),
+ var(--c-3) var(--s-start-3),
+ transparent var(--s-end-3)
+ ),
+ radial-gradient(
+ circle at var(--x-4) var(--y-4),
+ var(--c-4) var(--s-start-4),
+ transparent var(--s-end-4)
+ ),
+ radial-gradient(
+ circle at var(--x-5) var(--y-5),
+ var(--c-5) var(--s-start-5),
+ transparent var(--s-end-5)
+ ),
+ radial-gradient(
+ circle at var(--x-6) var(--y-6),
+ var(--c-6) var(--s-start-6),
+ transparent var(--s-end-6)
+ ),
+ radial-gradient(
+ circle at var(--x-7) var(--y-7),
+ var(--c-7) var(--s-start-7),
+ transparent var(--s-end-7)
+ ),
+ radial-gradient(
+ circle at var(--x-8) var(--y-8),
+ var(--c-8) var(--s-start-8),
+ transparent var(--s-end-8)
+ ),
+ radial-gradient(
+ circle at var(--x-9) var(--y-9),
+ var(--c-9) var(--s-start-9),
+ transparent var(--s-end-9)
+ );
+ animation: ani-gradient 10s linear infinite alternate;
+ background-blend-mode:
+ normal, normal, normal, normal, normal, normal, normal, normal, normal,
+ normal;
+ will-change: transform, opacity;
+ contain: paint;
+ }
+
+ .back_to_login {
+ margin-bottom: 1rem;
+ }
+
+ .login-tenant-select-form {
+ margin-bottom: 1rem;
+ }
+
+ .login-tenant-select-label {
+ display: block;
+ margin-bottom: 0.5rem;
+ }
+
+ .login-tenant-choice-grid {
+ display: grid;
+ gap: 0.625rem;
+ margin-bottom: 2rem;
+ }
+ .login-tenant-choice {
+ align-items: stretch;
+ margin: 0;
+ width: 100%;
+ padding: 0.625rem 0.75rem;
+ border: 1px solid var(--app-border);
+ border-radius: var(--app-border-radius);
+ background: var(--app-card-background-color);
+ justify-content: space-between;
+ transition:
+ border-color 0.15s ease,
+ box-shadow 0.15s ease,
+ background-color 0.15s ease;
+ flex-direction: row-reverse;
+ }
+
+ .login-tenant-choice:hover {
+ border-color: var(--app-primary);
+ }
+
+ .login-tenant-choice:has(input[type="radio"]:checked) {
+ border-color: var(--app-primary);
+ box-shadow: 0 0 0 1px var(--app-primary);
+ background: color-mix(
+ in srgb,
+ var(--app-primary) 8%,
+ var(--app-card-background-color)
+ );
+ }
+
+ .login-tenant-choice:has(input[type="radio"]:focus-visible) {
+ outline: 2px solid var(--app-primary-focus);
+ outline-offset: 2px;
+ }
+
+ .login-tenant-choice input[type="radio"] {
+ align-self: center;
+ }
+
+ .login-tenant-choice-avatar {
+ width: 8rem;
+ height: 3rem;
+ display: block;
+ object-fit: contain;
+ object-position: left center;
+ justify-self: start;
+ }
+
+ .login-tenant-choice-avatar-placeholder {
+ width: 8rem;
+ height: 3rem;
+ border-radius: var(--app-border-radius);
+ display: inline-flex;
+ align-items: center;
+ justify-content: flex-start;
+ padding-left: 0.5rem;
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: var(--app-contrast);
+ }
+
+ .login-alt-separator {
+ position: relative;
+ margin: 1rem 0;
+ text-align: center;
+ }
+
+ .login-alt-separator::before {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ border-top: 1px solid var(--app-border);
+ transform: translateY(-50%);
+ }
+
+ .login-alt-separator span {
+ position: relative;
+ z-index: 1;
+ display: inline-block;
+ padding: 0 0.75rem;
+ font-size: 0.875rem;
+ color: var(--app-muted);
+ background: var(--app-surface);
+ }
+
+ .login-alt-separator + [role="button"] {
+ width: 100%;
+ }
+
+ @media (min-width: 600px) {
+ main {
+ min-height: 90vh;
+ place-content: center;
+ }
}
}
diff --git a/web/css/components/vendor-editorjs.css b/web/css/vendor-overrides/editorjs.css
similarity index 97%
rename from web/css/components/vendor-editorjs.css
rename to web/css/vendor-overrides/editorjs.css
index 0f8a3b6..b3ce094 100644
--- a/web/css/components/vendor-editorjs.css
+++ b/web/css/vendor-overrides/editorjs.css
@@ -1,3 +1,4 @@
+@layer vendor-overrides {
.codex-editor {
font-family: var(--app-font-family);
color: var(--app-color);
@@ -71,4 +72,5 @@ table.tc-table {
.ce-popover--inline .ce-popover-item__icon svg {
color: black;
-}
\ No newline at end of file
+}
+}
diff --git a/web/css/vendor-overrides/gridjs.css b/web/css/vendor-overrides/gridjs.css
new file mode 100644
index 0000000..783a10c
--- /dev/null
+++ b/web/css/vendor-overrides/gridjs.css
@@ -0,0 +1,253 @@
+@layer vendor-overrides {
+ .gridjs-container {
+ color: var(--app-color);
+ width: 100%;
+ padding: 0;
+ }
+
+ .gridjs-wrapper {
+ border: 0;
+ border-radius: 0;
+ box-shadow: none;
+ background-color: var(--app-background-color);
+ border-top: var(--app-border-width) solid var(--app-table-border-color);
+ padding-block-end: 1rem;
+ min-height: 515px;
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+
+ .gridjs-footer {
+ background-color: var(--app-background-color);
+ border: 0;
+ border-top: 0;
+ box-shadow: none;
+ color: var(--app-muted-color);
+ padding: 1rem 0 0;
+ }
+
+ .gridjs-table {
+ color: var(--app-color);
+ min-width: 100%;
+ width: max-content;
+ }
+
+ th.gridjs-th {
+ padding: calc(var(--app-spacing) / 2) var(--app-spacing);
+ border: none;
+ border-bottom: var(--app-border-width) solid var(--app-table-border-color);
+ background-color: var(--app-background-color);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ text-align: left;
+ text-align: start;
+ }
+
+ button.gridjs-sort {
+ height: 15px;
+ }
+
+ th.gridjs-th-sort:hover,
+ th.gridjs-th-sort:focus {
+ background-color: var(--app-table-row-stripped-background-color);
+ }
+
+ td.gridjs-td {
+ background-color: var(--app-background-color);
+ border: none;
+ border-color: var(--app-table-border-color);
+ padding: calc(var(--app-spacing) / 2) var(--app-spacing);
+ border-bottom: var(--app-border-width) solid var(--app-table-border-color);
+ background-color: var(--app-background-color);
+ color: var(--app-color);
+ font-weight: var(--app-font-weight);
+ text-align: left;
+ text-align: start;
+ }
+
+ .gridjs-search {
+ float: none;
+ }
+
+ .gridjs-search-input {
+ width: min(320px, 100%);
+ }
+
+ input.gridjs-input {
+ background-color: var(--app-background-color);
+ border: var(--app-border-width) solid var(--app-form-element-border-color);
+ border-radius: var(--app-border-radius);
+ color: var(--app-color);
+ font-size: 0.95rem;
+ padding: 0.5rem 0.75rem;
+ }
+
+ input.gridjs-input:focus {
+ border-color: var(--app-primary);
+ box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ }
+
+ .gridjs-pagination {
+ color: var(--app-muted-color);
+ }
+
+ .gridjs-pagination .gridjs-pages button {
+ background-color: var(--app-background-color);
+ border: var(--app-border-width) solid var(--app-table-border-color);
+ color: var(--app-color);
+ padding: 1px 10px;
+ }
+
+ .gridjs-pagination .gridjs-pages button:hover {
+ background-color: var(--app-primary-hover-background);
+ border-color: var(--app-primary-hover-border);
+ color: var(--app-primary-inverse);
+ }
+
+ .gridjs-pagination .gridjs-pages button:focus {
+ box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ }
+
+ .gridjs-pagination .gridjs-pages button.gridjs-currentPage {
+ background-color: var(--app-primary) !important;
+ font-weight: 400;
+ padding: 2px 10px;
+ color: var(--app-secondary-inverse) !important;
+ }
+
+ .gridjs-pagination .gridjs-pages button:disabled,
+ .gridjs-pagination .gridjs-pages button[disabled] {
+ background-color: var(--app-background-color);
+ color: var(--app-muted-color);
+ cursor: default;
+ padding: 2px 10px;
+ border: 0;
+ }
+
+ .gridjs-pagination .gridjs-pages {
+ display: inline-flex;
+ gap: 5px;
+ }
+
+ .gridjs-loading-bar {
+ background-color: var(--app-background-color);
+ opacity: 0.7;
+ }
+
+ .grid-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 999px;
+ border: 1px solid var(--app-muted-border-color);
+ background: var(--app-card-background-color);
+ object-fit: cover;
+ display: inline-flex;
+ flex-shrink: 0;
+ }
+
+ .grid-avatar-placeholder {
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ color: var(--app-muted-color);
+ font-size: 11px;
+ background: var(--app-background-color);
+ }
+
+ .grid-name-cell {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ min-width: 0;
+ }
+
+ .grid-name-cell > a {
+ display: inline-flex;
+ flex-shrink: 0;
+ }
+
+ .grid-name-cell > span:last-child {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .gridjs-loading-bar:after {
+ background-image: linear-gradient(
+ 90deg,
+ transparent,
+ var(--app-primary-focus),
+ transparent
+ );
+ }
+
+ /* .gridjs-container:not(.gridjs-has-loaded) .gridjs-message.gridjs-notfound {
+ display: none;
+ } */
+
+ .gridjs-container.gridjs-is-updating .gridjs-message.gridjs-notfound {
+ display: none;
+ }
+
+ .gridjs-pages button {
+ background: var(--app-form-element-background-color) !important;
+ color: var(--app-contrast) !important;
+ }
+
+ .gridjs-summary {
+ font-size: small;
+ }
+
+ tr.gridjs-tr {
+ cursor: pointer;
+ }
+
+ tr.gridjs-tr:hover td {
+ background: var(--app-table-row-stripped-background-color);
+ }
+
+ html[data-theme="dark"] button.gridjs-sort,
+ html[data-theme="dark"] button.gridjs-sort-neutral {
+ filter: invert(1);
+ }
+
+ html[data-theme="dark-green"] button.gridjs-sort,
+ html[data-theme="dark-green"] button.gridjs-sort-neutral {
+ filter: invert(1);
+ }
+
+ .gridjs-tbody,
+ td.gridjs-td {
+ background-color: var(--app-background-color);
+ }
+
+ .gridjs-table input[data-grid-select-all] {
+ width: 1em;
+ height: 1em;
+ margin: 0;
+ border-radius: 4px;
+ border-width: 0.5px;
+ }
+
+ .gridjs-th-content:has(input[data-grid-select-all]) {
+ text-align: center;
+ }
+
+ .gridjs-pagination .gridjs-pages button:last-child {
+ border-right: none;
+ }
+ button.gridjs-sort {
+ background-color: transparent;
+ background-position-x: center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ border: none;
+ cursor: pointer;
+ float: right;
+ height: 24px;
+ margin: 0;
+ outline: none;
+ padding: 0;
+ width: 13px;
+ }
+}
diff --git a/web/css/components/vendor-multi-select.css b/web/css/vendor-overrides/multi-select.css
similarity index 99%
rename from web/css/components/vendor-multi-select.css
rename to web/css/vendor-overrides/multi-select.css
index c1e6a04..248f1e8 100644
--- a/web/css/components/vendor-multi-select.css
+++ b/web/css/vendor-overrides/multi-select.css
@@ -1,3 +1,4 @@
+@layer vendor-overrides {
/* Overrides for MultiSelect */
.multi-select {
@@ -101,3 +102,4 @@
opacity: 0.45;
cursor: not-allowed;
}
+}
diff --git a/web/css/vendor-overrides/swagger-ui.css b/web/css/vendor-overrides/swagger-ui.css
new file mode 100644
index 0000000..56c10e3
--- /dev/null
+++ b/web/css/vendor-overrides/swagger-ui.css
@@ -0,0 +1,150 @@
+@import url("../../vendor/swagger-ui/swagger-ui.css") layer(vendor);
+
+@layer vendor-overrides {
+ .app-swagger-container {
+ background: var(--app-background-color);
+ color: var(--app-color);
+ }
+
+ .swagger-ui {
+ color: var(--app-color);
+ font-family: var(--app-font-family);
+ }
+
+ .swagger-ui .info .title,
+ .swagger-ui .info h1,
+ .swagger-ui .info h2,
+ .swagger-ui .info h3,
+ .swagger-ui h1,
+ .swagger-ui h2,
+ .swagger-ui h3,
+ .swagger-ui h4 {
+ color: var(--app-color);
+ }
+
+ .swagger-ui .info a,
+ .swagger-ui a.nostyle,
+ .swagger-ui a.nostyle:visited {
+ color: var(--app-primary);
+ }
+
+ .swagger-ui .scheme-container {
+ background: var(--app-card-background-color);
+ box-shadow: none;
+ border: var(--app-border-width) solid var(--app-form-element-border-color);
+ border-radius: var(--app-border-radius);
+ }
+
+ .swagger-ui .opblock {
+ border-color: var(--app-form-element-border-color);
+ border-radius: var(--app-border-radius);
+ background: var(--app-card-background-color);
+ }
+
+ .swagger-ui .opblock .opblock-summary {
+ border-color: var(--app-form-element-border-color);
+ }
+
+ .swagger-ui .opblock-tag {
+ border-color: var(--app-form-element-border-color);
+ color: var(--app-color);
+ }
+
+ .swagger-ui .responses-inner h4,
+ .swagger-ui .responses-inner h5,
+ .swagger-ui .response-col_status,
+ .swagger-ui .response-col_description__inner p,
+ .swagger-ui .tab li,
+ .swagger-ui .model-title {
+ color: var(--app-color);
+ }
+
+ .swagger-ui .parameter__name,
+ .swagger-ui .parameter__type,
+ .swagger-ui .parameter__deprecated,
+ .swagger-ui .parameter__in {
+ color: var(--app-color);
+ }
+
+ .swagger-ui input[type="text"],
+ .swagger-ui input[type="password"],
+ .swagger-ui input[type="search"],
+ .swagger-ui input[type="email"],
+ .swagger-ui textarea,
+ .swagger-ui select {
+ background: var(--app-form-element-background-color);
+ color: var(--app-form-element-color);
+ border: var(--app-border-width) solid var(--app-form-element-border-color);
+ border-radius: var(--app-border-radius);
+ box-shadow: none;
+ }
+
+ .swagger-ui input[type="text"]:focus,
+ .swagger-ui input[type="password"]:focus,
+ .swagger-ui input[type="search"]:focus,
+ .swagger-ui input[type="email"]:focus,
+ .swagger-ui textarea:focus,
+ .swagger-ui select:focus {
+ border-color: var(--app-primary);
+ box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
+ outline: none;
+ }
+
+ .swagger-ui .btn {
+ border-radius: var(--app-border-radius);
+ }
+
+ .swagger-ui .btn.authorize {
+ color: var(--app-primary);
+ border-color: var(--app-primary);
+ }
+
+ .swagger-ui .btn.authorize svg {
+ fill: currentColor;
+ }
+
+ .swagger-ui .model-box,
+ .swagger-ui .highlight-code,
+ .swagger-ui .microlight,
+ .swagger-ui .responses-table .response-col_description__inner {
+ background: var(--app-card-background-color);
+ color: var(--app-color);
+ }
+
+ .swagger-ui button {
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ }
+
+ .swagger-ui .opblock .opblock-summary-description {
+ color: var(--app-color);
+ }
+
+ .swagger-ui .opblock .opblock-section-header {
+ background: var(--app-accordion-border-color);
+ }
+
+ .swagger-ui section {
+ margin: 0;
+ }
+
+ .swagger-ui .servers > label {
+ margin: 0;
+ }
+
+ pre.version {
+ all: inherit;
+ padding: 0;
+ margin: 0;
+ font-size: inherit;
+ }
+
+ .swagger-ui .info .title small {
+ top: 0;
+ }
+
+ select#servers {
+ margin: 0;
+ }
+}
diff --git a/web/img/favicon.ico b/web/img/favicon.ico
deleted file mode 100644
index f9c244c..0000000
Binary files a/web/img/favicon.ico and /dev/null differ
diff --git a/web/img/forkme_right_red_aa0000.png b/web/img/forkme_right_red_aa0000.png
deleted file mode 100644
index 1e19c21..0000000
Binary files a/web/img/forkme_right_red_aa0000.png and /dev/null differ
diff --git a/web/img/minty_square.png b/web/img/minty_square.png
deleted file mode 100644
index 250db3a..0000000
Binary files a/web/img/minty_square.png and /dev/null differ
diff --git a/web/img/mintyphp_logo.png b/web/img/mintyphp_logo.png
deleted file mode 100644
index a5a2631..0000000
Binary files a/web/img/mintyphp_logo.png and /dev/null differ
diff --git a/web/index.php b/web/index.php
index d550c5a..8d01157 100644
--- a/web/index.php
+++ b/web/index.php
@@ -12,6 +12,7 @@ use MintyPHP\Http\Request;
use MintyPHP\Http\LocaleResolver;
use MintyPHP\Http\AccessControl;
use MintyPHP\Http\AssetDetector;
+use MintyPHP\Support\Flash;
// Change directory to project root
chdir(__DIR__ . '/..');
@@ -34,10 +35,8 @@ Session::start();
$defaultLocale = appDefaultLocale();
if ($defaultLocale !== null) {
I18n::$defaultLocale = $defaultLocale;
- if (!defined('APP_LOCALES') || in_array($defaultLocale, APP_LOCALES, true)) {
- if (I18n::$locale === '' || !in_array(I18n::$locale, APP_LOCALES, true)) {
- I18n::$locale = $defaultLocale;
- }
+ if (I18n::$locale === '') {
+ I18n::$locale = $defaultLocale;
}
}
@@ -72,15 +71,43 @@ I18n::$locale = $localeResolver->resolveLocale(
);
$isAssetRequest = AssetDetector::isAssetRequest($pathWithoutLocale);
+$isApiRequest = str_starts_with($pathWithoutLocale, 'api/');
-// Refresh tenant context if stale or missing (skip for assets)
-if (!empty($_SESSION['user']['id']) && !$isAssetRequest) {
+if ($isApiRequest) {
+ if (!defined('MINTY_API_REQUEST')) {
+ define('MINTY_API_REQUEST', true);
+ }
+
+ // Minty router enforces CSRF for non-GET requests before action execution.
+ // Our API is Bearer-token based and does not use form-CSRF, so mark only
+ // API write requests as AJAX to bypass the router-level form CSRF gate.
+ $requestMethod = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
+ $isApiWriteMethod = !in_array($requestMethod, ['GET', 'HEAD', 'OPTIONS'], true);
+ if ($isApiWriteMethod && empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
+ $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
+ }
+}
+
+// Refresh tenant context if stale or missing (skip for assets and API requests)
+if (!empty($_SESSION['user']['id']) && !$isAssetRequest && !$isApiRequest) {
$userId = (int) ($_SESSION['user']['id'] ?? 0);
if ($userId > 0) {
- $ttl = defined('TENANT_SNAPSHOT_TTL') ? (int) TENANT_SNAPSHOT_TTL : 120;
+ $authState = \MintyPHP\Service\Auth\AuthService::refreshSessionAuthState($userId);
+ if (!empty($authState['logout_required'])) {
+ \MintyPHP\Service\Auth\AuthService::logout();
+ $reason = (string) ($authState['reason'] ?? '');
+ if ($reason === 'inactive') {
+ Flash::error(t('Account is inactive'), 'login', 'login_inactive');
+ } else {
+ Flash::error(t('No active tenant assigned'), 'login', 'no_active_tenant');
+ }
+ Router::redirect('login');
+ }
+
+ $ttl = 120;
$lastRefresh = (int) ($_SESSION['tenant_snapshot_at'] ?? 0);
$needsRefresh = empty($_SESSION['current_tenant']) || empty($_SESSION['available_tenants']);
- if ($ttl > 0 && (time() - $lastRefresh) >= $ttl) {
+ if ((time() - $lastRefresh) >= $ttl) {
$needsRefresh = true;
}
if ($needsRefresh) {
@@ -90,7 +117,7 @@ if (!empty($_SESSION['user']['id']) && !$isAssetRequest) {
}
}
-if ($requestedLocale === '' && !$isAssetRequest) {
+if ($requestedLocale === '' && !$isAssetRequest && !$isApiRequest) {
$method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
if (in_array($method, ['GET', 'HEAD'], true)) {
$target = Request::withLocale($pathWithoutLocale, I18n::$locale ?? I18n::$defaultLocale);
diff --git a/web/js/app-init.js b/web/js/app-init.js
index 6a72a7d..e3d4605 100644
--- a/web/js/app-init.js
+++ b/web/js/app-init.js
@@ -1,4 +1,5 @@
import './components/app-flash-auto-dismiss.js';
+import './components/app-tabs.js';
import './components/app-fslightbox-refresh.js';
import './components/app-password-hints.js';
import './components/app-copy-badge.js';
@@ -7,13 +8,13 @@ import './components/app-nav-history.js';
import './components/app-toggle-sidebar.js';
import './components/app-toggle-aside-panels.js';
import './components/app-toggle-details-aside.js';
-import { initToolbarToggles } from './components/app-toggle-toolbar.js';
+import './components/app-toggle-toolbar.js';
import './components/app-filter-overflow.js';
import './components/app-global-search.js';
import './components/app-theme-toggle.js';
import './components/app-contrast-toggle.js';
+import './components/app-details-state.js';
import './components/app-tenant-switcher.js';
-import './components/app-tabs.js';
import './components/app-color-default-toggle.js';
-
-initToolbarToggles();
+import './components/app-custom-field-options-toggle.js';
+import './components/app-tenant-sso-toggle.js';
diff --git a/web/js/components/_template.js b/web/js/components/_template.js
new file mode 100644
index 0000000..517a4fd
--- /dev/null
+++ b/web/js/components/_template.js
@@ -0,0 +1,28 @@
+import { optionalEl, warnOnce } from '../core/app-dom.js';
+
+export function initTemplateFeature(root = document) {
+ const host = optionalEl('[data-template-feature]');
+ if (!host) {
+ return;
+ }
+ if (host.dataset.templateFeatureBound === '1') {
+ return;
+ }
+ host.dataset.templateFeatureBound = '1';
+
+ const action = host.querySelector('[data-template-action]');
+ if (!action) {
+ warnOnce('UI_EL_MISSING', 'Missing [data-template-action]', { module: 'template-feature' });
+ return;
+ }
+
+ action.addEventListener('click', () => {
+ host.classList.toggle('is-active');
+ });
+}
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => initTemplateFeature());
+} else {
+ initTemplateFeature();
+}
diff --git a/web/js/components/app-contrast-toggle.js b/web/js/components/app-contrast-toggle.js
index 0c3c4b8..0de414d 100644
--- a/web/js/components/app-contrast-toggle.js
+++ b/web/js/components/app-contrast-toggle.js
@@ -9,14 +9,14 @@ const setContrast = (contrast) => {
const setIcon = (button, contrast) => {
const icon = button.querySelector('i');
- if (!icon) return;
+ if (!icon) {return;}
icon.classList.remove('bi-circle-half', 'bi-highlights');
icon.classList.add(contrast === 'high' ? 'bi-highlights' : 'bi-circle-half');
};
const initContrastToggle = () => {
const button = requireEl('[data-contrast-toggle]', { module: 'contrast-toggle' });
- if (!button) return;
+ if (!button) {return;}
const root = document.documentElement;
const getCurrent = () => (root.dataset.contrast === 'high' ? 'high' : 'normal');
setIcon(button, getCurrent());
diff --git a/web/js/components/app-copy-badge.js b/web/js/components/app-copy-badge.js
index b6ceab1..8c56e73 100644
--- a/web/js/components/app-copy-badge.js
+++ b/web/js/components/app-copy-badge.js
@@ -10,7 +10,7 @@ const getCopyValue = (badge) => {
};
const copyText = async (value) => {
- if (!value) return false;
+ if (!value) {return false;}
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value);
return true;
@@ -28,7 +28,7 @@ const copyText = async (value) => {
};
const enhanceBadge = (badge) => {
- if (badge.querySelector('.badge-copy-icon')) return;
+ if (badge.querySelector('.badge-copy-icon')) {return;}
const icon = document.createElement('span');
icon.className = 'badge-copy-icon';
icon.setAttribute('aria-hidden', 'true');
@@ -43,7 +43,7 @@ const enhanceBadge = (badge) => {
event.preventDefault();
const value = getCopyValue(badge);
const ok = await copyText(value);
- if (!ok) return;
+ if (!ok) {return;}
badge.classList.add(COPIED_CLASS);
window.setTimeout(() => badge.classList.remove(COPIED_CLASS), 1200);
};
diff --git a/web/js/components/app-custom-field-options-toggle.js b/web/js/components/app-custom-field-options-toggle.js
new file mode 100644
index 0000000..97269dd
--- /dev/null
+++ b/web/js/components/app-custom-field-options-toggle.js
@@ -0,0 +1,98 @@
+import { warnOnce } from '../core/app-dom.js';
+
+const TYPES_WITH_OPTIONS = new Set(['select', 'multiselect']);
+const FILTERABLE_TYPES = new Set(['select', 'multiselect', 'boolean', 'date']);
+const sources = document.querySelectorAll('[data-custom-field-type-source]');
+
+const syncOptionsVisibility = (source, target) => {
+ const selectedType = String(source.value || '').trim().toLowerCase();
+ const showOptions = TYPES_WITH_OPTIONS.has(selectedType);
+
+ target.hidden = !showOptions;
+
+ target.querySelectorAll('textarea, input, select').forEach((control) => {
+ if (!control.dataset.initialDisabled) {
+ control.dataset.initialDisabled = control.hasAttribute('disabled') ? '1' : '0';
+ }
+
+ if (!showOptions) {
+ control.setAttribute('disabled', 'disabled');
+ return;
+ }
+
+ if (control.dataset.initialDisabled === '1') {
+ control.setAttribute('disabled', 'disabled');
+ return;
+ }
+
+ control.removeAttribute('disabled');
+ });
+};
+
+const syncFilterableAvailability = (source, target) => {
+ const selectedType = String(source.value || '').trim().toLowerCase();
+ const filterableAllowed = FILTERABLE_TYPES.has(selectedType);
+ const checkbox = target.querySelector('[data-custom-field-filterable-input]');
+
+ if (!checkbox) {
+ warnOnce('UI_EL_MISSING', 'Missing filterable checkbox in custom field group', {
+ module: 'custom-field-options-toggle'
+ });
+ return;
+ }
+
+ if (!checkbox.dataset.initialDisabled) {
+ checkbox.dataset.initialDisabled = checkbox.hasAttribute('disabled') ? '1' : '0';
+ }
+
+ if (!filterableAllowed) {
+ checkbox.checked = false;
+ checkbox.setAttribute('disabled', 'disabled');
+ target.setAttribute('aria-disabled', 'true');
+ return;
+ }
+
+ target.removeAttribute('aria-disabled');
+ if (checkbox.dataset.initialDisabled === '1') {
+ checkbox.setAttribute('disabled', 'disabled');
+ return;
+ }
+
+ checkbox.removeAttribute('disabled');
+};
+
+sources.forEach((source) => {
+ const group = String(source.dataset.customFieldGroup || '').trim();
+ if (!group) {
+ warnOnce('UI_EL_MISSING', 'Missing data-custom-field-group', { module: 'custom-field-options-toggle' });
+ return;
+ }
+
+ const target = document.querySelector(
+ `[data-custom-field-options-target][data-custom-field-group="${group}"]`
+ );
+ if (!target) {
+ warnOnce('UI_EL_MISSING', `Missing custom field options target for group: ${group}`, {
+ module: 'custom-field-options-toggle'
+ });
+ return;
+ }
+
+ const filterableTarget = document.querySelector(
+ `[data-custom-field-filterable-target][data-custom-field-group="${group}"]`
+ );
+ if (!filterableTarget) {
+ warnOnce('UI_EL_MISSING', `Missing custom field filterable target for group: ${group}`, {
+ module: 'custom-field-options-toggle'
+ });
+ return;
+ }
+
+ source.addEventListener('change', () => {
+ syncOptionsVisibility(source, target);
+ syncFilterableAvailability(source, filterableTarget);
+ });
+
+ syncOptionsVisibility(source, target);
+ syncFilterableAvailability(source, filterableTarget);
+});
diff --git a/web/js/components/app-details-state.js b/web/js/components/app-details-state.js
new file mode 100644
index 0000000..f719563
--- /dev/null
+++ b/web/js/components/app-details-state.js
@@ -0,0 +1,80 @@
+const readStored = (storageKey) => {
+ try {
+ const raw = window.localStorage.getItem(storageKey);
+ if (!raw) {
+ return [];
+ }
+ const parsed = JSON.parse(raw);
+ return Array.isArray(parsed) ? parsed : [];
+ } catch (error) {
+ return [];
+ }
+};
+
+const writeStored = (storageKey, openKeys) => {
+ try {
+ window.localStorage.setItem(storageKey, JSON.stringify(openKeys));
+ } catch (error) {
+ // ignore storage errors
+ }
+};
+
+const initDetailsGroup = (group) => {
+ if (!group || group.dataset.detailsStorageBound === '1') {
+ return;
+ }
+
+ const storageKey = (group.dataset.detailsStorage || '').trim();
+ if (!storageKey) {
+ return;
+ }
+
+ const managedDetails = Array.from(group.querySelectorAll('details[data-details-key]'));
+ const alwaysOpenDetails = Array.from(group.querySelectorAll('details[data-details-always-open]'));
+
+ if (!managedDetails.length && !alwaysOpenDetails.length) {
+ return;
+ }
+
+ const storedOpenKeys = readStored(storageKey);
+ if (storedOpenKeys.length > 0) {
+ managedDetails.forEach((details) => {
+ const key = (details.dataset.detailsKey || '').trim();
+ if (key !== '') {
+ details.open = storedOpenKeys.includes(key);
+ }
+ });
+ }
+
+ alwaysOpenDetails.forEach((details) => {
+ details.open = true;
+ details.addEventListener('toggle', () => {
+ if (!details.open) {
+ details.open = true;
+ }
+ });
+ });
+
+ managedDetails.forEach((details) => {
+ details.addEventListener('toggle', () => {
+ const openKeys = managedDetails
+ .filter((item) => item.open)
+ .map((item) => (item.dataset.detailsKey || '').trim())
+ .filter(Boolean);
+ writeStored(storageKey, openKeys);
+ });
+ });
+
+ group.dataset.detailsStorageBound = '1';
+};
+
+const initDetailsState = () => {
+ const groups = Array.from(document.querySelectorAll('[data-details-storage]'));
+ groups.forEach(initDetailsGroup);
+};
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initDetailsState);
+} else {
+ initDetailsState();
+}
diff --git a/web/js/components/app-filter-overflow.js b/web/js/components/app-filter-overflow.js
index 1b69a10..1fced6b 100644
--- a/web/js/components/app-filter-overflow.js
+++ b/web/js/components/app-filter-overflow.js
@@ -12,10 +12,10 @@ const getEmptyValues = (field) => {
};
const isFieldActive = (field) => {
- if (!field) return false;
- if (field.disabled) return false;
- if (field.type === 'hidden') return false;
- if (field.type === 'checkbox') return field.checked;
+ if (!field) {return false;}
+ if (field.disabled) {return false;}
+ if (field.type === 'hidden') {return false;}
+ if (field.type === 'checkbox') {return field.checked;}
if (field.tagName === 'SELECT' && field.multiple) {
return Array.from(field.selectedOptions || []).some((option) => option.value);
}
@@ -37,11 +37,11 @@ const isOptionalActive = (item) => {
export function initFilterOverflow(root = document) {
const toolbars = root.querySelectorAll('[data-filter-overflow]');
toolbars.forEach((toolbar) => {
- if (toolbar.dataset.filterOverflowBound === '1') return;
+ if (toolbar.dataset.filterOverflowBound === '1') {return;}
toolbar.dataset.filterOverflowBound = '1';
const optional = Array.from(toolbar.querySelectorAll('[data-filter-optional]'));
- if (!optional.length) return;
+ if (!optional.length) {return;}
const toggle = toolbar.querySelector('[data-filter-toggle]');
if (!toggle) {
diff --git a/web/js/components/app-flash-auto-dismiss.js b/web/js/components/app-flash-auto-dismiss.js
index 0a64ddc..4e4f25b 100644
--- a/web/js/components/app-flash-auto-dismiss.js
+++ b/web/js/components/app-flash-auto-dismiss.js
@@ -11,7 +11,7 @@ export function initFlashAutoDismiss(options = {}) {
const postForm = async (form) => {
const action = form.getAttribute('action');
- if (!action) return null;
+ if (!action) {return null;}
const body = new URLSearchParams(new FormData(form));
return fetch(action, {
method: 'POST',
diff --git a/web/js/components/app-fslightbox-refresh.js b/web/js/components/app-fslightbox-refresh.js
index 1fb6158..bcb87a6 100644
--- a/web/js/components/app-fslightbox-refresh.js
+++ b/web/js/components/app-fslightbox-refresh.js
@@ -13,7 +13,7 @@ const refreshFsLightbox = () => {
let refreshTimer = null;
const scheduleRefresh = () => {
- if (refreshTimer) return;
+ if (refreshTimer) {return;}
refreshTimer = window.setTimeout(() => {
refreshTimer = null;
refreshFsLightbox();
@@ -27,7 +27,7 @@ const initObserver = () => {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
- if (!(node instanceof HTMLElement)) continue;
+ if (!(node instanceof HTMLElement)) {continue;}
if (node.matches?.('[data-fslightbox]') || node.querySelector?.('[data-fslightbox]')) {
scheduleRefresh();
return;
diff --git a/web/js/components/app-global-search.js b/web/js/components/app-global-search.js
index 09a972e..6984520 100644
--- a/web/js/components/app-global-search.js
+++ b/web/js/components/app-global-search.js
@@ -4,6 +4,9 @@ const input = requireEl('#side-search', { module: 'global-search' });
const resultsEl = requireEl('[data-global-search-results]', { module: 'global-search' });
if (input && resultsEl) {
+ const emptyStateEl = optionalEl('[data-global-search-empty]');
+ const emptyHintEl = optionalEl('[data-search-empty-hint-template]');
+ const shortcutEl = optionalEl('[data-search-shortcut]');
const panel = optionalEl('#aside-panel-search');
const toggleButton = optionalEl('[data-search-details-toggle]');
const toggleIcon = optionalEl('[data-search-details-icon]');
@@ -15,14 +18,19 @@ if (input && resultsEl) {
const shortcutLabel = /(Mac|iPhone|iPad|iPod)/i.test(navigator.platform || navigator.userAgent)
? '⌘K'
: 'Ctrl+K';
- if (input.placeholder && !input.placeholder.includes('⌘') && !input.placeholder.includes('Ctrl+K')) {
- input.placeholder = `${input.placeholder} (${shortcutLabel})`;
+
+ if (emptyHintEl) {
+ const template = emptyHintEl.getAttribute('data-search-empty-hint-template') || '';
+ emptyHintEl.textContent = template.replace('{shortcut}', shortcutLabel);
+ }
+ if (shortcutEl) {
+ shortcutEl.textContent = shortcutLabel;
}
const itemsByKey = new Map();
resultsEl.querySelectorAll('[data-search-key]').forEach((item) => {
const key = item.getAttribute('data-search-key');
- if (key) itemsByKey.set(key, item);
+ if (key) {itemsByKey.set(key, item);}
});
if (itemsByKey.size === 0) {
warnOnce('UI_EL_MISSING', 'No [data-search-key] elements found in results container', { module: 'global-search' });
@@ -34,13 +42,22 @@ if (input && resultsEl) {
});
};
+ const setIdleState = (idle) => {
+ if (emptyStateEl) {
+ emptyStateEl.hidden = !idle;
+ }
+ resultsEl.hidden = idle;
+ };
+
const render = (items, query) => {
+ const renderedKeys = new Set();
items.forEach((item) => {
const li = itemsByKey.get(item.key);
if (!li) {
warnOnce('UI_EL_MISSING', `No element found for key: ${item.key}`, { module: 'global-search' });
return;
}
+ renderedKeys.add(item.key);
const countEl = li.querySelector('[data-search-count]');
const link = li.querySelector('a');
const previewEl = li.querySelector('[data-search-preview]');
@@ -49,7 +66,7 @@ if (input && resultsEl) {
if (item.key !== 'pages') {
url.searchParams.set('search', query);
}
- if (countEl) countEl.textContent = item.count.toString();
+ if (countEl) {countEl.textContent = item.count.toString();}
if (link) {
link.href = item.count > 0 ? url.toString() : base;
link.setAttribute('aria-disabled', item.count > 0 ? 'false' : 'true');
@@ -80,9 +97,29 @@ if (input && resultsEl) {
li.hidden = true;
}
});
+
+ itemsByKey.forEach((li, key) => {
+ if (renderedKeys.has(key)) {
+ return;
+ }
+ const countEl = li.querySelector('[data-search-count]');
+ const link = li.querySelector('a');
+ const previewEl = li.querySelector('[data-search-preview]');
+ const base = li.getAttribute('data-search-base') || '#';
+ if (countEl) {countEl.textContent = '0';}
+ if (link) {
+ link.href = base;
+ link.setAttribute('aria-disabled', 'true');
+ }
+ if (previewEl) {
+ previewEl.innerHTML = '';
+ }
+ li.hidden = true;
+ });
};
const clear = () => {
+ setIdleState(true);
setLoadingState('0');
resultsEl.querySelectorAll('a').forEach((link) => {
link.setAttribute('aria-disabled', 'true');
@@ -98,6 +135,7 @@ if (input && resultsEl) {
};
const fetchCounts = async (value) => {
+ setIdleState(false);
const url = new URL(endpoint.toString());
url.searchParams.set('q', value);
setLoadingState('…');
@@ -127,7 +165,7 @@ if (input && resultsEl) {
clear();
return;
}
- if (pending) window.clearTimeout(pending);
+ if (pending) {window.clearTimeout(pending);}
pending = window.setTimeout(() => {
fetchCounts(value).catch((err) => {
warnOnce('FETCH_ERROR', 'Global search fetch error', { module: 'global-search', err });
@@ -139,26 +177,26 @@ if (input && resultsEl) {
input.addEventListener('input', onInput);
const submitSearch = () => {
const value = input.value.trim();
- if (value.length < minLength) return;
+ if (value.length < minLength) {return;}
resultsPage.searchParams.set('search', value);
window.location.href = resultsPage.toString();
};
input.addEventListener('keydown', (event) => {
- if (event.key !== 'Enter') return;
+ if (event.key !== 'Enter') {return;}
event.preventDefault();
submitSearch();
});
const isEditableTarget = (target) => {
- if (!target) return false;
- if (target.isContentEditable) return true;
+ if (!target) {return false;}
+ if (target.isContentEditable) {return true;}
const tag = target.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';
};
const focusSearch = () => {
- if (!input) return;
+ if (!input) {return;}
window.requestAnimationFrame(() => {
input.focus();
input.select();
@@ -174,11 +212,17 @@ if (input && resultsEl) {
focusSearch();
};
+ if (emptyStateEl) {
+ emptyStateEl.addEventListener('click', () => {
+ focusSearch();
+ });
+ }
+
document.addEventListener('keydown', (event) => {
- if (!(event.metaKey || event.ctrlKey)) return;
+ if (!(event.metaKey || event.ctrlKey)) {return;}
const key = event.key.toLowerCase();
- if (key !== 'k' && key !== '/') return;
- if (isEditableTarget(event.target) && event.target !== input) return;
+ if (key !== 'k' && key !== '/') {return;}
+ if (isEditableTarget(event.target) && event.target !== input) {return;}
event.preventDefault();
openSearch();
});
@@ -201,11 +245,20 @@ if (input && resultsEl) {
});
}
- // Seed from current URL search param if present
+ // Seed from current URL search param if present.
const currentUrl = new URL(window.location.href);
- const preset = currentUrl.searchParams.get('search');
+ const preset = (currentUrl.searchParams.get('search') || '').trim();
if (preset && !input.value) {
input.value = preset;
- onInput();
+ }
+
+ const initialValue = input.value.trim();
+ if (initialValue.length >= minLength) {
+ fetchCounts(initialValue).catch((err) => {
+ warnOnce('FETCH_ERROR', 'Global search fetch error', { module: 'global-search', err });
+ clear();
+ });
+ } else {
+ clear();
}
}
diff --git a/web/js/components/app-multiselect-cascade.js b/web/js/components/app-multiselect-cascade.js
index 9579bb8..e457cee 100644
--- a/web/js/components/app-multiselect-cascade.js
+++ b/web/js/components/app-multiselect-cascade.js
@@ -29,7 +29,7 @@ const setDisabledState = (option, disabled) => {
const toggleSelectAll = (instance, disabled) => {
const selectAll = instance?.element?.querySelector('.multi-select-all');
- if (!selectAll) return;
+ if (!selectAll) {return;}
selectAll.classList.toggle('is-disabled', disabled);
selectAll.setAttribute('aria-disabled', disabled ? 'true' : 'false');
selectAll.style.pointerEvents = disabled ? 'none' : '';
@@ -86,7 +86,7 @@ export const initMultiSelectCascade = ({
options.forEach((option) => {
const isAllowed = allowAll || allowed.has(String(option.dataset.value || ''));
const disabled = mode === 'disable' ? !isAllowed : false;
- if (disabled) disabledCount += 1;
+ if (disabled) {disabledCount += 1;}
setDisabledState(option, disabled);
});
diff --git a/web/js/components/app-multiselect-init.js b/web/js/components/app-multiselect-init.js
index f5f5be7..e5ae249 100644
--- a/web/js/components/app-multiselect-init.js
+++ b/web/js/components/app-multiselect-init.js
@@ -3,7 +3,7 @@ import { warnOnce } from '../core/app-dom.js';
let multiSelectLoader = null;
const resolveScriptUrl = (script) => {
- if (script) return script;
+ if (script) {return script;}
const assetBase = window.APP_ASSET_BASE || document.baseURI;
return new URL('vendor/multi-select/MultiSelect.js', assetBase).toString();
};
@@ -27,17 +27,17 @@ const ensureMultiSelect = async (script) => {
export const initMultiSelect = async (target = '[data-multi-select]') => {
const elements = typeof target === 'string' ? document.querySelectorAll(target) : [target];
- if (!elements.length) return [];
+ if (!elements.length) {return [];}
const MultiSelect = await ensureMultiSelect();
const instances = [];
elements.forEach((element) => {
- if (!element || element.dataset.multiSelectInit === '1') return;
+ if (!element || element.dataset.multiSelectInit === '1') {return;}
const syncTarget = element.dataset.syncTarget;
const syncInput = syncTarget ? document.querySelector(syncTarget) : null;
const options = {};
const placeholder = element.dataset.placeholder;
- if (placeholder) options.placeholder = placeholder;
+ if (placeholder) {options.placeholder = placeholder;}
if (element.dataset.search !== undefined) {
options.search = element.dataset.search === 'true';
}
@@ -79,7 +79,7 @@ export const initMultiSelect = async (target = '[data-multi-select]') => {
if (syncInput) {
syncInput._multiSelectInstance = instance;
const syncValues = () => {
- if (!syncInput || isSyncing) return;
+ if (!syncInput || isSyncing) {return;}
isSyncing = true;
const values = instance.selectedValues || [];
syncInput.value = Array.isArray(values) ? values.join(',') : '';
@@ -90,7 +90,7 @@ export const initMultiSelect = async (target = '[data-multi-select]') => {
const values = instance.selectedValues || [];
syncInput.value = Array.isArray(values) ? values.join(',') : '';
syncInput.addEventListener('change', () => {
- if (isSyncing) return;
+ if (isSyncing) {return;}
const nextValues = syncInput.value
? syncInput.value.split(',').map((item) => item.trim()).filter(Boolean)
: [];
@@ -103,12 +103,12 @@ export const initMultiSelect = async (target = '[data-multi-select]') => {
export const getMultiSelectInstance = (target) => {
const element = typeof target === 'string' ? document.querySelector(target) : target;
- if (!element) return null;
- if (element._multiSelectInstance) return element._multiSelectInstance;
+ if (!element) {return null;}
+ if (element._multiSelectInstance) {return element._multiSelectInstance;}
const syncTarget = element.dataset?.syncTarget;
if (syncTarget) {
const syncElement = document.querySelector(syncTarget);
- if (syncElement && syncElement._multiSelectInstance) return syncElement._multiSelectInstance;
+ if (syncElement && syncElement._multiSelectInstance) {return syncElement._multiSelectInstance;}
}
return null;
};
diff --git a/web/js/components/app-nav-history.js b/web/js/components/app-nav-history.js
index c44e3c6..c3f707f 100644
--- a/web/js/components/app-nav-history.js
+++ b/web/js/components/app-nav-history.js
@@ -1,7 +1,7 @@
const updateHistoryButtons = () => {
const back = document.querySelector('#global-back');
const forward = document.querySelector('#global-forward');
- if (!back && !forward) return;
+ if (!back && !forward) {return;}
const hasHistory = window.history.length > 1;
@@ -20,15 +20,15 @@ const initHistoryButtons = () => {
const forward = document.querySelector('#global-forward');
const isEditableTarget = (target) => {
- if (!target) return false;
- if (target.isContentEditable) return true;
+ if (!target) {return false;}
+ if (target.isContentEditable) {return true;}
const tag = target.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';
};
document.addEventListener('keydown', (event) => {
- if (!event.altKey || event.metaKey || event.ctrlKey) return;
- if (isEditableTarget(event.target)) return;
+ if (!event.altKey || event.metaKey || event.ctrlKey) {return;}
+ if (isEditableTarget(event.target)) {return;}
if (event.key === 'ArrowLeft') {
if (window.history.length > 1) {
event.preventDefault();
diff --git a/web/js/components/app-password-hints.js b/web/js/components/app-password-hints.js
index b2637a8..f1e4a40 100644
--- a/web/js/components/app-password-hints.js
+++ b/web/js/components/app-password-hints.js
@@ -7,18 +7,18 @@ const rules = {
number: (value) => /\d/.test(value),
symbol: (value) => /[^a-zA-Z0-9]/.test(value),
email: (value, _min, email) => {
- if (!email) return true;
+ if (!email) {return true;}
return !value.toLowerCase().includes(email.toLowerCase());
},
match: (_value, _min, _email, confirm) => {
- if (!confirm) return false;
+ if (!confirm) {return false;}
return true;
}
};
export function initPasswordHints() {
const containers = document.querySelectorAll('[data-password-hints]');
- if (!containers.length) return;
+ if (!containers.length) {return;}
containers.forEach((container) => {
const passwordSelector = container.dataset.passwordInput;
@@ -41,8 +41,8 @@ export function initPasswordHints() {
const setState = (item, state) => {
item.classList.remove('is-valid', 'is-invalid');
- if (state === 'valid') item.classList.add('is-valid');
- if (state === 'invalid') item.classList.add('is-invalid');
+ if (state === 'valid') {item.classList.add('is-valid');}
+ if (state === 'invalid') {item.classList.add('is-invalid');}
};
const evaluate = () => {
@@ -53,7 +53,7 @@ export function initPasswordHints() {
items.forEach((item) => {
const rule = item.dataset.rule;
- if (!rule) return;
+ if (!rule) {return;}
if (!hasValue) {
setState(item, 'neutral');
return;
@@ -67,15 +67,15 @@ export function initPasswordHints() {
return;
}
const check = rules[rule];
- if (!check) return;
+ if (!check) {return;}
const ok = check(password, minLength, email, confirm);
setState(item, ok ? 'valid' : 'invalid');
});
};
- if (passwordInput) passwordInput.addEventListener('input', evaluate);
- if (confirmInput) confirmInput.addEventListener('input', evaluate);
- if (emailInput) emailInput.addEventListener('input', evaluate);
+ if (passwordInput) {passwordInput.addEventListener('input', evaluate);}
+ if (confirmInput) {confirmInput.addEventListener('input', evaluate);}
+ if (emailInput) {emailInput.addEventListener('input', evaluate);}
evaluate();
});
}
diff --git a/web/js/components/app-tabs.js b/web/js/components/app-tabs.js
index f1b12cb..8a4973f 100644
--- a/web/js/components/app-tabs.js
+++ b/web/js/components/app-tabs.js
@@ -10,13 +10,14 @@ export function initTabs(root = document) {
const containers = root.querySelectorAll('[data-tabs]');
containers.forEach((container) => {
- if (container.dataset.tabsBound === '1') return;
+ if (container.dataset.tabsBound === '1') {return;}
container.dataset.tabsBound = '1';
+ container.dataset.tabsReady = '0';
const tabs = Array.from(container.querySelectorAll('[data-tab]'));
const panels = Array.from(container.querySelectorAll('[data-tab-panel]'));
- if (!tabs.length || !panels.length) return;
+ if (!tabs.length || !panels.length) {return;}
const storageKey = container.dataset.tabsStorageKey || (container.id ? `tabs:${container.id}` : null);
const urlParamName = container.dataset.tabsParam || 'tab';
@@ -99,6 +100,114 @@ export function initTabs(root = document) {
if (activeTab) {
activateTab(activeTab);
}
+ container.dataset.tabsReady = '1';
+
+ // --- Form validation awareness ---
+ const form = container.closest('form');
+ if (form) {
+ const inputSelector = 'input,select,textarea';
+ const formId = form.id;
+
+ const belongsToForm = (field) => {
+ const f = field.getAttribute('form');
+ if (!f) return true; // kein form-Attr → gehört zum Ancestor-Form
+ if (!formId) return false; // Feld hat form-Attr, unser Form hat keine ID
+ return f === formId;
+ };
+
+ const clearInvalidMarkers = () => {
+ tabs.forEach(tab => tab.classList.remove('has-invalid'));
+ };
+
+ const findInvalidPanels = () => {
+ clearInvalidMarkers();
+ let firstInvalidTab = null;
+
+ panels.forEach(panel => {
+ const fields = panel.querySelectorAll(inputSelector);
+ const hasInvalid = Array.from(fields).some(f => belongsToForm(f) && !f.disabled && !f.checkValidity());
+ if (hasInvalid) {
+ const tabName = panel.dataset.tabPanel;
+ const tab = tabs.find(t => t.dataset.tab === tabName);
+ if (tab) {
+ tab.classList.add('has-invalid');
+ }
+ if (!firstInvalidTab) {
+ firstInvalidTab = tabName;
+ }
+ }
+ });
+
+ return firstInvalidTab;
+ };
+
+ // Intercept submit buttons — both inside the form and external ones linked via form="id".
+ // We use document-level click (capture) so we catch ALL submit triggers before native validation.
+ document.addEventListener('click', (e) => {
+ const btn = e.target.closest('button, [type="submit"]');
+ if (!btn) {return;}
+
+ // Check if this button submits OUR form
+ const btnFormAttr = btn.getAttribute('form');
+ const isInternalSubmit = !btnFormAttr && form.contains(btn) && (btn.type === 'submit' || (!btn.type && btn.tagName === 'BUTTON'));
+ const isExternalSubmit = btnFormAttr && formId && btnFormAttr === formId && btn.type === 'submit';
+ if (!isInternalSubmit && !isExternalSubmit) {return;}
+
+ const firstInvalidTab = findInvalidPanels();
+ if (!firstInvalidTab) {return;}
+
+ // Active panel already shows the first invalid tab — let native validation handle it
+ const activePanel = panels.find(p => !p.hidden);
+ const needsTabSwitch = activePanel?.dataset.tabPanel !== firstInvalidTab;
+
+ // Open any closed ancestors of invalid fields so the browser can focus them
+ const invalidFields = form.querySelectorAll(inputSelector);
+ for (const field of invalidFields) {
+ if (!belongsToForm(field) || field.disabled || field.checkValidity()) {continue;}
+ let el = field.parentElement;
+ while (el && el !== form) {
+ if (el.tagName === 'DETAILS' && !el.open) {
+ el.open = true;
+ }
+ el = el.parentElement;
+ }
+ }
+
+ if (!needsTabSwitch) {return;}
+
+ // Prevent native submit so the browser doesn't try to focus a hidden field
+ e.preventDefault();
+ activateTab(firstInvalidTab);
+
+ requestAnimationFrame(() => {
+ form.reportValidity();
+ });
+ }, true);
+
+ form.addEventListener('input', (e) => {
+ const panel = e.target.closest('[data-tab-panel]');
+ if (!panel) {return;}
+ const tabName = panel.dataset.tabPanel;
+ const tab = tabs.find(t => t.dataset.tab === tabName);
+ if (!tab) {return;}
+ const fields = panel.querySelectorAll(inputSelector);
+ if (Array.from(fields).every(f => !belongsToForm(f) || f.disabled || f.checkValidity())) {
+ tab.classList.remove('has-invalid');
+ }
+ });
+
+ form.addEventListener('change', (e) => {
+ const panel = e.target.closest('[data-tab-panel]');
+ if (!panel) {return;}
+ const tabName = panel.dataset.tabPanel;
+ const tab = tabs.find(t => t.dataset.tab === tabName);
+ if (!tab) {return;}
+ const fields = panel.querySelectorAll(inputSelector);
+ if (Array.from(fields).every(f => !belongsToForm(f) || f.disabled || f.checkValidity())) {
+ tab.classList.remove('has-invalid');
+ }
+ });
+ }
// Listen for popstate (back/forward navigation)
window.addEventListener('popstate', () => {
diff --git a/web/js/components/app-tenant-sso-toggle.js b/web/js/components/app-tenant-sso-toggle.js
new file mode 100644
index 0000000..aa1808e
--- /dev/null
+++ b/web/js/components/app-tenant-sso-toggle.js
@@ -0,0 +1,75 @@
+const roots = document.querySelectorAll('[data-tenant-sso-root]');
+
+const syncControlState = (container, show) => {
+ if (!container) {
+ return;
+ }
+
+ container.hidden = !show;
+
+ container.querySelectorAll('input, select, textarea, button').forEach((control) => {
+ if ((control instanceof HTMLInputElement) && control.type === 'hidden') {
+ return;
+ }
+
+ if (!control.dataset.initialDisabled) {
+ control.dataset.initialDisabled = control.hasAttribute('disabled') ? '1' : '0';
+ }
+
+ if (!show) {
+ control.setAttribute('disabled', 'disabled');
+ return;
+ }
+
+ if (control.dataset.initialDisabled === '1') {
+ control.setAttribute('disabled', 'disabled');
+ return;
+ }
+
+ control.removeAttribute('disabled');
+ });
+};
+
+const initRoot = (root) => {
+ const enabledInput = root.querySelector('[data-tenant-sso-enabled]');
+ if (!(enabledInput instanceof HTMLInputElement)) {
+ return;
+ }
+
+ const syncToggle = root.querySelector('[data-tenant-sso-sync-toggle]');
+ const sharedToggle = root.querySelector('[data-tenant-sso-shared-toggle]');
+ const enabledBlocks = root.querySelectorAll('[data-tenant-sso-when-enabled]');
+ const syncFieldsBlock = root.querySelector('[data-tenant-sso-sync-fields]');
+ const overrideDetails = root.querySelector('[data-tenant-sso-override-details]');
+ const overrideFields = root.querySelectorAll('[data-tenant-sso-override-fields]');
+
+ const updateUi = () => {
+ const ssoEnabled = enabledInput.checked;
+ const syncEnabled = syncToggle instanceof HTMLInputElement ? syncToggle.checked : false;
+ const useSharedApp = sharedToggle instanceof HTMLInputElement ? sharedToggle.checked : true;
+
+ enabledBlocks.forEach((block) => syncControlState(block, ssoEnabled));
+ syncControlState(syncFieldsBlock, ssoEnabled && syncEnabled);
+
+ if (overrideDetails instanceof HTMLElement) {
+ overrideDetails.hidden = !ssoEnabled;
+ if (!ssoEnabled && overrideDetails instanceof HTMLDetailsElement) {
+ overrideDetails.open = false;
+ }
+ }
+
+ overrideFields.forEach((block) => syncControlState(block, ssoEnabled && !useSharedApp));
+ };
+
+ enabledInput.addEventListener('change', updateUi);
+ if (syncToggle instanceof HTMLInputElement) {
+ syncToggle.addEventListener('change', updateUi);
+ }
+ if (sharedToggle instanceof HTMLInputElement) {
+ sharedToggle.addEventListener('change', updateUi);
+ }
+
+ updateUi();
+};
+
+roots.forEach(initRoot);
diff --git a/web/js/components/app-theme-toggle.js b/web/js/components/app-theme-toggle.js
index 2e81a16..2d7b6a2 100644
--- a/web/js/components/app-theme-toggle.js
+++ b/web/js/components/app-theme-toggle.js
@@ -7,7 +7,7 @@ const setTheme = (theme) => {
const isDarkTheme = (theme) => theme && theme.startsWith('dark');
const setIcon = (iconEl, theme) => {
- if (!iconEl) return;
+ if (!iconEl) {return;}
iconEl.classList.remove('bi-sun-fill', 'bi-moon-stars-fill');
iconEl.classList.add(isDarkTheme(theme) ? 'bi-moon-stars-fill' : 'bi-sun-fill');
};
@@ -34,7 +34,7 @@ const updateTheme = async (menu, theme) => {
const initThemeMenu = () => {
const menu = optionalEl('[data-theme-menu]');
- if (!menu) return;
+ if (!menu) {return;}
const icon = menu.querySelector('[data-theme-icon]');
const options = Array.from(menu.querySelectorAll('[data-theme-option]'));
if (!options.length) {
@@ -62,9 +62,9 @@ const initThemeMenu = () => {
option.addEventListener('click', async (event) => {
event.preventDefault();
const next = option.dataset.themeValue || '';
- if (!next) return;
+ if (!next) {return;}
const current = getCurrent();
- if (next === current) return;
+ if (next === current) {return;}
setTheme(next);
setIcon(icon, next);
setActive(next);
@@ -80,7 +80,7 @@ const initThemeMenu = () => {
const initThemeToggle = () => {
const button = optionalEl('[data-theme-toggle]');
- if (!button) return;
+ if (!button) {return;}
const icon = button.querySelector('i');
const getCurrent = () => document.documentElement.dataset.theme || '';
setIcon(icon, getCurrent());
diff --git a/web/js/components/app-toggle-aside-panels.js b/web/js/components/app-toggle-aside-panels.js
index f16bcac..0459755 100644
--- a/web/js/components/app-toggle-aside-panels.js
+++ b/web/js/components/app-toggle-aside-panels.js
@@ -11,7 +11,7 @@ export function initAsidePanels(options = {}) {
} = options;
const bar = requireEl(barSelector, { module: 'aside-panels' });
- if (!bar) return;
+ if (!bar) {return;}
const tabs = Array.from(bar.querySelectorAll('[data-aside-target]'));
if (!tabs.length) {
@@ -37,18 +37,18 @@ export function initAsidePanels(options = {}) {
const getPanelTools = (panel) => panel?.querySelector('[data-aside-panel-tools]') || null;
const getTabHref = (tab) => tab?.dataset?.asideHref || '';
const isEditableTarget = (target) => {
- if (!target) return false;
- if (target.isContentEditable) return true;
+ if (!target) {return false;}
+ if (target.isContentEditable) {return true;}
const tag = target.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';
};
const initPanelDetails = (panel) => {
- if (!panel || panel.dataset.detailsBound === '1') return;
+ if (!panel || panel.dataset.detailsBound === '1') {return;}
const storageKey = panel.dataset.asideDetailsStorage || '';
- if (!storageKey) return;
+ if (!storageKey) {return;}
const detailsEls = Array.from(panel.querySelectorAll('details[data-details-key]'));
- if (!detailsEls.length) return;
+ if (!detailsEls.length) {return;}
const readStored = () => {
try {
@@ -70,7 +70,7 @@ export function initAsidePanels(options = {}) {
const applyStored = () => {
const stored = readStored();
- if (!stored.length) return;
+ if (!stored.length) {return;}
detailsEls.forEach((details) => {
details.open = stored.includes(details.dataset.detailsKey || '');
});
@@ -91,7 +91,7 @@ export function initAsidePanels(options = {}) {
};
const readStored = () => {
- if (!storageKey) return null;
+ if (!storageKey) {return null;}
try {
return window.localStorage.getItem(storageKey);
} catch (error) {
@@ -100,7 +100,7 @@ export function initAsidePanels(options = {}) {
};
const writeStored = (key) => {
- if (!storageKey) return;
+ if (!storageKey) {return;}
try {
window.localStorage.setItem(storageKey, key);
} catch (error) {
@@ -109,29 +109,29 @@ export function initAsidePanels(options = {}) {
};
const syncTools = (panel) => {
- if (!toolsHost) return;
+ if (!toolsHost) {return;}
toolsHost.innerHTML = '';
const tools = getPanelTools(panel);
- if (!tools) return;
+ if (!tools) {return;}
toolsHost.innerHTML = tools.innerHTML;
};
const openSidebar = (persist) => {
- if (!revealSidebarOnActivate || !sidebarController) return;
+ if (!revealSidebarOnActivate || !sidebarController) {return;}
if (typeof sidebarController.isHidden === 'function' && sidebarController.isHidden()) {
sidebarController.show({ persist });
}
- if (!sidebarController.isCollapsed()) return;
+ if (!sidebarController.isCollapsed()) {return;}
sidebarController.open({ persist });
};
const setActive = (key, { fromUser = false } = {}) => {
- if (!key) return;
+ if (!key) {return;}
let activePanel = null;
panels.forEach((panel) => {
const isActive = getPanelKey(panel) === key;
- if (isActive) activePanel = panel;
+ if (isActive) {activePanel = panel;}
panel.hidden = !isActive;
panel.setAttribute('aria-hidden', isActive ? 'false' : 'true');
});
@@ -165,9 +165,9 @@ export function initAsidePanels(options = {}) {
return stored;
}
const activeTab = tabs.find((tab) => tab.classList.contains('active'));
- if (activeTab) return getTabKey(activeTab);
+ if (activeTab) {return getTabKey(activeTab);}
const visiblePanel = panels.find((panel) => !panel.hidden);
- if (visiblePanel) return getPanelKey(visiblePanel);
+ if (visiblePanel) {return getPanelKey(visiblePanel);}
return getTabKey(tabs[0]);
};
@@ -180,7 +180,7 @@ export function initAsidePanels(options = {}) {
shortcutItems.forEach((item, idx) => {
const base = item.dataset.tooltipBase || item.getAttribute('data-tooltip') || item.getAttribute('aria-label') || '';
- if (!base) return;
+ if (!base) {return;}
const shortcutKey = idx === 9 ? '0' : String(idx + 1);
item.dataset.tooltipBase = base;
item.setAttribute('data-tooltip', `${base} (${shortcutPrefix}${shortcutKey})`);
@@ -221,13 +221,13 @@ export function initAsidePanels(options = {}) {
});
document.addEventListener('keydown', (event) => {
- if (!(event.metaKey || event.ctrlKey)) return;
- if (event.altKey) return;
- if (isEditableTarget(event.target)) return;
+ if (!(event.metaKey || event.ctrlKey)) {return;}
+ if (event.altKey) {return;}
+ if (isEditableTarget(event.target)) {return;}
const key = event.key;
- if (!/^[0-9]$/.test(key)) return;
+ if (!/^[0-9]$/.test(key)) {return;}
const index = key === '0' ? 9 : (Number.parseInt(key, 10) - 1);
- if (index < 0 || index >= shortcutItems.length) return;
+ if (index < 0 || index >= shortcutItems.length) {return;}
event.preventDefault();
shortcutItems[index].click();
});
diff --git a/web/js/components/app-toggle-details-aside.js b/web/js/components/app-toggle-details-aside.js
index 5b1c150..9d1a031 100644
--- a/web/js/components/app-toggle-details-aside.js
+++ b/web/js/components/app-toggle-details-aside.js
@@ -10,7 +10,7 @@ export function initDetailsAsideToggle(options = {}) {
const button = optionalEl(buttonSelector);
const aside = optionalEl(asideSelector);
- if (!button || !aside) return;
+ if (!button || !aside) {return;}
const container = aside.closest(containerSelector) || document.querySelector(containerSelector);
if (!container) {
diff --git a/web/js/components/app-toggle-sidebar.js b/web/js/components/app-toggle-sidebar.js
index 33b9c2b..f0b4cd8 100644
--- a/web/js/components/app-toggle-sidebar.js
+++ b/web/js/components/app-toggle-sidebar.js
@@ -10,7 +10,7 @@ export function initSidebarToggle(options = {}) {
} = options;
const aside = requireEl(asideSelector, { module: 'sidebar-toggle' });
- if (!aside) return null;
+ if (!aside) {return null;}
const buttons = Array.from(document.querySelectorAll(buttonSelector));
if (!buttons.length) {
@@ -135,12 +135,12 @@ export function initSidebarToggle(options = {}) {
const detail = event.detail || {};
const action = detail.action;
const persist = detail.persist ?? false;
- if (action === 'open') controller.open({ persist });
- if (action === 'close') controller.close({ persist });
- if (action === 'toggle') controller.toggle({ persist });
- if (action === 'show') controller.show({ persist });
- if (action === 'hide') controller.hide({ persist });
- if (action === 'toggle-visibility') controller.toggleVisibility({ persist });
+ if (action === 'open') {controller.open({ persist });}
+ if (action === 'close') {controller.close({ persist });}
+ if (action === 'toggle') {controller.toggle({ persist });}
+ if (action === 'show') {controller.show({ persist });}
+ if (action === 'hide') {controller.hide({ persist });}
+ if (action === 'toggle-visibility') {controller.toggleVisibility({ persist });}
});
window.AppSidebar = controller;
@@ -148,18 +148,18 @@ export function initSidebarToggle(options = {}) {
}
const isEditableTarget = (target) => {
- if (!target) return false;
- if (target.isContentEditable) return true;
+ if (!target) {return false;}
+ if (target.isContentEditable) {return true;}
const tag = target.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';
};
document.addEventListener('keydown', (event) => {
- if (!(event.metaKey || event.ctrlKey)) return;
- if (event.altKey) return;
- if (event.key.toLowerCase() !== 'b') return;
- if (isEditableTarget(event.target)) return;
- if (!window.AppSidebar || typeof window.AppSidebar.toggleVisibility !== 'function') return;
+ if (!(event.metaKey || event.ctrlKey)) {return;}
+ if (event.altKey) {return;}
+ if (event.key.toLowerCase() !== 'b') {return;}
+ if (isEditableTarget(event.target)) {return;}
+ if (!window.AppSidebar || typeof window.AppSidebar.toggleVisibility !== 'function') {return;}
event.preventDefault();
window.AppSidebar.toggleVisibility({ persist: true });
});
diff --git a/web/js/components/app-toggle-toolbar.js b/web/js/components/app-toggle-toolbar.js
index 5a3a3ea..e196489 100644
--- a/web/js/components/app-toggle-toolbar.js
+++ b/web/js/components/app-toggle-toolbar.js
@@ -84,3 +84,9 @@ export function initToolbarToggles(root = document) {
});
});
}
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => initToolbarToggles());
+} else {
+ initToolbarToggles();
+}
diff --git a/web/js/core/app-dom.js b/web/js/core/app-dom.js
index 493db8d..98691ed 100644
--- a/web/js/core/app-dom.js
+++ b/web/js/core/app-dom.js
@@ -2,7 +2,7 @@ const warned = new Set();
export const warnOnce = (code, message, details = {}) => {
const key = `${code}:${message}`;
- if (warned.has(key)) return;
+ if (warned.has(key)) {return;}
warned.add(key);
console.warn(`[${code}] ${message}`, details);
};
diff --git a/web/js/core/app-grid-factory.js b/web/js/core/app-grid-factory.js
index ce6fecf..b83af23 100644
--- a/web/js/core/app-grid-factory.js
+++ b/web/js/core/app-grid-factory.js
@@ -14,6 +14,7 @@ export function createServerGrid(options) {
search = null,
filters = [],
urlSync = true,
+ urlState = null,
gridjs,
rowDblClick = null,
actions = null,
@@ -34,20 +35,64 @@ export function createServerGrid(options) {
}
const params = new URLSearchParams(window.location.search);
+ const urlStateConfig = {
+ pageParam: 'page',
+ sortOrderParam: 'order',
+ sortDirParam: 'dir',
+ cleanFirstPage: true,
+ syncPage: true,
+ syncSort: true,
+ ...(urlState || {})
+ };
+ const pageParam = urlStateConfig.pageParam || 'page';
+ const sortOrderParam = urlStateConfig.sortOrderParam || 'order';
+ const sortDirParam = urlStateConfig.sortDirParam || 'dir';
const resolveUrl = (path) => new URL(path, appBase).toString();
const addParam = (url, key, value) => {
const nextUrl = new URL(url);
nextUrl.searchParams.set(key, value);
return nextUrl.toString();
};
+ const deleteParam = (url, key) => {
+ const nextUrl = new URL(url);
+ nextUrl.searchParams.delete(key);
+ return nextUrl.toString();
+ };
+ const clearSortParams = (url) => deleteParam(deleteParam(url, sortOrderParam), sortDirParam);
+ const parsePage = (rawValue) => {
+ const parsed = Number.parseInt(String(rawValue ?? ''), 10);
+ if (!Number.isFinite(parsed) || parsed < 1) {
+ return 1;
+ }
+ return parsed;
+ };
+ const validSortKeys = new Set(
+ (sortColumns || [])
+ .filter((key) => typeof key === 'string')
+ .map((key) => key.trim())
+ .filter(Boolean)
+ );
+ const normalizeDir = (rawValue) => {
+ const normalized = String(rawValue ?? '').trim().toLowerCase();
+ return normalized === 'asc' || normalized === 'desc' ? normalized : '';
+ };
+ let currentPage = urlStateConfig.syncPage ? parsePage(params.get(pageParam)) : 1;
+ let currentSort = null;
+ if (urlStateConfig.syncSort) {
+ const initialOrder = String(params.get(sortOrderParam) ?? '').trim();
+ const initialDir = normalizeDir(params.get(sortDirParam));
+ if (initialOrder !== '' && initialDir !== '' && validSortKeys.has(initialOrder)) {
+ currentSort = { order: initialOrder, dir: initialDir };
+ }
+ }
const getInput = (input) => {
- if (!input) return null;
+ if (!input) {return null;}
return typeof input === 'string' ? document.querySelector(input) : input;
};
const getInputValue = (input) => {
- if (!input) return '';
+ if (!input) {return '';}
if (input.type === 'checkbox') {
return input.checked ? (input.value || '1') : '';
}
@@ -58,7 +103,7 @@ export function createServerGrid(options) {
};
const setInputValue = (input, value) => {
- if (!input) return;
+ if (!input) {return;}
if (input.type === 'checkbox') {
input.checked = value === true || value === 'true' || value === '1';
} else if (input.tagName === 'SELECT' && input.multiple) {
@@ -116,7 +161,7 @@ export function createServerGrid(options) {
return value;
};
- const buildParams = () => {
+ const buildDataParams = () => {
const query = new URLSearchParams();
if (searchValue) {
query.set(searchParam, searchValue);
@@ -135,24 +180,47 @@ export function createServerGrid(options) {
query.set(filter.param, normalized);
}
});
+ if (currentSort?.order && currentSort?.dir) {
+ query.set(sortOrderParam, currentSort.order);
+ query.set(sortDirParam, currentSort.dir);
+ }
+ return query;
+ };
+
+ const buildUrlParams = () => {
+ const query = buildDataParams();
+ if (!urlStateConfig.syncSort) {
+ query.delete(sortOrderParam);
+ query.delete(sortDirParam);
+ }
+ if (urlStateConfig.syncPage) {
+ if (urlStateConfig.cleanFirstPage && currentPage <= 1) {
+ query.delete(pageParam);
+ } else {
+ query.set(pageParam, String(currentPage));
+ }
+ } else {
+ query.delete(pageParam);
+ }
return query;
};
const baseUrl = () => {
const url = new URL(dataUrl, appBase);
- const query = buildParams();
+ const query = buildDataParams();
query.forEach((value, key) => url.searchParams.set(key, value));
return url.toString();
};
const updateUrl = () => {
- if (!urlSync) return;
+ if (!urlSync) {return;}
const url = new URL(window.location.href);
- if (searchParam) {
- url.searchParams.delete(searchParam);
- }
+ if (searchParam) { url.searchParams.delete(searchParam); }
filterState.forEach((filter) => url.searchParams.delete(filter.param));
- const query = buildParams();
+ url.searchParams.delete(sortOrderParam);
+ url.searchParams.delete(sortDirParam);
+ url.searchParams.delete(pageParam);
+ const query = buildUrlParams();
query.forEach((value, key) => url.searchParams.set(key, value));
window.history.replaceState({}, '', url.toString());
};
@@ -177,7 +245,7 @@ export function createServerGrid(options) {
} : null;
const insertActionColumn = (cols) => {
- if (!actionConfig) return cols;
+ if (!actionConfig) {return cols;}
const actionColumn = {
name: actionConfig.label,
sort: false,
@@ -187,9 +255,9 @@ export function createServerGrid(options) {
return gridjsLib.html('');
}
const buttons = actionConfig.items.map((item) => {
- if (!item || !item.key) return '';
+ if (!item || !item.key) {return '';}
const label = typeof item.label === 'function' ? item.label(row, id) : item.label;
- if (!label) return '';
+ if (!label) {return '';}
const className = item.className ? ` ${item.className}` : '';
const type = item.type || 'button';
if (type === 'link') {
@@ -210,7 +278,7 @@ export function createServerGrid(options) {
};
const insertSelectionColumn = (cols) => {
- if (!selectionConfig) return cols;
+ if (!selectionConfig) {return cols;}
const headerLabel = selectionConfig.selectAllLabel || 'Select all';
const header = selectionConfig.selectAllEnabled
? gridjsLib.html(``)
@@ -231,7 +299,7 @@ export function createServerGrid(options) {
};
const insertActionSort = (cols) => {
- if (!actionConfig || !cols.length) return cols;
+ if (!actionConfig || !cols.length) {return cols;}
const next = [...cols];
const index = actionConfig.index === null ? next.length : Math.min(Math.max(actionConfig.index, 0), next.length);
next.splice(index, 0, null);
@@ -239,7 +307,7 @@ export function createServerGrid(options) {
};
const insertSelectionSort = (cols) => {
- if (!selectionConfig || !cols.length) return cols;
+ if (!selectionConfig || !cols.length) {return cols;}
const next = [...cols];
const index = Math.min(Math.max(selectionConfig.index ?? 0, 0), next.length);
next.splice(index, 0, null);
@@ -253,7 +321,7 @@ export function createServerGrid(options) {
}
const index = actionConfig.index === null ? null : Math.min(Math.max(actionConfig.index, 0), Infinity);
return rows.map((row) => {
- if (!Array.isArray(row)) return row;
+ if (!Array.isArray(row)) {return row;}
const next = [...row];
const insertAt = index === null ? next.length : Math.min(index, next.length);
next.splice(insertAt, 0, null);
@@ -274,34 +342,54 @@ export function createServerGrid(options) {
if (actionConfig) {
finalSortColumns = insertActionSort(finalSortColumns);
}
- let currentSort = null;
const sortConfig = finalSortColumns.length ? {
enabled: true,
server: {
url: (prev, columns) => {
if (!columns.length) {
+ // Keep URL/bootstrap sort when grid has no active sort columns yet (e.g. initial load from deep-link).
+ if (currentSort?.order && currentSort?.dir) {
+ return addParam(addParam(clearSortParams(prev), sortOrderParam, currentSort.order), sortDirParam, currentSort.dir);
+ }
currentSort = null;
- return prev;
+ return clearSortParams(prev);
}
const column = columns[0];
const key = finalSortColumns[column.index];
if (!key) {
+ if (currentSort?.order && currentSort?.dir) {
+ return addParam(addParam(clearSortParams(prev), sortOrderParam, currentSort.order), sortDirParam, currentSort.dir);
+ }
currentSort = null;
- return prev;
+ return clearSortParams(prev);
}
const direction = column.direction === 1 ? 'asc' : 'desc';
currentSort = { order: key, dir: direction };
- return addParam(addParam(prev, 'order', key), 'dir', direction);
+ if (urlSync && urlStateConfig.syncSort) {
+ updateUrl();
+ }
+ return addParam(addParam(clearSortParams(prev), sortOrderParam, key), sortDirParam, direction);
}
}
} : { enabled: false };
const paginationConfig = {
limit: paginationLimit,
+ page: Math.max(currentPage - 1, 0),
+ // We control page resets explicitly (search/filter/reset actions) to keep deep-link pages stable.
+ resetPageOnUpdate: false,
server: {
url: (prev, page, limit) => {
- const offset = page * limit;
- return addParam(addParam(prev, 'limit', limit), 'offset', offset);
+ const parsedPage = Number.parseInt(String(page ?? ''), 10);
+ const parsedLimit = Number.parseInt(String(limit ?? ''), 10);
+ const nextPage = Number.isFinite(parsedPage) && parsedPage >= 0 ? parsedPage : 0;
+ const nextLimit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : paginationLimit;
+ currentPage = nextPage + 1;
+ if (urlSync && urlStateConfig.syncPage) {
+ updateUrl();
+ }
+ const offset = nextPage * nextLimit;
+ return addParam(addParam(prev, 'limit', nextLimit), 'offset', offset);
}
}
};
@@ -333,7 +421,7 @@ export function createServerGrid(options) {
// Prevent empty-state flash before data arrives.
let hasLoadedOnce = false;
const markLoadedOnce = () => {
- if (hasLoadedOnce) return;
+ if (hasLoadedOnce) {return;}
hasLoadedOnce = true;
containerEl.classList.add('gridjs-has-loaded');
};
@@ -343,7 +431,7 @@ export function createServerGrid(options) {
const store = grid?.config?.store;
if (store?.subscribe) {
store.subscribe((state) => {
- if (!state) return;
+ if (!state) {return;}
// Grid.js status: 0=Init, 1=Loading, 2=Loaded, 3=Rendered, 4=Error
if (state.status === 1) {
setUpdating();
@@ -360,12 +448,12 @@ export function createServerGrid(options) {
}
const applyRowDataset = () => {
- if (typeof rowDataset !== 'function') return;
+ if (typeof rowDataset !== 'function') {return;}
const rowEls = containerEl.querySelectorAll('.gridjs-tbody .gridjs-tr');
const dataRows = grid.config.store.getState().data?.rows || [];
rowEls.forEach((rowEl, index) => {
const rowData = dataRows[index] || null;
- if (!rowData) return;
+ if (!rowData) {return;}
const attrs = rowDataset(rowData, index) || {};
Object.keys(attrs).forEach((key) => {
const value = attrs[key];
@@ -380,9 +468,9 @@ export function createServerGrid(options) {
};
const initSelectAll = () => {
- if (!selectionConfig?.component || !selectionConfig.selectAllEnabled) return;
+ if (!selectionConfig?.component || !selectionConfig.selectAllEnabled) {return;}
const header = containerEl.querySelector(`th[data-column-id="${selectionConfig.id}"] input[data-grid-select-all]`);
- if (!header) return;
+ if (!header) {return;}
if (header.dataset.bound === '1') {
return;
}
@@ -421,13 +509,13 @@ export function createServerGrid(options) {
}
const getRowDataByElement = (rowEl) => {
- if (!rowEl) return null;
+ if (!rowEl) {return null;}
const rows = Array.from(rowEl.parentElement?.children || []);
const rowIndex = rows.indexOf(rowEl);
- if (rowIndex < 0) return null;
+ if (rowIndex < 0) {return null;}
const dataRows = grid.config.store.getState().data?.rows || [];
const rowData = dataRows[rowIndex] || null;
- if (!rowData) return null;
+ if (!rowData) {return null;}
return { rowData, rowIndex };
};
@@ -498,11 +586,19 @@ export function createServerGrid(options) {
});
}
- const updateGrid = () => {
+ const updateGrid = (options = {}) => {
+ const resetPage = options && options.resetPage === true;
+ if (resetPage) {
+ currentPage = 1;
+ }
updateUrl();
- grid.updateConfig({
+ const nextConfig = {
server: { ...serverConfig, url: baseUrl() }
- }).forceRender();
+ };
+ if (resetPage) {
+ nextConfig.pagination = { ...paginationConfig, page: 0 };
+ }
+ grid.updateConfig(nextConfig).forceRender();
};
const debounce = (fn, delay = 250) => {
@@ -516,16 +612,16 @@ export function createServerGrid(options) {
if (searchInput) {
searchInput.addEventListener('input', debounce((event) => {
searchValue = event.target.value.trim();
- updateGrid();
+ updateGrid({ resetPage: true });
}, searchDebounce));
}
filterState.forEach((filter) => {
- if (!filter.input) return;
+ if (!filter.input) {return;}
const eventName = filter.event || 'change';
filter.input.addEventListener(eventName, () => {
filter.value = getInputValue(filter.input);
- updateGrid();
+ updateGrid({ resetPage: true });
});
});
@@ -544,7 +640,7 @@ export function createServerGrid(options) {
setInputValue(filter.input, defaultValue);
}
});
- updateGrid();
+ updateGrid({ resetPage: true });
};
const getSortParams = () => (currentSort ? { ...currentSort } : null);
@@ -556,14 +652,14 @@ export function createServerGrid(options) {
const plugin = grid?.config?.plugin?.get?.(selectionConfig.id);
const store = plugin?.props?.store;
const state = store?.state ?? store?.getState?.();
- if (!state) return [];
- if (Array.isArray(state.selected)) return state.selected;
- if (Array.isArray(state.ids)) return state.ids;
+ if (!state) {return [];}
+ if (Array.isArray(state.selected)) {return state.selected;}
+ if (Array.isArray(state.ids)) {return state.ids;}
if (state.rows && typeof state.rows === 'object') {
return Object.keys(state.rows).filter((key) => state.rows[key]);
}
- if (state instanceof Set) return Array.from(state);
- if (Array.isArray(state)) return state;
+ if (state instanceof Set) {return Array.from(state);}
+ if (Array.isArray(state)) {return state;}
if (typeof state === 'object') {
return Object.keys(state).filter((key) => state[key]);
}
@@ -587,8 +683,8 @@ export function createServerGrid(options) {
const sync = () => {
selectionConfig.onChange(selectionApi?.getSelectedIds?.() || []);
};
- if (store?.on) store.on('updated', sync);
- if (store?.subscribe) store.subscribe(sync);
+ if (store?.on) {store.on('updated', sync);}
+ if (store?.subscribe) {store.subscribe(sync);}
sync();
});
}
diff --git a/web/js/pages/app-list-utils.js b/web/js/pages/app-list-utils.js
index 11cbfad..db14bdf 100644
--- a/web/js/pages/app-list-utils.js
+++ b/web/js/pages/app-list-utils.js
@@ -29,7 +29,7 @@ export const buildBadgeList = (items, options = {}) => {
list = Array.isArray(items.items) ? items.items : [];
primary = String(items.primary ?? '');
}
- if (!Array.isArray(list) || list.length === 0) return '';
+ if (!Array.isArray(list) || list.length === 0) {return '';}
const tooltipAttr = primaryTooltip
? ` data-tooltip="${escapeHtml(primaryTooltip)}" data-tooltip-pos="top"`
diff --git a/web/js/pages/app-users-list.js b/web/js/pages/app-users-list.js
index eaf6823..95a0774 100644
--- a/web/js/pages/app-users-list.js
+++ b/web/js/pages/app-users-list.js
@@ -5,6 +5,7 @@ export function initUsersListPage(options = {}) {
csrf,
labels = {},
selectors = {},
+ bulkDownloadForms = {},
exportPath = 'admin/users/export',
listPath = 'admin/users',
buildBulkUrl,
@@ -12,7 +13,7 @@ export function initUsersListPage(options = {}) {
withLoading
} = options;
- if (!gridConfig) return;
+ if (!gridConfig) {return;}
const exportSelector = selectors.exportButton || '[data-users-export]';
const resetSelector = selectors.resetButton || '[data-users-reset]';
@@ -67,21 +68,40 @@ export function initUsersListPage(options = {}) {
button.addEventListener('click', async () => {
const action = button.getAttribute('data-users-bulk') || '';
const ids = gridConfig.selection?.getSelectedIds?.() || [];
- const validActions = ['activate', 'deactivate', 'delete', 'send-access'];
+ const validActions = ['activate', 'deactivate', 'delete', 'send-access', 'access-pdf'];
if (!ids.length || !validActions.includes(action)) {
+ if (action && !validActions.includes(action)) {
+ console.warn(`Unsupported users bulk action: ${action}`);
+ }
return;
}
const confirmTexts = {
'activate': labels.bulkActivateConfirm,
'deactivate': labels.bulkDeactivateConfirm,
'delete': labels.bulkDeleteConfirm,
- 'send-access': labels.bulkSendAccessConfirm
+ 'send-access': labels.bulkSendAccessConfirm,
+ 'access-pdf': labels.bulkAccessPdfConfirm
};
const confirmText = confirmTexts[action];
if (confirmText && !window.confirm(confirmText)) {
return;
}
+ const downloadFormSelector = bulkDownloadForms?.[action];
+ if (downloadFormSelector) {
+ const downloadForm = document.querySelector(downloadFormSelector);
+ if (!downloadForm) {
+ window.location.href = new URL(listPath, appBase).toString();
+ return;
+ }
+ const uuidsInput = downloadForm.querySelector('input[name="uuids"]');
+ if (uuidsInput) {
+ uuidsInput.value = ids.join(',');
+ }
+ downloadForm.submit();
+ return;
+ }
+
const executeBulk = async () => {
const url = resolveBulkUrl(action);
const response = await postAction(url, { uuids: ids.join(',') });
diff --git a/web/vendor/swagger-ui/swagger-ui-bundle.js b/web/vendor/swagger-ui/swagger-ui-bundle.js
new file mode 100644
index 0000000..4526219
--- /dev/null
+++ b/web/vendor/swagger-ui/swagger-ui-bundle.js
@@ -0,0 +1,2 @@
+/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */
+!function webpackUniversalModuleDefinition(s,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.SwaggerUIBundle=o():s.SwaggerUIBundle=o()}(this,(()=>(()=>{var s,o,i={69119:(s,o)=>{"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.BLANK_URL=o.relativeFirstCharacters=o.whitespaceEscapeCharsRegex=o.urlSchemeRegex=o.ctrlCharactersRegex=o.htmlCtrlEntityRegex=o.htmlEntitiesRegex=o.invalidProtocolRegex=void 0,o.invalidProtocolRegex=/^([^\w]*)(javascript|data|vbscript)/im,o.htmlEntitiesRegex=/(\w+)(^\w|;)?/g,o.htmlCtrlEntityRegex=/&(newline|tab);/gi,o.ctrlCharactersRegex=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,o.urlSchemeRegex=/^.+(:|:)/gim,o.whitespaceEscapeCharsRegex=/(\\|%5[cC])((%(6[eE]|72|74))|[nrt])/g,o.relativeFirstCharacters=[".","/"],o.BLANK_URL="about:blank"},16750:(s,o,i)=>{"use strict";o.J=void 0;var u=i(69119);function decodeURI(s){try{return decodeURIComponent(s)}catch(o){return s}}o.J=function sanitizeUrl(s){if(!s)return u.BLANK_URL;var o,i,_=decodeURI(s);do{o=(_=decodeURI(_=(i=_,i.replace(u.ctrlCharactersRegex,"").replace(u.htmlEntitiesRegex,(function(s,o){return String.fromCharCode(o)}))).replace(u.htmlCtrlEntityRegex,"").replace(u.ctrlCharactersRegex,"").replace(u.whitespaceEscapeCharsRegex,"").trim())).match(u.ctrlCharactersRegex)||_.match(u.htmlEntitiesRegex)||_.match(u.htmlCtrlEntityRegex)||_.match(u.whitespaceEscapeCharsRegex)}while(o&&o.length>0);var w=_;if(!w)return u.BLANK_URL;if(function isRelativeUrlWithoutProtocol(s){return u.relativeFirstCharacters.indexOf(s[0])>-1}(w))return w;var x=w.match(u.urlSchemeRegex);if(!x)return w;var C=x[0];return u.invalidProtocolRegex.test(C)?u.BLANK_URL:w}},67526:(s,o)=>{"use strict";o.byteLength=function byteLength(s){var o=getLens(s),i=o[0],u=o[1];return 3*(i+u)/4-u},o.toByteArray=function toByteArray(s){var o,i,w=getLens(s),x=w[0],C=w[1],j=new _(function _byteLength(s,o,i){return 3*(o+i)/4-i}(0,x,C)),L=0,B=C>0?x-4:x;for(i=0;i>16&255,j[L++]=o>>8&255,j[L++]=255&o;2===C&&(o=u[s.charCodeAt(i)]<<2|u[s.charCodeAt(i+1)]>>4,j[L++]=255&o);1===C&&(o=u[s.charCodeAt(i)]<<10|u[s.charCodeAt(i+1)]<<4|u[s.charCodeAt(i+2)]>>2,j[L++]=o>>8&255,j[L++]=255&o);return j},o.fromByteArray=function fromByteArray(s){for(var o,u=s.length,_=u%3,w=[],x=16383,C=0,j=u-_;Cj?j:C+x));1===_?(o=s[u-1],w.push(i[o>>2]+i[o<<4&63]+"==")):2===_&&(o=(s[u-2]<<8)+s[u-1],w.push(i[o>>10]+i[o>>4&63]+i[o<<2&63]+"="));return w.join("")};for(var i=[],u=[],_="undefined"!=typeof Uint8Array?Uint8Array:Array,w="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",x=0;x<64;++x)i[x]=w[x],u[w.charCodeAt(x)]=x;function getLens(s){var o=s.length;if(o%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var i=s.indexOf("=");return-1===i&&(i=o),[i,i===o?0:4-i%4]}function encodeChunk(s,o,u){for(var _,w,x=[],C=o;C>18&63]+i[w>>12&63]+i[w>>6&63]+i[63&w]);return x.join("")}u["-".charCodeAt(0)]=62,u["_".charCodeAt(0)]=63},48287:(s,o,i)=>{"use strict";const u=i(67526),_=i(251),w="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;o.Buffer=Buffer,o.SlowBuffer=function SlowBuffer(s){+s!=s&&(s=0);return Buffer.alloc(+s)},o.INSPECT_MAX_BYTES=50;const x=2147483647;function createBuffer(s){if(s>x)throw new RangeError('The value "'+s+'" is invalid for option "size"');const o=new Uint8Array(s);return Object.setPrototypeOf(o,Buffer.prototype),o}function Buffer(s,o,i){if("number"==typeof s){if("string"==typeof o)throw new TypeError('The "string" argument must be of type string. Received type number');return allocUnsafe(s)}return from(s,o,i)}function from(s,o,i){if("string"==typeof s)return function fromString(s,o){"string"==typeof o&&""!==o||(o="utf8");if(!Buffer.isEncoding(o))throw new TypeError("Unknown encoding: "+o);const i=0|byteLength(s,o);let u=createBuffer(i);const _=u.write(s,o);_!==i&&(u=u.slice(0,_));return u}(s,o);if(ArrayBuffer.isView(s))return function fromArrayView(s){if(isInstance(s,Uint8Array)){const o=new Uint8Array(s);return fromArrayBuffer(o.buffer,o.byteOffset,o.byteLength)}return fromArrayLike(s)}(s);if(null==s)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof s);if(isInstance(s,ArrayBuffer)||s&&isInstance(s.buffer,ArrayBuffer))return fromArrayBuffer(s,o,i);if("undefined"!=typeof SharedArrayBuffer&&(isInstance(s,SharedArrayBuffer)||s&&isInstance(s.buffer,SharedArrayBuffer)))return fromArrayBuffer(s,o,i);if("number"==typeof s)throw new TypeError('The "value" argument must not be of type number. Received type number');const u=s.valueOf&&s.valueOf();if(null!=u&&u!==s)return Buffer.from(u,o,i);const _=function fromObject(s){if(Buffer.isBuffer(s)){const o=0|checked(s.length),i=createBuffer(o);return 0===i.length||s.copy(i,0,0,o),i}if(void 0!==s.length)return"number"!=typeof s.length||numberIsNaN(s.length)?createBuffer(0):fromArrayLike(s);if("Buffer"===s.type&&Array.isArray(s.data))return fromArrayLike(s.data)}(s);if(_)return _;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof s[Symbol.toPrimitive])return Buffer.from(s[Symbol.toPrimitive]("string"),o,i);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof s)}function assertSize(s){if("number"!=typeof s)throw new TypeError('"size" argument must be of type number');if(s<0)throw new RangeError('The value "'+s+'" is invalid for option "size"')}function allocUnsafe(s){return assertSize(s),createBuffer(s<0?0:0|checked(s))}function fromArrayLike(s){const o=s.length<0?0:0|checked(s.length),i=createBuffer(o);for(let u=0;u=x)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+x.toString(16)+" bytes");return 0|s}function byteLength(s,o){if(Buffer.isBuffer(s))return s.length;if(ArrayBuffer.isView(s)||isInstance(s,ArrayBuffer))return s.byteLength;if("string"!=typeof s)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof s);const i=s.length,u=arguments.length>2&&!0===arguments[2];if(!u&&0===i)return 0;let _=!1;for(;;)switch(o){case"ascii":case"latin1":case"binary":return i;case"utf8":case"utf-8":return utf8ToBytes(s).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*i;case"hex":return i>>>1;case"base64":return base64ToBytes(s).length;default:if(_)return u?-1:utf8ToBytes(s).length;o=(""+o).toLowerCase(),_=!0}}function slowToString(s,o,i){let u=!1;if((void 0===o||o<0)&&(o=0),o>this.length)return"";if((void 0===i||i>this.length)&&(i=this.length),i<=0)return"";if((i>>>=0)<=(o>>>=0))return"";for(s||(s="utf8");;)switch(s){case"hex":return hexSlice(this,o,i);case"utf8":case"utf-8":return utf8Slice(this,o,i);case"ascii":return asciiSlice(this,o,i);case"latin1":case"binary":return latin1Slice(this,o,i);case"base64":return base64Slice(this,o,i);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return utf16leSlice(this,o,i);default:if(u)throw new TypeError("Unknown encoding: "+s);s=(s+"").toLowerCase(),u=!0}}function swap(s,o,i){const u=s[o];s[o]=s[i],s[i]=u}function bidirectionalIndexOf(s,o,i,u,_){if(0===s.length)return-1;if("string"==typeof i?(u=i,i=0):i>2147483647?i=2147483647:i<-2147483648&&(i=-2147483648),numberIsNaN(i=+i)&&(i=_?0:s.length-1),i<0&&(i=s.length+i),i>=s.length){if(_)return-1;i=s.length-1}else if(i<0){if(!_)return-1;i=0}if("string"==typeof o&&(o=Buffer.from(o,u)),Buffer.isBuffer(o))return 0===o.length?-1:arrayIndexOf(s,o,i,u,_);if("number"==typeof o)return o&=255,"function"==typeof Uint8Array.prototype.indexOf?_?Uint8Array.prototype.indexOf.call(s,o,i):Uint8Array.prototype.lastIndexOf.call(s,o,i):arrayIndexOf(s,[o],i,u,_);throw new TypeError("val must be string, number or Buffer")}function arrayIndexOf(s,o,i,u,_){let w,x=1,C=s.length,j=o.length;if(void 0!==u&&("ucs2"===(u=String(u).toLowerCase())||"ucs-2"===u||"utf16le"===u||"utf-16le"===u)){if(s.length<2||o.length<2)return-1;x=2,C/=2,j/=2,i/=2}function read(s,o){return 1===x?s[o]:s.readUInt16BE(o*x)}if(_){let u=-1;for(w=i;wC&&(i=C-j),w=i;w>=0;w--){let i=!0;for(let u=0;u_&&(u=_):u=_;const w=o.length;let x;for(u>w/2&&(u=w/2),x=0;x>8,_=i%256,w.push(_),w.push(u);return w}(o,s.length-i),s,i,u)}function base64Slice(s,o,i){return 0===o&&i===s.length?u.fromByteArray(s):u.fromByteArray(s.slice(o,i))}function utf8Slice(s,o,i){i=Math.min(s.length,i);const u=[];let _=o;for(;_239?4:o>223?3:o>191?2:1;if(_+x<=i){let i,u,C,j;switch(x){case 1:o<128&&(w=o);break;case 2:i=s[_+1],128==(192&i)&&(j=(31&o)<<6|63&i,j>127&&(w=j));break;case 3:i=s[_+1],u=s[_+2],128==(192&i)&&128==(192&u)&&(j=(15&o)<<12|(63&i)<<6|63&u,j>2047&&(j<55296||j>57343)&&(w=j));break;case 4:i=s[_+1],u=s[_+2],C=s[_+3],128==(192&i)&&128==(192&u)&&128==(192&C)&&(j=(15&o)<<18|(63&i)<<12|(63&u)<<6|63&C,j>65535&&j<1114112&&(w=j))}}null===w?(w=65533,x=1):w>65535&&(w-=65536,u.push(w>>>10&1023|55296),w=56320|1023&w),u.push(w),_+=x}return function decodeCodePointsArray(s){const o=s.length;if(o<=C)return String.fromCharCode.apply(String,s);let i="",u=0;for(;uu.length?(Buffer.isBuffer(o)||(o=Buffer.from(o)),o.copy(u,_)):Uint8Array.prototype.set.call(u,o,_);else{if(!Buffer.isBuffer(o))throw new TypeError('"list" argument must be an Array of Buffers');o.copy(u,_)}_+=o.length}return u},Buffer.byteLength=byteLength,Buffer.prototype._isBuffer=!0,Buffer.prototype.swap16=function swap16(){const s=this.length;if(s%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let o=0;oi&&(s+=" ... "),""},w&&(Buffer.prototype[w]=Buffer.prototype.inspect),Buffer.prototype.compare=function compare(s,o,i,u,_){if(isInstance(s,Uint8Array)&&(s=Buffer.from(s,s.offset,s.byteLength)),!Buffer.isBuffer(s))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof s);if(void 0===o&&(o=0),void 0===i&&(i=s?s.length:0),void 0===u&&(u=0),void 0===_&&(_=this.length),o<0||i>s.length||u<0||_>this.length)throw new RangeError("out of range index");if(u>=_&&o>=i)return 0;if(u>=_)return-1;if(o>=i)return 1;if(this===s)return 0;let w=(_>>>=0)-(u>>>=0),x=(i>>>=0)-(o>>>=0);const C=Math.min(w,x),j=this.slice(u,_),L=s.slice(o,i);for(let s=0;s>>=0,isFinite(i)?(i>>>=0,void 0===u&&(u="utf8")):(u=i,i=void 0)}const _=this.length-o;if((void 0===i||i>_)&&(i=_),s.length>0&&(i<0||o<0)||o>this.length)throw new RangeError("Attempt to write outside buffer bounds");u||(u="utf8");let w=!1;for(;;)switch(u){case"hex":return hexWrite(this,s,o,i);case"utf8":case"utf-8":return utf8Write(this,s,o,i);case"ascii":case"latin1":case"binary":return asciiWrite(this,s,o,i);case"base64":return base64Write(this,s,o,i);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return ucs2Write(this,s,o,i);default:if(w)throw new TypeError("Unknown encoding: "+u);u=(""+u).toLowerCase(),w=!0}},Buffer.prototype.toJSON=function toJSON(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const C=4096;function asciiSlice(s,o,i){let u="";i=Math.min(s.length,i);for(let _=o;_u)&&(i=u);let _="";for(let u=o;ui)throw new RangeError("Trying to access beyond buffer length")}function checkInt(s,o,i,u,_,w){if(!Buffer.isBuffer(s))throw new TypeError('"buffer" argument must be a Buffer instance');if(o>_||os.length)throw new RangeError("Index out of range")}function wrtBigUInt64LE(s,o,i,u,_){checkIntBI(o,u,_,s,i,7);let w=Number(o&BigInt(4294967295));s[i++]=w,w>>=8,s[i++]=w,w>>=8,s[i++]=w,w>>=8,s[i++]=w;let x=Number(o>>BigInt(32)&BigInt(4294967295));return s[i++]=x,x>>=8,s[i++]=x,x>>=8,s[i++]=x,x>>=8,s[i++]=x,i}function wrtBigUInt64BE(s,o,i,u,_){checkIntBI(o,u,_,s,i,7);let w=Number(o&BigInt(4294967295));s[i+7]=w,w>>=8,s[i+6]=w,w>>=8,s[i+5]=w,w>>=8,s[i+4]=w;let x=Number(o>>BigInt(32)&BigInt(4294967295));return s[i+3]=x,x>>=8,s[i+2]=x,x>>=8,s[i+1]=x,x>>=8,s[i]=x,i+8}function checkIEEE754(s,o,i,u,_,w){if(i+u>s.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("Index out of range")}function writeFloat(s,o,i,u,w){return o=+o,i>>>=0,w||checkIEEE754(s,0,i,4),_.write(s,o,i,u,23,4),i+4}function writeDouble(s,o,i,u,w){return o=+o,i>>>=0,w||checkIEEE754(s,0,i,8),_.write(s,o,i,u,52,8),i+8}Buffer.prototype.slice=function slice(s,o){const i=this.length;(s=~~s)<0?(s+=i)<0&&(s=0):s>i&&(s=i),(o=void 0===o?i:~~o)<0?(o+=i)<0&&(o=0):o>i&&(o=i),o>>=0,o>>>=0,i||checkOffset(s,o,this.length);let u=this[s],_=1,w=0;for(;++w>>=0,o>>>=0,i||checkOffset(s,o,this.length);let u=this[s+--o],_=1;for(;o>0&&(_*=256);)u+=this[s+--o]*_;return u},Buffer.prototype.readUint8=Buffer.prototype.readUInt8=function readUInt8(s,o){return s>>>=0,o||checkOffset(s,1,this.length),this[s]},Buffer.prototype.readUint16LE=Buffer.prototype.readUInt16LE=function readUInt16LE(s,o){return s>>>=0,o||checkOffset(s,2,this.length),this[s]|this[s+1]<<8},Buffer.prototype.readUint16BE=Buffer.prototype.readUInt16BE=function readUInt16BE(s,o){return s>>>=0,o||checkOffset(s,2,this.length),this[s]<<8|this[s+1]},Buffer.prototype.readUint32LE=Buffer.prototype.readUInt32LE=function readUInt32LE(s,o){return s>>>=0,o||checkOffset(s,4,this.length),(this[s]|this[s+1]<<8|this[s+2]<<16)+16777216*this[s+3]},Buffer.prototype.readUint32BE=Buffer.prototype.readUInt32BE=function readUInt32BE(s,o){return s>>>=0,o||checkOffset(s,4,this.length),16777216*this[s]+(this[s+1]<<16|this[s+2]<<8|this[s+3])},Buffer.prototype.readBigUInt64LE=defineBigIntMethod((function readBigUInt64LE(s){validateNumber(s>>>=0,"offset");const o=this[s],i=this[s+7];void 0!==o&&void 0!==i||boundsError(s,this.length-8);const u=o+256*this[++s]+65536*this[++s]+this[++s]*2**24,_=this[++s]+256*this[++s]+65536*this[++s]+i*2**24;return BigInt(u)+(BigInt(_)<>>=0,"offset");const o=this[s],i=this[s+7];void 0!==o&&void 0!==i||boundsError(s,this.length-8);const u=o*2**24+65536*this[++s]+256*this[++s]+this[++s],_=this[++s]*2**24+65536*this[++s]+256*this[++s]+i;return(BigInt(u)<>>=0,o>>>=0,i||checkOffset(s,o,this.length);let u=this[s],_=1,w=0;for(;++w=_&&(u-=Math.pow(2,8*o)),u},Buffer.prototype.readIntBE=function readIntBE(s,o,i){s>>>=0,o>>>=0,i||checkOffset(s,o,this.length);let u=o,_=1,w=this[s+--u];for(;u>0&&(_*=256);)w+=this[s+--u]*_;return _*=128,w>=_&&(w-=Math.pow(2,8*o)),w},Buffer.prototype.readInt8=function readInt8(s,o){return s>>>=0,o||checkOffset(s,1,this.length),128&this[s]?-1*(255-this[s]+1):this[s]},Buffer.prototype.readInt16LE=function readInt16LE(s,o){s>>>=0,o||checkOffset(s,2,this.length);const i=this[s]|this[s+1]<<8;return 32768&i?4294901760|i:i},Buffer.prototype.readInt16BE=function readInt16BE(s,o){s>>>=0,o||checkOffset(s,2,this.length);const i=this[s+1]|this[s]<<8;return 32768&i?4294901760|i:i},Buffer.prototype.readInt32LE=function readInt32LE(s,o){return s>>>=0,o||checkOffset(s,4,this.length),this[s]|this[s+1]<<8|this[s+2]<<16|this[s+3]<<24},Buffer.prototype.readInt32BE=function readInt32BE(s,o){return s>>>=0,o||checkOffset(s,4,this.length),this[s]<<24|this[s+1]<<16|this[s+2]<<8|this[s+3]},Buffer.prototype.readBigInt64LE=defineBigIntMethod((function readBigInt64LE(s){validateNumber(s>>>=0,"offset");const o=this[s],i=this[s+7];void 0!==o&&void 0!==i||boundsError(s,this.length-8);const u=this[s+4]+256*this[s+5]+65536*this[s+6]+(i<<24);return(BigInt(u)<>>=0,"offset");const o=this[s],i=this[s+7];void 0!==o&&void 0!==i||boundsError(s,this.length-8);const u=(o<<24)+65536*this[++s]+256*this[++s]+this[++s];return(BigInt(u)<>>=0,o||checkOffset(s,4,this.length),_.read(this,s,!0,23,4)},Buffer.prototype.readFloatBE=function readFloatBE(s,o){return s>>>=0,o||checkOffset(s,4,this.length),_.read(this,s,!1,23,4)},Buffer.prototype.readDoubleLE=function readDoubleLE(s,o){return s>>>=0,o||checkOffset(s,8,this.length),_.read(this,s,!0,52,8)},Buffer.prototype.readDoubleBE=function readDoubleBE(s,o){return s>>>=0,o||checkOffset(s,8,this.length),_.read(this,s,!1,52,8)},Buffer.prototype.writeUintLE=Buffer.prototype.writeUIntLE=function writeUIntLE(s,o,i,u){if(s=+s,o>>>=0,i>>>=0,!u){checkInt(this,s,o,i,Math.pow(2,8*i)-1,0)}let _=1,w=0;for(this[o]=255&s;++w>>=0,i>>>=0,!u){checkInt(this,s,o,i,Math.pow(2,8*i)-1,0)}let _=i-1,w=1;for(this[o+_]=255&s;--_>=0&&(w*=256);)this[o+_]=s/w&255;return o+i},Buffer.prototype.writeUint8=Buffer.prototype.writeUInt8=function writeUInt8(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,1,255,0),this[o]=255&s,o+1},Buffer.prototype.writeUint16LE=Buffer.prototype.writeUInt16LE=function writeUInt16LE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,2,65535,0),this[o]=255&s,this[o+1]=s>>>8,o+2},Buffer.prototype.writeUint16BE=Buffer.prototype.writeUInt16BE=function writeUInt16BE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,2,65535,0),this[o]=s>>>8,this[o+1]=255&s,o+2},Buffer.prototype.writeUint32LE=Buffer.prototype.writeUInt32LE=function writeUInt32LE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,4,4294967295,0),this[o+3]=s>>>24,this[o+2]=s>>>16,this[o+1]=s>>>8,this[o]=255&s,o+4},Buffer.prototype.writeUint32BE=Buffer.prototype.writeUInt32BE=function writeUInt32BE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,4,4294967295,0),this[o]=s>>>24,this[o+1]=s>>>16,this[o+2]=s>>>8,this[o+3]=255&s,o+4},Buffer.prototype.writeBigUInt64LE=defineBigIntMethod((function writeBigUInt64LE(s,o=0){return wrtBigUInt64LE(this,s,o,BigInt(0),BigInt("0xffffffffffffffff"))})),Buffer.prototype.writeBigUInt64BE=defineBigIntMethod((function writeBigUInt64BE(s,o=0){return wrtBigUInt64BE(this,s,o,BigInt(0),BigInt("0xffffffffffffffff"))})),Buffer.prototype.writeIntLE=function writeIntLE(s,o,i,u){if(s=+s,o>>>=0,!u){const u=Math.pow(2,8*i-1);checkInt(this,s,o,i,u-1,-u)}let _=0,w=1,x=0;for(this[o]=255&s;++_>>=0,!u){const u=Math.pow(2,8*i-1);checkInt(this,s,o,i,u-1,-u)}let _=i-1,w=1,x=0;for(this[o+_]=255&s;--_>=0&&(w*=256);)s<0&&0===x&&0!==this[o+_+1]&&(x=1),this[o+_]=(s/w|0)-x&255;return o+i},Buffer.prototype.writeInt8=function writeInt8(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,1,127,-128),s<0&&(s=255+s+1),this[o]=255&s,o+1},Buffer.prototype.writeInt16LE=function writeInt16LE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,2,32767,-32768),this[o]=255&s,this[o+1]=s>>>8,o+2},Buffer.prototype.writeInt16BE=function writeInt16BE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,2,32767,-32768),this[o]=s>>>8,this[o+1]=255&s,o+2},Buffer.prototype.writeInt32LE=function writeInt32LE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,4,2147483647,-2147483648),this[o]=255&s,this[o+1]=s>>>8,this[o+2]=s>>>16,this[o+3]=s>>>24,o+4},Buffer.prototype.writeInt32BE=function writeInt32BE(s,o,i){return s=+s,o>>>=0,i||checkInt(this,s,o,4,2147483647,-2147483648),s<0&&(s=4294967295+s+1),this[o]=s>>>24,this[o+1]=s>>>16,this[o+2]=s>>>8,this[o+3]=255&s,o+4},Buffer.prototype.writeBigInt64LE=defineBigIntMethod((function writeBigInt64LE(s,o=0){return wrtBigUInt64LE(this,s,o,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),Buffer.prototype.writeBigInt64BE=defineBigIntMethod((function writeBigInt64BE(s,o=0){return wrtBigUInt64BE(this,s,o,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),Buffer.prototype.writeFloatLE=function writeFloatLE(s,o,i){return writeFloat(this,s,o,!0,i)},Buffer.prototype.writeFloatBE=function writeFloatBE(s,o,i){return writeFloat(this,s,o,!1,i)},Buffer.prototype.writeDoubleLE=function writeDoubleLE(s,o,i){return writeDouble(this,s,o,!0,i)},Buffer.prototype.writeDoubleBE=function writeDoubleBE(s,o,i){return writeDouble(this,s,o,!1,i)},Buffer.prototype.copy=function copy(s,o,i,u){if(!Buffer.isBuffer(s))throw new TypeError("argument should be a Buffer");if(i||(i=0),u||0===u||(u=this.length),o>=s.length&&(o=s.length),o||(o=0),u>0&&u=this.length)throw new RangeError("Index out of range");if(u<0)throw new RangeError("sourceEnd out of bounds");u>this.length&&(u=this.length),s.length-o>>=0,i=void 0===i?this.length:i>>>0,s||(s=0),"number"==typeof s)for(_=o;_=u+4;i-=3)o=`_${s.slice(i-3,i)}${o}`;return`${s.slice(0,i)}${o}`}function checkIntBI(s,o,i,u,_,w){if(s>i||s3?0===o||o===BigInt(0)?`>= 0${u} and < 2${u} ** ${8*(w+1)}${u}`:`>= -(2${u} ** ${8*(w+1)-1}${u}) and < 2 ** ${8*(w+1)-1}${u}`:`>= ${o}${u} and <= ${i}${u}`,new j.ERR_OUT_OF_RANGE("value",_,s)}!function checkBounds(s,o,i){validateNumber(o,"offset"),void 0!==s[o]&&void 0!==s[o+i]||boundsError(o,s.length-(i+1))}(u,_,w)}function validateNumber(s,o){if("number"!=typeof s)throw new j.ERR_INVALID_ARG_TYPE(o,"number",s)}function boundsError(s,o,i){if(Math.floor(s)!==s)throw validateNumber(s,i),new j.ERR_OUT_OF_RANGE(i||"offset","an integer",s);if(o<0)throw new j.ERR_BUFFER_OUT_OF_BOUNDS;throw new j.ERR_OUT_OF_RANGE(i||"offset",`>= ${i?1:0} and <= ${o}`,s)}E("ERR_BUFFER_OUT_OF_BOUNDS",(function(s){return s?`${s} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"}),RangeError),E("ERR_INVALID_ARG_TYPE",(function(s,o){return`The "${s}" argument must be of type number. Received type ${typeof o}`}),TypeError),E("ERR_OUT_OF_RANGE",(function(s,o,i){let u=`The value of "${s}" is out of range.`,_=i;return Number.isInteger(i)&&Math.abs(i)>2**32?_=addNumericalSeparator(String(i)):"bigint"==typeof i&&(_=String(i),(i>BigInt(2)**BigInt(32)||i<-(BigInt(2)**BigInt(32)))&&(_=addNumericalSeparator(_)),_+="n"),u+=` It must be ${o}. Received ${_}`,u}),RangeError);const L=/[^+/0-9A-Za-z-_]/g;function utf8ToBytes(s,o){let i;o=o||1/0;const u=s.length;let _=null;const w=[];for(let x=0;x55295&&i<57344){if(!_){if(i>56319){(o-=3)>-1&&w.push(239,191,189);continue}if(x+1===u){(o-=3)>-1&&w.push(239,191,189);continue}_=i;continue}if(i<56320){(o-=3)>-1&&w.push(239,191,189),_=i;continue}i=65536+(_-55296<<10|i-56320)}else _&&(o-=3)>-1&&w.push(239,191,189);if(_=null,i<128){if((o-=1)<0)break;w.push(i)}else if(i<2048){if((o-=2)<0)break;w.push(i>>6|192,63&i|128)}else if(i<65536){if((o-=3)<0)break;w.push(i>>12|224,i>>6&63|128,63&i|128)}else{if(!(i<1114112))throw new Error("Invalid code point");if((o-=4)<0)break;w.push(i>>18|240,i>>12&63|128,i>>6&63|128,63&i|128)}}return w}function base64ToBytes(s){return u.toByteArray(function base64clean(s){if((s=(s=s.split("=")[0]).trim().replace(L,"")).length<2)return"";for(;s.length%4!=0;)s+="=";return s}(s))}function blitBuffer(s,o,i,u){let _;for(_=0;_=o.length||_>=s.length);++_)o[_+i]=s[_];return _}function isInstance(s,o){return s instanceof o||null!=s&&null!=s.constructor&&null!=s.constructor.name&&s.constructor.name===o.name}function numberIsNaN(s){return s!=s}const B=function(){const s="0123456789abcdef",o=new Array(256);for(let i=0;i<16;++i){const u=16*i;for(let _=0;_<16;++_)o[u+_]=s[i]+s[_]}return o}();function defineBigIntMethod(s){return"undefined"==typeof BigInt?BufferBigIntNotDefined:s}function BufferBigIntNotDefined(){throw new Error("BigInt not supported")}},17965:(s,o,i)=>{"use strict";var u=i(16426),_={"text/plain":"Text","text/html":"Url",default:"Text"};s.exports=function copy(s,o){var i,w,x,C,j,L,B=!1;o||(o={}),i=o.debug||!1;try{if(x=u(),C=document.createRange(),j=document.getSelection(),(L=document.createElement("span")).textContent=s,L.ariaHidden="true",L.style.all="unset",L.style.position="fixed",L.style.top=0,L.style.clip="rect(0, 0, 0, 0)",L.style.whiteSpace="pre",L.style.webkitUserSelect="text",L.style.MozUserSelect="text",L.style.msUserSelect="text",L.style.userSelect="text",L.addEventListener("copy",(function(u){if(u.stopPropagation(),o.format)if(u.preventDefault(),void 0===u.clipboardData){i&&console.warn("unable to use e.clipboardData"),i&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var w=_[o.format]||_.default;window.clipboardData.setData(w,s)}else u.clipboardData.clearData(),u.clipboardData.setData(o.format,s);o.onCopy&&(u.preventDefault(),o.onCopy(u.clipboardData))})),document.body.appendChild(L),C.selectNodeContents(L),j.addRange(C),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");B=!0}catch(u){i&&console.error("unable to copy using execCommand: ",u),i&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(o.format||"text",s),o.onCopy&&o.onCopy(window.clipboardData),B=!0}catch(u){i&&console.error("unable to copy using clipboardData: ",u),i&&console.error("falling back to prompt"),w=function format(s){var o=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C";return s.replace(/#{\s*key\s*}/g,o)}("message"in o?o.message:"Copy to clipboard: #{key}, Enter"),window.prompt(w,s)}}finally{j&&("function"==typeof j.removeRange?j.removeRange(C):j.removeAllRanges()),L&&document.body.removeChild(L),x()}return B}},2205:function(s,o,i){var u;u=void 0!==i.g?i.g:this,s.exports=function(s){if(s.CSS&&s.CSS.escape)return s.CSS.escape;var cssEscape=function(s){if(0==arguments.length)throw new TypeError("`CSS.escape` requires an argument.");for(var o,i=String(s),u=i.length,_=-1,w="",x=i.charCodeAt(0);++_=1&&o<=31||127==o||0==_&&o>=48&&o<=57||1==_&&o>=48&&o<=57&&45==x?"\\"+o.toString(16)+" ":0==_&&1==u&&45==o||!(o>=128||45==o||95==o||o>=48&&o<=57||o>=65&&o<=90||o>=97&&o<=122)?"\\"+i.charAt(_):i.charAt(_):w+="�";return w};return s.CSS||(s.CSS={}),s.CSS.escape=cssEscape,cssEscape}(u)},81919:(s,o,i)=>{"use strict";var u=i(48287).Buffer;function isSpecificValue(s){return s instanceof u||s instanceof Date||s instanceof RegExp}function cloneSpecificValue(s){if(s instanceof u){var o=u.alloc?u.alloc(s.length):new u(s.length);return s.copy(o),o}if(s instanceof Date)return new Date(s.getTime());if(s instanceof RegExp)return new RegExp(s);throw new Error("Unexpected situation")}function deepCloneArray(s){var o=[];return s.forEach((function(s,i){"object"==typeof s&&null!==s?Array.isArray(s)?o[i]=deepCloneArray(s):isSpecificValue(s)?o[i]=cloneSpecificValue(s):o[i]=_({},s):o[i]=s})),o}function safeGetProperty(s,o){return"__proto__"===o?void 0:s[o]}var _=s.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var s,o,i=arguments[0];return Array.prototype.slice.call(arguments,1).forEach((function(u){"object"!=typeof u||null===u||Array.isArray(u)||Object.keys(u).forEach((function(w){return o=safeGetProperty(i,w),(s=safeGetProperty(u,w))===i?void 0:"object"!=typeof s||null===s?void(i[w]=s):Array.isArray(s)?void(i[w]=deepCloneArray(s)):isSpecificValue(s)?void(i[w]=cloneSpecificValue(s)):"object"!=typeof o||null===o||Array.isArray(o)?void(i[w]=_({},s)):void(i[w]=_(o,s))}))})),i}},14744:s=>{"use strict";var o=function isMergeableObject(s){return function isNonNullObject(s){return!!s&&"object"==typeof s}(s)&&!function isSpecial(s){var o=Object.prototype.toString.call(s);return"[object RegExp]"===o||"[object Date]"===o||function isReactElement(s){return s.$$typeof===i}(s)}(s)};var i="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function cloneUnlessOtherwiseSpecified(s,o){return!1!==o.clone&&o.isMergeableObject(s)?deepmerge(function emptyTarget(s){return Array.isArray(s)?[]:{}}(s),s,o):s}function defaultArrayMerge(s,o,i){return s.concat(o).map((function(s){return cloneUnlessOtherwiseSpecified(s,i)}))}function getKeys(s){return Object.keys(s).concat(function getEnumerableOwnPropertySymbols(s){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(s).filter((function(o){return Object.propertyIsEnumerable.call(s,o)})):[]}(s))}function propertyIsOnObject(s,o){try{return o in s}catch(s){return!1}}function mergeObject(s,o,i){var u={};return i.isMergeableObject(s)&&getKeys(s).forEach((function(o){u[o]=cloneUnlessOtherwiseSpecified(s[o],i)})),getKeys(o).forEach((function(_){(function propertyIsUnsafe(s,o){return propertyIsOnObject(s,o)&&!(Object.hasOwnProperty.call(s,o)&&Object.propertyIsEnumerable.call(s,o))})(s,_)||(propertyIsOnObject(s,_)&&i.isMergeableObject(o[_])?u[_]=function getMergeFunction(s,o){if(!o.customMerge)return deepmerge;var i=o.customMerge(s);return"function"==typeof i?i:deepmerge}(_,i)(s[_],o[_],i):u[_]=cloneUnlessOtherwiseSpecified(o[_],i))})),u}function deepmerge(s,i,u){(u=u||{}).arrayMerge=u.arrayMerge||defaultArrayMerge,u.isMergeableObject=u.isMergeableObject||o,u.cloneUnlessOtherwiseSpecified=cloneUnlessOtherwiseSpecified;var _=Array.isArray(i);return _===Array.isArray(s)?_?u.arrayMerge(s,i,u):mergeObject(s,i,u):cloneUnlessOtherwiseSpecified(i,u)}deepmerge.all=function deepmergeAll(s,o){if(!Array.isArray(s))throw new Error("first argument should be an array");return s.reduce((function(s,i){return deepmerge(s,i,o)}),{})};var u=deepmerge;s.exports=u},42838:function(s){s.exports=function(){"use strict";const{entries:s,setPrototypeOf:o,isFrozen:i,getPrototypeOf:u,getOwnPropertyDescriptor:_}=Object;let{freeze:w,seal:x,create:C}=Object,{apply:j,construct:L}="undefined"!=typeof Reflect&&Reflect;w||(w=function freeze(s){return s}),x||(x=function seal(s){return s}),j||(j=function apply(s,o,i){return s.apply(o,i)}),L||(L=function construct(s,o){return new s(...o)});const B=unapply(Array.prototype.forEach),$=unapply(Array.prototype.pop),V=unapply(Array.prototype.push),U=unapply(String.prototype.toLowerCase),z=unapply(String.prototype.toString),Y=unapply(String.prototype.match),Z=unapply(String.prototype.replace),ee=unapply(String.prototype.indexOf),ie=unapply(String.prototype.trim),ae=unapply(Object.prototype.hasOwnProperty),le=unapply(RegExp.prototype.test),ce=unconstruct(TypeError);function unapply(s){return function(o){for(var i=arguments.length,u=new Array(i>1?i-1:0),_=1;_2&&void 0!==arguments[2]?arguments[2]:U;o&&o(s,null);let w=u.length;for(;w--;){let o=u[w];if("string"==typeof o){const s=_(o);s!==o&&(i(u)||(u[w]=s),o=s)}s[o]=!0}return s}function cleanArray(s){for(let o=0;o/gm),$e=x(/\${[\w\W]*}/gm),ze=x(/^data-[\-\w.\u00B7-\uFFFF]/),We=x(/^aria-[\-\w]+$/),He=x(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Ye=x(/^(?:\w+script|data):/i),Xe=x(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Qe=x(/^html$/i),et=x(/^[a-z][.\w]*(-[.\w]+)+$/i);var tt=Object.freeze({__proto__:null,MUSTACHE_EXPR:Re,ERB_EXPR:qe,TMPLIT_EXPR:$e,DATA_ATTR:ze,ARIA_ATTR:We,IS_ALLOWED_URI:He,IS_SCRIPT_OR_DATA:Ye,ATTR_WHITESPACE:Xe,DOCTYPE_NAME:Qe,CUSTOM_ELEMENT:et});const rt={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},nt=function getGlobal(){return"undefined"==typeof window?null:window},st=function _createTrustedTypesPolicy(s,o){if("object"!=typeof s||"function"!=typeof s.createPolicy)return null;let i=null;const u="data-tt-policy-suffix";o&&o.hasAttribute(u)&&(i=o.getAttribute(u));const _="dompurify"+(i?"#"+i:"");try{return s.createPolicy(_,{createHTML:s=>s,createScriptURL:s=>s})}catch(s){return console.warn("TrustedTypes policy "+_+" could not be created."),null}};function createDOMPurify(){let o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:nt();const DOMPurify=s=>createDOMPurify(s);if(DOMPurify.version="3.1.6",DOMPurify.removed=[],!o||!o.document||o.document.nodeType!==rt.document)return DOMPurify.isSupported=!1,DOMPurify;let{document:i}=o;const u=i,_=u.currentScript,{DocumentFragment:x,HTMLTemplateElement:j,Node:L,Element:Re,NodeFilter:qe,NamedNodeMap:$e=o.NamedNodeMap||o.MozNamedAttrMap,HTMLFormElement:ze,DOMParser:We,trustedTypes:Ye}=o,Xe=Re.prototype,et=lookupGetter(Xe,"cloneNode"),ot=lookupGetter(Xe,"remove"),it=lookupGetter(Xe,"nextSibling"),at=lookupGetter(Xe,"childNodes"),lt=lookupGetter(Xe,"parentNode");if("function"==typeof j){const s=i.createElement("template");s.content&&s.content.ownerDocument&&(i=s.content.ownerDocument)}let ct,ut="";const{implementation:pt,createNodeIterator:ht,createDocumentFragment:dt,getElementsByTagName:mt}=i,{importNode:gt}=u;let yt={};DOMPurify.isSupported="function"==typeof s&&"function"==typeof lt&&pt&&void 0!==pt.createHTMLDocument;const{MUSTACHE_EXPR:vt,ERB_EXPR:bt,TMPLIT_EXPR:_t,DATA_ATTR:Et,ARIA_ATTR:wt,IS_SCRIPT_OR_DATA:St,ATTR_WHITESPACE:xt,CUSTOM_ELEMENT:kt}=tt;let{IS_ALLOWED_URI:Ct}=tt,Ot=null;const At=addToSet({},[...pe,...de,...fe,...be,...we]);let jt=null;const It=addToSet({},[...Se,...xe,...Pe,...Te]);let Pt=Object.seal(C(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Mt=null,Tt=null,Nt=!0,Rt=!0,Dt=!1,Lt=!0,Bt=!1,Ft=!0,qt=!1,$t=!1,Vt=!1,Ut=!1,zt=!1,Wt=!1,Kt=!0,Ht=!1;const Jt="user-content-";let Gt=!0,Yt=!1,Xt={},Zt=null;const Qt=addToSet({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let er=null;const tr=addToSet({},["audio","video","img","source","image","track"]);let rr=null;const nr=addToSet({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),sr="http://www.w3.org/1998/Math/MathML",ir="http://www.w3.org/2000/svg",ar="http://www.w3.org/1999/xhtml";let lr=ar,cr=!1,ur=null;const pr=addToSet({},[sr,ir,ar],z);let dr=null;const fr=["application/xhtml+xml","text/html"],mr="text/html";let gr=null,yr=null;const vr=i.createElement("form"),br=function isRegexOrFunction(s){return s instanceof RegExp||s instanceof Function},_r=function _parseConfig(){let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!yr||yr!==s){if(s&&"object"==typeof s||(s={}),s=clone(s),dr=-1===fr.indexOf(s.PARSER_MEDIA_TYPE)?mr:s.PARSER_MEDIA_TYPE,gr="application/xhtml+xml"===dr?z:U,Ot=ae(s,"ALLOWED_TAGS")?addToSet({},s.ALLOWED_TAGS,gr):At,jt=ae(s,"ALLOWED_ATTR")?addToSet({},s.ALLOWED_ATTR,gr):It,ur=ae(s,"ALLOWED_NAMESPACES")?addToSet({},s.ALLOWED_NAMESPACES,z):pr,rr=ae(s,"ADD_URI_SAFE_ATTR")?addToSet(clone(nr),s.ADD_URI_SAFE_ATTR,gr):nr,er=ae(s,"ADD_DATA_URI_TAGS")?addToSet(clone(tr),s.ADD_DATA_URI_TAGS,gr):tr,Zt=ae(s,"FORBID_CONTENTS")?addToSet({},s.FORBID_CONTENTS,gr):Qt,Mt=ae(s,"FORBID_TAGS")?addToSet({},s.FORBID_TAGS,gr):{},Tt=ae(s,"FORBID_ATTR")?addToSet({},s.FORBID_ATTR,gr):{},Xt=!!ae(s,"USE_PROFILES")&&s.USE_PROFILES,Nt=!1!==s.ALLOW_ARIA_ATTR,Rt=!1!==s.ALLOW_DATA_ATTR,Dt=s.ALLOW_UNKNOWN_PROTOCOLS||!1,Lt=!1!==s.ALLOW_SELF_CLOSE_IN_ATTR,Bt=s.SAFE_FOR_TEMPLATES||!1,Ft=!1!==s.SAFE_FOR_XML,qt=s.WHOLE_DOCUMENT||!1,Ut=s.RETURN_DOM||!1,zt=s.RETURN_DOM_FRAGMENT||!1,Wt=s.RETURN_TRUSTED_TYPE||!1,Vt=s.FORCE_BODY||!1,Kt=!1!==s.SANITIZE_DOM,Ht=s.SANITIZE_NAMED_PROPS||!1,Gt=!1!==s.KEEP_CONTENT,Yt=s.IN_PLACE||!1,Ct=s.ALLOWED_URI_REGEXP||He,lr=s.NAMESPACE||ar,Pt=s.CUSTOM_ELEMENT_HANDLING||{},s.CUSTOM_ELEMENT_HANDLING&&br(s.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Pt.tagNameCheck=s.CUSTOM_ELEMENT_HANDLING.tagNameCheck),s.CUSTOM_ELEMENT_HANDLING&&br(s.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Pt.attributeNameCheck=s.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),s.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof s.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Pt.allowCustomizedBuiltInElements=s.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Bt&&(Rt=!1),zt&&(Ut=!0),Xt&&(Ot=addToSet({},we),jt=[],!0===Xt.html&&(addToSet(Ot,pe),addToSet(jt,Se)),!0===Xt.svg&&(addToSet(Ot,de),addToSet(jt,xe),addToSet(jt,Te)),!0===Xt.svgFilters&&(addToSet(Ot,fe),addToSet(jt,xe),addToSet(jt,Te)),!0===Xt.mathMl&&(addToSet(Ot,be),addToSet(jt,Pe),addToSet(jt,Te))),s.ADD_TAGS&&(Ot===At&&(Ot=clone(Ot)),addToSet(Ot,s.ADD_TAGS,gr)),s.ADD_ATTR&&(jt===It&&(jt=clone(jt)),addToSet(jt,s.ADD_ATTR,gr)),s.ADD_URI_SAFE_ATTR&&addToSet(rr,s.ADD_URI_SAFE_ATTR,gr),s.FORBID_CONTENTS&&(Zt===Qt&&(Zt=clone(Zt)),addToSet(Zt,s.FORBID_CONTENTS,gr)),Gt&&(Ot["#text"]=!0),qt&&addToSet(Ot,["html","head","body"]),Ot.table&&(addToSet(Ot,["tbody"]),delete Mt.tbody),s.TRUSTED_TYPES_POLICY){if("function"!=typeof s.TRUSTED_TYPES_POLICY.createHTML)throw ce('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof s.TRUSTED_TYPES_POLICY.createScriptURL)throw ce('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ct=s.TRUSTED_TYPES_POLICY,ut=ct.createHTML("")}else void 0===ct&&(ct=st(Ye,_)),null!==ct&&"string"==typeof ut&&(ut=ct.createHTML(""));w&&w(s),yr=s}},Er=addToSet({},["mi","mo","mn","ms","mtext"]),wr=addToSet({},["foreignobject","annotation-xml"]),Sr=addToSet({},["title","style","font","a","script"]),xr=addToSet({},[...de,...fe,...ye]),kr=addToSet({},[...be,..._e]),Cr=function _checkValidNamespace(s){let o=lt(s);o&&o.tagName||(o={namespaceURI:lr,tagName:"template"});const i=U(s.tagName),u=U(o.tagName);return!!ur[s.namespaceURI]&&(s.namespaceURI===ir?o.namespaceURI===ar?"svg"===i:o.namespaceURI===sr?"svg"===i&&("annotation-xml"===u||Er[u]):Boolean(xr[i]):s.namespaceURI===sr?o.namespaceURI===ar?"math"===i:o.namespaceURI===ir?"math"===i&&wr[u]:Boolean(kr[i]):s.namespaceURI===ar?!(o.namespaceURI===ir&&!wr[u])&&!(o.namespaceURI===sr&&!Er[u])&&!kr[i]&&(Sr[i]||!xr[i]):!("application/xhtml+xml"!==dr||!ur[s.namespaceURI]))},Or=function _forceRemove(s){V(DOMPurify.removed,{element:s});try{lt(s).removeChild(s)}catch(o){ot(s)}},Ar=function _removeAttribute(s,o){try{V(DOMPurify.removed,{attribute:o.getAttributeNode(s),from:o})}catch(s){V(DOMPurify.removed,{attribute:null,from:o})}if(o.removeAttribute(s),"is"===s&&!jt[s])if(Ut||zt)try{Or(o)}catch(s){}else try{o.setAttribute(s,"")}catch(s){}},jr=function _initDocument(s){let o=null,u=null;if(Vt)s=""+s;else{const o=Y(s,/^[\r\n\t ]+/);u=o&&o[0]}"application/xhtml+xml"===dr&&lr===ar&&(s=''+s+"");const _=ct?ct.createHTML(s):s;if(lr===ar)try{o=(new We).parseFromString(_,dr)}catch(s){}if(!o||!o.documentElement){o=pt.createDocument(lr,"template",null);try{o.documentElement.innerHTML=cr?ut:_}catch(s){}}const w=o.body||o.documentElement;return s&&u&&w.insertBefore(i.createTextNode(u),w.childNodes[0]||null),lr===ar?mt.call(o,qt?"html":"body")[0]:qt?o.documentElement:w},Ir=function _createNodeIterator(s){return ht.call(s.ownerDocument||s,s,qe.SHOW_ELEMENT|qe.SHOW_COMMENT|qe.SHOW_TEXT|qe.SHOW_PROCESSING_INSTRUCTION|qe.SHOW_CDATA_SECTION,null)},Pr=function _isClobbered(s){return s instanceof ze&&("string"!=typeof s.nodeName||"string"!=typeof s.textContent||"function"!=typeof s.removeChild||!(s.attributes instanceof $e)||"function"!=typeof s.removeAttribute||"function"!=typeof s.setAttribute||"string"!=typeof s.namespaceURI||"function"!=typeof s.insertBefore||"function"!=typeof s.hasChildNodes)},Mr=function _isNode(s){return"function"==typeof L&&s instanceof L},Tr=function _executeHook(s,o,i){yt[s]&&B(yt[s],(s=>{s.call(DOMPurify,o,i,yr)}))},Nr=function _sanitizeElements(s){let o=null;if(Tr("beforeSanitizeElements",s,null),Pr(s))return Or(s),!0;const i=gr(s.nodeName);if(Tr("uponSanitizeElement",s,{tagName:i,allowedTags:Ot}),s.hasChildNodes()&&!Mr(s.firstElementChild)&&le(/<[/\w]/g,s.innerHTML)&&le(/<[/\w]/g,s.textContent))return Or(s),!0;if(s.nodeType===rt.progressingInstruction)return Or(s),!0;if(Ft&&s.nodeType===rt.comment&&le(/<[/\w]/g,s.data))return Or(s),!0;if(!Ot[i]||Mt[i]){if(!Mt[i]&&Dr(i)){if(Pt.tagNameCheck instanceof RegExp&&le(Pt.tagNameCheck,i))return!1;if(Pt.tagNameCheck instanceof Function&&Pt.tagNameCheck(i))return!1}if(Gt&&!Zt[i]){const o=lt(s)||s.parentNode,i=at(s)||s.childNodes;if(i&&o)for(let u=i.length-1;u>=0;--u){const _=et(i[u],!0);_.__removalCount=(s.__removalCount||0)+1,o.insertBefore(_,it(s))}}return Or(s),!0}return s instanceof Re&&!Cr(s)?(Or(s),!0):"noscript"!==i&&"noembed"!==i&&"noframes"!==i||!le(/<\/no(script|embed|frames)/i,s.innerHTML)?(Bt&&s.nodeType===rt.text&&(o=s.textContent,B([vt,bt,_t],(s=>{o=Z(o,s," ")})),s.textContent!==o&&(V(DOMPurify.removed,{element:s.cloneNode()}),s.textContent=o)),Tr("afterSanitizeElements",s,null),!1):(Or(s),!0)},Rr=function _isValidAttribute(s,o,u){if(Kt&&("id"===o||"name"===o)&&(u in i||u in vr))return!1;if(Rt&&!Tt[o]&&le(Et,o));else if(Nt&&le(wt,o));else if(!jt[o]||Tt[o]){if(!(Dr(s)&&(Pt.tagNameCheck instanceof RegExp&&le(Pt.tagNameCheck,s)||Pt.tagNameCheck instanceof Function&&Pt.tagNameCheck(s))&&(Pt.attributeNameCheck instanceof RegExp&&le(Pt.attributeNameCheck,o)||Pt.attributeNameCheck instanceof Function&&Pt.attributeNameCheck(o))||"is"===o&&Pt.allowCustomizedBuiltInElements&&(Pt.tagNameCheck instanceof RegExp&&le(Pt.tagNameCheck,u)||Pt.tagNameCheck instanceof Function&&Pt.tagNameCheck(u))))return!1}else if(rr[o]);else if(le(Ct,Z(u,xt,"")));else if("src"!==o&&"xlink:href"!==o&&"href"!==o||"script"===s||0!==ee(u,"data:")||!er[s])if(Dt&&!le(St,Z(u,xt,"")));else if(u)return!1;return!0},Dr=function _isBasicCustomElement(s){return"annotation-xml"!==s&&Y(s,kt)},Lr=function _sanitizeAttributes(s){Tr("beforeSanitizeAttributes",s,null);const{attributes:o}=s;if(!o)return;const i={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:jt};let u=o.length;for(;u--;){const _=o[u],{name:w,namespaceURI:x,value:C}=_,j=gr(w);let L="value"===w?C:ie(C);if(i.attrName=j,i.attrValue=L,i.keepAttr=!0,i.forceKeepAttr=void 0,Tr("uponSanitizeAttribute",s,i),L=i.attrValue,Ft&&le(/((--!?|])>)|<\/(style|title)/i,L)){Ar(w,s);continue}if(i.forceKeepAttr)continue;if(Ar(w,s),!i.keepAttr)continue;if(!Lt&&le(/\/>/i,L)){Ar(w,s);continue}Bt&&B([vt,bt,_t],(s=>{L=Z(L,s," ")}));const V=gr(s.nodeName);if(Rr(V,j,L)){if(!Ht||"id"!==j&&"name"!==j||(Ar(w,s),L=Jt+L),ct&&"object"==typeof Ye&&"function"==typeof Ye.getAttributeType)if(x);else switch(Ye.getAttributeType(V,j)){case"TrustedHTML":L=ct.createHTML(L);break;case"TrustedScriptURL":L=ct.createScriptURL(L)}try{x?s.setAttributeNS(x,w,L):s.setAttribute(w,L),Pr(s)?Or(s):$(DOMPurify.removed)}catch(s){}}}Tr("afterSanitizeAttributes",s,null)},Br=function _sanitizeShadowDOM(s){let o=null;const i=Ir(s);for(Tr("beforeSanitizeShadowDOM",s,null);o=i.nextNode();)Tr("uponSanitizeShadowNode",o,null),Nr(o)||(o.content instanceof x&&_sanitizeShadowDOM(o.content),Lr(o));Tr("afterSanitizeShadowDOM",s,null)};return DOMPurify.sanitize=function(s){let o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=null,_=null,w=null,C=null;if(cr=!s,cr&&(s="\x3c!--\x3e"),"string"!=typeof s&&!Mr(s)){if("function"!=typeof s.toString)throw ce("toString is not a function");if("string"!=typeof(s=s.toString()))throw ce("dirty is not a string, aborting")}if(!DOMPurify.isSupported)return s;if($t||_r(o),DOMPurify.removed=[],"string"==typeof s&&(Yt=!1),Yt){if(s.nodeName){const o=gr(s.nodeName);if(!Ot[o]||Mt[o])throw ce("root node is forbidden and cannot be sanitized in-place")}}else if(s instanceof L)i=jr("\x3c!----\x3e"),_=i.ownerDocument.importNode(s,!0),_.nodeType===rt.element&&"BODY"===_.nodeName||"HTML"===_.nodeName?i=_:i.appendChild(_);else{if(!Ut&&!Bt&&!qt&&-1===s.indexOf("<"))return ct&&Wt?ct.createHTML(s):s;if(i=jr(s),!i)return Ut?null:Wt?ut:""}i&&Vt&&Or(i.firstChild);const j=Ir(Yt?s:i);for(;w=j.nextNode();)Nr(w)||(w.content instanceof x&&Br(w.content),Lr(w));if(Yt)return s;if(Ut){if(zt)for(C=dt.call(i.ownerDocument);i.firstChild;)C.appendChild(i.firstChild);else C=i;return(jt.shadowroot||jt.shadowrootmode)&&(C=gt.call(u,C,!0)),C}let $=qt?i.outerHTML:i.innerHTML;return qt&&Ot["!doctype"]&&i.ownerDocument&&i.ownerDocument.doctype&&i.ownerDocument.doctype.name&&le(Qe,i.ownerDocument.doctype.name)&&($="\n"+$),Bt&&B([vt,bt,_t],(s=>{$=Z($,s," ")})),ct&&Wt?ct.createHTML($):$},DOMPurify.setConfig=function(){_r(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),$t=!0},DOMPurify.clearConfig=function(){yr=null,$t=!1},DOMPurify.isValidAttribute=function(s,o,i){yr||_r({});const u=gr(s),_=gr(o);return Rr(u,_,i)},DOMPurify.addHook=function(s,o){"function"==typeof o&&(yt[s]=yt[s]||[],V(yt[s],o))},DOMPurify.removeHook=function(s){if(yt[s])return $(yt[s])},DOMPurify.removeHooks=function(s){yt[s]&&(yt[s]=[])},DOMPurify.removeAllHooks=function(){yt={}},DOMPurify}return createDOMPurify()}()},78004:s=>{"use strict";class SubRange{constructor(s,o){this.low=s,this.high=o,this.length=1+o-s}overlaps(s){return!(this.highs.high)}touches(s){return!(this.high+1s.high)}add(s){return new SubRange(Math.min(this.low,s.low),Math.max(this.high,s.high))}subtract(s){return s.low<=this.low&&s.high>=this.high?[]:s.low>this.low&&s.highs+o.length),0)}add(s,o){var _add=s=>{for(var o=0;o{for(var o=0;o{for(var o=0;o{for(var i=o.low;i<=o.high;)s.push(i),i++;return s}),[])}subranges(){return this.ranges.map((s=>({low:s.low,high:s.high,length:1+s.high-s.low})))}}s.exports=DRange},37007:s=>{"use strict";var o,i="object"==typeof Reflect?Reflect:null,u=i&&"function"==typeof i.apply?i.apply:function ReflectApply(s,o,i){return Function.prototype.apply.call(s,o,i)};o=i&&"function"==typeof i.ownKeys?i.ownKeys:Object.getOwnPropertySymbols?function ReflectOwnKeys(s){return Object.getOwnPropertyNames(s).concat(Object.getOwnPropertySymbols(s))}:function ReflectOwnKeys(s){return Object.getOwnPropertyNames(s)};var _=Number.isNaN||function NumberIsNaN(s){return s!=s};function EventEmitter(){EventEmitter.init.call(this)}s.exports=EventEmitter,s.exports.once=function once(s,o){return new Promise((function(i,u){function errorListener(i){s.removeListener(o,resolver),u(i)}function resolver(){"function"==typeof s.removeListener&&s.removeListener("error",errorListener),i([].slice.call(arguments))}eventTargetAgnosticAddListener(s,o,resolver,{once:!0}),"error"!==o&&function addErrorHandlerIfEventEmitter(s,o,i){"function"==typeof s.on&&eventTargetAgnosticAddListener(s,"error",o,i)}(s,errorListener,{once:!0})}))},EventEmitter.EventEmitter=EventEmitter,EventEmitter.prototype._events=void 0,EventEmitter.prototype._eventsCount=0,EventEmitter.prototype._maxListeners=void 0;var w=10;function checkListener(s){if("function"!=typeof s)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof s)}function _getMaxListeners(s){return void 0===s._maxListeners?EventEmitter.defaultMaxListeners:s._maxListeners}function _addListener(s,o,i,u){var _,w,x;if(checkListener(i),void 0===(w=s._events)?(w=s._events=Object.create(null),s._eventsCount=0):(void 0!==w.newListener&&(s.emit("newListener",o,i.listener?i.listener:i),w=s._events),x=w[o]),void 0===x)x=w[o]=i,++s._eventsCount;else if("function"==typeof x?x=w[o]=u?[i,x]:[x,i]:u?x.unshift(i):x.push(i),(_=_getMaxListeners(s))>0&&x.length>_&&!x.warned){x.warned=!0;var C=new Error("Possible EventEmitter memory leak detected. "+x.length+" "+String(o)+" listeners added. Use emitter.setMaxListeners() to increase limit");C.name="MaxListenersExceededWarning",C.emitter=s,C.type=o,C.count=x.length,function ProcessEmitWarning(s){console&&console.warn&&console.warn(s)}(C)}return s}function onceWrapper(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function _onceWrap(s,o,i){var u={fired:!1,wrapFn:void 0,target:s,type:o,listener:i},_=onceWrapper.bind(u);return _.listener=i,u.wrapFn=_,_}function _listeners(s,o,i){var u=s._events;if(void 0===u)return[];var _=u[o];return void 0===_?[]:"function"==typeof _?i?[_.listener||_]:[_]:i?function unwrapListeners(s){for(var o=new Array(s.length),i=0;i0&&(x=o[0]),x instanceof Error)throw x;var C=new Error("Unhandled error."+(x?" ("+x.message+")":""));throw C.context=x,C}var j=w[s];if(void 0===j)return!1;if("function"==typeof j)u(j,this,o);else{var L=j.length,B=arrayClone(j,L);for(i=0;i=0;w--)if(i[w]===o||i[w].listener===o){x=i[w].listener,_=w;break}if(_<0)return this;0===_?i.shift():function spliceOne(s,o){for(;o+1=0;u--)this.removeListener(s,o[u]);return this},EventEmitter.prototype.listeners=function listeners(s){return _listeners(this,s,!0)},EventEmitter.prototype.rawListeners=function rawListeners(s){return _listeners(this,s,!1)},EventEmitter.listenerCount=function(s,o){return"function"==typeof s.listenerCount?s.listenerCount(o):listenerCount.call(s,o)},EventEmitter.prototype.listenerCount=listenerCount,EventEmitter.prototype.eventNames=function eventNames(){return this._eventsCount>0?o(this._events):[]}},85587:(s,o,i)=>{"use strict";var u=i(26311),_=create(Error);function create(s){return FormattedError.displayName=s.displayName||s.name,FormattedError;function FormattedError(o){return o&&(o=u.apply(null,arguments)),new s(o)}}s.exports=_,_.eval=create(EvalError),_.range=create(RangeError),_.reference=create(ReferenceError),_.syntax=create(SyntaxError),_.type=create(TypeError),_.uri=create(URIError),_.create=create},26311:s=>{!function(){var o;function format(s){for(var o,i,u,_,w=1,x=[].slice.call(arguments),C=0,j=s.length,L="",B=!1,$=!1,nextArg=function(){return x[w++]},slurpNumber=function(){for(var i="";/\d/.test(s[C]);)i+=s[C++],o=s[C];return i.length>0?parseInt(i):null};C{function deepFreeze(s){return s instanceof Map?s.clear=s.delete=s.set=function(){throw new Error("map is read-only")}:s instanceof Set&&(s.add=s.clear=s.delete=function(){throw new Error("set is read-only")}),Object.freeze(s),Object.getOwnPropertyNames(s).forEach((function(o){var i=s[o];"object"!=typeof i||Object.isFrozen(i)||deepFreeze(i)})),s}var o=deepFreeze,i=deepFreeze;o.default=i;class Response{constructor(s){void 0===s.data&&(s.data={}),this.data=s.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function escapeHTML(s){return s.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function inherit(s,...o){const i=Object.create(null);for(const o in s)i[o]=s[o];return o.forEach((function(s){for(const o in s)i[o]=s[o]})),i}const emitsWrappingTags=s=>!!s.kind;class HTMLRenderer{constructor(s,o){this.buffer="",this.classPrefix=o.classPrefix,s.walk(this)}addText(s){this.buffer+=escapeHTML(s)}openNode(s){if(!emitsWrappingTags(s))return;let o=s.kind;s.sublanguage||(o=`${this.classPrefix}${o}`),this.span(o)}closeNode(s){emitsWrappingTags(s)&&(this.buffer+="")}value(){return this.buffer}span(s){this.buffer+=``}}class TokenTree{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(s){this.top.children.push(s)}openNode(s){const o={kind:s,children:[]};this.add(o),this.stack.push(o)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(s){return this.constructor._walk(s,this.rootNode)}static _walk(s,o){return"string"==typeof o?s.addText(o):o.children&&(s.openNode(o),o.children.forEach((o=>this._walk(s,o))),s.closeNode(o)),s}static _collapse(s){"string"!=typeof s&&s.children&&(s.children.every((s=>"string"==typeof s))?s.children=[s.children.join("")]:s.children.forEach((s=>{TokenTree._collapse(s)})))}}class TokenTreeEmitter extends TokenTree{constructor(s){super(),this.options=s}addKeyword(s,o){""!==s&&(this.openNode(o),this.addText(s),this.closeNode())}addText(s){""!==s&&this.add(s)}addSublanguage(s,o){const i=s.root;i.kind=o,i.sublanguage=!0,this.add(i)}toHTML(){return new HTMLRenderer(this,this.options).value()}finalize(){return!0}}function source(s){return s?"string"==typeof s?s:s.source:null}const u=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;const _="[a-zA-Z]\\w*",w="[a-zA-Z_]\\w*",x="\\b\\d+(\\.\\d+)?",C="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",j="\\b(0b[01]+)",L={begin:"\\\\[\\s\\S]",relevance:0},B={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[L]},$={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[L]},V={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},COMMENT=function(s,o,i={}){const u=inherit({className:"comment",begin:s,end:o,contains:[]},i);return u.contains.push(V),u.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),u},U=COMMENT("//","$"),z=COMMENT("/\\*","\\*/"),Y=COMMENT("#","$"),Z={className:"number",begin:x,relevance:0},ee={className:"number",begin:C,relevance:0},ie={className:"number",begin:j,relevance:0},ae={className:"number",begin:x+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},le={begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[L,{begin:/\[/,end:/\]/,relevance:0,contains:[L]}]}]},ce={className:"title",begin:_,relevance:0},pe={className:"title",begin:w,relevance:0},de={begin:"\\.\\s*"+w,relevance:0};var fe=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:_,UNDERSCORE_IDENT_RE:w,NUMBER_RE:x,C_NUMBER_RE:C,BINARY_NUMBER_RE:j,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(s={})=>{const o=/^#![ ]*\//;return s.binary&&(s.begin=function concat(...s){return s.map((s=>source(s))).join("")}(o,/.*\b/,s.binary,/\b.*/)),inherit({className:"meta",begin:o,end:/$/,relevance:0,"on:begin":(s,o)=>{0!==s.index&&o.ignoreMatch()}},s)},BACKSLASH_ESCAPE:L,APOS_STRING_MODE:B,QUOTE_STRING_MODE:$,PHRASAL_WORDS_MODE:V,COMMENT,C_LINE_COMMENT_MODE:U,C_BLOCK_COMMENT_MODE:z,HASH_COMMENT_MODE:Y,NUMBER_MODE:Z,C_NUMBER_MODE:ee,BINARY_NUMBER_MODE:ie,CSS_NUMBER_MODE:ae,REGEXP_MODE:le,TITLE_MODE:ce,UNDERSCORE_TITLE_MODE:pe,METHOD_GUARD:de,END_SAME_AS_BEGIN:function(s){return Object.assign(s,{"on:begin":(s,o)=>{o.data._beginMatch=s[1]},"on:end":(s,o)=>{o.data._beginMatch!==s[1]&&o.ignoreMatch()}})}});function skipIfhasPrecedingDot(s,o){"."===s.input[s.index-1]&&o.ignoreMatch()}function beginKeywords(s,o){o&&s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",s.__beforeBegin=skipIfhasPrecedingDot,s.keywords=s.keywords||s.beginKeywords,delete s.beginKeywords,void 0===s.relevance&&(s.relevance=0))}function compileIllegal(s,o){Array.isArray(s.illegal)&&(s.illegal=function either(...s){return"("+s.map((s=>source(s))).join("|")+")"}(...s.illegal))}function compileMatch(s,o){if(s.match){if(s.begin||s.end)throw new Error("begin & end are not supported with match");s.begin=s.match,delete s.match}}function compileRelevance(s,o){void 0===s.relevance&&(s.relevance=1)}const ye=["of","and","for","in","not","or","if","then","parent","list","value"];function compileKeywords(s,o,i="keyword"){const u={};return"string"==typeof s?compileList(i,s.split(" ")):Array.isArray(s)?compileList(i,s):Object.keys(s).forEach((function(i){Object.assign(u,compileKeywords(s[i],o,i))})),u;function compileList(s,i){o&&(i=i.map((s=>s.toLowerCase()))),i.forEach((function(o){const i=o.split("|");u[i[0]]=[s,scoreForKeyword(i[0],i[1])]}))}}function scoreForKeyword(s,o){return o?Number(o):function commonKeyword(s){return ye.includes(s.toLowerCase())}(s)?0:1}function compileLanguage(s,{plugins:o}){function langRe(o,i){return new RegExp(source(o),"m"+(s.case_insensitive?"i":"")+(i?"g":""))}class MultiRegex{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(s,o){o.position=this.position++,this.matchIndexes[this.matchAt]=o,this.regexes.push([o,s]),this.matchAt+=function countMatchGroups(s){return new RegExp(s.toString()+"|").exec("").length-1}(s)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const s=this.regexes.map((s=>s[1]));this.matcherRe=langRe(function join(s,o="|"){let i=0;return s.map((s=>{i+=1;const o=i;let _=source(s),w="";for(;_.length>0;){const s=u.exec(_);if(!s){w+=_;break}w+=_.substring(0,s.index),_=_.substring(s.index+s[0].length),"\\"===s[0][0]&&s[1]?w+="\\"+String(Number(s[1])+o):(w+=s[0],"("===s[0]&&i++)}return w})).map((s=>`(${s})`)).join(o)}(s),!0),this.lastIndex=0}exec(s){this.matcherRe.lastIndex=this.lastIndex;const o=this.matcherRe.exec(s);if(!o)return null;const i=o.findIndex(((s,o)=>o>0&&void 0!==s)),u=this.matchIndexes[i];return o.splice(0,i),Object.assign(o,u)}}class ResumableMultiRegex{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(s){if(this.multiRegexes[s])return this.multiRegexes[s];const o=new MultiRegex;return this.rules.slice(s).forEach((([s,i])=>o.addRule(s,i))),o.compile(),this.multiRegexes[s]=o,o}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(s,o){this.rules.push([s,o]),"begin"===o.type&&this.count++}exec(s){const o=this.getMatcher(this.regexIndex);o.lastIndex=this.lastIndex;let i=o.exec(s);if(this.resumingScanAtSamePosition())if(i&&i.index===this.lastIndex);else{const o=this.getMatcher(0);o.lastIndex=this.lastIndex+1,i=o.exec(s)}return i&&(this.regexIndex+=i.position+1,this.regexIndex===this.count&&this.considerAll()),i}}if(s.compilerExtensions||(s.compilerExtensions=[]),s.contains&&s.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return s.classNameAliases=inherit(s.classNameAliases||{}),function compileMode(o,i){const u=o;if(o.isCompiled)return u;[compileMatch].forEach((s=>s(o,i))),s.compilerExtensions.forEach((s=>s(o,i))),o.__beforeBegin=null,[beginKeywords,compileIllegal,compileRelevance].forEach((s=>s(o,i))),o.isCompiled=!0;let _=null;if("object"==typeof o.keywords&&(_=o.keywords.$pattern,delete o.keywords.$pattern),o.keywords&&(o.keywords=compileKeywords(o.keywords,s.case_insensitive)),o.lexemes&&_)throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return _=_||o.lexemes||/\w+/,u.keywordPatternRe=langRe(_,!0),i&&(o.begin||(o.begin=/\B|\b/),u.beginRe=langRe(o.begin),o.endSameAsBegin&&(o.end=o.begin),o.end||o.endsWithParent||(o.end=/\B|\b/),o.end&&(u.endRe=langRe(o.end)),u.terminatorEnd=source(o.end)||"",o.endsWithParent&&i.terminatorEnd&&(u.terminatorEnd+=(o.end?"|":"")+i.terminatorEnd)),o.illegal&&(u.illegalRe=langRe(o.illegal)),o.contains||(o.contains=[]),o.contains=[].concat(...o.contains.map((function(s){return function expandOrCloneMode(s){s.variants&&!s.cachedVariants&&(s.cachedVariants=s.variants.map((function(o){return inherit(s,{variants:null},o)})));if(s.cachedVariants)return s.cachedVariants;if(dependencyOnParent(s))return inherit(s,{starts:s.starts?inherit(s.starts):null});if(Object.isFrozen(s))return inherit(s);return s}("self"===s?o:s)}))),o.contains.forEach((function(s){compileMode(s,u)})),o.starts&&compileMode(o.starts,i),u.matcher=function buildModeRegex(s){const o=new ResumableMultiRegex;return s.contains.forEach((s=>o.addRule(s.begin,{rule:s,type:"begin"}))),s.terminatorEnd&&o.addRule(s.terminatorEnd,{type:"end"}),s.illegal&&o.addRule(s.illegal,{type:"illegal"}),o}(u),u}(s)}function dependencyOnParent(s){return!!s&&(s.endsWithParent||dependencyOnParent(s.starts))}function BuildVuePlugin(s){const o={props:["language","code","autodetect"],data:function(){return{detectedLanguage:"",unknownLanguage:!1}},computed:{className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){if(!this.autoDetect&&!s.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`),this.unknownLanguage=!0,escapeHTML(this.code);let o={};return this.autoDetect?(o=s.highlightAuto(this.code),this.detectedLanguage=o.language):(o=s.highlight(this.language,this.code,this.ignoreIllegals),this.detectedLanguage=this.language),o.value},autoDetect(){return!this.language||function hasValueOrEmptyAttribute(s){return Boolean(s||""===s)}(this.autodetect)},ignoreIllegals:()=>!0},render(s){return s("pre",{},[s("code",{class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{Component:o,VuePlugin:{install(s){s.component("highlightjs",o)}}}}const be={"after:highlightElement":({el:s,result:o,text:i})=>{const u=nodeStream(s);if(!u.length)return;const _=document.createElement("div");_.innerHTML=o.value,o.value=function mergeStreams(s,o,i){let u=0,_="";const w=[];function selectStream(){return s.length&&o.length?s[0].offset!==o[0].offset?s[0].offset"}function close(s){_+=""+tag(s)+">"}function render(s){("start"===s.event?open:close)(s.node)}for(;s.length||o.length;){let o=selectStream();if(_+=escapeHTML(i.substring(u,o[0].offset)),u=o[0].offset,o===s){w.reverse().forEach(close);do{render(o.splice(0,1)[0]),o=selectStream()}while(o===s&&o.length&&o[0].offset===u);w.reverse().forEach(open)}else"start"===o[0].event?w.push(o[0].node):w.pop(),render(o.splice(0,1)[0])}return _+escapeHTML(i.substr(u))}(u,nodeStream(_),i)}};function tag(s){return s.nodeName.toLowerCase()}function nodeStream(s){const o=[];return function _nodeStream(s,i){for(let u=s.firstChild;u;u=u.nextSibling)3===u.nodeType?i+=u.nodeValue.length:1===u.nodeType&&(o.push({event:"start",offset:i,node:u}),i=_nodeStream(u,i),tag(u).match(/br|hr|img|input/)||o.push({event:"stop",offset:i,node:u}));return i}(s,0),o}const _e={},error=s=>{console.error(s)},warn=(s,...o)=>{console.log(`WARN: ${s}`,...o)},deprecated=(s,o)=>{_e[`${s}/${o}`]||(console.log(`Deprecated as of ${s}. ${o}`),_e[`${s}/${o}`]=!0)},we=escapeHTML,Se=inherit,xe=Symbol("nomatch");var Pe=function(s){const i=Object.create(null),u=Object.create(null),_=[];let w=!0;const x=/(^(<[^>]+>|\t|)+|\n)/gm,C="Could not find the language '{}', did you forget to load/include a language module?",j={disableAutodetect:!0,name:"Plain text",contains:[]};let L={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:TokenTreeEmitter};function shouldNotHighlight(s){return L.noHighlightRe.test(s)}function highlight(s,o,i,u){let _="",w="";"object"==typeof o?(_=s,i=o.ignoreIllegals,w=o.language,u=void 0):(deprecated("10.7.0","highlight(lang, code, ...args) has been deprecated."),deprecated("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),w=s,_=o);const x={code:_,language:w};fire("before:highlight",x);const C=x.result?x.result:_highlight(x.language,x.code,i,u);return C.code=x.code,fire("after:highlight",C),C}function _highlight(s,o,u,x){function keywordData(s,o){const i=B.case_insensitive?o[0].toLowerCase():o[0];return Object.prototype.hasOwnProperty.call(s.keywords,i)&&s.keywords[i]}function processBuffer(){null!=U.subLanguage?function processSubLanguage(){if(""===Z)return;let s=null;if("string"==typeof U.subLanguage){if(!i[U.subLanguage])return void Y.addText(Z);s=_highlight(U.subLanguage,Z,!0,z[U.subLanguage]),z[U.subLanguage]=s.top}else s=highlightAuto(Z,U.subLanguage.length?U.subLanguage:null);U.relevance>0&&(ee+=s.relevance),Y.addSublanguage(s.emitter,s.language)}():function processKeywords(){if(!U.keywords)return void Y.addText(Z);let s=0;U.keywordPatternRe.lastIndex=0;let o=U.keywordPatternRe.exec(Z),i="";for(;o;){i+=Z.substring(s,o.index);const u=keywordData(U,o);if(u){const[s,_]=u;if(Y.addText(i),i="",ee+=_,s.startsWith("_"))i+=o[0];else{const i=B.classNameAliases[s]||s;Y.addKeyword(o[0],i)}}else i+=o[0];s=U.keywordPatternRe.lastIndex,o=U.keywordPatternRe.exec(Z)}i+=Z.substr(s),Y.addText(i)}(),Z=""}function startNewMode(s){return s.className&&Y.openNode(B.classNameAliases[s.className]||s.className),U=Object.create(s,{parent:{value:U}}),U}function endOfMode(s,o,i){let u=function startsWith(s,o){const i=s&&s.exec(o);return i&&0===i.index}(s.endRe,i);if(u){if(s["on:end"]){const i=new Response(s);s["on:end"](o,i),i.isMatchIgnored&&(u=!1)}if(u){for(;s.endsParent&&s.parent;)s=s.parent;return s}}if(s.endsWithParent)return endOfMode(s.parent,o,i)}function doIgnore(s){return 0===U.matcher.regexIndex?(Z+=s[0],1):(le=!0,0)}function doBeginMatch(s){const o=s[0],i=s.rule,u=new Response(i),_=[i.__beforeBegin,i["on:begin"]];for(const i of _)if(i&&(i(s,u),u.isMatchIgnored))return doIgnore(o);return i&&i.endSameAsBegin&&(i.endRe=function escape(s){return new RegExp(s.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}(o)),i.skip?Z+=o:(i.excludeBegin&&(Z+=o),processBuffer(),i.returnBegin||i.excludeBegin||(Z=o)),startNewMode(i),i.returnBegin?0:o.length}function doEndMatch(s){const i=s[0],u=o.substr(s.index),_=endOfMode(U,s,u);if(!_)return xe;const w=U;w.skip?Z+=i:(w.returnEnd||w.excludeEnd||(Z+=i),processBuffer(),w.excludeEnd&&(Z=i));do{U.className&&Y.closeNode(),U.skip||U.subLanguage||(ee+=U.relevance),U=U.parent}while(U!==_.parent);return _.starts&&(_.endSameAsBegin&&(_.starts.endRe=_.endRe),startNewMode(_.starts)),w.returnEnd?0:i.length}let j={};function processLexeme(i,_){const x=_&&_[0];if(Z+=i,null==x)return processBuffer(),0;if("begin"===j.type&&"end"===_.type&&j.index===_.index&&""===x){if(Z+=o.slice(_.index,_.index+1),!w){const o=new Error("0 width match regex");throw o.languageName=s,o.badRule=j.rule,o}return 1}if(j=_,"begin"===_.type)return doBeginMatch(_);if("illegal"===_.type&&!u){const s=new Error('Illegal lexeme "'+x+'" for mode "'+(U.className||"")+'"');throw s.mode=U,s}if("end"===_.type){const s=doEndMatch(_);if(s!==xe)return s}if("illegal"===_.type&&""===x)return 1;if(ae>1e5&&ae>3*_.index){throw new Error("potential infinite loop, way more iterations than matches")}return Z+=x,x.length}const B=getLanguage(s);if(!B)throw error(C.replace("{}",s)),new Error('Unknown language: "'+s+'"');const $=compileLanguage(B,{plugins:_});let V="",U=x||$;const z={},Y=new L.__emitter(L);!function processContinuations(){const s=[];for(let o=U;o!==B;o=o.parent)o.className&&s.unshift(o.className);s.forEach((s=>Y.openNode(s)))}();let Z="",ee=0,ie=0,ae=0,le=!1;try{for(U.matcher.considerAll();;){ae++,le?le=!1:U.matcher.considerAll(),U.matcher.lastIndex=ie;const s=U.matcher.exec(o);if(!s)break;const i=processLexeme(o.substring(ie,s.index),s);ie=s.index+i}return processLexeme(o.substr(ie)),Y.closeAllNodes(),Y.finalize(),V=Y.toHTML(),{relevance:Math.floor(ee),value:V,language:s,illegal:!1,emitter:Y,top:U}}catch(i){if(i.message&&i.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:i.message,context:o.slice(ie-100,ie+100),mode:i.mode},sofar:V,relevance:0,value:we(o),emitter:Y};if(w)return{illegal:!1,relevance:0,value:we(o),emitter:Y,language:s,top:U,errorRaised:i};throw i}}function highlightAuto(s,o){o=o||L.languages||Object.keys(i);const u=function justTextHighlightResult(s){const o={relevance:0,emitter:new L.__emitter(L),value:we(s),illegal:!1,top:j};return o.emitter.addText(s),o}(s),_=o.filter(getLanguage).filter(autoDetection).map((o=>_highlight(o,s,!1)));_.unshift(u);const w=_.sort(((s,o)=>{if(s.relevance!==o.relevance)return o.relevance-s.relevance;if(s.language&&o.language){if(getLanguage(s.language).supersetOf===o.language)return 1;if(getLanguage(o.language).supersetOf===s.language)return-1}return 0})),[x,C]=w,B=x;return B.second_best=C,B}const B={"before:highlightElement":({el:s})=>{L.useBR&&(s.innerHTML=s.innerHTML.replace(/\n/g,"").replace(/ /g,"\n"))},"after:highlightElement":({result:s})=>{L.useBR&&(s.value=s.value.replace(/\n/g," "))}},$=/^(<[^>]+>|\t)+/gm,V={"after:highlightElement":({result:s})=>{L.tabReplace&&(s.value=s.value.replace($,(s=>s.replace(/\t/g,L.tabReplace))))}};function highlightElement(s){let o=null;const i=function blockLanguage(s){let o=s.className+" ";o+=s.parentNode?s.parentNode.className:"";const i=L.languageDetectRe.exec(o);if(i){const o=getLanguage(i[1]);return o||(warn(C.replace("{}",i[1])),warn("Falling back to no-highlight mode for this block.",s)),o?i[1]:"no-highlight"}return o.split(/\s+/).find((s=>shouldNotHighlight(s)||getLanguage(s)))}(s);if(shouldNotHighlight(i))return;fire("before:highlightElement",{el:s,language:i}),o=s;const _=o.textContent,w=i?highlight(_,{language:i,ignoreIllegals:!0}):highlightAuto(_);fire("after:highlightElement",{el:s,result:w,text:_}),s.innerHTML=w.value,function updateClassName(s,o,i){const _=o?u[o]:i;s.classList.add("hljs"),_&&s.classList.add(_)}(s,i,w.language),s.result={language:w.language,re:w.relevance,relavance:w.relevance},w.second_best&&(s.second_best={language:w.second_best.language,re:w.second_best.relevance,relavance:w.second_best.relevance})}const initHighlighting=()=>{if(initHighlighting.called)return;initHighlighting.called=!0,deprecated("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead.");document.querySelectorAll("pre code").forEach(highlightElement)};let U=!1;function highlightAll(){if("loading"===document.readyState)return void(U=!0);document.querySelectorAll("pre code").forEach(highlightElement)}function getLanguage(s){return s=(s||"").toLowerCase(),i[s]||i[u[s]]}function registerAliases(s,{languageName:o}){"string"==typeof s&&(s=[s]),s.forEach((s=>{u[s.toLowerCase()]=o}))}function autoDetection(s){const o=getLanguage(s);return o&&!o.disableAutodetect}function fire(s,o){const i=s;_.forEach((function(s){s[i]&&s[i](o)}))}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(function boot(){U&&highlightAll()}),!1),Object.assign(s,{highlight,highlightAuto,highlightAll,fixMarkup:function deprecateFixMarkup(s){return deprecated("10.2.0","fixMarkup will be removed entirely in v11.0"),deprecated("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),function fixMarkup(s){return L.tabReplace||L.useBR?s.replace(x,(s=>"\n"===s?L.useBR?" ":s:L.tabReplace?s.replace(/\t/g,L.tabReplace):s)):s}(s)},highlightElement,highlightBlock:function deprecateHighlightBlock(s){return deprecated("10.7.0","highlightBlock will be removed entirely in v12.0"),deprecated("10.7.0","Please use highlightElement now."),highlightElement(s)},configure:function configure(s){s.useBR&&(deprecated("10.3.0","'useBR' will be removed entirely in v11.0"),deprecated("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),L=Se(L,s)},initHighlighting,initHighlightingOnLoad:function initHighlightingOnLoad(){deprecated("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),U=!0},registerLanguage:function registerLanguage(o,u){let _=null;try{_=u(s)}catch(s){if(error("Language definition for '{}' could not be registered.".replace("{}",o)),!w)throw s;error(s),_=j}_.name||(_.name=o),i[o]=_,_.rawDefinition=u.bind(null,s),_.aliases&®isterAliases(_.aliases,{languageName:o})},unregisterLanguage:function unregisterLanguage(s){delete i[s];for(const o of Object.keys(u))u[o]===s&&delete u[o]},listLanguages:function listLanguages(){return Object.keys(i)},getLanguage,registerAliases,requireLanguage:function requireLanguage(s){deprecated("10.4.0","requireLanguage will be removed entirely in v11."),deprecated("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844");const o=getLanguage(s);if(o)return o;throw new Error("The '{}' language is required, but not loaded.".replace("{}",s))},autoDetection,inherit:Se,addPlugin:function addPlugin(s){!function upgradePluginAPI(s){s["before:highlightBlock"]&&!s["before:highlightElement"]&&(s["before:highlightElement"]=o=>{s["before:highlightBlock"](Object.assign({block:o.el},o))}),s["after:highlightBlock"]&&!s["after:highlightElement"]&&(s["after:highlightElement"]=o=>{s["after:highlightBlock"](Object.assign({block:o.el},o))})}(s),_.push(s)},vuePlugin:BuildVuePlugin(s).VuePlugin}),s.debugMode=function(){w=!1},s.safeMode=function(){w=!0},s.versionString="10.7.3";for(const s in fe)"object"==typeof fe[s]&&o(fe[s]);return Object.assign(s,fe),s.addPlugin(B),s.addPlugin(be),s.addPlugin(V),s}({});s.exports=Pe},35344:s=>{function concat(...s){return s.map((s=>function source(s){return s?"string"==typeof s?s:s.source:null}(s))).join("")}s.exports=function bash(s){const o={},i={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[o]}]};Object.assign(o,{className:"variable",variants:[{begin:concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},i]});const u={className:"subst",begin:/\$\(/,end:/\)/,contains:[s.BACKSLASH_ESCAPE]},_={begin:/<<-?\s*(?=\w+)/,starts:{contains:[s.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},w={className:"string",begin:/"/,end:/"/,contains:[s.BACKSLASH_ESCAPE,o,u]};u.contains.push(w);const x={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},s.NUMBER_MODE,o]},C=s.SHEBANG({binary:`(${["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"].join("|")})`,relevance:10}),j={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[s.inherit(s.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"},contains:[C,s.SHEBANG(),j,x,s.HASH_COMMENT_MODE,_,w,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},o]}}},73402:s=>{function concat(...s){return s.map((s=>function source(s){return s?"string"==typeof s?s:s.source:null}(s))).join("")}s.exports=function http(s){const o="HTTP/(2|1\\.[01])",i={className:"attribute",begin:concat("^",/[A-Za-z][A-Za-z0-9-]*/,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},u=[i,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+o+" \\d{3})",end:/$/,contains:[{className:"meta",begin:o},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:u}},{begin:"(?=^[A-Z]+ (.*?) "+o+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:o},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:u}},s.inherit(i,{relevance:0})]}}},95089:s=>{const o="[A-Za-z$_][0-9A-Za-z$_]*",i=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],u=["true","false","null","undefined","NaN","Infinity"],_=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function lookahead(s){return concat("(?=",s,")")}function concat(...s){return s.map((s=>function source(s){return s?"string"==typeof s?s:s.source:null}(s))).join("")}s.exports=function javascript(s){const w=o,x="<>",C=">",j={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(s,o)=>{const i=s[0].length+s.index,u=s.input[i];"<"!==u?">"===u&&(((s,{after:o})=>{const i=""+s[0].slice(1);return-1!==s.input.indexOf(i,o)})(s,{after:i})||o.ignoreMatch()):o.ignoreMatch()}},L={$pattern:o,keyword:i,literal:u,built_in:_},B="[0-9](_?[0-9])*",$=`\\.(${B})`,V="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",U={className:"number",variants:[{begin:`(\\b(${V})((${$})|\\.)?|(${$}))[eE][+-]?(${B})\\b`},{begin:`\\b(${V})\\b((${$})\\b|\\.)?|(${$})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},z={className:"subst",begin:"\\$\\{",end:"\\}",keywords:L,contains:[]},Y={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[s.BACKSLASH_ESCAPE,z],subLanguage:"xml"}},Z={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[s.BACKSLASH_ESCAPE,z],subLanguage:"css"}},ee={className:"string",begin:"`",end:"`",contains:[s.BACKSLASH_ESCAPE,z]},ie={className:"comment",variants:[s.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:w+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),s.C_BLOCK_COMMENT_MODE,s.C_LINE_COMMENT_MODE]},ae=[s.APOS_STRING_MODE,s.QUOTE_STRING_MODE,Y,Z,ee,U,s.REGEXP_MODE];z.contains=ae.concat({begin:/\{/,end:/\}/,keywords:L,contains:["self"].concat(ae)});const le=[].concat(ie,z.contains),ce=le.concat([{begin:/\(/,end:/\)/,keywords:L,contains:["self"].concat(le)}]),pe={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:L,contains:ce};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:L,exports:{PARAMS_CONTAINS:ce},illegal:/#(?![$_A-z])/,contains:[s.SHEBANG({label:"shebang",binary:"node",relevance:5}),{label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},s.APOS_STRING_MODE,s.QUOTE_STRING_MODE,Y,Z,ee,ie,U,{begin:concat(/[{,\n]\s*/,lookahead(concat(/(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,w+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:w+lookahead("\\s*:"),relevance:0}]},{begin:"("+s.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[ie,s.REGEXP_MODE,{className:"function",begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+s.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:s.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:L,contains:ce}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:x,end:C},{begin:j.begin,"on:begin":j.isTrulyOpeningTag,end:j.end}],subLanguage:"xml",contains:[{begin:j.begin,end:j.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/,excludeEnd:!0,keywords:L,contains:["self",s.inherit(s.TITLE_MODE,{begin:w}),pe],illegal:/%/},{beginKeywords:"while if switch catch for"},{className:"function",begin:s.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,contains:[pe,s.inherit(s.TITLE_MODE,{begin:w})]},{variants:[{begin:"\\."+w},{begin:"\\$"+w}],relevance:0},{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"[\]]/,contains:[{beginKeywords:"extends"},s.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/,end:/[{;]/,excludeEnd:!0,contains:[s.inherit(s.TITLE_MODE,{begin:w}),"self",pe]},{begin:"(get|set)\\s+(?="+w+"\\()",end:/\{/,keywords:"get set",contains:[s.inherit(s.TITLE_MODE,{begin:w}),{begin:/\(\)/},pe]},{begin:/\$[(.]/}]}}},65772:s=>{s.exports=function json(s){const o={literal:"true false null"},i=[s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE],u=[s.QUOTE_STRING_MODE,s.C_NUMBER_MODE],_={end:",",endsWithParent:!0,excludeEnd:!0,contains:u,keywords:o},w={begin:/\{/,end:/\}/,contains:[{className:"attr",begin:/"/,end:/"/,contains:[s.BACKSLASH_ESCAPE],illegal:"\\n"},s.inherit(_,{begin:/:/})].concat(i),illegal:"\\S"},x={begin:"\\[",end:"\\]",contains:[s.inherit(_)],illegal:"\\S"};return u.push(w,x),i.forEach((function(s){u.push(s)})),{name:"JSON",contains:u,keywords:o,illegal:"\\S"}}},26571:s=>{s.exports=function powershell(s){const o={$pattern:/-?[A-z\.\-]+\b/,keyword:"if else foreach return do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch hidden static parameter",built_in:"ac asnp cat cd CFS chdir clc clear clhy cli clp cls clv cnsn compare copy cp cpi cpp curl cvpa dbp del diff dir dnsn ebp echo|0 epal epcsv epsn erase etsn exsn fc fhx fl ft fw gal gbp gc gcb gci gcm gcs gdr gerr ghy gi gin gjb gl gm gmo gp gps gpv group gsn gsnp gsv gtz gu gv gwmi h history icm iex ihy ii ipal ipcsv ipmo ipsn irm ise iwmi iwr kill lp ls man md measure mi mount move mp mv nal ndr ni nmo npssc nsn nv ogv oh popd ps pushd pwd r rbp rcjb rcsn rd rdr ren ri rjb rm rmdir rmo rni rnp rp rsn rsnp rujb rv rvpa rwmi sajb sal saps sasv sbp sc scb select set shcm si sl sleep sls sort sp spjb spps spsv start stz sujb sv swmi tee trcm type wget where wjb write"},i={begin:"`[\\s\\S]",relevance:0},u={className:"variable",variants:[{begin:/\$\B/},{className:"keyword",begin:/\$this/},{begin:/\$[\w\d][\w\d_:]*/}]},_={className:"string",variants:[{begin:/"/,end:/"/},{begin:/@"/,end:/^"@/}],contains:[i,u,{className:"variable",begin:/\$[A-z]/,end:/[^A-z]/}]},w={className:"string",variants:[{begin:/'/,end:/'/},{begin:/@'/,end:/^'@/}]},x=s.inherit(s.COMMENT(null,null),{variants:[{begin:/#/,end:/$/},{begin:/<#/,end:/#>/}],contains:[{className:"doctag",variants:[{begin:/\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/},{begin:/\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/}]}]}),C={className:"built_in",variants:[{begin:"(".concat("Add|Clear|Close|Copy|Enter|Exit|Find|Format|Get|Hide|Join|Lock|Move|New|Open|Optimize|Pop|Push|Redo|Remove|Rename|Reset|Resize|Search|Select|Set|Show|Skip|Split|Step|Switch|Undo|Unlock|Watch|Backup|Checkpoint|Compare|Compress|Convert|ConvertFrom|ConvertTo|Dismount|Edit|Expand|Export|Group|Import|Initialize|Limit|Merge|Mount|Out|Publish|Restore|Save|Sync|Unpublish|Update|Approve|Assert|Build|Complete|Confirm|Deny|Deploy|Disable|Enable|Install|Invoke|Register|Request|Restart|Resume|Start|Stop|Submit|Suspend|Uninstall|Unregister|Wait|Debug|Measure|Ping|Repair|Resolve|Test|Trace|Connect|Disconnect|Read|Receive|Send|Write|Block|Grant|Protect|Revoke|Unblock|Unprotect|Use|ForEach|Sort|Tee|Where",")+(-)[\\w\\d]+")}]},j={className:"class",beginKeywords:"class enum",end:/\s*[{]/,excludeEnd:!0,relevance:0,contains:[s.TITLE_MODE]},L={className:"function",begin:/function\s+/,end:/\s*\{|$/,excludeEnd:!0,returnBegin:!0,relevance:0,contains:[{begin:"function",relevance:0,className:"keyword"},{className:"title",begin:/\w[\w\d]*((-)[\w\d]+)*/,relevance:0},{begin:/\(/,end:/\)/,className:"params",relevance:0,contains:[u]}]},B={begin:/using\s/,end:/$/,returnBegin:!0,contains:[_,w,{className:"keyword",begin:/(using|assembly|command|module|namespace|type)/}]},$={variants:[{className:"operator",begin:"(".concat("-and|-as|-band|-bnot|-bor|-bxor|-casesensitive|-ccontains|-ceq|-cge|-cgt|-cle|-clike|-clt|-cmatch|-cne|-cnotcontains|-cnotlike|-cnotmatch|-contains|-creplace|-csplit|-eq|-exact|-f|-file|-ge|-gt|-icontains|-ieq|-ige|-igt|-ile|-ilike|-ilt|-imatch|-in|-ine|-inotcontains|-inotlike|-inotmatch|-ireplace|-is|-isnot|-isplit|-join|-le|-like|-lt|-match|-ne|-not|-notcontains|-notin|-notlike|-notmatch|-or|-regex|-replace|-shl|-shr|-split|-wildcard|-xor",")\\b")},{className:"literal",begin:/(-)[\w\d]+/,relevance:0}]},V={className:"function",begin:/\[.*\]\s*[\w]+[ ]??\(/,end:/$/,returnBegin:!0,relevance:0,contains:[{className:"keyword",begin:"(".concat(o.keyword.toString().replace(/\s/g,"|"),")\\b"),endsParent:!0,relevance:0},s.inherit(s.TITLE_MODE,{endsParent:!0})]},U=[V,x,i,s.NUMBER_MODE,_,w,C,u,{className:"literal",begin:/\$(null|true|false)\b/},{className:"selector-tag",begin:/@\B/,relevance:0}],z={begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[].concat("self",U,{begin:"("+["string","char","byte","int","long","bool","decimal","single","double","DateTime","xml","array","hashtable","void"].join("|")+")",className:"built_in",relevance:0},{className:"type",begin:/[\.\w\d]+/,relevance:0})};return V.contains.unshift(z),{name:"PowerShell",aliases:["ps","ps1"],case_insensitive:!0,keywords:o,contains:U.concat(j,L,B,$,z)}}},17285:s=>{function source(s){return s?"string"==typeof s?s:s.source:null}function lookahead(s){return concat("(?=",s,")")}function concat(...s){return s.map((s=>source(s))).join("")}function either(...s){return"("+s.map((s=>source(s))).join("|")+")"}s.exports=function xml(s){const o=concat(/[A-Z_]/,function optional(s){return concat("(",s,")?")}(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),i={className:"symbol",begin:/&[a-z]+;|[0-9]+;|[a-f0-9]+;/},u={begin:/\s/,contains:[{className:"meta-keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},_=s.inherit(u,{begin:/\(/,end:/\)/}),w=s.inherit(s.APOS_STRING_MODE,{className:"meta-string"}),x=s.inherit(s.QUOTE_STRING_MODE,{className:"meta-string"}),C={endsWithParent:!0,illegal:/,relevance:0,contains:[{className:"attr",begin:/[A-Za-z0-9._:-]+/,relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[i]},{begin:/'/,end:/'/,contains:[i]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[u,x,w,_,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[u,_,x,w]}]}]},s.COMMENT(//,{relevance:10}),{begin://,relevance:10},i,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/ | |