kempo-server 1.10.4 → 1.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33,6 +33,10 @@ jobs:
33
33
 
34
34
  - run: npm ci
35
35
 
36
+ - name: Build project and documentation
37
+ run: |
38
+ npm run build
39
+
36
40
  - name: Set version type
37
41
  id: version
38
42
  run: |
@@ -0,0 +1,23 @@
1
+ name: Run Unit Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ token: ${{ secrets.GITHUB_TOKEN }}
15
+
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: '20.x'
19
+
20
+ - run: npm ci
21
+
22
+ - name: Run Unit Tests
23
+ run: npm test
package/README.md CHANGED
@@ -366,6 +366,12 @@ npm run tests:gui # Start the GUI test runner
366
366
  For advanced usage (filters, flags, GUI options), see:
367
367
  https://github.com/dustinpoissant/kempo-testing-framework
368
368
 
369
+ ## Single-Page Applications
370
+
371
+ Kempo Server makes it easy to serve SPAs by using `customRoutes` to redirect all HTML requests to your shell page while still serving individual page fragments from a `pages/` directory.
372
+
373
+ See **[SPA.md](./SPA.md)** for a full walkthrough.
374
+
369
375
  ## Documentation
370
376
 
371
377
  - **[Getting Started](./docs/getting-started.html)** - Installation and basic usage
package/SPA.md ADDED
@@ -0,0 +1,153 @@
1
+ # Single-Page Applications
2
+
3
+ Kempo Server supports single-page applications (SPAs) with no framework required. The approach uses `customRoutes` to redirect every HTML URL to one shell page, while individual page content lives as HTML fragments in a `pages/` directory. Client-side JavaScript handles navigation using the History API.
4
+
5
+ ## How It Works
6
+
7
+ 1. All top-level HTML requests (e.g. `/about.html`) are redirected to `app.html` via `customRoutes`.
8
+ 2. `app.html` is the shell — it contains the `<nav>`, a `<main>` content area, and loads `spa.js`.
9
+ 3. `spa.js` reads the current URL, fetches the matching fragment from `/pages/`, and injects it into `<main>`.
10
+ 4. Click events on `<a>` tags are intercepted to update the URL with `history.pushState` and load content without a full page reload.
11
+ 5. The `popstate` event handles browser back/forward navigation.
12
+
13
+ Requests to `/pages/*.html` are **not** redirected, so the fragments are still served directly by the server.
14
+
15
+ ## File Structure
16
+
17
+ ```
18
+ spa/
19
+ ├─ .config.json ← server config (routes + caching)
20
+ ├─ app.html ← shell page (loaded for every route)
21
+ ├─ spa.js ← client-side routing logic
22
+ └─ pages/
23
+ ├─ index.html ← home page fragment
24
+ ├─ page1.html
25
+ ├─ about.html
26
+ ├─ contact.html
27
+ └─ settings.html
28
+ ```
29
+
30
+ ## Configuration
31
+
32
+ Create a `.config.json` in your SPA root:
33
+
34
+ ```json
35
+ {
36
+ "customRoutes": {
37
+ "/kempo.css": "../node_modules/kempo-css/dist/kempo.min.css",
38
+ "/*.html": "./app.html",
39
+ "/": "./app.html"
40
+ },
41
+ "middleware": {
42
+ "security": {
43
+ "enabled": true,
44
+ "headers": {
45
+ "Cache-Control": "public, max-age=3600"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ - `"/*.html": "./app.html"` — the `*` wildcard matches a single path segment, so it catches `/about.html` but not `/pages/about.html`.
53
+ - `"/": "./app.html"` — handles requests to the root.
54
+ - The `Cache-Control` header tells browsers to cache responses for 1 hour.
55
+
56
+ ## Shell Page (`app.html`)
57
+
58
+ The shell page is a minimal HTML document. Navigation links use absolute paths so they work regardless of the current URL. The `<main>` element is where page content gets injected.
59
+
60
+ ```html
61
+ <!doctype html>
62
+ <html lang="en">
63
+ <head>
64
+ <meta charset="UTF-8">
65
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
66
+ <title>My SPA</title>
67
+ <link rel="stylesheet" href="/kempo.css" />
68
+ </head>
69
+ <body>
70
+ <nav>
71
+ <a href="/">Home</a>
72
+ <a href="/about.html">About</a>
73
+ <a href="/contact.html">Contact</a>
74
+ </nav>
75
+ <main id="main"></main>
76
+ <script src="/spa.js"></script>
77
+ </body>
78
+ </html>
79
+ ```
80
+
81
+ ## Client-Side Router (`spa.js`)
82
+
83
+ ```javascript
84
+ const main = document.getElementById("main");
85
+
86
+ const loadPage = path => {
87
+ const page = (path === "/" || path === "/index.html")
88
+ ? "/pages/index.html"
89
+ : `/pages${path}`;
90
+ fetch(page)
91
+ .then(r => {
92
+ if(!r.ok) throw new Error(r.status);
93
+ return r.text();
94
+ })
95
+ .then(html => {
96
+ main.innerHTML = html;
97
+ })
98
+ .catch(() => {
99
+ main.innerHTML = "<h1>Page Not Found</h1>";
100
+ });
101
+ };
102
+
103
+ document.addEventListener("click", e => {
104
+ const a = e.target.closest("a");
105
+ if(!a || a.origin !== location.origin) return;
106
+ e.preventDefault();
107
+ history.pushState(null, "", a.href);
108
+ loadPage(a.pathname);
109
+ });
110
+
111
+ window.addEventListener("popstate", () => {
112
+ loadPage(location.pathname);
113
+ });
114
+
115
+ loadPage(location.pathname);
116
+ ```
117
+
118
+ ### How it works
119
+
120
+ - `loadPage` maps the URL pathname to a fragment file under `/pages/` and fetches it. The root path `/` maps to `/pages/index.html`.
121
+ - The `click` listener intercepts same-origin link clicks, prevents the default navigation, pushes the new URL into the browser history, and loads the content.
122
+ - The `popstate` listener handles back/forward button presses.
123
+ - On initial load, `loadPage(location.pathname)` renders the correct content for any URL — including direct navigation and browser refreshes.
124
+
125
+ ## Page Fragments
126
+
127
+ Each file inside `pages/` is a plain HTML fragment — just the content, no `<html>` or `<body>` wrapper needed:
128
+
129
+ ```html
130
+ <!-- pages/about.html -->
131
+ <h1>About</h1>
132
+ <p>This is an example single-page application powered by Kempo-Server.</p>
133
+ ```
134
+
135
+ ## Running the SPA
136
+
137
+ Add a script to your `package.json`:
138
+
139
+ ```json
140
+ {
141
+ "scripts": {
142
+ "spa": "kempo-server --root ./spa"
143
+ }
144
+ }
145
+ ```
146
+
147
+ Then run:
148
+
149
+ ```bash
150
+ npm run spa
151
+ ```
152
+
153
+ The server starts on `http://localhost:3000` by default. All `.html` URLs load `app.html` and client-side routing takes over from there.
@@ -1 +1 @@
1
- :root{color-scheme:light;--ff_body:"Helvetica Neue",Helvetica,Arial,sans-serif;--ff_heading:"Helvetica Neue",Helvetica,Arial,sans-serif;--ff_mono:Consolas,monaco,monospace;--fs_base:16px;--fs_small:calc(0.6 * var(--fs_base));--fs_large:calc(1.5 * var(--fs_base));--fs_h6:var(--fs_base);--fs_h5:calc(1.25 * var(--fs_base));--fs_h4:calc(1.5 * var(--fs_base));--fs_h3:calc(1.75 * var(--fs_base));--fs_h2:calc(2 * var(--fs_base));--fs_h1:calc(2.5 * var(--fs_base));--fw_base:400;--fw_bold:700;--spacer:1rem;--spacer_h:calc(0.5 * var(--spacer));--spacer_q:calc(0.25 * var(--spacer));--line-height:1.35em;--container_width:90rem;--animation_ms:256ms;--radius:0.25rem;--link_decoration:underline;--input_padding:var(--spacer_h) var(--spacer);--input_border_width:1px;--btn_padding:var(--spacer_h) var(--spacer);--c_bg:light-dark(rgb(249, 249, 249), rgb(51, 51, 51));--c_bg__inv:light-dark(rgb(51, 51, 51), rgb(249, 249, 249));--c_bg__alt:light-dark(rgb(238, 238, 238), rgb(34, 34, 34));--c_overscroll:light-dark(rgb(255, 255, 255), rgb(0, 0, 0));--c_border:light-dark(rgb(204, 204, 204), rgb(119, 119, 119));--c_border__inv:light-dark(rgb(119, 119, 119), rgb(204, 204, 204));--c_primary:rgb(51, 102, 255);--c_primary__hover:rgb(17, 68, 221);--c_secondary:rgb(153, 51, 255);--c_secondary__hover:rgb(119, 17, 221);--c_success:rgb(0, 136, 0);--c_success__hover:rgb(0, 102, 0);--c_warning:rgb(255, 102, 0);--c_warning__hover:rgb(221, 68, 0);--c_danger:rgb(255, 0, 51);--c_danger__hover:rgb(221, 0, 17);--c_input_accent:rgb(51, 102, 255);--c_input_border:var(--c_border);--c_highlight:light-dark(rgba(41, 100, 210, 0.25), rgba(0, 89, 255, 0.25));--tc:light-dark(rgba(0, 0, 0, 0.93), rgba(255, 255, 255, 0.93));--tc_dark:light-dark(rgba(0, 0, 0, 0.93), rgba(0, 0, 0, 0.93));--tc_light:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_inv:light-dark(rgba(255, 255, 255, 0.93), rgba(0, 0, 0, 0.93));--tc_muted:light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.5));--tc_on_primary:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_secondary:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_success:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_warning:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_danger:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--c_overlay:rgba(0, 0, 0, 0.5);--tc_primary:light-dark(#36f, rgb(138, 180, 248));--tc_secondary:light-dark(#93f, rgb(187, 102, 255));--tc_success:light-dark(#080, rgb(102, 187, 102));--tc_warning:light-dark(#f60, rgb(255, 153, 51));--tc_danger:light-dark(#f03, rgb(255, 85, 119));--btn_box_shadow:0 0 0 transparent;--btn_box_shadow__hover:0 0 0 transparent;--btn_border:transparent;--btn_bg:light-dark(rgb(221, 221, 221), rgb(170, 170, 170));--btn_bg__hover:light-dark(rgb(204, 204, 204), rgb(187, 187, 187));--btn_tc:light-dark(rgba(0, 0, 0, 0.93), rgba(0, 0, 0, 0.93));--btn_transparent__hover:light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));--tc_link:var(--tc_primary);--tc_link__hover:var(--tc_secondary);--tc_link__inv:var(--tc_primary__inv);--tc_link__inv__hover:var(--tc_secondary__inv);--focus_shadow:0 0 2px 2px var(--c_primary);--focus_shadow_on_primary:0 0 2px 2px var(--tc_on_primary);--input_bg:light-dark(white, var(--c_bg__alt));--input_tc:light-dark(rgba(0, 0, 0, 0.93), var(--tc));--drop_shadow__light:0 0.25rem 0.5rem rgba(0, 0, 0, 0.333);--drop_shadow__dark:0 0.25rem 0.5rem rgba(0, 0, 0, 0.5);--drop_shadow:var(--drop_shadow__light);--date_picker_icon_filter:light-dark(invert(0), invert(1));--elevation_-2_bg:light-dark(rgb(215, 215, 215), rgb(25, 25, 25));--elevation_-1_bg:light-dark(rgb(232, 232, 232), rgb(38, 38, 38));--elevation_0_bg:var(--c_bg);--elevation_1_bg:light-dark(rgb(255, 255, 255), rgb(64, 64, 64));--elevation_2_bg:light-dark(rgb(255, 255, 255), rgb(77, 77, 77));--elevation_3_bg:light-dark(rgb(255, 255, 255), rgb(90, 90, 90));--elevation_-2_shadow__light:inset 0 2px 6px rgba(0, 0, 0, 0.18),inset 0 1px 3px rgba(0, 0, 0, 0.12);--elevation_-1_shadow__light:inset 0 1px 3px rgba(0, 0, 0, 0.1),inset 0 1px 2px rgba(0, 0, 0, 0.06);--elevation_0_shadow:none;--elevation_1_shadow__light:0 1px 3px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.16);--elevation_2_shadow__light:0 3px 6px rgba(0, 0, 0, 0.12),0 2px 4px rgba(0, 0, 0, 0.1);--elevation_3_shadow__light:0 8px 16px rgba(0, 0, 0, 0.14),0 3px 6px rgba(0, 0, 0, 0.1);--elevation_-2_shadow__dark:inset 0 2px 8px rgba(0, 0, 0, 0.5),inset 0 1px 4px rgba(0, 0, 0, 0.4);--elevation_-1_shadow__dark:inset 0 1px 4px rgba(0, 0, 0, 0.35),inset 0 1px 2px rgba(0, 0, 0, 0.25);--elevation_1_shadow__dark:0 2px 6px rgba(0, 0, 0, 0.5),0 1px 3px rgba(0, 0, 0, 0.4);--elevation_2_shadow__dark:0 4px 12px rgba(0, 0, 0, 0.55),0 2px 4px rgba(0, 0, 0, 0.45);--elevation_3_shadow__dark:0 8px 20px rgba(0, 0, 0, 0.6),0 4px 8px rgba(0, 0, 0, 0.5);--elevation_-2_shadow:var(--elevation_-2_shadow__light);--elevation_-1_shadow:var(--elevation_-1_shadow__light);--elevation_1_shadow:var(--elevation_1_shadow__light);--elevation_2_shadow:var(--elevation_2_shadow__light);--elevation_3_shadow:var(--elevation_3_shadow__light)}[theme=light]{color-scheme:light}[theme=dark]{color-scheme:dark;--drop_shadow:var(--drop_shadow__dark);--elevation_-2_shadow:var(--elevation_-2_shadow__dark);--elevation_-1_shadow:var(--elevation_-1_shadow__dark);--elevation_1_shadow:var(--elevation_1_shadow__dark);--elevation_2_shadow:var(--elevation_2_shadow__dark);--elevation_3_shadow:var(--elevation_3_shadow__dark)}[theme=auto]{color-scheme:light dark}@media (prefers-color-scheme:dark){[theme=auto]{--drop_shadow:var(--drop_shadow__dark);--elevation_-2_shadow:var(--elevation_-2_shadow__dark);--elevation_-1_shadow:var(--elevation_-1_shadow__dark);--elevation_1_shadow:var(--elevation_1_shadow__dark);--elevation_2_shadow:var(--elevation_2_shadow__dark);--elevation_3_shadow:var(--elevation_3_shadow__dark)}}:root{interpolate-size:allow-keywords}*,::after,::before{font-family:inherit;box-sizing:border-box;line-height:var(--line-height)}blockquote,body,code,dd,dl,dt,h1,h2,h3,h4,h5,h6,li,ol,p,pre,ul{margin:0;padding:.1px}html{font-family:var(--ff_body);font-size:var(--fs_base);font-weight:var(--fw_base);color:var(--tc);scrollbar-gutter:stable}::selection{background:var(--c_highlight)}body{min-height:100vh;background-color:var(--c_bg);color:var(--tc);overflow-y:scroll;font-family:var(--ff_body);position:relative}body.no-scroll{overflow:hidden!important}.container,main{max-width:var(--container_width);margin-left:auto;margin-right:auto;padding-top:var(--spacer);padding-left:var(--spacer);padding-right:var(--spacer)}nav>.link,nav>a{display:inline-block;padding:var(--spacer)!important;text-decoration:none}menu{margin:0;padding:0}menu a{display:block;padding:var(--spacer_q);text-decoration:none;color:inherit}summary{cursor:pointer;margin-bottom:var(--sapcer);outline:0;box-shadow:0 0 0 transparent;transition:box-shadow var(--animation_ms);border-radius:var(--radius)}summary:focus{box-shadow:var(--focus_shadow)}.d-b{display:block!important}.d-ib{display:inline-block!important}.d-g{display:grid!important}.d-i{display:inline!important}.d-n{display:none!important}.d-f{display:flex!important;flex-wrap:wrap}.d-if{display:inline-flex!important;flex-wrap:wrap}@media (min-width:1024px){.d-d-b{display:block!important}.d-d-ib{display:inline-block!important}.d-d-g{display:grid!important}.d-d-i{display:inline!important}.d-d-n{display:none!important}.d-d-f{display:flex!important;flex-wrap:wrap}.d-d-if{display:inline-flex!important;flex-wrap:wrap}}@media (min-width:769px) and (max-width:1023px){.t-d-b{display:block!important}.t-d-ib{display:inline-block!important}.t-d-g{display:grid!important}.t-d-i{display:inline!important}.t-d-n{display:none!important}.t-d-f{display:flex!important;flex-wrap:wrap}.t-d-if{display:inline-flex!important;flex-wrap:wrap}}@media (max-width:768px){.m-d-b{display:block!important}.m-d-ib{display:inline-block!important}.m-d-g{display:grid!important}.m-d-i{display:inline!important}.m-d-n{display:none!important}.m-d-f{display:flex!important;flex-wrap:wrap}.m-d-if{display:inline-flex!important;flex-wrap:wrap}}.flex,.flex-1{flex:1 1 auto}.flex-0{flex:0 0}.flex-2{flex:2 2 auto}.flex-3{flex:3 3 auto}.flex-4{flex:4 4 auto}.flex-5{flex:5 5 auto}.flex-6{flex:6 6 auto}.flex-7{flex:7 7 auto}.flex-8{flex:8 8 auto}.flex-9{flex:9 9 auto}.flex-10{flex:10 10 auto}@media (min-width:1024px){.d-d-b{display:block!important}.d-d-ib{display:inline-block!important}.d-d-g{display:grid!important}.d-d-i{display:inline!important}.d-d-n{display:none!important}.d-d-if{display:inline-flex!important;flex-wrap:wrap}.d-d-f{display:flex!important;flex-wrap:wrap}.d-flex,.d-flex-1{flex:1 1 auto}.d-flex-0{flex:0 0}.d-flex-2{flex:2 2 auto}.d-flex-3{flex:3 3 auto}.d-flex-4{flex:4 4 auto}.d-flex-5{flex:5 5 auto}.d-flex-6{flex:6 6 auto}.d-flex-7{flex:7 7 auto}.d-flex-8{flex:8 8 auto}.d-flex-9{flex:9 9 auto}.d-flex-10{flex:10 10 auto}}@media (min-width:769px) and (max-width:1023px){.t-d-b{display:block!important}.t-d-ib{display:inline-block!important}.t-d-g{display:grid!important}.t-d-i{display:inline!important}.t-d-n{display:none!important}.t-d-if{display:inline-flex!important;flex-wrap:wrap}.t-d-f{display:flex!important;flex-wrap:wrap}.t-flex,.t-flex-1{flex:1 1 auto}.t-flex-0{flex:0 0}.t-flex-2{flex:2 2 auto}.t-flex-3{flex:3 3 auto}.t-flex-4{flex:4 4 auto}.t-flex-5{flex:5 5 auto}.t-flex-6{flex:6 6 auto}.t-flex-7{flex:7 7 auto}.t-flex-8{flex:8 8 auto}.t-flex-9{flex:9 9 auto}.t-flex-10{flex:10 10 auto}}@media (max-width:768px){.m-d-b{display:block!important}.m-d-ib{display:inline-block!important}.m-d-g{display:grid!important}.m-d-i{display:inline!important}.m-d-n{display:none!important}.m-d-if{display:inline-flex!important;flex-wrap:wrap}.m-d-f{display:flex!important;flex-wrap:wrap}.m-flex,.m-flex-1{flex:1 1 auto}.m-flex-0{flex:0 0}.m-flex-2{flex:2 2 auto}.m-flex-3{flex:3 3 auto}.m-flex-4{flex:4 4 auto}.m-flex-5{flex:5 5 auto}.m-flex-6{flex:6 6 auto}.m-flex-7{flex:7 7 auto}.m-flex-8{flex:8 8 auto}.m-flex-9{flex:9 9 auto}.m-flex-10{flex:10 10 auto}}.fixed{position:fixed;top:0;width:100%;z-index:99;box-shadow:none;transition:box-shadow var(--animation_ms)}.fixed.scrolled{box-shadow:var(--elevation_2_shadow)}.small,small{font-size:var(--fs_small)!important}.large{font-size:var(--fs_large)!important}.h1,.h2,.h3,.h4,.h5,.h6,b,h1,h2,h3,h4,h5,h6,strong{font-weight:var(--fw_bold)}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:var(--ff_heading)}.h1,h1{font-size:var(--fs_h1)}.h2,h2{font-size:var(--fs_h2)}.h3,h3{font-size:var(--fs_h3)}.h4,h4{font-size:var(--fs_h4)}.h5,h5{font-size:var(--fs_h5)}.h6,h6{font-size:var(--fs_h6)}blockquote,dd,dl,h1,h2,h3,h4,h5,h6,hr,ol,p,pre,ul{margin-bottom:var(--spacer)}dl,ol,ul{padding-left:calc(1.5 * var(--spacer))}blockquote{border-left:2px solid var(--c_border);padding:var(--spacer)}mark{background-color:var(--c_highlight);color:inherit}.ff-mono,code,pre{font-family:var(--ff_mono)}code{background-color:var(--c_bg__alt);border-radius:var(--radius);word-break:break-word;padding:calc(.125 * var(--spacer)) var(--spacer_q)}pre code{display:block;padding:var(--spacer);word-break:normal;overflow:auto;white-space:pre-wrap}output{display:block;border:1px solid var(--c_border);border-radius:var(--radius);padding:var(--spacer) var(--spacer) 0 var(--spacer)}.ta-left{text-align:left}.ta-center{text-align:center}.ta-right{text-align:right}.link,a{color:var(--tc_link);box-shadow:0 0 0 transparent;transition:color var(--animation_ms),box-shadow var(--animation_ms);outline:0;border-radius:var(--radius);text-decoration:var(--link_decoration)}.link:hover,a:hover{color:var(--tc_link__hover)}.link:focus-visible,a:focus{box-shadow:var(--focus_shadow)}.no-link,.no-link:hover{text-decoration:none;color:inherit}hr{border:none;border-top:1px solid var(--c_border)}small{font-size:.75em}dl{padding:0;margin:0}dd,dt{padding-left:var(--spacer);border-left:2px solid var(--c_border)}dt{padding-top:var(--spacer_h)}dd{padding-bottom:var(--spacer_h)}dd+dd{margin-top:calc(-1 * var(--spacer));padding-top:0}li ul{margin-bottom:0}.td-n{text-decoration:none}.p,.pt,.py{padding-top:var(--spacer)!important}.p,.pr,.px{padding-right:var(--spacer)!important}.p,.pb,.py{padding-bottom:var(--spacer)!important}.p,.pl,.px{padding-left:var(--spacer)!important}.ph,.pth,.pyh{padding-top:var(--spacer_h)!important}.ph,.prh,.pxh{padding-right:var(--spacer_h)!important}.pbh,.ph,.pyh{padding-bottom:var(--spacer_h)!important}.ph,.plh,.pxh{padding-left:var(--spacer_h)!important}.pq,.ptq,.pyq{padding-top:var(--spacer_q)!important}.pq,.prq,.pxq{padding-right:var(--spacer_q)!important}.pbq,.pq,.pyq{padding-bottom:var(--spacer_q)!important}.plq,.pq,.pxq{padding-left:var(--spacer_q)!important}.p0,.pt0,.py0{padding-top:.1px!important}.p0,.pr0,.px0{padding-right:.1px!important}.p0,.pb0,.py0{padding-bottom:.1px!important}.p0,.pl0,.px0{padding-left:.1px!important}.m,.mt,.my{margin-top:var(--spacer)!important}.m,.mr,.mx{margin-right:var(--spacer)!important}.m,.mb,.my{margin-bottom:var(--spacer)!important}.m,.ml,.mx{margin-left:var(--spacer)!important}.mh,.mth,.myh{margin-top:var(--spacer_h)!important}.mh,.mrh,.mxh{margin-right:var(--spacer_h)!important}.mbh,.mh,.myh{margin-bottom:var(--spacer_h)!important}.mh,.mlh,.mxh{margin-left:var(--spacer_h)!important}.mq,.mtq,.myq{margin-top:var(--spacer_q)!important}.mq,.mrq,.mxq{margin-right:var(--spacer_q)!important}.mbq,.mq,.myq{margin-bottom:var(--spacer_q)!important}.mlq,.mq,.mxq{margin-left:var(--spacer_q)!important}.m0,.mt0,.my0{margin-top:0!important}.m0,.mr0,.mx0{margin-right:0!important}.m0,.mb0,.my0{margin-bottom:0!important}.m0,.ml0,.mx0{margin-left:0!important}.-m,.-mt,.-my{margin-top:calc(-1 * var(--spacer))!important}.-m,.-mr,.-mx{margin-right:calc(-1 * var(--spacer))!important}.-m,.-mb,.-my{margin-bottom:calc(-1 * var(--spacer))!important}.-m,.-ml,.-mx{margin-left:calc(-1 * var(--spacer))!important}.b,.bt,.by{border-top:1px solid var(--c_border)!important}.b,.br,.bx{border-right:1px solid var(--c_border)!important}.b,.bb,.by{border-bottom:1px solid var(--c_border)!important}.b,.bl,.bx{border-left:1px solid var(--c_border)!important}.b0,.bt0,.by0{border-top:none!important}.b0,.br0,.bx0{border-right:none!important}.b0,.bb0,.by0{border-bottom:none!important}.b0,.bl0,.bx0{border-left:none!important}.r,.rl,.rt,.rtl{border-top-left-radius:var(--radius)!important}.r,.rr,.rt,.rtr{border-top-right-radius:var(--radius)!important}.r,.rb,.rbr,.rr{border-bottom-right-radius:var(--radius)!important}.r,.rb,.rbl,.rl{border-bottom-left-radius:var(--radius)!important}.r0,.rl0,.rt0,.rtl0{border-top-left-radius:0!important}.r0,.rr0,.rt0,.rtr0{border-top-right-radius:0!important}.r0,.rb0,.rbr0,.rr0{border-bottom-right-radius:0!important}.r0,.rb0,.rbl0,.rl0{border-bottom-left-radius:0!important}.round{border-radius:9999rem!important}.row{display:flex;flex-wrap:wrap}.col{flex:1 1}.span-1{min-width:8.333%;flex-basis:8.333%}.span-2{min-width:16.666%;flex-basis:16.666%}.span-3{min-width:25%;flex-basis:25%}.span-4{min-width:33.333%;flex-basis:33.333%}.span-5{min-width:41.666%;flex-basis:41.666%}.span-6{min-width:50%;flex-basis:50%}.span-7{min-width:58.333%;flex-basis:58.333%}.span-8{min-width:66.666%;flex-basis:66.666%}.span-9{min-width:75%;flex-basis:75%}.span-10{min-width:83.333%;flex-basis:83.333%}.span-11{min-width:91.333%;flex-basis:91.333%}.span-12{min-width:100%;flex-basis:100%}@media (min-width:1024px){.d-span-1{min-width:8.333%;flex-basis:8.333%}.d-span-2{min-width:16.666%;flex-basis:16.666%}.d-span-3{min-width:25%;flex-basis:25%}.d-span-4{min-width:33.333%;flex-basis:33.333%}.d-span-5{min-width:41.666%;flex-basis:41.666%}.d-span-6{min-width:50%;flex-basis:50%}.d-span-7{min-width:58.333%;flex-basis:58.333%}.d-span-8{min-width:66.666%;flex-basis:66.666%}.d-span-9{min-width:75%;flex-basis:75%}.d-span-10{min-width:83.333%;flex-basis:83.333%}.d-span-11{min-width:91.333%;flex-basis:91.333%}.d-span-12{min-width:100%;flex-basis:100%}}@media (min-width:769px) and (max-width:1023px){.t-span-1{min-width:8.333%;flex-basis:8.333%}.t-span-2{min-width:16.666%;flex-basis:16.666%}.t-span-3{min-width:25%;flex-basis:25%}.t-span-4{min-width:33.333%;flex-basis:33.333%}.t-span-5{min-width:41.666%;flex-basis:41.666%}.t-span-6{min-width:50%;flex-basis:50%}.t-span-7{min-width:58.333%;flex-basis:58.333%}.t-span-8{min-width:66.666%;flex-basis:66.666%}.t-span-9{min-width:75%;flex-basis:75%}.t-span-10{min-width:83.333%;flex-basis:83.333%}.t-span-11{min-width:91.333%;flex-basis:91.333%}.t-span-12{min-width:100%;flex-basis:100%}}@media (max-width:768px){.m-span-1{min-width:8.333%;flex-basis:8.333%}.m-span-2{min-width:16.666%;flex-basis:16.666%}.m-span-3{min-width:25%;flex-basis:25%}.m-span-4{min-width:33.333%;flex-basis:33.333%}.m-span-5{min-width:41.666%;flex-basis:41.666%}.m-span-6{min-width:50%;flex-basis:50%}.m-span-7{min-width:58.333%;flex-basis:58.333%}.m-span-8{min-width:66.666%;flex-basis:66.666%}.m-span-9{min-width:75%;flex-basis:75%}.m-span-10{min-width:83.333%;flex-basis:83.333%}.m-span-11{min-width:91.333%;flex-basis:91.333%}.m-span-12{min-width:100%;flex-basis:100%}}.cols-2{grid-template-columns:repeat(2,1fr)}.cols-3{grid-template-columns:repeat(3,1fr)}.cols-4{grid-template-columns:repeat(4,1fr)}.cols-5{grid-template-columns:repeat(5,1fr)}.cols-6{grid-template-columns:repeat(6,1fr)}.cols-7{grid-template-columns:repeat(7,1fr)}.cols-8{grid-template-columns:repeat(8,1fr)}.cols-9{grid-template-columns:repeat(9,1fr)}.cols-10{grid-template-columns:repeat(10,1fr)}@media (min-width:1024px){.d-cols-2{grid-template-columns:repeat(2,1fr)}.d-cols-3{grid-template-columns:repeat(3,1fr)}.d-cols-4{grid-template-columns:repeat(4,1fr)}.d-cols-5{grid-template-columns:repeat(5,1fr)}.d-cols-6{grid-template-columns:repeat(6,1fr)}.d-cols-7{grid-template-columns:repeat(7,1fr)}.d-cols-8{grid-template-columns:repeat(8,1fr)}.d-cols-9{grid-template-columns:repeat(9,1fr)}.d-cols-10{grid-template-columns:repeat(10,1fr)}}@media (min-width:769px) and (max-width:1023px){.t-cols-2{grid-template-columns:repeat(2,1fr)}.t-cols-3{grid-template-columns:repeat(3,1fr)}.t-cols-4{grid-template-columns:repeat(4,1fr)}.t-cols-5{grid-template-columns:repeat(5,1fr)}.t-cols-6{grid-template-columns:repeat(6,1fr)}.t-cols-7{grid-template-columns:repeat(7,1fr)}.t-cols-8{grid-template-columns:repeat(8,1fr)}.t-cols-9{grid-template-columns:repeat(9,1fr)}.t-cols-10{grid-template-columns:repeat(10,1fr)}}@media (max-width:768px){.m-cols-2{grid-template-columns:repeat(2,1fr)}.m-cols-3{grid-template-columns:repeat(3,1fr)}.m-cols-4{grid-template-columns:repeat(4,1fr)}.m-cols-5{grid-template-columns:repeat(5,1fr)}.m-cols-6{grid-template-columns:repeat(6,1fr)}.m-cols-7{grid-template-columns:repeat(7,1fr)}.m-cols-8{grid-template-columns:repeat(8,1fr)}.m-cols-9{grid-template-columns:repeat(9,1fr)}.m-cols-10{grid-template-columns:repeat(10,1fr)}}.btn,button:not(.no-btn):not(.no-style),input[type=button],input[type=reset],input[type=submit]{display:inline-block;padding:var(--btn_padding);background-color:var(--btn_bg);border:1px solid var(--btn_border);cursor:pointer;outline:0;border-radius:var(--radius);color:var(--btn_tc);transition:background-color var(--animation_ms),box-shadow var(--animation_ms);text-decoration:none;box-shadow:var(--btn_box_shadow);font-size:inherit;vertical-align:middle}.btn:hover,button:not(.no-btn):not(.no-style):hover,input[type=button]:hover,input[type=reset]:hover,input[type=submit]:hover{background-color:var(--btn_bg__hover);color:var(--btn_tc);box-shadow:var(--btn_box_shadow__hover)}.btn:focus,button:not(.no-btn):not(.no-style):focus,input[type=button]:focus,input[type=reset]:focus,input[type=submit]:focus{box-shadow:var(--btn_box_shadow__hover),var(--focus_shadow);z-index:1}.btn[disabled],button:not(.no-btn):not(.no-style):disabled,input[type=button]:disabled,input[type=reset]:disabled,input[type=submit]:disabled{opacity:.6}.btn.primary,button:not(.no-btn).primary,input[type=button].primary,input[type=reset].primary,input[type=submit].primary{background-color:var(--c_primary);--btn_tc:var(--tc_on_primary)}.btn.primary:hover,button:not(.no-btn).primary:hover,input[type=button].primary:hover,input[type=reset].primary:hover,input[type=submit].primary:hover{background-color:var(--c_primary__hover)}.btn.secondary,button:not(.no-btn).secondary,input[type=button].secondary,input[type=reset].secondary,input[type=submit].secondary{background-color:var(--c_secondary);--btn_tc:var(--tc_on_secondary)}.btn.secondary:hover,button:not(.no-btn).secondary:hover,input[type=button].secondary:hover,input[type=reset].secondary:hover,input[type=submit].secondary:hover{background-color:var(--c_secondary__hover)}.btn.success,button:not(.no-btn).success,input[type=button].success,input[type=reset].success,input[type=submit].success{background-color:var(--c_success);--btn_tc:var(--tc_on_success)}.btn.success:hover,button:not(.no-btn).success:hover,input[type=button].success:hover,input[type=reset].success:hover,input[type=submit].success:hover{background-color:var(--c_success__hover)}.btn.warning,button:not(.no-btn).warning,input[type=button].warning,input[type=reset].warning,input[type=submit].warning{background-color:var(--c_warning);--btn_tc:var(--tc_on_warning)}.btn.warning:hover,button:not(.no-btn).warning:hover,input[type=button].warning:hover,input[type=reset].warning:hover,input[type=submit].warning:hover{background-color:var(--c_warning__hover)}.btn.danger,button:not(.no-btn).danger,input[type=button].danger,input[type=reset].danger,input[type=submit].danger{background-color:var(--c_danger);--btn_tc:var(--tc_on_danger)}.btn.danger:hover,button:not(.no-btn).danger:hover,input[type=button].danger:hover,input[type=reset].danger:hover,input[type=submit].danger:hover{background-color:var(--c_danger__hover)}.btn.link,button:not(.no-btn):not(.no-style).link,input[type=button].link,input[type=reset].link,input[type=submit].link{background-color:transparent;color:inherit;box-shadow:0 0 0 transparent;border:none;padding:.1px;font-size:inherit}.btn-grp{display:inline-flex}.btn-grp .btn:not(:first-child),.btn-grp button:not(.no-btn):not(:first-child),.btn-grp input[type=button]:not(:first-child),.btn-grp input[type=reset]:not(:first-child),.btn-grp input[type=submit]:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0;border-left:1px solid rgba(0,0,0,.25)}.btn-grp .btn:not(:last-child),.btn-grp button:not(.no-btn):not(:last-child),.btn-grp input[type=button]:not(:last-child),.btn-grp input[type=reset]:not(:last-child),.btn-grp input[type=submit]:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.no-btn{display:inline;border:none;background-color:transparent;padding:0;font-size:inherit;font-family:inherit;cursor:pointer;outline:0;box-shadow:0 0 0 transparent;transition:box-shadow var(--animation_ms);border-radius:0;text-align:left;color:inherit}.no-btn:focus{box-shadow:var(--focus_shadow)}.full{display:block;width:100%}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]),select,textarea{display:block;width:100%;background-color:var(--input_bg);color:var(--input_tc);border:var(--input_border_width) solid var(--c_input_border);padding:var(--input_padding);border-radius:var(--radius);outline:0;transition:box-shadow var(--animation_ms)}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]):focus,input[type=checkbox]:focus,input[type=radio]:focus,select:focus,textarea:focus{box-shadow:var(--focus_shadow)}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]):disabled,input[type=checkbox]:disabled,input[type=radio]:disabled,select:disabled,textarea:disabled{opacity:.6}select[multiple],textarea{resize:vertical;max-height:75vh;height:6rem;min-height:4rem}select[multiple]{height:8rem}select{cursor:pointer}label{display:block;cursor:pointer;padding-bottom:var(--spacer_h)}label.checkbox,label.radio{display:inline-block;vertical-align:top;width:calc(100% - 1em - (2 * var(--spacer_h)) - 6px);margin-top:2px}input[type=checkbox],input[type=radio]{display:inline-block;width:1em;height:1em;cursor:pointer;vertical-align:top;outline:0;accent-color:var(--c_input_accent);margin:var(--spacer_q) var(--spacer_h)}select option{padding:var(--spacer_h) var(--spacer);background-color:var(--input_bg);color:var(--input_tc)}select[multiple]{padding:.1px}select[multiple] option{padding:var(--spacer_h) var(--spacer)}input[type=color]{padding:0!important;height:2.35em}input[type=color]::-webkit-color-swatch-wrapper{padding:0}input[type=color]::-webkit-color-swatch{border-radius:var(--radius,.25rem);cursor:pointer}input[type=date]::-webkit-calendar-picker-indicator,input[type=month]::-webkit-calendar-picker-indicator,input[type=search]::-webkit-search-cancel-button,input[type=time]::-webkit-calendar-picker-indicator,input[type=week]::-webkit-calendar-picker-indicator{filter:var(--date_picker_icon_filter)}.table-wrapper{overflow-x:auto}table{width:100%;border-spacing:0}th{font-weight:var(--fw_bold);text-align:left;background-color:var(--c_bg__alt);border-top:1px solid var(--c_border)}td,th{padding:var(--spacer_h) var(--spacer);border-bottom:1px solid var(--c_border);border-left:1px solid var(--c_border)}td:last-child,th:last-child{border-right:1px solid var(--c_border)}th:first-child{border-top-left-radius:var(--radius)}th:last-child{border-top-right-radius:var(--radius)}tr:last-child td:first-child{border-bottom-left-radius:var(--radius)}tr:last-child td:last-child{border-bottom-right-radius:var(--radius)}.bg-default{background-color:var(--c_bg);color:var(--tc)}.bg-alt{background-color:var(--c_bg__alt);color:var(--tc)}.bg-inv{--c_primary:var(--c_primary__inv);--c_primary__hover:var(--c_primary__inv__hover);--c_secondary:var(--c_secondary__inv);--c_secondary__hover:var(--c_secondary__inv__hover);--c_success:var(--c_success__inv);--c_success__hover:var(--c_success__inv__hover);--c_warning:var(--c_warning__inv);--c_warning__hover:var(--c_warning__inv__hover);--c_danger:var(--c_danger__inv);--c_danger__hover:var(--c_danger__inv__hover);--tc_link:var(--tc_link__inv);--tc_link__hover:var(--tc_link__inv__hover);background-color:var(--c_bg__inv);color:var(--tc_inv)}.bg-primary{--tc_link:var(--tc_on_primary);--tc_link__hover:var(--tc_on_primary);--c_border:var(--tc_on_primary);background-color:var(--c_primary);color:var(--tc_on_primary);--focus_shadow:var(--focus_shadow_on_primary)}.bg-secondary{--tc_link:var(--tc_on_secondary);--tc_link__hover:var(--tc_on_secondary);background-color:var(--c_secondary);color:var(--tc_on_secondary)}.bg-success{--tc_link:var(--tc_on_success);--tc_link__hover:var(--tc_on_success);background-color:var(--c_success);color:var(--tc_on_success)}.bg-warning{--tc_link:var(--tc_on_warning);--tc_link__hover:var(--tc_on_warning);background-color:var(--c_warning);color:var(--tc_on_warning)}.bg-danger{--tc_link:var(--tc_on_danger);--tc_link__hover:var(--tc_on_danger);background-color:var(--c_danger);color:var(--tc_on_danger)}.tc-default{color:var(--tc)}.tc-inv{color:var(--tc__inv)}.tc-primary{color:var(--tc_primary)}.bg-inv .tc-primary,.is-inv .tc-primary{color:var(--tc_primary__inv)}.tc-secondary{color:var(--tc_secondary)}.bg-inv .tc-secondary,.is-inv .tc-secondary{color:var(--tc_secondary__inv)}.tc-success{color:var(--tc_success)}.bg-inv .tc-success,.is-inv .tc-success{color:var(--tc_success__inv)}.tc-warning{color:var(--tc_warning)}.bg-inv .tc-warning,.is-inv .tc-warning{color:var(--tc_warning__inv)}.tc-danger{color:var(--tc_danger)}.bg-inv .tc-danger,.is-inv .tc-danger{color:var(--tc_danger__inv)}.tc-muted{color:var(--tc_muted)}.card{border:1px solid var(--c_border);border-radius:var(--radius);padding-top:var(--spacer);padding-left:var(--spacer);padding-right:var(--spacer);margin-bottom:var(--spacer)}.drop-shadow{box-shadow:var(--drop_shadow)}.elevation--2{background-color:var(--elevation_-2_bg);box-shadow:var(--elevation_-2_shadow)}.elevation--1{background-color:var(--elevation_-1_bg);box-shadow:var(--elevation_-1_shadow)}.elevation-0{background-color:var(--elevation_0_bg);box-shadow:var(--elevation_0_shadow)}.elevation-1{background-color:var(--elevation_1_bg);box-shadow:var(--elevation_1_shadow)}.elevation-2{background-color:var(--elevation_2_bg);box-shadow:var(--elevation_2_shadow)}.elevation-3{background-color:var(--elevation_3_bg);box-shadow:var(--elevation_3_shadow)}.icon{display:inline-block;width:1.35em;vertical-align:top;margin-left:auto;margin-right:auto}iframe{border:none;width:100%}
1
+ :root{color-scheme:light;--ff_body:"Helvetica Neue",Helvetica,Arial,sans-serif;--ff_heading:"Helvetica Neue",Helvetica,Arial,sans-serif;--ff_mono:Consolas,monaco,monospace;--fs_base:16px;--fs_small:calc(0.6 * var(--fs_base));--fs_large:calc(1.5 * var(--fs_base));--fs_h6:var(--fs_base);--fs_h5:calc(1.25 * var(--fs_base));--fs_h4:calc(1.5 * var(--fs_base));--fs_h3:calc(1.75 * var(--fs_base));--fs_h2:calc(2 * var(--fs_base));--fs_h1:calc(2.5 * var(--fs_base));--fw_base:400;--fw_bold:700;--spacer:1rem;--spacer_h:calc(0.5 * var(--spacer));--spacer_q:calc(0.25 * var(--spacer));--line-height:1.35em;--container_width:90rem;--animation_ms:256ms;--radius:0.25rem;--link_decoration:underline;--input_padding:var(--spacer_h) var(--spacer);--input_border_width:1px;--btn_padding:var(--spacer_h) var(--spacer);--c_bg:light-dark(rgb(249, 249, 249), rgb(51, 51, 51));--c_bg__inv:light-dark(rgb(51, 51, 51), rgb(249, 249, 249));--c_bg__alt:light-dark(rgb(238, 238, 238), rgb(34, 34, 34));--c_overscroll:light-dark(rgb(255, 255, 255), rgb(0, 0, 0));--c_border:light-dark(rgb(204, 204, 204), rgb(119, 119, 119));--c_border__inv:light-dark(rgb(119, 119, 119), rgb(204, 204, 204));--c_primary:rgb(51, 102, 255);--c_primary__hover:rgb(17, 68, 221);--c_secondary:rgb(153, 51, 255);--c_secondary__hover:rgb(119, 17, 221);--c_success:rgb(0, 136, 0);--c_success__hover:rgb(0, 102, 0);--c_warning:rgb(255, 102, 0);--c_warning__hover:rgb(221, 68, 0);--c_danger:rgb(255, 0, 51);--c_danger__hover:rgb(221, 0, 17);--c_input_accent:rgb(51, 102, 255);--c_input_border:var(--c_border);--c_highlight:light-dark(rgba(41, 100, 210, 0.25), rgba(0, 89, 255, 0.25));--tc:light-dark(rgba(0, 0, 0, 0.93), rgba(255, 255, 255, 0.93));--tc_dark:light-dark(rgba(0, 0, 0, 0.93), rgba(0, 0, 0, 0.93));--tc_light:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_inv:light-dark(rgba(255, 255, 255, 0.93), rgba(0, 0, 0, 0.93));--tc_muted:light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.5));--tc_on_primary:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_secondary:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_success:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_warning:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--tc_on_danger:light-dark(rgba(255, 255, 255, 0.93), rgba(255, 255, 255, 0.93));--c_overlay:rgba(0, 0, 0, 0.5);--tc_primary:light-dark(#36f, rgb(138, 180, 248));--tc_secondary:light-dark(#93f, rgb(187, 102, 255));--tc_success:light-dark(#080, rgb(102, 187, 102));--tc_warning:light-dark(#f60, rgb(255, 153, 51));--tc_danger:light-dark(#f03, rgb(255, 85, 119));--btn_box_shadow:0 0 0 transparent;--btn_box_shadow__hover:0 0 0 transparent;--btn_border:transparent;--btn_bg:light-dark(rgb(221, 221, 221), rgb(170, 170, 170));--btn_bg__hover:light-dark(rgb(204, 204, 204), rgb(187, 187, 187));--btn_tc:light-dark(rgba(0, 0, 0, 0.93), rgba(0, 0, 0, 0.93));--btn_transparent__hover:light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));--tc_link:var(--tc_primary);--tc_link__hover:var(--tc_secondary);--tc_link__inv:var(--tc_primary__inv);--tc_link__inv__hover:var(--tc_secondary__inv);--focus_shadow:0 0 2px 2px var(--c_primary);--focus_shadow_on_primary:0 0 2px 2px var(--tc_on_primary);--input_bg:light-dark(white, var(--c_bg__alt));--input_tc:light-dark(rgba(0, 0, 0, 0.93), var(--tc));--drop_shadow__light:0 0.25rem 0.5rem rgba(0, 0, 0, 0.333);--drop_shadow__dark:0 0.25rem 0.5rem rgba(0, 0, 0, 0.5);--drop_shadow:var(--drop_shadow__light);--date_picker_icon_filter:light-dark(invert(0), invert(1));--elevation_-2_bg:light-dark(rgb(215, 215, 215), rgb(25, 25, 25));--elevation_-1_bg:light-dark(rgb(232, 232, 232), rgb(38, 38, 38));--elevation_0_bg:var(--c_bg);--elevation_1_bg:light-dark(rgb(255, 255, 255), rgb(64, 64, 64));--elevation_2_bg:light-dark(rgb(255, 255, 255), rgb(77, 77, 77));--elevation_3_bg:light-dark(rgb(255, 255, 255), rgb(90, 90, 90));--elevation_-2_shadow__light:inset 0 2px 6px rgba(0, 0, 0, 0.18),inset 0 1px 3px rgba(0, 0, 0, 0.12);--elevation_-1_shadow__light:inset 0 1px 3px rgba(0, 0, 0, 0.1),inset 0 1px 2px rgba(0, 0, 0, 0.06);--elevation_0_shadow:none;--elevation_1_shadow__light:0 1px 3px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.16);--elevation_2_shadow__light:0 3px 6px rgba(0, 0, 0, 0.12),0 2px 4px rgba(0, 0, 0, 0.1);--elevation_3_shadow__light:0 8px 16px rgba(0, 0, 0, 0.14),0 3px 6px rgba(0, 0, 0, 0.1);--elevation_-2_shadow__dark:inset 0 2px 8px rgba(0, 0, 0, 0.5),inset 0 1px 4px rgba(0, 0, 0, 0.4);--elevation_-1_shadow__dark:inset 0 1px 4px rgba(0, 0, 0, 0.35),inset 0 1px 2px rgba(0, 0, 0, 0.25);--elevation_1_shadow__dark:0 2px 6px rgba(0, 0, 0, 0.5),0 1px 3px rgba(0, 0, 0, 0.4);--elevation_2_shadow__dark:0 4px 12px rgba(0, 0, 0, 0.55),0 2px 4px rgba(0, 0, 0, 0.45);--elevation_3_shadow__dark:0 8px 20px rgba(0, 0, 0, 0.6),0 4px 8px rgba(0, 0, 0, 0.5);--elevation_-2_shadow:var(--elevation_-2_shadow__light);--elevation_-1_shadow:var(--elevation_-1_shadow__light);--elevation_1_shadow:var(--elevation_1_shadow__light);--elevation_2_shadow:var(--elevation_2_shadow__light);--elevation_3_shadow:var(--elevation_3_shadow__light)}[theme=light]{color-scheme:light}[theme=dark]{color-scheme:dark;--drop_shadow:var(--drop_shadow__dark);--elevation_-2_shadow:var(--elevation_-2_shadow__dark);--elevation_-1_shadow:var(--elevation_-1_shadow__dark);--elevation_1_shadow:var(--elevation_1_shadow__dark);--elevation_2_shadow:var(--elevation_2_shadow__dark);--elevation_3_shadow:var(--elevation_3_shadow__dark)}[theme=auto]{color-scheme:light dark}@media (prefers-color-scheme:dark){[theme=auto]{--drop_shadow:var(--drop_shadow__dark);--elevation_-2_shadow:var(--elevation_-2_shadow__dark);--elevation_-1_shadow:var(--elevation_-1_shadow__dark);--elevation_1_shadow:var(--elevation_1_shadow__dark);--elevation_2_shadow:var(--elevation_2_shadow__dark);--elevation_3_shadow:var(--elevation_3_shadow__dark)}}:root{interpolate-size:allow-keywords}*,::after,::before{font-family:inherit;box-sizing:border-box;line-height:var(--line-height)}blockquote,body,code,dd,dl,dt,h1,h2,h3,h4,h5,h6,li,ol,p,pre,ul{margin:0;padding:.1px}html{font-family:var(--ff_body);font-size:var(--fs_base);font-weight:var(--fw_base);color:var(--tc);scrollbar-gutter:stable}::selection{background:var(--c_highlight)}body{min-height:100vh;background-color:var(--c_bg);color:var(--tc);overflow-y:scroll;font-family:var(--ff_body);position:relative}body.no-scroll{overflow:hidden!important}.container,main{max-width:var(--container_width);margin-left:auto;margin-right:auto;padding-top:var(--spacer);padding-left:var(--spacer);padding-right:var(--spacer)}nav>.link,nav>a{display:inline-block;padding:var(--spacer)!important;text-decoration:none}menu{margin:0;padding:0}menu a{display:block;padding:var(--spacer_q);text-decoration:none;color:inherit}summary{cursor:pointer;margin-bottom:var(--sapcer);outline:0;box-shadow:0 0 0 transparent;transition:box-shadow var(--animation_ms);border-radius:var(--radius)}summary:focus{box-shadow:var(--focus_shadow)}.d-b{display:block!important}.d-ib{display:inline-block!important}.d-g{display:grid!important}.d-i{display:inline!important}.d-n{display:none!important}.d-f{display:flex!important;flex-wrap:wrap}.d-if{display:inline-flex!important;flex-wrap:wrap}@media (min-width:1024px){.d-d-b{display:block!important}.d-d-ib{display:inline-block!important}.d-d-g{display:grid!important}.d-d-i{display:inline!important}.d-d-n{display:none!important}.d-d-f{display:flex!important;flex-wrap:wrap}.d-d-if{display:inline-flex!important;flex-wrap:wrap}}@media (min-width:769px) and (max-width:1023px){.t-d-b{display:block!important}.t-d-ib{display:inline-block!important}.t-d-g{display:grid!important}.t-d-i{display:inline!important}.t-d-n{display:none!important}.t-d-f{display:flex!important;flex-wrap:wrap}.t-d-if{display:inline-flex!important;flex-wrap:wrap}}@media (max-width:768px){.m-d-b{display:block!important}.m-d-ib{display:inline-block!important}.m-d-g{display:grid!important}.m-d-i{display:inline!important}.m-d-n{display:none!important}.m-d-f{display:flex!important;flex-wrap:wrap}.m-d-if{display:inline-flex!important;flex-wrap:wrap}}.flex,.flex-1{flex:1 1 auto}.flex-0{flex:0 0}.flex-2{flex:2 2 auto}.flex-3{flex:3 3 auto}.flex-4{flex:4 4 auto}.flex-5{flex:5 5 auto}.flex-6{flex:6 6 auto}.flex-7{flex:7 7 auto}.flex-8{flex:8 8 auto}.flex-9{flex:9 9 auto}.flex-10{flex:10 10 auto}@media (min-width:1024px){.d-d-b{display:block!important}.d-d-ib{display:inline-block!important}.d-d-g{display:grid!important}.d-d-i{display:inline!important}.d-d-n{display:none!important}.d-d-if{display:inline-flex!important;flex-wrap:wrap}.d-d-f{display:flex!important;flex-wrap:wrap}.d-flex,.d-flex-1{flex:1 1 auto}.d-flex-0{flex:0 0}.d-flex-2{flex:2 2 auto}.d-flex-3{flex:3 3 auto}.d-flex-4{flex:4 4 auto}.d-flex-5{flex:5 5 auto}.d-flex-6{flex:6 6 auto}.d-flex-7{flex:7 7 auto}.d-flex-8{flex:8 8 auto}.d-flex-9{flex:9 9 auto}.d-flex-10{flex:10 10 auto}}@media (min-width:769px) and (max-width:1023px){.t-d-b{display:block!important}.t-d-ib{display:inline-block!important}.t-d-g{display:grid!important}.t-d-i{display:inline!important}.t-d-n{display:none!important}.t-d-if{display:inline-flex!important;flex-wrap:wrap}.t-d-f{display:flex!important;flex-wrap:wrap}.t-flex,.t-flex-1{flex:1 1 auto}.t-flex-0{flex:0 0}.t-flex-2{flex:2 2 auto}.t-flex-3{flex:3 3 auto}.t-flex-4{flex:4 4 auto}.t-flex-5{flex:5 5 auto}.t-flex-6{flex:6 6 auto}.t-flex-7{flex:7 7 auto}.t-flex-8{flex:8 8 auto}.t-flex-9{flex:9 9 auto}.t-flex-10{flex:10 10 auto}}@media (max-width:768px){.m-d-b{display:block!important}.m-d-ib{display:inline-block!important}.m-d-g{display:grid!important}.m-d-i{display:inline!important}.m-d-n{display:none!important}.m-d-if{display:inline-flex!important;flex-wrap:wrap}.m-d-f{display:flex!important;flex-wrap:wrap}.m-flex,.m-flex-1{flex:1 1 auto}.m-flex-0{flex:0 0}.m-flex-2{flex:2 2 auto}.m-flex-3{flex:3 3 auto}.m-flex-4{flex:4 4 auto}.m-flex-5{flex:5 5 auto}.m-flex-6{flex:6 6 auto}.m-flex-7{flex:7 7 auto}.m-flex-8{flex:8 8 auto}.m-flex-9{flex:9 9 auto}.m-flex-10{flex:10 10 auto}}.fixed{position:fixed;top:0;width:100%;z-index:99;box-shadow:none;transition:box-shadow var(--animation_ms)}.fixed.scrolled{box-shadow:var(--elevation_2_shadow)}.small,small{font-size:var(--fs_small)!important}.large{font-size:var(--fs_large)!important}.h1,.h2,.h3,.h4,.h5,.h6,b,h1,h2,h3,h4,h5,h6,strong{font-weight:var(--fw_bold)}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:var(--ff_heading)}.h1,h1{font-size:var(--fs_h1)}.h2,h2{font-size:var(--fs_h2)}.h3,h3{font-size:var(--fs_h3)}.h4,h4{font-size:var(--fs_h4)}.h5,h5{font-size:var(--fs_h5)}.h6,h6{font-size:var(--fs_h6)}blockquote,dd,dl,h1,h2,h3,h4,h5,h6,hr,ol,p,pre,ul{margin-bottom:var(--spacer)}dl,ol,ul{padding-left:calc(1.5 * var(--spacer))}blockquote{border-left:2px solid var(--c_border);padding:var(--spacer)}mark{background-color:var(--c_highlight);color:inherit}.ff-mono,code,pre{font-family:var(--ff_mono)}code{background-color:var(--c_bg__alt);border-radius:var(--radius);word-break:break-word;padding:calc(.125 * var(--spacer)) var(--spacer_q)}pre code{display:block;padding:var(--spacer);word-break:normal;overflow:auto;white-space:pre-wrap}output{display:block;border:1px solid var(--c_border);border-radius:var(--radius);padding:var(--spacer) var(--spacer) 0 var(--spacer)}.ta-left{text-align:left}.ta-center{text-align:center}.ta-right{text-align:right}.link,a{color:var(--tc_link);box-shadow:0 0 0 transparent;transition:color var(--animation_ms),box-shadow var(--animation_ms);outline:0;border-radius:var(--radius);text-decoration:var(--link_decoration)}.link:hover,a:hover{color:var(--tc_link__hover)}.link:focus-visible,a:focus{box-shadow:var(--focus_shadow)}.no-link,.no-link:hover{text-decoration:none;color:inherit}hr{border:none;border-top:1px solid var(--c_border)}small{font-size:.75em}dl{padding:0;margin:0}dd,dt{padding-left:var(--spacer);border-left:2px solid var(--c_border)}dt{padding-top:var(--spacer_h)}dd{padding-bottom:var(--spacer_h)}dd+dd{margin-top:calc(-1 * var(--spacer));padding-top:0}li ul{margin-bottom:0}.td-n{text-decoration:none}.p,.pt,.py{padding-top:var(--spacer)!important}.p,.pr,.px{padding-right:var(--spacer)!important}.p,.pb,.py{padding-bottom:var(--spacer)!important}.p,.pl,.px{padding-left:var(--spacer)!important}.ph,.pth,.pyh{padding-top:var(--spacer_h)!important}.ph,.prh,.pxh{padding-right:var(--spacer_h)!important}.pbh,.ph,.pyh{padding-bottom:var(--spacer_h)!important}.ph,.plh,.pxh{padding-left:var(--spacer_h)!important}.pq,.ptq,.pyq{padding-top:var(--spacer_q)!important}.pq,.prq,.pxq{padding-right:var(--spacer_q)!important}.pbq,.pq,.pyq{padding-bottom:var(--spacer_q)!important}.plq,.pq,.pxq{padding-left:var(--spacer_q)!important}.p0,.pt0,.py0{padding-top:.1px!important}.p0,.pr0,.px0{padding-right:.1px!important}.p0,.pb0,.py0{padding-bottom:.1px!important}.p0,.pl0,.px0{padding-left:.1px!important}.m,.mt,.my{margin-top:var(--spacer)!important}.m,.mr,.mx{margin-right:var(--spacer)!important}.m,.mb,.my{margin-bottom:var(--spacer)!important}.m,.ml,.mx{margin-left:var(--spacer)!important}.mh,.mth,.myh{margin-top:var(--spacer_h)!important}.mh,.mrh,.mxh{margin-right:var(--spacer_h)!important}.mbh,.mh,.myh{margin-bottom:var(--spacer_h)!important}.mh,.mlh,.mxh{margin-left:var(--spacer_h)!important}.mq,.mtq,.myq{margin-top:var(--spacer_q)!important}.mq,.mrq,.mxq{margin-right:var(--spacer_q)!important}.mbq,.mq,.myq{margin-bottom:var(--spacer_q)!important}.mlq,.mq,.mxq{margin-left:var(--spacer_q)!important}.m0,.mt0,.my0{margin-top:0!important}.m0,.mr0,.mx0{margin-right:0!important}.m0,.mb0,.my0{margin-bottom:0!important}.m0,.ml0,.mx0{margin-left:0!important}.-m,.-mt,.-my{margin-top:calc(-1 * var(--spacer))!important}.-m,.-mr,.-mx{margin-right:calc(-1 * var(--spacer))!important}.-m,.-mb,.-my{margin-bottom:calc(-1 * var(--spacer))!important}.-m,.-ml,.-mx{margin-left:calc(-1 * var(--spacer))!important}.b,.bt,.by{border-top:1px solid var(--c_border)!important}.b,.br,.bx{border-right:1px solid var(--c_border)!important}.b,.bb,.by{border-bottom:1px solid var(--c_border)!important}.b,.bl,.bx{border-left:1px solid var(--c_border)!important}.b0,.bt0,.by0{border-top:none!important}.b0,.br0,.bx0{border-right:none!important}.b0,.bb0,.by0{border-bottom:none!important}.b0,.bl0,.bx0{border-left:none!important}.r,.rl,.rt,.rtl{border-top-left-radius:var(--radius)!important}.r,.rr,.rt,.rtr{border-top-right-radius:var(--radius)!important}.r,.rb,.rbr,.rr{border-bottom-right-radius:var(--radius)!important}.r,.rb,.rbl,.rl{border-bottom-left-radius:var(--radius)!important}.r0,.rl0,.rt0,.rtl0{border-top-left-radius:0!important}.r0,.rr0,.rt0,.rtr0{border-top-right-radius:0!important}.r0,.rb0,.rbr0,.rr0{border-bottom-right-radius:0!important}.r0,.rb0,.rbl0,.rl0{border-bottom-left-radius:0!important}.round{border-radius:9999rem!important}.row{display:flex;flex-wrap:wrap}.col{flex:1 1}.span-1{min-width:8.333%;flex-basis:8.333%}.span-2{min-width:16.666%;flex-basis:16.666%}.span-3{min-width:25%;flex-basis:25%}.span-4{min-width:33.333%;flex-basis:33.333%}.span-5{min-width:41.666%;flex-basis:41.666%}.span-6{min-width:50%;flex-basis:50%}.span-7{min-width:58.333%;flex-basis:58.333%}.span-8{min-width:66.666%;flex-basis:66.666%}.span-9{min-width:75%;flex-basis:75%}.span-10{min-width:83.333%;flex-basis:83.333%}.span-11{min-width:91.333%;flex-basis:91.333%}.span-12{min-width:100%;flex-basis:100%}@media (min-width:1024px){.d-span-1{min-width:8.333%;flex-basis:8.333%}.d-span-2{min-width:16.666%;flex-basis:16.666%}.d-span-3{min-width:25%;flex-basis:25%}.d-span-4{min-width:33.333%;flex-basis:33.333%}.d-span-5{min-width:41.666%;flex-basis:41.666%}.d-span-6{min-width:50%;flex-basis:50%}.d-span-7{min-width:58.333%;flex-basis:58.333%}.d-span-8{min-width:66.666%;flex-basis:66.666%}.d-span-9{min-width:75%;flex-basis:75%}.d-span-10{min-width:83.333%;flex-basis:83.333%}.d-span-11{min-width:91.333%;flex-basis:91.333%}.d-span-12{min-width:100%;flex-basis:100%}}@media (min-width:769px) and (max-width:1023px){.t-span-1{min-width:8.333%;flex-basis:8.333%}.t-span-2{min-width:16.666%;flex-basis:16.666%}.t-span-3{min-width:25%;flex-basis:25%}.t-span-4{min-width:33.333%;flex-basis:33.333%}.t-span-5{min-width:41.666%;flex-basis:41.666%}.t-span-6{min-width:50%;flex-basis:50%}.t-span-7{min-width:58.333%;flex-basis:58.333%}.t-span-8{min-width:66.666%;flex-basis:66.666%}.t-span-9{min-width:75%;flex-basis:75%}.t-span-10{min-width:83.333%;flex-basis:83.333%}.t-span-11{min-width:91.333%;flex-basis:91.333%}.t-span-12{min-width:100%;flex-basis:100%}}@media (max-width:768px){.m-span-1{min-width:8.333%;flex-basis:8.333%}.m-span-2{min-width:16.666%;flex-basis:16.666%}.m-span-3{min-width:25%;flex-basis:25%}.m-span-4{min-width:33.333%;flex-basis:33.333%}.m-span-5{min-width:41.666%;flex-basis:41.666%}.m-span-6{min-width:50%;flex-basis:50%}.m-span-7{min-width:58.333%;flex-basis:58.333%}.m-span-8{min-width:66.666%;flex-basis:66.666%}.m-span-9{min-width:75%;flex-basis:75%}.m-span-10{min-width:83.333%;flex-basis:83.333%}.m-span-11{min-width:91.333%;flex-basis:91.333%}.m-span-12{min-width:100%;flex-basis:100%}}.cols-2{grid-template-columns:repeat(2,1fr)}.cols-3{grid-template-columns:repeat(3,1fr)}.cols-4{grid-template-columns:repeat(4,1fr)}.cols-5{grid-template-columns:repeat(5,1fr)}.cols-6{grid-template-columns:repeat(6,1fr)}.cols-7{grid-template-columns:repeat(7,1fr)}.cols-8{grid-template-columns:repeat(8,1fr)}.cols-9{grid-template-columns:repeat(9,1fr)}.cols-10{grid-template-columns:repeat(10,1fr)}@media (min-width:1024px){.d-cols-2{grid-template-columns:repeat(2,1fr)}.d-cols-3{grid-template-columns:repeat(3,1fr)}.d-cols-4{grid-template-columns:repeat(4,1fr)}.d-cols-5{grid-template-columns:repeat(5,1fr)}.d-cols-6{grid-template-columns:repeat(6,1fr)}.d-cols-7{grid-template-columns:repeat(7,1fr)}.d-cols-8{grid-template-columns:repeat(8,1fr)}.d-cols-9{grid-template-columns:repeat(9,1fr)}.d-cols-10{grid-template-columns:repeat(10,1fr)}}@media (min-width:769px) and (max-width:1023px){.t-cols-2{grid-template-columns:repeat(2,1fr)}.t-cols-3{grid-template-columns:repeat(3,1fr)}.t-cols-4{grid-template-columns:repeat(4,1fr)}.t-cols-5{grid-template-columns:repeat(5,1fr)}.t-cols-6{grid-template-columns:repeat(6,1fr)}.t-cols-7{grid-template-columns:repeat(7,1fr)}.t-cols-8{grid-template-columns:repeat(8,1fr)}.t-cols-9{grid-template-columns:repeat(9,1fr)}.t-cols-10{grid-template-columns:repeat(10,1fr)}}@media (max-width:768px){.m-cols-2{grid-template-columns:repeat(2,1fr)}.m-cols-3{grid-template-columns:repeat(3,1fr)}.m-cols-4{grid-template-columns:repeat(4,1fr)}.m-cols-5{grid-template-columns:repeat(5,1fr)}.m-cols-6{grid-template-columns:repeat(6,1fr)}.m-cols-7{grid-template-columns:repeat(7,1fr)}.m-cols-8{grid-template-columns:repeat(8,1fr)}.m-cols-9{grid-template-columns:repeat(9,1fr)}.m-cols-10{grid-template-columns:repeat(10,1fr)}}.btn,button:not(.no-btn):not(.no-style),input[type=button],input[type=reset],input[type=submit]{display:inline-block;padding:var(--btn_padding);background-color:var(--btn_bg);border:1px solid var(--btn_border);cursor:pointer;outline:0;border-radius:var(--radius);color:var(--btn_tc);transition:background-color var(--animation_ms),box-shadow var(--animation_ms);text-decoration:none;box-shadow:var(--btn_box_shadow);font-size:inherit;vertical-align:middle}.btn:hover,button:not(.no-btn):not(.no-style):hover,input[type=button]:hover,input[type=reset]:hover,input[type=submit]:hover{background-color:var(--btn_bg__hover);color:var(--btn_tc);box-shadow:var(--btn_box_shadow__hover)}.btn:focus,button:not(.no-btn):not(.no-style):focus,input[type=button]:focus,input[type=reset]:focus,input[type=submit]:focus{box-shadow:var(--btn_box_shadow__hover),var(--focus_shadow);z-index:1}.btn[disabled],button:not(.no-btn):not(.no-style):disabled,input[type=button]:disabled,input[type=reset]:disabled,input[type=submit]:disabled{opacity:.6}.btn.primary,button:not(.no-btn).primary,input[type=button].primary,input[type=reset].primary,input[type=submit].primary{background-color:var(--c_primary)!important;--btn_tc:var(--tc_on_primary)}.btn.primary:hover,button:not(.no-btn).primary:hover,input[type=button].primary:hover,input[type=reset].primary:hover,input[type=submit].primary:hover{background-color:var(--c_primary__hover)!important}.btn.secondary,button:not(.no-btn).secondary,input[type=button].secondary,input[type=reset].secondary,input[type=submit].secondary{background-color:var(--c_secondary)!important;--btn_tc:var(--tc_on_secondary)}.btn.secondary:hover,button:not(.no-btn).secondary:hover,input[type=button].secondary:hover,input[type=reset].secondary:hover,input[type=submit].secondary:hover{background-color:var(--c_secondary__hover)!important}.btn.success,button:not(.no-btn).success,input[type=button].success,input[type=reset].success,input[type=submit].success{background-color:var(--c_success)!important;--btn_tc:var(--tc_on_success)}.btn.success:hover,button:not(.no-btn).success:hover,input[type=button].success:hover,input[type=reset].success:hover,input[type=submit].success:hover{background-color:var(--c_success__hover)!important}.btn.warning,button:not(.no-btn).warning,input[type=button].warning,input[type=reset].warning,input[type=submit].warning{background-color:var(--c_warning)!important;--btn_tc:var(--tc_on_warning)}.btn.warning:hover,button:not(.no-btn).warning:hover,input[type=button].warning:hover,input[type=reset].warning:hover,input[type=submit].warning:hover{background-color:var(--c_warning__hover)!important}.btn.danger,button:not(.no-btn).danger,input[type=button].danger,input[type=reset].danger,input[type=submit].danger{background-color:var(--c_danger)!important;--btn_tc:var(--tc_on_danger)}.btn.danger:hover,button:not(.no-btn).danger:hover,input[type=button].danger:hover,input[type=reset].danger:hover,input[type=submit].danger:hover{background-color:var(--c_danger__hover)!important}.btn.link,button:not(.no-btn):not(.no-style).link,input[type=button].link,input[type=reset].link,input[type=submit].link{background-color:transparent;color:inherit;box-shadow:0 0 0 transparent;border:none;padding:.1px;font-size:inherit}.btn-grp{display:inline-flex}.btn-grp .btn:not(:first-child),.btn-grp button:not(.no-btn):not(:first-child),.btn-grp input[type=button]:not(:first-child),.btn-grp input[type=reset]:not(:first-child),.btn-grp input[type=submit]:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0;border-left:1px solid rgba(0,0,0,.25)}.btn-grp .btn:not(:last-child),.btn-grp button:not(.no-btn):not(:last-child),.btn-grp input[type=button]:not(:last-child),.btn-grp input[type=reset]:not(:last-child),.btn-grp input[type=submit]:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.no-btn{display:inline;border:none;background-color:transparent;padding:0;font-size:inherit;font-family:inherit;cursor:pointer;outline:0;box-shadow:0 0 0 transparent;transition:box-shadow var(--animation_ms);border-radius:0;text-align:left;color:inherit}.no-btn:focus{box-shadow:var(--focus_shadow)}.full{display:block;width:100%}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]),select,textarea{display:block;width:100%;background-color:var(--input_bg);color:var(--input_tc);border:var(--input_border_width) solid var(--c_input_border);padding:var(--input_padding);border-radius:var(--radius);outline:0;transition:box-shadow var(--animation_ms)}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]):focus,input[type=checkbox]:focus,input[type=radio]:focus,select:focus,textarea:focus{box-shadow:var(--focus_shadow)}input:not([type=button]):not([type=submit]):not([type=reset]):not([type=radio]):not([type=checkbox]):disabled,input[type=checkbox]:disabled,input[type=radio]:disabled,select:disabled,textarea:disabled{opacity:.6}select[multiple],textarea{resize:vertical;max-height:75vh;height:6rem;min-height:4rem}select[multiple]{height:8rem}select{cursor:pointer}label{display:block;cursor:pointer;padding-bottom:var(--spacer_h)}label.checkbox,label.radio{display:inline-block;vertical-align:middle;width:calc(100% - 2em - (2 * var(--spacer_h)) - 6px)}input[type=checkbox],input[type=radio]{display:inline-block;width:1em;height:1em;cursor:pointer;vertical-align:middle;accent-color:var(--c_input_accent);margin:var(--spacer_q) var(--spacer_h);transition:background-color var(--animation_ms),color var(--animation_ms),box-shadow var(--animation_ms)}input[type=checkbox]{width:1.75em;height:1.75em;appearance:none;-webkit-appearance:none;background-color:transparent;border:2px solid var(--c_border);border-radius:var(--radius);vertical-align:-.5em;position:relative}input[type=checkbox]::before{content:"";position:absolute;inset:0;border-radius:calc(var(--radius) - 2px);background-color:transparent;mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="200 -760 560 560"><path d="m424-312 282-282-56-56-226 226-114-114-56 56 170 170Z"/></svg>');-webkit-mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="200 -760 560 560"><path d="m424-312 282-282-56-56-226 226-114-114-56 56 170 170Z"/></svg>');mask-size:contain;-webkit-mask-size:contain;mask-position:center;-webkit-mask-position:center;mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;transition:background-color var(--animation_ms)}input[type=checkbox]:focus{box-shadow:var(--focus_shadow);outline:0}input[type=checkbox]:checked{background-color:var(--c_primary);border-color:var(--c_primary)}input[type=checkbox]:checked::before{background-color:var(--tc_on_primary)}input[type=radio]{width:1.75em;height:1.75em;appearance:none;-webkit-appearance:none;background-color:transparent;border:2px solid var(--c_border);border-radius:50%;vertical-align:-.5em}input[type=radio]:focus{box-shadow:var(--focus_shadow);outline:0}input[type=radio]:checked{border-color:var(--c_primary);background:radial-gradient(circle,var(--c_primary) 40%,transparent 45%)}select option{padding:var(--spacer_h) var(--spacer);background-color:var(--input_bg);color:var(--input_tc)}select[multiple]{padding:.1px}select[multiple] option{padding:var(--spacer_h) var(--spacer)}input[type=color]{padding:0!important;height:2.35em}input[type=color]::-webkit-color-swatch-wrapper{padding:0}input[type=color]::-webkit-color-swatch{border-radius:var(--radius,.25rem);cursor:pointer}input[type=date]::-webkit-calendar-picker-indicator,input[type=month]::-webkit-calendar-picker-indicator,input[type=search]::-webkit-search-cancel-button,input[type=time]::-webkit-calendar-picker-indicator,input[type=week]::-webkit-calendar-picker-indicator{filter:var(--date_picker_icon_filter)}.table-wrapper{overflow-x:auto}table{width:100%;border-spacing:0}th{font-weight:var(--fw_bold);text-align:left;background-color:var(--c_bg__alt);border-top:1px solid var(--c_border)}td,th{padding:var(--spacer_h) var(--spacer);border-bottom:1px solid var(--c_border);border-left:1px solid var(--c_border)}td:last-child,th:last-child{border-right:1px solid var(--c_border)}th:first-child{border-top-left-radius:var(--radius)}th:last-child{border-top-right-radius:var(--radius)}tr:last-child td:first-child{border-bottom-left-radius:var(--radius)}tr:last-child td:last-child{border-bottom-right-radius:var(--radius)}.bg-default{background-color:var(--c_bg)!important;color:var(--tc)!important}.bg-alt{background-color:var(--c_bg__alt)!important;color:var(--tc)!important}.bg-inv{--c_primary:var(--c_primary__inv);--c_primary__hover:var(--c_primary__inv__hover);--c_secondary:var(--c_secondary__inv);--c_secondary__hover:var(--c_secondary__inv__hover);--c_success:var(--c_success__inv);--c_success__hover:var(--c_success__inv__hover);--c_warning:var(--c_warning__inv);--c_warning__hover:var(--c_warning__inv__hover);--c_danger:var(--c_danger__inv);--c_danger__hover:var(--c_danger__inv__hover);--tc_link:var(--tc_link__inv);--tc_link__hover:var(--tc_link__inv__hover);background-color:var(--c_bg__inv)!important;color:var(--tc_inv)!important}.bg-primary{--tc_link:var(--tc_on_primary);--tc_link__hover:var(--tc_on_primary);--c_border:var(--tc_on_primary);background-color:var(--c_primary)!important;color:var(--tc_on_primary)!important;--focus_shadow:var(--focus_shadow_on_primary)}.bg-secondary{--tc_link:var(--tc_on_secondary);--tc_link__hover:var(--tc_on_secondary);background-color:var(--c_secondary)!important;color:var(--tc_on_secondary)!important}.bg-success{--tc_link:var(--tc_on_success);--tc_link__hover:var(--tc_on_success);background-color:var(--c_success)!important;color:var(--tc_on_success)!important}.bg-warning{--tc_link:var(--tc_on_warning);--tc_link__hover:var(--tc_on_warning);background-color:var(--c_warning)!important;color:var(--tc_on_warning)!important}.bg-danger{--tc_link:var(--tc_on_danger);--tc_link__hover:var(--tc_on_danger);background-color:var(--c_danger)!important;color:var(--tc_on_danger)!important}.tc-default{color:var(--tc)!important}.tc-inv{color:var(--tc__inv)!important}.tc-primary{color:var(--tc_primary)!important}.bg-inv .tc-primary,.is-inv .tc-primary{color:var(--tc_primary__inv)!important}.tc-secondary{color:var(--tc_secondary)!important}.bg-inv .tc-secondary,.is-inv .tc-secondary{color:var(--tc_secondary__inv)!important}.tc-success{color:var(--tc_success)!important}.bg-inv .tc-success,.is-inv .tc-success{color:var(--tc_success__inv)!important}.tc-warning{color:var(--tc_warning)!important}.bg-inv .tc-warning,.is-inv .tc-warning{color:var(--tc_warning__inv)!important}.tc-danger{color:var(--tc_danger)!important}.bg-inv .tc-danger,.is-inv .tc-danger{color:var(--tc_danger__inv)!important}.tc-muted{color:var(--tc_muted)!important}.card{border:1px solid var(--c_border);border-radius:var(--radius);padding-top:var(--spacer);padding-left:var(--spacer);padding-right:var(--spacer);margin-bottom:var(--spacer)}.drop-shadow{box-shadow:var(--drop_shadow)}.elevation--2{background-color:var(--elevation_-2_bg);box-shadow:var(--elevation_-2_shadow)}.elevation--1{background-color:var(--elevation_-1_bg);box-shadow:var(--elevation_-1_shadow)}.elevation-0{background-color:var(--elevation_0_bg);box-shadow:var(--elevation_0_shadow)}.elevation-1{background-color:var(--elevation_1_bg);box-shadow:var(--elevation_1_shadow)}.elevation-2{background-color:var(--elevation_2_bg);box-shadow:var(--elevation_2_shadow)}.elevation-3{background-color:var(--elevation_3_bg);box-shadow:var(--elevation_3_shadow)}.icon{display:inline-block;width:1.35em;vertical-align:top;margin-left:auto;margin-right:auto}iframe{border:none;width:100%}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kempo-server",
3
3
  "type": "module",
4
- "version": "1.10.4",
4
+ "version": "1.10.6",
5
5
  "description": "A lightweight, zero-dependency, file based routing server.",
6
6
  "main": "dist/index.js",
7
7
  "exports": {
@@ -15,6 +15,7 @@
15
15
  "scripts": {
16
16
  "build": "node scripts/build.js",
17
17
  "docs": "node dist/index.js -r ./docs",
18
+ "spa": "node dist/index.js -r ./spa",
18
19
  "test": "npx kempo-test",
19
20
  "test:gui": "npx kempo-test --gui",
20
21
  "test:browser": "npx kempo-test -b",
@@ -0,0 +1,15 @@
1
+ {
2
+ "customRoutes": {
3
+ "/kempo.css": "../node_modules/kempo-css/dist/kempo.min.css",
4
+ "/*.html": "./app.html",
5
+ "/": "./app.html"
6
+ },
7
+ "middleware": {
8
+ "security": {
9
+ "enabled": true,
10
+ "headers": {
11
+ "Cache-Control": "public, max-age=3600"
12
+ }
13
+ }
14
+ }
15
+ }
package/spa/app.html ADDED
@@ -0,0 +1,20 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Kempo-Server SPA</title>
7
+ <link rel="stylesheet" href="/kempo.css" />
8
+ </head>
9
+ <body>
10
+ <nav>
11
+ <a href="/">Home</a>
12
+ <a href="/page1.html">Page 1</a>
13
+ <a href="/about.html">About</a>
14
+ <a href="/contact.html">Contact</a>
15
+ <a href="/settings.html">Settings</a>
16
+ </nav>
17
+ <main id="main"></main>
18
+ <script src="/spa.js"></script>
19
+ </body>
20
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1>About</h1>
2
+ <p>This is an example single-page application powered by Kempo-Server.</p>
@@ -0,0 +1,2 @@
1
+ <h1>Contact</h1>
2
+ <p>Get in touch at <a href="mailto:hello@example.com">hello@example.com</a>.</p>
@@ -0,0 +1 @@
1
+ <h1>Hello <code>index.html</code></h1>
@@ -0,0 +1 @@
1
+ <h1>Hello <code>page1.html</code></h1>
@@ -0,0 +1,2 @@
1
+ <h1>Settings</h1>
2
+ <p>Configure your preferences here.</p>
package/spa/spa.js ADDED
@@ -0,0 +1,32 @@
1
+ const main = document.getElementById("main");
2
+
3
+ const loadPage = path => {
4
+ const page = (path === "/" || path === "/index.html")
5
+ ? "/pages/index.html"
6
+ : `/pages${path}`;
7
+ fetch(page)
8
+ .then(r => {
9
+ if(!r.ok) throw new Error(r.status);
10
+ return r.text();
11
+ })
12
+ .then(html => {
13
+ main.innerHTML = html;
14
+ })
15
+ .catch(() => {
16
+ main.innerHTML = "<h1>Page Not Found</h1>";
17
+ });
18
+ };
19
+
20
+ document.addEventListener("click", e => {
21
+ const a = e.target.closest("a");
22
+ if(!a || a.origin !== location.origin) return;
23
+ e.preventDefault();
24
+ history.pushState(null, "", a.href);
25
+ loadPage(a.pathname);
26
+ });
27
+
28
+ window.addEventListener("popstate", () => {
29
+ loadPage(location.pathname);
30
+ });
31
+
32
+ loadPage(location.pathname);