diff --git a/.github/profile/README.md b/.github/profile/README.md
index b389e09..ce8ab6f 100644
--- a/.github/profile/README.md
+++ b/.github/profile/README.md
@@ -5,7 +5,7 @@
**GDIPS** is a GDPS (Geometry Dash Private Server) hosted on **GDPSFH**. The GDPS originally started on November 28th, 2024.
***
## Downloading
-You can download the GDPS in [here](https://gdi.ps.fhgdps.com). Platforms that are supported are: **Android** and **Windows** | **iOS** not added.
+You can download the GDPS in [here](https://gdips.wasmer.app). Platforms that are supported are: **Android** and **Windows** | **iOS** not added.
***
## Repositories
[website](https://github.com/flessan/GDIPS) - The GDIPS website source code.
diff --git a/README.md b/README.md
index 803498b..05f2c01 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
GDIPS Website
@@ -43,7 +43,7 @@
๐ Buka Website ยท
๐ฅ Download Game ยท
- ๐ฎ Dashboard Server
+ ๐ฎ Dashboard Server
@@ -302,7 +302,7 @@ site/
| | Link | Deskripsi |
|---|------|-----------|
| ๐ | [gdips.pages.dev](https://gdips.pages.dev) | Website ini (live) |
-| ๐ฎ | [Dashboard](https://gdi.ps.fhgdps.com) | Game server dashboard |
+| ๐ฎ | [Dashboard](https://gdips.wasmer.app) | Game server dashboard |
| ๐ฅ | [Download](https://gdips.pages.dev/download) | Download game client |
| ๐ป | [gmdips/GDIPS](https://github.com/gmdips/server) | Repo game server |
| ๐ข | [gmdips org](https://github.com/gmdips) | Organization GitHub |
diff --git a/main/404.html b/main/404.html
new file mode 100644
index 0000000..3b42280
--- /dev/null
+++ b/main/404.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+ 404 ยท Halaman tidak ditemukan | GDIPS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GDIPS
+
+
+
+
+
+
+
+
+
+
+
+
+
Error 404
+
404
+
Halaman yang kamu cari tidak ditemukan
+
+ Mungkin tautannya salah ketik, atau halamannya sudah dipindahkan. Coba salah satu
+ tautan di bawah ini supaya kamu tetap bisa main.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/_headers b/main/_headers
index 6b885de..ea65fcb 100644
--- a/main/_headers
+++ b/main/_headers
@@ -3,3 +3,9 @@
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
+
+/assets/*
+ Cache-Control: public, max-age=604800
+
+/sw.js
+ Cache-Control: no-cache
diff --git a/main/_redirects b/main/_redirects
index faf1c8c..7857ea4 100644
--- a/main/_redirects
+++ b/main/_redirects
@@ -1,4 +1,10 @@
/ /pages 301
+/pages/id/rate /pages/id/rating-system/ 301
+/pages/id/rate.html /pages/id/rating-system/ 301
+
+# Dashboard: site links use /dashboard/... and are forwarded to the live dashboard host
+/dashboard https://gdips.wasmer.app/dashboard 302
+/dashboard/* https://gdips.wasmer.app/dashboard/:splat 302
# 404 fallback
/* /404.html 404
diff --git a/main/assets/batik.css b/main/assets/batik.css
deleted file mode 100644
index 32df393..0000000
--- a/main/assets/batik.css
+++ /dev/null
@@ -1,488 +0,0 @@
-:root {
- /* Warna Indonesia */
- --primary: #c8102e; /* Merah Indonesia */
- --secondary: #f9f9f9; /* Putih Indonesia */
- --accent: #d4af37; /* Emas Indonesia */
- --dark: #1a1a1a; /* Background gelap */
- --light: #e8eaed; /* Teks terang */
- --card-bg: #2d2d2d; /* Background kartu */
- --text-secondary: #a0a0a0; /* Teks sekunder */
- --border-color: rgba(200, 16, 46, 0.3); /* Warna border */
-}
-
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: 'Poppins', sans-serif;
- background-color: var(--dark);
- color: var(--light);
- line-height: 1.6;
- overflow-x: hidden;
- position: relative;
-}
-
-/* Indonesian pattern background */
-body::before {
- content: "";
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-image:
- linear-gradient(45deg, rgba(200, 16, 46, 0.05) 25%, transparent 25%),
- linear-gradient(-45deg, rgba(200, 16, 46, 0.05) 25%, transparent 25%),
- linear-gradient(45deg, transparent 75%, rgba(200, 16, 46, 0.05) 75%),
- linear-gradient(-45deg, transparent 75%, rgba(200, 16, 46, 0.05) 75%);
- background-size: 20px 20px;
- background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
- z-index: -1;
-}
-
-/* Header Styles */
-header {
- background: linear-gradient(135deg, var(--primary), #8b0000);
- padding: 15px 20px;
- position: sticky;
- top: 0;
- z-index: 100;
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
-}
-
-nav {
- display: flex;
- justify-content: space-between;
- align-items: center;
- max-width: 1200px;
- margin: 0 auto;
-}
-
-.logo {
- font-weight: 700;
- font-size: 1.5rem;
- color: var(--secondary);
- text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.logo i {
- font-size: 1.8rem;
- color: var(--accent);
-}
-
-.menu-toggle {
- display: none;
- background: none;
- border: none;
- color: var(--secondary);
- font-size: 1.5rem;
- cursor: pointer;
-}
-
-.nav-links {
- display: flex;
- gap: 20px;
- list-style: none;
-}
-
-.nav-links a {
- color: var(--secondary);
- text-decoration: none;
- font-weight: 500;
- padding: 5px 10px;
- border-radius: 20px;
- transition: all 0.3s ease;
- font-size: 0.9rem;
-}
-
-.nav-links a:hover {
- background-color: rgba(255,255,255,0.2);
- transform: translateY(-2px);
-}
-
-/* Hero Section */
-.hero {
- text-align: center;
- padding: 60px 20px;
- background: linear-gradient(135deg, var(--primary), #8b0000);
- position: relative;
- overflow: hidden;
-}
-
-.hero::before {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-image:
- linear-gradient(45deg, rgba(255,255,255,0.05) 25%, transparent 25%),
- linear-gradient(-45deg, rgba(255,255,255,0.05) 25%, transparent 25%),
- linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.05) 75%),
- linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.05) 75%);
- background-size: 20px 20px;
- background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
- opacity: 0.1;
- pointer-events: none;
-}
-
-.icon-container {
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- margin-bottom: 20px;
-}
-
-.icon {
- width: 100px;
- height: 100px;
- object-fit: contain;
- border-radius: 50%;
- border: 4px solid var(--secondary);
- box-shadow: 0 8px 20px rgba(0,0,0,0.2);
- transition: transform 0.3s ease;
- z-index: 1; /* Pastikan ikon berada di atas elemen pseudo */
-}
-
-.icon:hover {
- transform: scale(1.1) rotate(10deg);
-}
-
-.icon-container::after {
- content: "";
- position: absolute;
- width: 100px;
- height: 100px;
- border-radius: 50%;
- border: 2px dashed var(--accent);
- animation: rotate 20s linear infinite;
- z-index: 0; /* Pastikan elemen pseudo berada di bawah ikon */
-}
-
-@keyframes rotate {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
-}
-
-.hero h2 {
- font-size: clamp(1.8rem, 5vw, 2.5rem);
- margin-bottom: 15px;
- color: var(--secondary);
- text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
- position: relative;
- display: inline-block;
-}
-
-.hero h2::after {
- content: "";
- position: absolute;
- bottom: -5px;
- left: 50%;
- transform: translateX(-50%);
- width: 50px;
- height: 3px;
- background-color: var(--accent);
- border-radius: 3px;
-}
-
-.hero p {
- font-size: clamp(0.9rem, 2.5vw, 1.1rem);
- max-width: 600px;
- margin: 0 auto 30px;
- color: var(--secondary);
-}
-
-/* Credits Section */
-.credits-container {
- padding: 40px 20px;
- max-width: 1200px;
- margin: 0 auto;
-}
-
-.credit-card {
- background-color: var(--card-bg);
- border-radius: 15px;
- padding: 25px;
- margin-bottom: 30px;
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- box-shadow: 0 10px 20px rgba(0,0,0,0.2);
- transition: transform 0.3s ease, box-shadow 0.3s ease;
- position: relative;
- overflow: hidden;
- border: 1px solid var(--border-color);
-}
-
-.credit-card:hover {
- transform: translateY(-10px);
- box-shadow: 0 15px 30px rgba(0,0,0,0.4);
-}
-
-.credit-card::before {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 5px;
- background: linear-gradient(90deg, var(--primary), var(--accent));
-}
-
-.credit-img {
- width: 100px;
- height: 100px;
- border-radius: 50%;
- object-fit: cover;
- border: 4px solid var(--secondary);
- box-shadow: 0 5px 15px rgba(0,0,0,0.3);
- margin-bottom: 20px;
-}
-
-.credit-card h3 {
- font-size: 1.5rem;
- margin-bottom: 10px;
- color: var(--secondary);
-}
-
-.credit-card p {
- font-size: 0.95rem;
- margin-bottom: 20px;
- color: var(--light);
-}
-
-.role {
- display: inline-block;
- padding: 3px 10px;
- background: linear-gradient(90deg, var(--primary), var(--accent));
- color: var(--secondary);
- border-radius: 20px;
- font-size: 0.8rem;
- font-weight: 600;
- margin-bottom: 15px;
-}
-
-.view-btn {
- background-color: var(--primary);
- color: var(--secondary);
- border: none;
- padding: 10px 25px;
- border-radius: 30px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 0.9rem;
- box-shadow: 0 4px 10px rgba(200, 16, 46, 0.3);
-}
-
-.view-btn:hover {
- background-color: #a00d26;
- transform: translateY(-3px);
- box-shadow: 0 7px 15px rgba(200, 16, 46, 0.4);
-}
-
-/* Footer */
-footer {
- background-color: var(--card-bg);
- padding: 25px 20px;
- text-align: center;
- margin-top: 40px;
- border-top: 1px solid var(--border-color);
-}
-
-footer p {
- font-size: 0.9rem;
- color: var(--text-secondary);
-}
-
-footer a {
- color: var(--primary);
- text-decoration: none;
- font-weight: 600;
- transition: color 0.3s ease;
-}
-
-footer a:hover {
- color: var(--accent);
-}
-
-/* Floating Elements */
-.floating {
- position: absolute;
- animation: float 6s ease-in-out infinite;
- opacity: 0.7;
- z-index: 1;
-}
-
-@keyframes float {
- 0%, 100% { transform: translateY(0); }
- 50% { transform: translateY(-20px); }
-}
-
-.floating:nth-child(1) {
- top: 10%;
- left: 5%;
- animation-delay: 0s;
-}
-
-.floating:nth-child(2) {
- top: 30%;
- right: 8%;
- animation-delay: 1s;
-}
-
-.floating:nth-child(3) {
- bottom: 20%;
- left: 10%;
- animation-delay: 2s;
-}
-
-/* Special Effects */
-.sparkle {
- position: absolute;
- width: 5px;
- height: 5px;
- background-color: var(--accent);
- border-radius: 50%;
- opacity: 0;
- animation: sparkle 2s ease-in-out infinite;
-}
-
-@keyframes sparkle {
- 0% { opacity: 0; transform: scale(0); }
- 50% { opacity: 1; transform: scale(1); }
- 100% { opacity: 0; transform: scale(0); }
-}
-
-/* Cute Elements */
-.heart {
- color: var(--primary);
- font-size: 1.2rem;
- margin: 0 5px;
- animation: pulse 1.5s ease infinite;
-}
-
-@keyframes pulse {
- 0%, 100% { transform: scale(1); }
- 50% { transform: scale(1.3); }
-}
-
-/* Responsive Styles */
-@media (max-width: 768px) {
- .menu-toggle {
- display: block;
- }
-
- .nav-links {
- position: fixed;
- top: 70px;
- left: 0;
- width: 100%;
- background: linear-gradient(135deg, var(--primary), #8b0000);
- flex-direction: column;
- align-items: center;
- padding: 20px 0;
- gap: 15px;
- clip-path: circle(0px at 90% -10%);
- transition: all 0.5s ease-out;
- pointer-events: none;
- }
-
- .nav-links.active {
- clip-path: circle(1000px at 90% -10%);
- pointer-events: all;
- }
-
- .hero h2 {
- font-size: 1.8rem;
- }
-
- .hero p {
- font-size: 0.95rem;
- }
-
- .credit-card {
- padding: 20px;
- }
-}
-
-@media (min-width: 992px) {
- .credits-container {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 30px;
- }
-
- .credit-card {
- margin-bottom: 0;
- }
-}
-
-@media (max-width: 480px) {
- .credits-container {
- grid-template-columns: 1fr;
- }
-
- .hero {
- padding: 40px 15px;
- }
-
- .icon {
- width: 80px;
- height: 80px;
- }
-
- .icon-container::after {
- width: 80px;
- height: 80px;
- }
-
- .credit-card {
- padding: 15px;
- }
-
- .credit-img {
- width: 80px;
- height: 80px;
- }
-
- .view-btn {
- padding: 8px 20px;
- font-size: 0.85rem;
- }
-}
-
-/* Accessibility improvements */
-@media (prefers-reduced-motion: reduce) {
- * {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-/* High contrast mode support */
-@media (prefers-contrast: high) {
- :root {
- --primary: #ff0000;
- --secondary: #ffffff;
- --accent: #ffff00;
- --dark: #000000;
- --light: #ffffff;
- --card-bg: #222222;
- --text-secondary: #cccccc;
- --border-color: #ff0000;
- }
-}
\ No newline at end of file
diff --git a/main/assets/bg-pattern.png b/main/assets/bg-pattern.png
deleted file mode 100644
index d245508..0000000
Binary files a/main/assets/bg-pattern.png and /dev/null differ
diff --git a/main/assets/brand/apple-touch-icon.png b/main/assets/brand/apple-touch-icon.png
new file mode 100644
index 0000000..bf03e2d
Binary files /dev/null and b/main/assets/brand/apple-touch-icon.png differ
diff --git a/main/assets/brand/favicon-32.png b/main/assets/brand/favicon-32.png
new file mode 100644
index 0000000..5a4e16e
Binary files /dev/null and b/main/assets/brand/favicon-32.png differ
diff --git a/main/assets/brand/favicon.svg b/main/assets/brand/favicon.svg
new file mode 100644
index 0000000..ef6cc32
--- /dev/null
+++ b/main/assets/brand/favicon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/assets/brand/gdips-mark-maskable.svg b/main/assets/brand/gdips-mark-maskable.svg
new file mode 100644
index 0000000..e88c338
--- /dev/null
+++ b/main/assets/brand/gdips-mark-maskable.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/assets/brand/gdips-mark.svg b/main/assets/brand/gdips-mark.svg
new file mode 100644
index 0000000..ef6cc32
--- /dev/null
+++ b/main/assets/brand/gdips-mark.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/assets/brand/icon-192.png b/main/assets/brand/icon-192.png
new file mode 100644
index 0000000..a4ddc5d
Binary files /dev/null and b/main/assets/brand/icon-192.png differ
diff --git a/main/assets/brand/icon-512.png b/main/assets/brand/icon-512.png
new file mode 100644
index 0000000..775e56a
Binary files /dev/null and b/main/assets/brand/icon-512.png differ
diff --git a/main/assets/brand/icon-maskable-512.png b/main/assets/brand/icon-maskable-512.png
new file mode 100644
index 0000000..9069657
Binary files /dev/null and b/main/assets/brand/icon-maskable-512.png differ
diff --git a/main/assets/m3/README.md b/main/assets/m3/README.md
new file mode 100644
index 0000000..a158f7b
--- /dev/null
+++ b/main/assets/m3/README.md
@@ -0,0 +1,121 @@
+# GDIPS ยท Material You 3 design system
+
+Everything the redesigned site renders comes from this folder. No build step, no
+dependencies โ plain CSS and plain ES5-compatible JavaScript that runs straight
+from Cloudflare Pages.
+
+## Load order
+
+Every page links the same five stylesheets, in this order, then its own page
+stylesheet:
+
+```html
+
+
+
+
+
+
+
+```
+
+`color.js` is intentionally **not** deferred: it resolves the theme and paints the
+colour roles before first paint so there is no flash of the wrong theme.
+
+## Colour
+
+Colours are Material 3 *roles*, never raw hex values: `--m3-primary`,
+`--m3-on-primary`, `--m3-primary-container`, `--m3-surface-container-high`,
+`--m3-outline-variant`, `--m3-error-container`, โฆ Use the role that describes the
+meaning, and pair every `on-*` role with the surface it sits on.
+
+| Theme | Selector | Palette |
+| --- | --- | --- |
+| Light | `` or `` | `:root` block |
+| Dark | `` | `:root[data-theme="dark"]` |
+| System | no attribute, resolved by `color.js` | `@media (prefers-color-scheme: dark)` fallback |
+
+`` picks a named seed palette (`indigo`, `violet`, `crimson`,
+`emerald`, `amber`, `azure`); the default is the GDIPS brand red. The seed picker
+in the app bar (` `) can also generate a palette from any
+hex colour at runtime โ the result is stored in `localStorage['gdips:seed']`.
+
+### Regenerating the palettes
+
+```bash
+python3 main/assets/m3/gen_palette.py # rewrites main/assets/m3/palettes.css
+```
+
+The generator and the runtime engine in `color.js` share the same algorithm
+(CIELAB tone mapping with gamut-clamped chroma) and the same contrast rule: dark
+container roles step down the tonal ramp until they reach 4.5:1 against their
+`on-*` label. Never hand-edit `palettes.css`; change the generator and re-run it.
+
+## Typescale and spacing
+
+- `--m3-display-*`, `--m3-headline-*`, `--m3-title-*`, `--m3-body-*`,
+ `--m3-label-*` for size/weight/letter-spacing.
+- `--m3-space-1 โฆ --m3-space-16` for a 4 px-based spacing rhythm.
+- `--m3-shape-xs|sm|md|lg|xl|full` for corner radii.
+- `--m3-elevation-0 โฆ --m3-elevation-5` for the M3 shadow levels (the dark theme
+ raises them automatically).
+
+## Components
+
+`components.css` provides `.m3-btn` (filled/tonal/outlined/text/elevated),
+`.m3-icon-button`, `.m3-fab`, `.m3-chip` / `.m3-chip-set`, `.m3-card`,
+`.m3-list` / `.m3-list-item`, `.m3-menu`, `.m3-dialog`, `.m3-sheet`, `.m3-scrim`,
+`.m3-tabs`, `.m3-segmented`, `.m3-switch`, `.m3-slider`, `.m3-text-field`,
+`.m3-table`, `.m3-expansion`, `.m3-snackbar`, `.m3-tooltip`, `.m3-meter`,
+`.m3-empty`, plus loaders and skeletons. All of them define hover, focus-visible,
+pressed, disabled, loading and error states.
+
+## Behaviour hooks
+
+`ui.js` binds declarative attributes, so pages stay markup-only:
+
+| Hook | Purpose |
+| --- | --- |
+| `[data-m3-drawer-toggle="#id"]`, `[data-m3-drawer-legacy]` | open/close a navigation drawer |
+| `[data-m3-scrim-for="#id"]` | scrim that closes its drawer |
+| `[data-m3-menu-trigger="#id"]` | menu button + `aria-expanded` sync |
+| `[data-m3-dialog-open="#id"]` / `[data-m3-dialog-close]` | dialogs |
+| `[data-m3-tabs]`, `[data-m3-segmented]`, `[data-m3-chip-toggle]` | selection groups |
+| `[data-m3-copy]`, `[data-m3-range-output]`, `[data-m3-color-picker]` | copy buttons, slider output, seed picker |
+| `.m3-theme-toggle` | light/dark switch |
+| `.m3-reveal` | scroll-in animation (respects `prefers-reduced-motion`) |
+| `m3ui:refresh` (event) | re-scan after injecting markup |
+
+`M3UI` also exposes `snackbar`, `openDialog`, `closeDialog`, `openDrawer`,
+`setLoading`, `copy`, `lockScroll` and `unlockScroll`; `M3Color` exposes
+`applySeed`, `resetSeed`, `setTheme`, `toggleTheme`, `theme`, `preference`,
+`seed`, `presets`, `role`, `mountPicker` and emits `m3color:theme` /
+`m3color:seed`.
+
+## Accessibility
+
+- Light and dark palettes are generated so every `on-*` / surface pair clears
+ WCAG AA (โฅ 4.5:1); alternate seeds are checked the same way.
+- Focus states use `:focus-visible` with a visible ring; dialogs and drawers are
+ labelled and manage `aria-hidden`/`aria-expanded`; toasts and the list grid are
+ `aria-live` regions; icon-only controls carry `aria-label`s.
+- `prefers-reduced-motion` collapses animation and transition durations.
+
+## Print
+
+`site.css` and the page stylesheets trim chrome (app bar, drawers, action rows,
+pagination, toasts) and switch to plain black-on-white surfaces for printing.
+
+## Brand, people and vendored assets
+
+Every asset the site needs is served from this repository. Nothing is loaded from a third-party CDN except the AdSense script.
+
+| Folder | Contents | Notes |
+| --- | --- | --- |
+| `assets/brand/` | `gdips-mark.svg` (master mark), `favicon.svg`, `favicon-32.png`, `apple-touch-icon.png`, `icon-192.png`, `icon-512.png`, `icon-maskable-512.png` | Icons are rendered from the SVG masters. Re-render them after editing the SVG. |
+| `assets/people/` | One SVG avatar per contributor (`.svg`) | Initials on a tonal background. To use real photos, drop an image at the same path with the same name. |
+| `assets/vendor/fontawesome/` | Font Awesome Free 6.4.0 CSS and the solid, regular and brands WOFF2 files | CC BY 4.0 icons, SIL OFL fonts, MIT code. See `LICENSE.txt`. |
+| `assets/vendor/papaparse/` | PapaParse 5.3.2 (MIT) | Used by the demon list and feedback apps to read published Google Sheets CSV. |
+| `assets/vendor/fonts/` | Roboto Flex and JetBrains Mono, variable WOFF2 (Latin) | Declared in `tokens.css` as `Roboto Flex` and `JetBrains Mono`. SIL OFL. |
+
+`sw.js` (site root) precaches the app shell and serves same-origin requests network-first. Cross-origin data, such as the Google Sheets CSV, is never cached by the service worker.
diff --git a/main/assets/m3/color.js b/main/assets/m3/color.js
new file mode 100644
index 0000000..ce0fda6
--- /dev/null
+++ b/main/assets/m3/color.js
@@ -0,0 +1,440 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Dynamic colour runtime
+ ----------------------------------------------------------------------------
+ Generates a full Material 3 role set from any seed colour at runtime, so the
+ whole site can re-theme itself (Material You "dynamic colour") without a
+ build step. Tonal palettes use CIELAB tone mapping with sRGB gamut
+ clamping โ the same algorithm used to pre-generate assets/m3/palettes.css.
+
+ Public API
+ M3Color.applySeed(hex) apply an arbitrary seed colour
+ M3Color.seed() current seed (#RRGGBB)
+ M3Color.setTheme('light'|'dark'|'system')
+ M3Color.theme() resolved theme
+ M3Color.presets [{ id, label, seed }]
+ M3Color.mountPicker(el) render an accessible seed-colour picker
+ ========================================================================== */
+
+(function (global) {
+ 'use strict';
+
+ var STORAGE = { theme: 'gdips:theme', seed: 'gdips:seed' };
+ var LEGACY_THEME_KEY = 'theme'; // older GDIPS scripts store the theme here
+ var TONES = [0, 4, 5, 6, 10, 12, 17, 20, 22, 24, 25, 30, 35, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 98, 99, 100];
+
+ var PRESETS = [
+ { id: 'brand', label: 'GDIPS Merah', seed: '#C8102E' },
+ { id: 'indigo', label: 'Indigo', seed: '#6366F1' },
+ { id: 'violet', label: 'Violet', seed: '#8B5CF6' },
+ { id: 'azure', label: 'Azure', seed: '#2563EB' },
+ { id: 'emerald', label: 'Emerald', seed: '#0F9D58' },
+ { id: 'amber', label: 'Amber', seed: '#F59E0B' }
+ ];
+
+ /* โโ Colour maths โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function srgbToLin(c) {
+ c /= 255;
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
+ }
+
+ function linToSrgb(c) {
+ c = Math.min(1, Math.max(0, c));
+ var v = c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
+ return Math.round(Math.min(255, Math.max(0, v * 255)));
+ }
+
+ function hexToRgb(hex) {
+ hex = String(hex).trim().replace('#', '');
+ if (hex.length === 3) hex = hex.split('').map(function (c) { return c + c; }).join('');
+ var n = parseInt(hex, 16);
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
+ }
+
+ function rgbToHex(rgb) {
+ return '#' + rgb.map(function (c) {
+ var s = c.toString(16).toUpperCase();
+ return s.length === 1 ? '0' + s : s;
+ }).join('');
+ }
+
+ var WHITE = [0.95047, 1.0, 1.08883];
+
+ function rgbToLab(rgb) {
+ var r = srgbToLin(rgb[0]), g = srgbToLin(rgb[1]), b = srgbToLin(rgb[2]);
+ var x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) / WHITE[0];
+ var y = (r * 0.2126729 + g * 0.7151522 + b * 0.0721750) / WHITE[1];
+ var z = (r * 0.0193339 + g * 0.1191920 + b * 0.9503041) / WHITE[2];
+ function f(t) { return t > 216 / 24389 ? Math.cbrt(t) : (841 / 108) * t + 4 / 29; }
+ var fx = f(x), fy = f(y), fz = f(z);
+ return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
+ }
+
+ function labToRgb(lab) {
+ var fy = (lab[0] + 16) / 116;
+ var fx = fy + lab[1] / 500;
+ var fz = fy - lab[2] / 200;
+ function fi(t) { var t3 = t * t * t; return t3 > 216 / 24389 ? t3 : (t - 4 / 29) * (108 / 841); }
+ var x = fi(fx) * WHITE[0], y = fi(fy) * WHITE[1], z = fi(fz) * WHITE[2];
+ return [
+ linToSrgb(x * 3.2404542 + y * -1.5371385 + z * -0.4985314),
+ linToSrgb(x * -0.9692660 + y * 1.8760108 + z * 0.0415560),
+ linToSrgb(x * 0.0556434 + y * -0.2040259 + z * 1.0572252)
+ ];
+ }
+
+ function inGamut(lab) {
+ var fy = (lab[0] + 16) / 116;
+ var fx = fy + lab[1] / 500;
+ var fz = fy - lab[2] / 200;
+ function fi(t) { var t3 = t * t * t; return t3 > 216 / 24389 ? t3 : (t - 4 / 29) * (108 / 841); }
+ var x = fi(fx), y = fi(fy), z = fi(fz);
+ return x >= -1e-4 && x <= 1.0001 && y >= -1e-4 && y <= 1.0001 && z >= -1e-4 && z <= 1.0001;
+ }
+
+ /** Hex for target CIELAB lightness, chroma reduced until inside sRGB. */
+ function toneToHex(L, a, b) {
+ if (L >= 100) return '#FFFFFF';
+ if (L <= 0) return '#000000';
+ var lab = [L, a, b];
+ if (inGamut(lab)) return rgbToHex(labToRgb(lab));
+ var lo = 0, hi = 1, best = L > 50 ? [255, 255, 255] : [0, 0, 0];
+ for (var i = 0; i < 20; i++) {
+ var mid = (lo + hi) / 2;
+ lab = [L, a * mid, b * mid];
+ if (inGamut(lab)) { best = labToRgb(lab); lo = mid; } else { hi = mid; }
+ }
+ return rgbToHex(best);
+ }
+
+ function tonalPalette(seed, chromaScale, hueOverride) {
+ var lab = rgbToLab(hexToRgb(seed));
+ var hue = Math.atan2(lab[2], lab[1]);
+ var chroma = Math.hypot(lab[1], lab[2]) * (chromaScale === undefined ? 1 : chromaScale);
+ if (hueOverride !== undefined) hue = hueOverride;
+ var out = {};
+ for (var i = 0; i < TONES.length; i++) {
+ var t = TONES[i];
+ out[t] = toneToHex(t, chroma * Math.cos(hue), chroma * Math.sin(hue));
+ }
+ return out;
+ }
+
+ var ROLE_MAP_LIGHT = {
+ primary: ['primary', 40], 'on-primary': ['primary', 100],
+ 'primary-container': ['primary', 90], 'on-primary-container': ['primary', 10],
+ 'primary-fixed': ['primary', 90], 'primary-fixed-dim': ['primary', 80],
+ 'on-primary-fixed': ['primary', 10], 'on-primary-fixed-variant': ['primary', 30],
+ secondary: ['secondary', 40], 'on-secondary': ['secondary', 100],
+ 'secondary-container': ['secondary', 90], 'on-secondary-container': ['secondary', 10],
+ tertiary: ['tertiary', 40], 'on-tertiary': ['tertiary', 100],
+ 'tertiary-container': ['tertiary', 90], 'on-tertiary-container': ['tertiary', 10],
+ error: ['error', 40], 'on-error': ['error', 100],
+ 'error-container': ['error', 90], 'on-error-container': ['error', 10],
+ background: ['neutral', 98], 'on-background': ['neutral', 10],
+ surface: ['neutral', 98], 'on-surface': ['neutral', 10],
+ 'surface-variant': ['neutral-variant', 90], 'on-surface-variant': ['neutral-variant', 30],
+ 'surface-dim': ['neutral', 87], 'surface-bright': ['neutral', 98],
+ 'surface-container-lowest': ['neutral', 100], 'surface-container-low': ['neutral', 96],
+ 'surface-container': ['neutral', 94], 'surface-container-high': ['neutral', 92],
+ 'surface-container-highest': ['neutral', 90],
+ outline: ['neutral-variant', 50], 'outline-variant': ['neutral-variant', 80],
+ 'inverse-surface': ['neutral', 20], 'inverse-on-surface': ['neutral', 95],
+ 'inverse-primary': ['primary', 80],
+ scrim: ['neutral', 0], shadow: ['neutral', 0], 'surface-tint': ['primary', 40]
+ };
+
+ var DARK_OVERRIDES = {
+ primary: ['primary', 80], 'on-primary': ['primary', 20],
+ 'primary-container': ['primary', 30], 'on-primary-container': ['primary', 90],
+ secondary: ['secondary', 80], 'on-secondary': ['secondary', 20],
+ 'secondary-container': ['secondary', 30], 'on-secondary-container': ['secondary', 90],
+ tertiary: ['tertiary', 80], 'on-tertiary': ['tertiary', 20],
+ 'tertiary-container': ['tertiary', 30], 'on-tertiary-container': ['tertiary', 90],
+ error: ['error', 80], 'on-error': ['error', 20],
+ 'error-container': ['error', 30], 'on-error-container': ['error', 90],
+ background: ['neutral', 6], 'on-background': ['neutral', 90],
+ surface: ['neutral', 6], 'on-surface': ['neutral', 90],
+ 'surface-variant': ['neutral-variant', 30], 'on-surface-variant': ['neutral-variant', 80],
+ 'surface-dim': ['neutral', 6], 'surface-bright': ['neutral', 24],
+ 'surface-container-lowest': ['neutral', 4], 'surface-container-low': ['neutral', 10],
+ 'surface-container': ['neutral', 12], 'surface-container-high': ['neutral', 17],
+ 'surface-container-highest': ['neutral', 22],
+ outline: ['neutral-variant', 60], 'outline-variant': ['neutral-variant', 30],
+ 'inverse-surface': ['neutral', 90], 'inverse-on-surface': ['neutral', 20],
+ 'inverse-primary': ['primary', 40], 'surface-tint': ['primary', 80]
+ };
+
+ function roleMap(dark) {
+ var map = {};
+ for (var k in ROLE_MAP_LIGHT) map[k] = ROLE_MAP_LIGHT[k];
+ if (dark) for (var d in DARK_OVERRIDES) map[d] = DARK_OVERRIDES[d];
+ return map;
+ }
+
+ /** Build every M3 colour role for a seed colour. */
+ /* WCAG relative luminance / contrast, used to keep container pairs readable. */
+ function relLum(hex) {
+ var rgb = hexToRgb(hex), chan = [];
+ for (var i = 0; i < 3; i++) {
+ var v = rgb[i] / 255;
+ chan.push(v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4));
+ }
+ return 0.2126 * chan[0] + 0.7152 * chan[1] + 0.0722 * chan[2];
+ }
+
+ function contrast(a, b) {
+ var la = relLum(a), lb = relLum(b), hi = Math.max(la, lb), lo = Math.min(la, lb);
+ return (hi + 0.05) / (lo + 0.05);
+ }
+
+ function buildScheme(seed, dark) {
+ var primary = tonalPalette(seed, 1);
+ var secondary = tonalPalette(seed, 0.34);
+ var seedLab = rgbToLab(hexToRgb(seed));
+ var tertiary = tonalPalette(seed, 0.72, Math.atan2(seedLab[2], seedLab[1]) + Math.PI / 3);
+ var error = tonalPalette('#B3261E');
+ var hue = Math.atan2(seedLab[2], seedLab[1]);
+ var neutral = tonalPalette(seed, 0);
+ var neutralVariant = tonalPalette(seed, 0);
+ TONES.forEach(function (t) {
+ neutral[t] = toneToHex(t, 3.2 * Math.cos(hue), 3.2 * Math.sin(hue));
+ neutralVariant[t] = toneToHex(t, 9 * Math.cos(hue), 9 * Math.sin(hue));
+ });
+ var maps = { primary: primary, secondary: secondary, tertiary: tertiary, error: error, neutral: neutral, 'neutral-variant': neutralVariant };
+ var map = roleMap(dark);
+ var out = {};
+ Object.keys(map).forEach(function (role) {
+ var ref = map[role];
+ var tone = ref[1];
+ if (tone === 100) out['--m3-' + role] = '#FFFFFF';
+ else if (tone === 0) out['--m3-' + role] = '#000000';
+ else out['--m3-' + role] = maps[ref[0]][tone];
+ });
+
+ /* Dark container roles default to tone 30; bright hues (crimson, amber) can
+ fall short of 4.5:1 against their tone-90 label, so step the container
+ down the tonal ramp until the pair stays readable. */
+ if (dark) {
+ [['primary-container', 'on-primary-container'],
+ ['secondary-container', 'on-secondary-container'],
+ ['tertiary-container', 'on-tertiary-container'],
+ ['error-container', 'on-error-container']].forEach(function (pair) {
+ var ref = map[pair[0]];
+ if (!ref) return;
+ var label = out['--m3-' + pair[1]];
+ [ref[1], 25, 22, 20, 17, 12].some(function (tone) {
+ var value = tone === 100 ? '#FFFFFF' : (tone === 0 ? '#000000' : maps[ref[0]][tone]);
+ if (!value) return false;
+ if (contrast(value, label) >= 4.5) { out['--m3-' + pair[0]] = value; return true; }
+ return false;
+ });
+ });
+ }
+
+ return out;
+ }
+
+ /* โโ State โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ var media = global.matchMedia ? global.matchMedia('(prefers-color-scheme: dark)') : null;
+ var root = document.documentElement;
+
+ function read(key) {
+ try { return global.localStorage.getItem(key); } catch (e) { return null; }
+ }
+
+ function write(key, value) {
+ try { value === null ? global.localStorage.removeItem(key) : global.localStorage.setItem(key, value); } catch (e) { /* private mode */ }
+ }
+
+ function isHex(value) {
+ return typeof value === 'string' && /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.trim());
+ }
+
+ /* The data-seed attribute doubles as a *named* palette selector
+ (e.g. data-seed="indigo" is delivered by palettes.css) and as an inline hex
+ seed. Only hex values are generated at runtime; named seeds stay in CSS. */
+ var attrSeed = root.getAttribute('data-seed');
+ var state = {
+ theme: read(STORAGE.theme) || read(LEGACY_THEME_KEY) || 'system',
+ seed: read(STORAGE.seed) || (isHex(attrSeed) ? attrSeed.toUpperCase() : null)
+ };
+
+ function resolvedTheme() {
+ if (state.theme === 'system') return media && media.matches ? 'dark' : 'light';
+ return state.theme;
+ }
+
+ function applyVars(vars) {
+ Object.keys(vars).forEach(function (k) { root.style.setProperty(k, vars[k]); });
+ }
+
+ function syncMetaTheme() {
+ var meta = document.querySelector('meta[name="theme-color"]');
+ var color = getComputedStyle(document.body || root).getPropertyValue('--m3-surface').trim();
+ if (!meta) {
+ meta = document.createElement('meta');
+ meta.setAttribute('name', 'theme-color');
+ document.head.appendChild(meta);
+ }
+ if (color) meta.setAttribute('content', color);
+ }
+
+ var appliedVars = [];
+
+ function clearVars() {
+ appliedVars.forEach(function (key) { root.style.removeProperty(key); });
+ appliedVars = [];
+ }
+
+ function paint() {
+ var theme = resolvedTheme();
+ root.setAttribute('data-theme', theme);
+ if (state.seed) {
+ var vars = buildScheme(state.seed, theme === 'dark');
+ clearVars();
+ appliedVars = Object.keys(vars);
+ applyVars(vars);
+ } else {
+ clearVars(); // fall back to the palette declared in palettes.css
+ }
+ syncMetaTheme();
+ }
+
+ function announce(type, detail) {
+ root.dispatchEvent(new CustomEvent('m3color:' + type, { detail: detail }));
+ }
+
+ var api = {
+ presets: PRESETS,
+
+ seed: function () { return state.seed; },
+ theme: function () { return resolvedTheme(); },
+ preference: function () { return state.theme; },
+
+ /** Apply an arbitrary seed colour (#RGB / #RRGGBB). */
+ applySeed: function (seed, options) {
+ var hex = String(seed || '').trim();
+ if (!isHex(hex)) return false;
+ if (hex.charAt(0) !== '#') hex = '#' + hex;
+ state.seed = hex.toUpperCase();
+ if (!options || options.persist !== false) write(STORAGE.seed, state.seed);
+ paint();
+ announce('seed', { seed: state.seed });
+ return true;
+ },
+
+ /** Drop the custom seed and return to the page's declared palette. */
+ resetSeed: function () {
+ state.seed = isHex(attrSeed) ? attrSeed.toUpperCase() : null;
+ write(STORAGE.seed, null);
+ paint();
+ announce('seed', { seed: state.seed });
+ },
+
+ /** light ยท dark ยท system */
+ setTheme: function (mode) {
+ state.theme = ['light', 'dark', 'system'].indexOf(mode) === -1 ? 'system' : mode;
+ write(STORAGE.theme, state.theme);
+ write(LEGACY_THEME_KEY, state.theme);
+ paint();
+ announce('theme', { theme: resolvedTheme(), preference: state.theme });
+ },
+
+ toggleTheme: function () {
+ api.setTheme(resolvedTheme() === 'dark' ? 'light' : 'dark');
+ return resolvedTheme();
+ },
+
+ /** Read a generated role, e.g. M3Color.role('primary') */
+ role: function (name) {
+ return getComputedStyle(root).getPropertyValue('--m3-' + name).trim();
+ },
+
+ /** Render an accessible dynamic-colour picker inside `el`. */
+ mountPicker: function (el) {
+ if (!el) return;
+ el.innerHTML = '';
+ el.classList.add('m3-color-picker');
+
+ var row = document.createElement('div');
+ row.className = 'm3-chip-set';
+ row.setAttribute('role', 'radiogroup');
+ row.setAttribute('aria-label', 'Dynamic colour');
+
+ PRESETS.forEach(function (preset) {
+ var chip = document.createElement('button');
+ chip.type = 'button';
+ chip.className = 'm3-chip m3-chip--accent';
+ chip.dataset.seed = preset.seed;
+ chip.dataset.id = preset.seed === '#C8102E' ? '' : preset.id;
+ chip.setAttribute('role', 'radio');
+ chip.setAttribute('aria-label', preset.label);
+ chip.innerHTML = '' + preset.label + ' ';
+ chip.addEventListener('click', function () { api.applySeed(preset.seed); mark(); });
+ row.appendChild(chip);
+ });
+
+ var custom = document.createElement('label');
+ custom.className = 'm3-chip m3-chip--sm';
+ custom.style.cursor = 'pointer';
+ custom.innerHTML = 'Custom ' +
+ ' ';
+ custom.querySelector('input').addEventListener('input', function (e) {
+ api.applySeed(e.target.value);
+ mark();
+ });
+ row.appendChild(custom);
+
+ el.appendChild(row);
+
+ function mark() {
+ var chips = row.querySelectorAll('.m3-chip[data-seed]');
+ var named = root.getAttribute('data-seed') || '';
+ Array.prototype.forEach.call(chips, function (chip) {
+ var active = state.seed
+ ? chip.dataset.seed.toLowerCase() === state.seed.toLowerCase()
+ : chip.dataset.id === named;
+ chip.setAttribute('aria-checked', String(active));
+ chip.classList.toggle('is-selected', active);
+ });
+ }
+
+ mark();
+ root.addEventListener('m3color:seed', mark);
+ return el;
+ }
+ };
+
+ /* Pages that manage their own toggle (the demon list) simply set
+ ; adopt those changes so both systems stay in sync. */
+ if (global.MutationObserver) {
+ new MutationObserver(function () {
+ var value = root.getAttribute('data-theme');
+ if (value !== 'light' && value !== 'dark') return;
+ if (value === resolvedTheme() && state.theme !== 'system') return;
+ state.theme = value;
+ write(STORAGE.theme, value);
+ write(LEGACY_THEME_KEY, value);
+ paint();
+ }).observe(root, { attributes: true, attributeFilter: ['data-theme'] });
+ }
+
+ if (media) {
+ var onSystem = function () { if (state.theme === 'system') paint(); };
+ media.addEventListener ? media.addEventListener('change', onSystem) : media.addListener(onSystem);
+ }
+
+ root.addEventListener('m3color:theme', function () { syncMetaTheme(); });
+
+ paint();
+ global.M3Color = api;
+
+ // Upgrade every declarative picker on the page.
+ document.addEventListener('DOMContentLoaded', function () {
+ document.querySelectorAll('[data-m3-color-picker]').forEach(function (el) { api.mountPicker(el); });
+ });
+})(window);
diff --git a/main/assets/m3/components.css b/main/assets/m3/components.css
new file mode 100644
index 0000000..7c40344
--- /dev/null
+++ b/main/assets/m3/components.css
@@ -0,0 +1,1749 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Components
+ ----------------------------------------------------------------------------
+ A hand-written, dependency-free Material 3 component layer. Everything is
+ driven by the tokens in tokens.css + palettes.css, so all components adapt to
+ the active dynamic colour scheme and theme automatically.
+
+ Contents
+ 01 State layer 08 Checkbox / Radio / Switch
+ 02 Buttons 09 Slider
+ 03 Icon buttons / FAB 10 Lists
+ 04 Segmented buttons 11 Menus
+ 05 Cards 12 Dialogs & sheets
+ 06 Chips 13 Snackbar / tooltip / banner
+ 07 Text fields & selects 14 Tabs / nav bar / rail / drawer / app bar
+ 15 Tables, progress, badges, misc
+ ========================================================================== */
+
+/* ============================================================================
+ 01 ยท State layer
+ A reusable overlay that gives every interactive surface M3 hover / focus /
+ pressed states without hard-coding colours.
+ ========================================================================== */
+
+.m3-state-layer {
+ position: relative;
+ isolation: isolate;
+ overflow: hidden;
+}
+
+.m3-state-layer::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ pointer-events: none;
+ border-radius: inherit;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-state-layer:hover::after { opacity: var(--m3-state-hover); }
+}
+
+.m3-state-layer:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-state-layer:active::after { opacity: var(--m3-state-pressed); }
+.m3-state-layer[aria-disabled='true']::after,
+.m3-state-layer:disabled::after { opacity: 0; }
+
+/* Ripple -------------------------------------------------------------------- */
+.m3-ripple {
+ position: absolute;
+ border-radius: var(--m3-shape-full);
+ transform: scale(0);
+ background: currentColor;
+ opacity: 0.24;
+ pointer-events: none;
+ animation: m3-ripple-in 550ms var(--m3-ease-standard-decel) forwards;
+}
+
+@keyframes m3-ripple-in {
+ to { transform: scale(1); opacity: 0; }
+}
+
+/* ============================================================================
+ 02 ยท Buttons
+ Variants: filled (default) ยท tonal ยท elevated ยท outlined ยท text
+ ========================================================================== */
+
+.m3-button {
+ --m3-button-height: 40px;
+ --m3-button-pad: 24px;
+ --m3-button-gap: 8px;
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--m3-button-gap);
+ min-height: var(--m3-button-height);
+ padding: 0 var(--m3-button-pad);
+ border: 1px solid transparent;
+ border-radius: var(--m3-shape-full);
+ font-family: var(--m3-font-plain);
+ font-size: var(--m3-label-large-size);
+ line-height: var(--m3-label-large-line);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+ text-decoration: none;
+ white-space: nowrap;
+ cursor: pointer;
+ user-select: none;
+ isolation: isolate;
+ overflow: hidden;
+ background: var(--m3-primary);
+ color: var(--m3-on-primary);
+ box-shadow: var(--m3-elevation-0);
+ transition:
+ background-color var(--m3-duration-short) var(--m3-ease-standard),
+ color var(--m3-duration-short) var(--m3-ease-standard),
+ box-shadow var(--m3-duration-short-2) var(--m3-ease-standard),
+ border-radius var(--m3-duration-short-2) var(--m3-ease-emphasized),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.m3-button::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-button:hover::after { opacity: var(--m3-state-hover); }
+}
+
+.m3-button:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-button:active::after { opacity: var(--m3-state-pressed); }
+.m3-button:active { transform: scale(0.97); }
+
+.m3-button > * { position: relative; z-index: 1; }
+.m3-button i,
+.m3-button svg { font-size: 1.125em; }
+
+.m3-button--tonal {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+}
+
+.m3-button--elevated {
+ background: var(--m3-surface-container-low);
+ color: var(--m3-primary);
+ box-shadow: var(--m3-elevation-1);
+}
+
+@media (hover: hover) {
+ .m3-button--elevated:hover { box-shadow: var(--m3-elevation-2); }
+}
+
+.m3-button--outlined {
+ background: transparent;
+ color: var(--m3-primary);
+ border-color: var(--m3-outline-variant);
+}
+
+.m3-button--text {
+ background: transparent;
+ color: var(--m3-primary);
+ padding-inline: 12px;
+}
+
+.m3-button--danger {
+ background: var(--m3-error);
+ color: var(--m3-on-error);
+}
+
+.m3-button--danger-text {
+ background: transparent;
+ color: var(--m3-error);
+}
+
+.m3-button--full { width: 100%; }
+.m3-button--lg { --m3-button-height: 48px; --m3-button-pad: 28px; font-size: var(--m3-title-small-size); }
+.m3-button--sm { --m3-button-height: 32px; --m3-button-pad: 16px; font-size: var(--m3-label-medium-size); }
+
+.m3-button:disabled,
+.m3-button[aria-disabled='true'] {
+ background: color-mix(in srgb, var(--m3-on-surface) 12%, transparent);
+ color: color-mix(in srgb, var(--m3-on-surface) 38%, transparent);
+ box-shadow: none;
+ border-color: transparent;
+ transform: none;
+ pointer-events: none;
+}
+
+.m3-button.is-loading {
+ color: transparent;
+ pointer-events: none;
+}
+
+.m3-button.is-loading::before {
+ content: '';
+ position: absolute;
+ inset-inline: 0;
+ margin-inline: auto;
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ border: 2px solid currentColor;
+ border-top-color: transparent;
+ color: var(--m3-on-primary);
+ animation: m3-spin 900ms linear infinite;
+}
+
+.m3-button--tonal.is-loading::before,
+.m3-button--outlined.is-loading::before,
+.m3-button--text.is-loading::before,
+.m3-button--elevated.is-loading::before { color: var(--m3-primary); }
+
+.m3-button--outlined.is-loading::before,
+.m3-button--text.is-loading::before { color: var(--m3-primary); }
+
+.m3-button-group { display: inline-flex; gap: 8px; flex-wrap: wrap; }
+
+@keyframes m3-spin {
+ to { transform: rotate(360deg); }
+}
+
+/* ============================================================================
+ 03 ยท Icon buttons & FABs
+ ========================================================================== */
+
+.m3-icon-button {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ padding: 0;
+ border: 1px solid transparent;
+ border-radius: var(--m3-shape-full);
+ background: transparent;
+ color: var(--m3-on-surface-variant);
+ font-size: 1.15rem;
+ cursor: pointer;
+ isolation: isolate;
+ overflow: hidden;
+ text-decoration: none;
+ transition:
+ background-color var(--m3-duration-short) var(--m3-ease-standard),
+ color var(--m3-duration-short) var(--m3-ease-standard),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.m3-icon-button::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-icon-button:hover::after { opacity: var(--m3-state-hover); } }
+.m3-icon-button:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-icon-button:active::after { opacity: var(--m3-state-pressed); }
+.m3-icon-button:active { transform: scale(0.92); }
+.m3-icon-button > * { position: relative; z-index: 1; }
+
+.m3-icon-button--filled {
+ background: var(--m3-primary);
+ color: var(--m3-on-primary);
+}
+
+.m3-icon-button--tonal {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+}
+
+.m3-icon-button--outlined { border-color: var(--m3-outline-variant); }
+.m3-icon-button--selected { background: var(--m3-primary); color: var(--m3-on-primary); }
+.m3-icon-button--lg { width: 48px; height: 48px; font-size: 1.35rem; }
+.m3-icon-button--sm { width: 32px; height: 32px; font-size: 1rem; }
+
+.m3-icon-button:disabled {
+ color: color-mix(in srgb, var(--m3-on-surface) 38%, transparent);
+ pointer-events: none;
+}
+
+/* FAB ----------------------------------------------------------------------- */
+.m3-fab {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+ height: 56px;
+ min-width: 56px;
+ padding-inline: 16px;
+ border: none;
+ border-radius: var(--m3-shape-lg);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ font-size: 1.5rem;
+ box-shadow: var(--m3-elevation-3);
+ cursor: pointer;
+ isolation: isolate;
+ overflow: hidden;
+ transition:
+ box-shadow var(--m3-duration-short-2) var(--m3-ease-standard),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized),
+ border-radius var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.m3-fab::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-fab:hover::after { opacity: var(--m3-state-hover); }
+ .m3-fab:hover { box-shadow: var(--m3-elevation-4); }
+}
+
+.m3-fab:active { transform: scale(0.96); }
+.m3-fab:active::after { opacity: var(--m3-state-pressed); }
+.m3-fab > * { position: relative; z-index: 1; }
+.m3-fab--extended {
+ width: auto;
+ padding-inline: 20px;
+ font-family: var(--m3-font-plain);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+}
+.m3-fab--sm { height: 40px; min-width: 40px; font-size: 1.15rem; border-radius: var(--m3-shape-md); }
+.m3-fab--lg { height: 96px; min-width: 96px; font-size: 2.25rem; border-radius: var(--m3-shape-xl); }
+.m3-fab--fixed { position: fixed; inset-block-end: 24px; inset-inline-end: 24px; z-index: var(--m3-z-appbar); }
+
+/* ============================================================================
+ 04 ยท Segmented buttons
+ ========================================================================== */
+
+.m3-segmented {
+ display: inline-flex;
+ align-items: stretch;
+ border: 1px solid var(--m3-outline);
+ border-radius: var(--m3-shape-full);
+ overflow: hidden;
+ background: transparent;
+ max-width: 100%;
+}
+
+.m3-segmented__item {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ flex: 1 1 auto;
+ min-height: 40px;
+ padding-inline: 16px;
+ border: none;
+ border-inline-start: 1px solid var(--m3-outline);
+ background: transparent;
+ color: var(--m3-on-surface);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+ white-space: nowrap;
+ cursor: pointer;
+ isolation: isolate;
+ overflow: hidden;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-segmented__item:first-child { border-inline-start: none; }
+
+.m3-segmented__item::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-segmented__item:hover::after { opacity: var(--m3-state-hover); } }
+.m3-segmented__item:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-segmented__item:active::after { opacity: var(--m3-state-pressed); }
+.m3-segmented__item[aria-selected='true'],
+.m3-segmented__item.is-selected {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+}
+.m3-segmented__item > * { position: relative; z-index: 1; }
+
+/* ============================================================================
+ 05 ยท Cards
+ ========================================================================== */
+
+.m3-card {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-surface-container-low);
+ color: var(--m3-on-surface);
+ overflow: hidden;
+ transition:
+ box-shadow var(--m3-duration-short-2) var(--m3-ease-standard),
+ background-color var(--m3-duration-short) var(--m3-ease-standard),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.m3-card--elevated { background: var(--m3-surface-container-low); box-shadow: var(--m3-elevation-1); }
+.m3-card--filled { background: var(--m3-surface-container-highest); }
+.m3-card--outlined { background: var(--m3-surface); border: 1px solid var(--m3-outline-variant); }
+
+@media (hover: hover) {
+ .m3-card--elevated:hover,
+ .m3-card--interactive:hover { box-shadow: var(--m3-elevation-2); }
+ .m3-card--interactive:hover { transform: translateY(-2px); }
+}
+
+.m3-card--interactive { cursor: pointer; }
+.m3-card--interactive:active { transform: translateY(0) scale(0.995); }
+
+.m3-card__media {
+ position: relative;
+ aspect-ratio: 16 / 9;
+ background: var(--m3-surface-container-highest);
+ overflow: hidden;
+}
+
+.m3-card__media img,
+.m3-card__media iframe {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.m3-card__content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-2);
+ padding: var(--m3-space-4);
+}
+
+.m3-card__title { font-size: var(--m3-title-medium-size); font-weight: var(--m3-title-medium-weight); letter-spacing: var(--m3-tracking-title); }
+.m3-card__subtitle { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); }
+.m3-card__text { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); }
+.m3-card__actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--m3-space-2);
+ padding: var(--m3-space-4);
+ padding-top: 0;
+ margin-top: auto;
+}
+.m3-card__actions--end { justify-content: flex-end; }
+
+.m3-card--accent::before {
+ content: '';
+ position: absolute;
+ inset-block-start: 0;
+ inset-inline: 0;
+ height: 4px;
+ background: linear-gradient(90deg, var(--m3-primary), var(--m3-tertiary));
+}
+
+/* ============================================================================
+ 06 ยท Chips
+ ========================================================================== */
+
+.m3-chip-set { display: flex; flex-wrap: wrap; gap: 8px; }
+
+.m3-chip {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ height: 32px;
+ padding-inline: 12px;
+ border: 1px solid var(--m3-outline-variant);
+ border-radius: var(--m3-shape-sm);
+ background: transparent;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+ cursor: pointer;
+ text-decoration: none;
+ isolation: isolate;
+ overflow: hidden;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-chip::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-chip:hover::after { opacity: var(--m3-state-hover); } }
+.m3-chip:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-chip:active::after { opacity: var(--m3-state-pressed); }
+.m3-chip > * { position: relative; z-index: 1; }
+.m3-chip--selected,
+.m3-chip[aria-pressed='true'],
+.m3-chip[aria-selected='true'] {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+ border-color: transparent;
+}
+.m3-chip--assist { border-color: var(--m3-outline); }
+.m3-chip--sm { height: 26px; padding-inline: 10px; font-size: var(--m3-label-medium-size); }
+.m3-chip--accent {
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ border-color: transparent;
+}
+
+/* ============================================================================
+ 07 ยท Text fields & selects
+ ========================================================================== */
+
+.m3-field {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ min-width: 0;
+}
+
+.m3-field__box {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-height: 56px;
+ padding-inline: 16px;
+ border-radius: var(--m3-shape-xs) var(--m3-shape-xs) 0 0;
+ background: var(--m3-surface-container-highest);
+ border-bottom: 1px solid var(--m3-on-surface-variant);
+ transition:
+ background-color var(--m3-duration-short) var(--m3-ease-standard),
+ border-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-field__box::after {
+ content: '';
+ position: absolute;
+ inset-block-end: -1px;
+ inset-inline: 0;
+ height: 2px;
+ background: var(--m3-primary);
+ transform: scaleX(0);
+ transition: transform var(--m3-duration-short-2) var(--m3-ease-emphasized-decel);
+}
+
+.m3-field__box:hover::after { transform: scaleX(1); opacity: 0.4; }
+.m3-field__box:focus-within::after { transform: scaleX(1); opacity: 1; }
+
+.m3-field__input {
+ flex: 1 1 auto;
+ width: 100%;
+ min-width: 0;
+ padding: 20px 0 6px;
+ border: none;
+ background: transparent;
+ color: var(--m3-on-surface);
+ font-size: var(--m3-body-large-size);
+ outline: none;
+}
+
+.m3-field__label {
+ position: absolute;
+ inset-inline-start: 16px;
+ inset-block-start: 50%;
+ translate: 0 -50%;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-large-size);
+ pointer-events: none;
+ transform-origin: left top;
+ transition:
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized-decel),
+ color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-field__box:focus-within .m3-field__label,
+.m3-field__input:not(:placeholder-shown) + .m3-field__label,
+.m3-field__input:focus + .m3-field__label,
+.m3-field--filled .m3-field__label,
+.m3-field__box.has-value .m3-field__label,
+.m3-field__select.has-value ~ .m3-field__label {
+ transform: translateY(-14px) scale(0.78);
+}
+
+.m3-field__icon { color: var(--m3-on-surface-variant); font-size: 1.05rem; }
+.m3-field__suffix { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); white-space: nowrap; }
+.m3-field__support {
+ padding-inline: 16px;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-small-size);
+ line-height: var(--m3-body-small-line);
+}
+
+.m3-field__input::placeholder { color: transparent; }
+
+textarea.m3-field__input {
+ padding-top: 22px;
+ resize: vertical;
+ min-height: 96px;
+ line-height: 1.5;
+}
+
+select.m3-field__input {
+ appearance: none;
+ padding-inline-end: 24px;
+ cursor: pointer;
+}
+
+.m3-field__chevron {
+ position: absolute;
+ inset-inline-end: 16px;
+ color: var(--m3-on-surface-variant);
+ pointer-events: none;
+}
+
+/* Outlined variant ---------------------------------------------------------- */
+.m3-field--outlined .m3-field__box {
+ border: 1px solid var(--m3-outline);
+ border-radius: var(--m3-shape-xs);
+ background: transparent;
+ padding-block: 0;
+}
+
+.m3-field--outlined .m3-field__box::after { display: none; }
+.m3-field--outlined .m3-field__box:hover { border-color: var(--m3-on-surface); }
+.m3-field--outlined .m3-field__box:focus-within {
+ border-color: var(--m3-primary);
+ box-shadow: inset 0 0 0 1px var(--m3-primary);
+}
+.m3-field--outlined .m3-field__input { padding-block: 16px; }
+.m3-field--outlined .m3-field__label {
+ inset-block-start: 0;
+ translate: 0 -50%;
+ padding-inline: 4px;
+ background: var(--m3-surface);
+ border-radius: 2px;
+ font-size: var(--m3-body-medium-size);
+}
+
+/* Error state --------------------------------------------------------------- */
+.m3-field--error .m3-field__box { border-color: var(--m3-error); }
+.m3-field--error .m3-field__box::after { background: var(--m3-error); opacity: 1; }
+.m3-field--error .m3-field__support,
+.m3-field--error .m3-field__label,
+.m3-field--error .m3-field__icon { color: var(--m3-error); }
+
+.m3-field--disabled { opacity: 0.38; pointer-events: none; }
+
+/* Search bar (M3 "search bar" surface) -------------------------------------- */
+.m3-search-bar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ width: 100%;
+ height: 56px;
+ padding-inline: 16px;
+ border: 1px solid transparent;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-high);
+ color: var(--m3-on-surface-variant);
+ box-shadow: var(--m3-elevation-1);
+ transition: box-shadow var(--m3-duration-short-2) var(--m3-ease-standard), background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-search-bar:focus-within {
+ background: var(--m3-surface-container-highest);
+ box-shadow: var(--m3-elevation-2);
+}
+
+.m3-search-bar input {
+ flex: 1 1 auto;
+ min-width: 0;
+ border: none;
+ background: transparent;
+ outline: none;
+ color: var(--m3-on-surface);
+ font-size: var(--m3-body-large-size);
+}
+
+.m3-search-bar input::placeholder { color: var(--m3-on-surface-variant); }
+
+/* ============================================================================
+ 08 ยท Checkbox / Radio / Switch
+ ========================================================================== */
+
+.m3-check {
+ display: inline-flex;
+ align-items: center;
+ gap: 12px;
+ min-height: 40px;
+ cursor: pointer;
+ font-size: var(--m3-body-medium-size);
+ color: var(--m3-on-surface);
+}
+
+.m3-check input {
+ appearance: none;
+ flex: 0 0 auto;
+ width: 18px;
+ height: 18px;
+ margin: 0;
+ border: 2px solid var(--m3-on-surface-variant);
+ border-radius: 2px;
+ background: transparent;
+ cursor: pointer;
+ position: relative;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard), border-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-check input::after {
+ content: '';
+ position: absolute;
+ inset: -14px;
+ border-radius: 50%;
+ background: var(--m3-primary);
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+ z-index: -1;
+}
+
+@media (hover: hover) { .m3-check:hover input::after { opacity: var(--m3-state-hover); } }
+.m3-check input:focus-visible { outline: 2px solid var(--m3-primary); outline-offset: 3px; }
+.m3-check input:checked {
+ background: var(--m3-primary);
+ border-color: var(--m3-primary);
+}
+.m3-check input:checked::before {
+ content: '';
+ position: absolute;
+ inset-inline-start: 4.5px;
+ inset-block-start: 1px;
+ width: 5px;
+ height: 9px;
+ border: solid var(--m3-on-primary);
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+}
+.m3-check input:disabled { opacity: 0.38; pointer-events: none; }
+
+.m3-check--radio input { border-radius: 50%; }
+.m3-check--radio input:checked { background: transparent; border-color: var(--m3-primary); }
+.m3-check--radio input:checked::before {
+ inset: 3px;
+ width: auto;
+ height: auto;
+ border: none;
+ border-radius: 50%;
+ background: var(--m3-primary);
+ transform: none;
+}
+
+.m3-switch {
+ display: inline-flex;
+ align-items: center;
+ gap: 12px;
+ cursor: pointer;
+ font-size: var(--m3-body-medium-size);
+}
+
+.m3-switch input {
+ appearance: none;
+ position: relative;
+ flex: 0 0 auto;
+ width: 52px;
+ height: 32px;
+ margin: 0;
+ border: 2px solid var(--m3-outline);
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+ cursor: pointer;
+ transition: background-color var(--m3-duration-short-2) var(--m3-ease-standard), border-color var(--m3-duration-short-2) var(--m3-ease-standard);
+}
+
+.m3-switch input::before {
+ content: '';
+ position: absolute;
+ inset-block-start: 50%;
+ inset-inline-start: 5px;
+ translate: 0 -50%;
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background: var(--m3-outline);
+ transition: width var(--m3-duration-short-2) var(--m3-ease-emphasized), height var(--m3-duration-short-2) var(--m3-ease-emphasized), inset-inline-start var(--m3-duration-short-2) var(--m3-ease-emphasized), background-color var(--m3-duration-short-2) var(--m3-ease-standard);
+}
+
+.m3-switch input:checked {
+ background: var(--m3-primary);
+ border-color: var(--m3-primary);
+}
+
+.m3-switch input:checked::before {
+ inset-inline-start: 24px;
+ width: 24px;
+ height: 24px;
+ background: var(--m3-on-primary);
+}
+
+@media (hover: hover) {
+ .m3-switch:hover input::before { width: 20px; height: 20px; }
+ .m3-switch:hover input:checked::before { inset-inline-start: 20px; width: 28px; height: 28px; }
+}
+
+.m3-switch input:focus-visible { outline: 2px solid var(--m3-primary); outline-offset: 3px; }
+.m3-switch input:disabled { opacity: 0.38; pointer-events: none; }
+
+/* ============================================================================
+ 09 ยท Slider
+ ========================================================================== */
+
+.m3-slider {
+ --m3-slider-fill: 50%;
+ appearance: none;
+ width: 100%;
+ height: 32px;
+ background: transparent;
+ cursor: pointer;
+}
+
+.m3-slider::-webkit-slider-runnable-track {
+ height: 16px;
+ border-radius: var(--m3-shape-full);
+ background:
+ linear-gradient(var(--m3-primary), var(--m3-primary)) 0 / var(--m3-slider-fill) 100% no-repeat,
+ var(--m3-surface-container-highest);
+}
+
+.m3-slider::-moz-range-track {
+ height: 16px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+}
+
+.m3-slider::-moz-range-progress {
+ height: 16px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary);
+}
+
+.m3-slider::-webkit-slider-thumb {
+ appearance: none;
+ width: 6px;
+ height: 24px;
+ margin-top: -4px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary);
+ border: 2px solid var(--m3-primary);
+ box-shadow: 0 0 0 0 color-mix(in srgb, var(--m3-primary) 16%, transparent);
+ transition: box-shadow var(--m3-duration-short) var(--m3-ease-standard), height var(--m3-duration-short) var(--m3-ease-emphasized);
+}
+
+.m3-slider::-moz-range-thumb {
+ width: 6px;
+ height: 24px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary);
+ border: none;
+}
+
+.m3-slider:hover::-webkit-slider-thumb { box-shadow: 0 0 0 6px color-mix(in srgb, var(--m3-primary) 12%, transparent); }
+.m3-slider:active::-webkit-slider-thumb { height: 28px; margin-top: -6px; }
+.m3-slider:focus-visible { outline: none; }
+.m3-slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 10px color-mix(in srgb, var(--m3-primary) 16%, transparent); }
+
+/* ============================================================================
+ 10 ยท Lists
+ ========================================================================== */
+
+.m3-list {
+ display: flex;
+ flex-direction: column;
+ padding: var(--m3-space-2) 0;
+ list-style: none;
+ margin: 0;
+}
+
+.m3-list-item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-4);
+ min-height: 56px;
+ padding: var(--m3-space-2) var(--m3-space-4);
+ border-radius: var(--m3-shape-xs);
+ color: var(--m3-on-surface);
+ text-decoration: none;
+ isolation: isolate;
+ overflow: hidden;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-list-item::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-list-item:hover::after { opacity: var(--m3-state-hover); } }
+.m3-list-item:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-list-item:active::after { opacity: var(--m3-state-pressed); }
+.m3-list-item > * { position: relative; z-index: 1; }
+.m3-list-item:hover { text-decoration: none; }
+
+.m3-list-item__leading {
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ width: 40px;
+ height: 40px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+ color: var(--m3-on-surface-variant);
+ font-size: 1.05rem;
+}
+
+.m3-list-item__text { display: flex; flex-direction: column; min-width: 0; }
+.m3-list-item__headline { font-size: var(--m3-body-large-size); line-height: 1.35; }
+.m3-list-item__supporting { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); }
+.m3-list-item__trailing { margin-inline-start: auto; color: var(--m3-on-surface-variant); font-size: var(--m3-label-medium-size); }
+
+.m3-divider { height: 1px; border: 0; background: var(--m3-outline-variant); margin: 0; }
+.m3-divider--inset { margin-inline: var(--m3-space-4); }
+
+/* ============================================================================
+ 11 ยท Menus
+ ========================================================================== */
+
+.m3-menu-anchor { position: relative; display: inline-flex; }
+
+.m3-menu {
+ position: absolute;
+ z-index: var(--m3-z-menu);
+ min-width: 200px;
+ max-width: min(320px, calc(100vw - 32px));
+ max-height: 60vh;
+ overflow-y: auto;
+ padding: var(--m3-space-2);
+ border-radius: var(--m3-shape-xs);
+ background: var(--m3-surface-container);
+ color: var(--m3-on-surface);
+ box-shadow: var(--m3-elevation-2);
+ opacity: 0;
+ transform: scale(0.9) translateY(-6px);
+ transform-origin: top left;
+ visibility: hidden;
+ transition:
+ opacity var(--m3-duration-short) var(--m3-ease-standard),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized-decel),
+ visibility var(--m3-duration-short);
+}
+
+.m3-menu--open,
+.m3-menu.is-open {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ visibility: visible;
+}
+
+.m3-menu--end { inset-inline-end: 0; transform-origin: top right; }
+.m3-menu--bottom { top: 100%; margin-block-start: 4px; }
+
+.m3-menu-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ width: 100%;
+ min-height: 48px;
+ padding: var(--m3-space-2) var(--m3-space-3);
+ border: none;
+ border-radius: var(--m3-shape-xs);
+ background: transparent;
+ color: inherit;
+ font-size: var(--m3-body-large-size);
+ text-align: start;
+ text-decoration: none;
+ cursor: pointer;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-menu-item:hover { background: color-mix(in srgb, var(--m3-on-surface) 8%, transparent); text-decoration: none; } }
+.m3-menu-item:focus-visible { background: color-mix(in srgb, var(--m3-on-surface) 10%, transparent); }
+.m3-menu-item[aria-checked='true'],
+.m3-menu-item.is-selected { background: var(--m3-secondary-container); color: var(--m3-on-secondary-container); }
+.m3-menu-item i:first-child { width: 22px; text-align: center; color: var(--m3-on-surface-variant); }
+.m3-menu-item[aria-checked='true'] i:first-child,
+.m3-menu-item.is-selected i:first-child { color: inherit; }
+.m3-menu-item__meta { margin-inline-start: auto; color: var(--m3-on-surface-variant); font-size: var(--m3-label-medium-size); }
+
+/* ============================================================================
+ 12 ยท Dialogs, bottom sheets, scrims
+ ========================================================================== */
+
+.m3-scrim {
+ position: fixed;
+ inset: 0;
+ z-index: var(--m3-z-drawer);
+ background: color-mix(in srgb, var(--m3-scrim) 42%, transparent);
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity var(--m3-duration-medium) var(--m3-ease-standard), visibility var(--m3-duration-medium);
+}
+
+.m3-scrim.is-open { opacity: 1; visibility: visible; }
+
+.m3-dialog {
+ position: fixed;
+ inset: 0;
+ z-index: var(--m3-z-dialog);
+ display: grid;
+ place-items: center;
+ padding: var(--m3-space-4);
+ background: color-mix(in srgb, var(--m3-scrim) 45%, transparent);
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity var(--m3-duration-medium) var(--m3-ease-standard), visibility var(--m3-duration-medium);
+}
+
+.m3-dialog.is-open,
+.m3-dialog[open] { opacity: 1; visibility: visible; }
+
+.m3-dialog__surface {
+ width: min(560px, 100%);
+ max-height: min(88vh, 880px);
+ display: flex;
+ flex-direction: column;
+ border-radius: var(--m3-shape-xl);
+ background: var(--m3-surface-container-high);
+ color: var(--m3-on-surface);
+ box-shadow: var(--m3-elevation-3);
+ transform: scale(0.9);
+ opacity: 0;
+ transition:
+ transform var(--m3-duration-medium) var(--m3-ease-emphasized-decel),
+ opacity var(--m3-duration-medium) var(--m3-ease-standard);
+}
+
+.m3-dialog.is-open .m3-dialog__surface { transform: scale(1); opacity: 1; }
+.m3-dialog--wide .m3-dialog__surface { width: min(880px, 100%); }
+.m3-dialog--full .m3-dialog__surface { width: min(1100px, 100%); height: min(88vh, 900px); }
+
+.m3-dialog__head {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-4);
+ padding: var(--m3-space-6) var(--m3-space-6) var(--m3-space-4);
+}
+
+.m3-dialog__head--centered { flex-direction: column; text-align: center; padding-inline: var(--m3-space-6); }
+
+.m3-dialog__icon {
+ display: grid;
+ place-items: center;
+ color: var(--m3-secondary);
+ font-size: 1.75rem;
+}
+
+.m3-dialog__title {
+ font-size: var(--m3-headline-small-size);
+ line-height: var(--m3-headline-small-line);
+ font-weight: 500;
+ letter-spacing: var(--m3-tracking-headline);
+}
+
+.m3-dialog__body {
+ flex: 1 1 auto;
+ overflow-y: auto;
+ padding: 0 var(--m3-space-6) var(--m3-space-4);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-medium-size);
+ line-height: var(--m3-body-medium-line);
+}
+
+.m3-dialog__actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: var(--m3-space-2);
+ padding: var(--m3-space-4) var(--m3-space-6) var(--m3-space-6);
+ flex-wrap: wrap;
+}
+
+/* Bottom sheet -------------------------------------------------------------- */
+.m3-sheet {
+ position: fixed;
+ inset-inline: 0;
+ inset-block-end: 0;
+ z-index: var(--m3-z-dialog);
+ display: flex;
+ flex-direction: column;
+ max-height: 90dvh;
+ padding: var(--m3-space-3) var(--m3-space-4) calc(var(--m3-space-6) + env(safe-area-inset-bottom));
+ border-radius: var(--m3-shape-xl) var(--m3-shape-xl) 0 0;
+ background: var(--m3-surface-container-low);
+ color: var(--m3-on-surface);
+ box-shadow: var(--m3-elevation-2);
+ transform: translateY(100%);
+ visibility: hidden;
+ transition: transform var(--m3-duration-medium) var(--m3-ease-emphasized-decel), visibility var(--m3-duration-medium);
+}
+
+.m3-sheet.is-open { transform: translateY(0); visibility: visible; }
+
+.m3-sheet__handle {
+ width: 32px;
+ height: 4px;
+ margin: 0 auto var(--m3-space-4);
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-outline-variant);
+}
+
+/* ============================================================================
+ 13 ยท Snackbar, tooltip, banner
+ ========================================================================== */
+
+.m3-snackbar-region {
+ position: fixed;
+ z-index: var(--m3-z-snackbar);
+ inset-block-end: calc(var(--m3-space-5) + env(safe-area-inset-bottom));
+ inset-inline: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--m3-space-2);
+ padding-inline: var(--m3-space-4);
+ pointer-events: none;
+}
+
+.m3-snackbar {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-3);
+ width: min(560px, 100%);
+ min-height: 48px;
+ padding: var(--m3-space-3) var(--m3-space-4);
+ border-radius: var(--m3-shape-xs);
+ background: var(--m3-inverse-surface);
+ color: var(--m3-inverse-on-surface);
+ font-size: var(--m3-body-medium-size);
+ box-shadow: var(--m3-elevation-3);
+ pointer-events: auto;
+ animation: m3-snackbar-in var(--m3-duration-medium) var(--m3-ease-emphasized-decel);
+}
+
+.m3-snackbar.is-leaving { animation: m3-snackbar-out var(--m3-duration-short-2) var(--m3-ease-standard-accel) forwards; }
+.m3-snackbar__action {
+ margin-inline-start: auto;
+ padding: 6px 10px;
+ border: none;
+ border-radius: var(--m3-shape-full);
+ background: transparent;
+ color: var(--m3-inverse-primary);
+ font-weight: var(--m3-label-large-weight);
+ font-size: var(--m3-label-large-size);
+ cursor: pointer;
+}
+
+.m3-snackbar__action:hover { background: color-mix(in srgb, var(--m3-inverse-primary) 16%, transparent); }
+.m3-snackbar--error { background: var(--m3-error-container); color: var(--m3-on-error-container); }
+
+@keyframes m3-snackbar-in {
+ from { opacity: 0; transform: translateY(16px) scale(0.96); }
+ to { opacity: 1; transform: translateY(0) scale(1); }
+}
+
+@keyframes m3-snackbar-out {
+ to { opacity: 0; transform: translateY(12px) scale(0.96); }
+}
+
+.m3-tooltip {
+ position: relative;
+}
+
+.m3-tooltip::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ inset-block-end: calc(100% + 6px);
+ inset-inline-start: 50%;
+ translate: -50% 0;
+ z-index: var(--m3-z-tooltip);
+ padding: 4px 8px;
+ border-radius: var(--m3-shape-xs);
+ background: var(--m3-inverse-surface);
+ color: var(--m3-inverse-on-surface);
+ font-size: var(--m3-body-small-size);
+ white-space: nowrap;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-tooltip:hover::after,
+ .m3-tooltip:focus-visible::after { opacity: 1; }
+}
+
+.m3-banner {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-4);
+ padding: var(--m3-space-3) var(--m3-space-4);
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-surface-container-high);
+ color: var(--m3-on-surface);
+ font-size: var(--m3-body-medium-size);
+}
+
+.m3-banner--info { background: var(--m3-secondary-container); color: var(--m3-on-secondary-container); }
+.m3-banner--warn { background: var(--m3-tertiary-container); color: var(--m3-on-tertiary-container); }
+.m3-banner--error { background: var(--m3-error-container); color: var(--m3-on-error-container); }
+
+/* ============================================================================
+ 14 ยท Tabs, navigation bar / rail / drawer, app bar
+ ========================================================================== */
+
+.m3-tabs {
+ position: relative;
+ display: flex;
+ align-items: stretch;
+ gap: var(--m3-space-2);
+ overflow-x: auto;
+ scrollbar-width: none;
+ border-block-end: 1px solid var(--m3-outline-variant);
+}
+
+.m3-tabs::-webkit-scrollbar { display: none; }
+
+.m3-tab {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ flex: 1 1 auto;
+ min-width: max-content;
+ min-height: 48px;
+ padding: 0 var(--m3-space-4);
+ border: none;
+ background: transparent;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-title-small-size);
+ font-weight: var(--m3-title-small-weight);
+ letter-spacing: var(--m3-tracking-title);
+ text-decoration: none;
+ cursor: pointer;
+ transition: color var(--m3-duration-short) var(--m3-ease-standard), background-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-tab:hover { color: var(--m3-on-surface); text-decoration: none; }
+.m3-tab[aria-selected='true'],
+.m3-tab.is-active {
+ color: var(--m3-primary);
+}
+
+.m3-tab[aria-selected='true']::after,
+.m3-tab.is-active::after {
+ content: '';
+ position: absolute;
+ inset-block-end: 0;
+ inset-inline: var(--m3-space-4);
+ height: 3px;
+ border-radius: var(--m3-shape-full) var(--m3-shape-full) 0 0;
+ background: var(--m3-primary);
+}
+
+.m3-tab-panel[hidden] { display: none; }
+.m3-tab-panel { animation: m3-fade-in var(--m3-duration-medium) var(--m3-ease-standard-decel); }
+
+@keyframes m3-fade-in {
+ from { opacity: 0; transform: translateY(8px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+/* Navigation bar (mobile) --------------------------------------------------- */
+.m3-nav-bar {
+ position: fixed;
+ inset-block-end: 0;
+ inset-inline: 0;
+ z-index: var(--m3-z-appbar);
+ display: flex;
+ justify-content: space-around;
+ align-items: stretch;
+ height: calc(80px + env(safe-area-inset-bottom));
+ padding-block-end: env(safe-area-inset-bottom);
+ background: var(--m3-surface-container);
+ box-shadow: var(--m3-elevation-2);
+}
+
+.m3-nav-bar__item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ flex: 1 1 0;
+ max-width: 120px;
+ padding: var(--m3-space-2) 0;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-medium-size);
+ font-weight: var(--m3-label-medium-weight);
+ text-decoration: none;
+ transition: color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-nav-bar__item:hover { text-decoration: none; }
+
+.m3-nav-bar__icon {
+ display: grid;
+ place-items: center;
+ width: 64px;
+ height: 32px;
+ border-radius: var(--m3-shape-full);
+ font-size: 1.15rem;
+ transition: background-color var(--m3-duration-short-2) var(--m3-ease-emphasized), color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-nav-bar__item[aria-current='page'] { color: var(--m3-on-secondary-container); }
+.m3-nav-bar__item[aria-current='page'] .m3-nav-bar__icon {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+}
+
+/* Navigation drawer --------------------------------------------------------- */
+.m3-drawer {
+ position: fixed;
+ inset-block: 0;
+ inset-inline-start: 0;
+ z-index: calc(var(--m3-z-drawer) + 1);
+ width: min(320px, 88vw);
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-2);
+ padding: var(--m3-space-3) var(--m3-space-3) calc(var(--m3-space-4) + env(safe-area-inset-bottom));
+ background: var(--m3-surface-container-low);
+ color: var(--m3-on-surface);
+ box-shadow: var(--m3-elevation-1);
+ border-start-end-radius: var(--m3-shape-lg);
+ border-end-end-radius: var(--m3-shape-lg);
+ overflow-y: auto;
+ transform: translateX(-105%);
+ visibility: hidden;
+ transition:
+ transform var(--m3-duration-medium) var(--m3-ease-emphasized-decel),
+ visibility var(--m3-duration-medium);
+}
+
+.m3-drawer.is-open,
+.m3-drawer.active,
+.m3-drawer[data-open='true'] {
+ transform: translateX(0);
+ visibility: visible;
+}
+
+.m3-drawer__head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-2) var(--m3-space-2) var(--m3-space-4);
+}
+
+.m3-drawer__brand {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-3);
+ font-size: var(--m3-title-large-size);
+ font-weight: 600;
+ color: var(--m3-on-surface);
+}
+
+.m3-drawer__brand img {
+ width: 40px;
+ height: 40px;
+ border-radius: var(--m3-shape-md);
+ object-fit: cover;
+}
+
+.m3-drawer__label {
+ padding: var(--m3-space-4) var(--m3-space-4) var(--m3-space-2);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+ text-transform: uppercase;
+}
+
+.m3-drawer__item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-3);
+ min-height: 56px;
+ padding: var(--m3-space-2) var(--m3-space-4);
+ border-radius: var(--m3-shape-full);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-large-size);
+ font-weight: 500;
+ text-decoration: none;
+ isolation: isolate;
+ overflow: hidden;
+ transition: background-color var(--m3-duration-short-2) var(--m3-ease-standard), color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+.m3-drawer__item::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: currentColor;
+ opacity: 0;
+ transition: opacity var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-drawer__item:hover::after { opacity: var(--m3-state-hover); } }
+.m3-drawer__item:focus-visible::after { opacity: var(--m3-state-focus); }
+.m3-drawer__item:active::after { opacity: var(--m3-state-pressed); }
+.m3-drawer__item > * { position: relative; z-index: 1; }
+.m3-drawer__item:hover { text-decoration: none; color: var(--m3-on-surface); }
+
+.m3-drawer__item[aria-current='page'],
+.m3-drawer__item.active,
+.m3-drawer__item.is-active {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+ font-weight: 600;
+}
+
+.m3-drawer__item i { width: 22px; text-align: center; }
+.m3-drawer__footer { margin-top: auto; padding: var(--m3-space-4); color: var(--m3-on-surface-variant); font-size: var(--m3-body-small-size); }
+
+/* Top app bar --------------------------------------------------------------- */
+.m3-app-bar {
+ position: sticky;
+ inset-block-start: 0;
+ z-index: var(--m3-z-appbar);
+ background: var(--m3-surface);
+ color: var(--m3-on-surface);
+ transition: background-color var(--m3-duration-short-2) var(--m3-ease-standard), box-shadow var(--m3-duration-short-2) var(--m3-ease-standard);
+}
+
+.m3-app-bar.is-scrolled {
+ background: var(--m3-surface-container);
+ box-shadow: var(--m3-elevation-2);
+}
+
+.m3-app-bar__row {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-2);
+ min-height: var(--m3-appbar-height);
+}
+
+.m3-app-bar__row:not(.m3-container) { padding-inline: var(--m3-space-2); }
+/* Header and page body share one measure so their edges line up. */
+.m3-app-bar__row.m3-container--wide { max-width: var(--m3-content-max); }
+
+.m3-app-bar__title {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-2);
+ margin-inline-start: var(--m3-space-2);
+ font-family: var(--m3-font-brand);
+ font-size: var(--m3-title-large-size);
+ font-weight: 600;
+ letter-spacing: var(--m3-tracking-title);
+ color: inherit;
+ text-decoration: none;
+}
+
+.m3-app-bar__title:hover { text-decoration: none; color: inherit; }
+.m3-app-bar__title img { width: 36px; height: 36px; border-radius: var(--m3-shape-sm); object-fit: cover; }
+.m3-app-bar__actions { display: flex; align-items: center; gap: 4px; margin-inline-start: auto; }
+
+.m3-app-bar--large { display: flex; flex-direction: column; }
+.m3-app-bar--large .m3-app-bar__headline {
+ padding: var(--m3-space-2) var(--m3-space-6) var(--m3-space-6);
+ font-size: var(--m3-headline-medium-size);
+ line-height: var(--m3-headline-medium-line);
+}
+
+/* ============================================================================
+ 15 ยท Tables, progress, badges & misc
+ ========================================================================== */
+
+.m3-table-wrap {
+ width: 100%;
+ overflow-x: auto;
+ border-radius: var(--m3-shape-md);
+ border: 1px solid var(--m3-outline-variant);
+ background: var(--m3-surface);
+ -webkit-overflow-scrolling: touch;
+}
+
+.m3-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: var(--m3-body-medium-size);
+}
+
+.m3-table caption {
+ caption-side: top;
+ padding: var(--m3-space-4);
+ text-align: start;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-small-size);
+}
+
+.m3-table th,
+.m3-table td {
+ padding: var(--m3-space-3) var(--m3-space-4);
+ text-align: start;
+ border-block-end: 1px solid var(--m3-outline-variant);
+ vertical-align: middle;
+}
+
+.m3-table thead th {
+ position: sticky;
+ inset-block-start: 0;
+ z-index: 1;
+ background: var(--m3-surface-container);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+ white-space: nowrap;
+}
+
+.m3-table tbody tr { transition: background-color var(--m3-duration-short) var(--m3-ease-standard); }
+@media (hover: hover) { .m3-table tbody tr:hover { background: color-mix(in srgb, var(--m3-on-surface) 6%, transparent); } }
+.m3-table tbody tr:last-child td { border-block-end: none; }
+.m3-table__num { font-variant-numeric: tabular-nums; font-family: var(--m3-font-mono); }
+.m3-table__actions { width: 1%; white-space: nowrap; text-align: end; }
+
+.m3-progress-linear {
+ position: relative;
+ height: 4px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+ overflow: hidden;
+}
+
+.m3-progress-linear__bar {
+ height: 100%;
+ border-radius: inherit;
+ background: var(--m3-primary);
+ transition: width var(--m3-duration-long) var(--m3-ease-emphasized-decel);
+}
+
+.m3-progress-linear--indeterminate::after {
+ content: '';
+ position: absolute;
+ inset-block: 0;
+ inset-inline-start: -40%;
+ width: 40%;
+ border-radius: inherit;
+ background: var(--m3-primary);
+ animation: m3-indeterminate 1.6s var(--m3-ease-standard) infinite;
+}
+
+@keyframes m3-indeterminate {
+ 0% { inset-inline-start: -40%; }
+ 100% { inset-inline-start: 100%; }
+}
+
+.m3-circular {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ border: 3px solid var(--m3-surface-container-highest);
+ border-top-color: var(--m3-primary);
+ animation: m3-spin 900ms linear infinite;
+}
+
+.m3-circular--sm { width: 18px; height: 18px; border-width: 2px; }
+
+.m3-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 10px;
+ border-radius: var(--m3-shape-sm);
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+ font-size: var(--m3-label-medium-size);
+ font-weight: var(--m3-label-medium-weight);
+ letter-spacing: var(--m3-tracking-label);
+}
+
+.m3-badge--primary { background: var(--m3-primary-container); color: var(--m3-on-primary-container); }
+.m3-badge--tertiary { background: var(--m3-tertiary-container); color: var(--m3-on-tertiary-container); }
+.m3-badge--error { background: var(--m3-error-container); color: var(--m3-on-error-container); }
+.m3-badge--outline { background: transparent; border: 1px solid var(--m3-outline-variant); color: var(--m3-on-surface-variant); }
+.m3-badge--dot {
+ width: 8px;
+ height: 8px;
+ padding: 0;
+ border-radius: 50%;
+ background: var(--m3-error);
+}
+
+.m3-avatar {
+ display: grid;
+ place-items: center;
+ width: 48px;
+ height: 48px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ object-fit: cover;
+ font-weight: 600;
+ overflow: hidden;
+}
+
+.m3-avatar--sm { width: 32px; height: 32px; font-size: var(--m3-body-small-size); }
+.m3-avatar--lg { width: 88px; height: 88px; font-size: 2rem; }
+
+.m3-skeleton {
+ position: relative;
+ overflow: hidden;
+ border-radius: var(--m3-shape-sm);
+ background: var(--m3-surface-container-high);
+}
+
+.m3-skeleton::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--m3-on-surface) 8%, transparent), transparent);
+ transform: translateX(-100%);
+ animation: m3-shimmer 1.4s var(--m3-ease-standard) infinite;
+}
+
+@keyframes m3-shimmer {
+ to { transform: translateX(100%); }
+}
+
+.m3-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-12) var(--m3-space-4);
+ text-align: center;
+ color: var(--m3-on-surface-variant);
+}
+
+.m3-empty i,
+.m3-empty svg { font-size: 2.5rem; color: var(--m3-outline); }
+.m3-empty h3 { color: var(--m3-on-surface); }
+
+.m3-expansion {
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-surface-container-low);
+ overflow: hidden;
+}
+
+.m3-expansion + .m3-expansion { margin-block-start: var(--m3-space-3); }
+
+.m3-expansion__summary {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-4);
+ cursor: pointer;
+ list-style: none;
+ font-size: var(--m3-title-medium-size);
+ font-weight: var(--m3-title-medium-weight);
+ color: var(--m3-on-surface);
+}
+
+.m3-expansion__summary::-webkit-details-marker { display: none; }
+.m3-expansion__summary::after {
+ content: '\f107';
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 900;
+ margin-inline-start: auto;
+ color: var(--m3-on-surface-variant);
+ transition: transform var(--m3-duration-medium) var(--m3-ease-emphasized);
+}
+
+.m3-expansion[open] > .m3-expansion__summary::after { transform: rotate(180deg); }
+.m3-expansion__content { padding: 0 var(--m3-space-4) var(--m3-space-4); color: var(--m3-on-surface-variant); }
+
+.m3-stepper { display: flex; align-items: center; gap: var(--m3-space-2); }
+.m3-stepper__btn {
+ display: grid;
+ place-items: center;
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ border: 1px solid var(--m3-outline);
+ background: transparent;
+ color: var(--m3-on-surface-variant);
+ cursor: pointer;
+}
+.m3-stepper__value { min-width: 3ch; text-align: center; font-variant-numeric: tabular-nums; font-family: var(--m3-font-mono); }
+
+.m3-pagination {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ flex-wrap: wrap;
+}
+
+.m3-page-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 40px;
+ height: 40px;
+ padding-inline: 12px;
+ border: none;
+ border-radius: var(--m3-shape-full);
+ background: transparent;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ cursor: pointer;
+ transition: background-color var(--m3-duration-short) var(--m3-ease-standard), color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) { .m3-page-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--m3-on-surface) 8%, transparent); color: var(--m3-on-surface); } }
+.m3-page-btn[aria-current='page'],
+.m3-page-btn.is-active { background: var(--m3-primary); color: var(--m3-on-primary); }
+.m3-page-btn:disabled { opacity: 0.38; cursor: not-allowed; }
+
+.m3-label-float { color: var(--m3-on-surface-variant); font-size: var(--m3-label-large-size); font-weight: var(--m3-label-large-weight); letter-spacing: var(--m3-tracking-label); }
+
+/* Motion utilities ---------------------------------------------------------- */
+.m3-animate-in { animation: m3-fade-in var(--m3-duration-medium) var(--m3-ease-emphasized-decel) both; }
+.m3-press { transition: transform var(--m3-duration-short-2) var(--m3-ease-emphasized); }
+.m3-press:active { transform: scale(0.96); }
+
+@media (prefers-reduced-motion: reduce) {
+ .m3-dialog__surface,
+ .m3-drawer,
+ .m3-sheet { transform: none !important; }
+}
+
+/* โโ Dynamic colour picker (rendered by assets/m3/color.js) โโโโโโโโโโโโโโโ */
+
+.m3-color-picker { display: flex; flex-direction: column; gap: var(--m3-space-2); }
+.m3-color-picker .m3-chip { gap: 10px; }
+.m3-color-picker input[type='color'] { border-radius: var(--m3-shape-full); }
diff --git a/main/assets/m3/gen_palette.py b/main/assets/m3/gen_palette.py
new file mode 100644
index 0000000..7810528
--- /dev/null
+++ b/main/assets/m3/gen_palette.py
@@ -0,0 +1,277 @@
+"""Generate Material You 3 tonal palettes from seed colors (offline, one-shot).
+Mirrors the runtime generator in main/assets/m3/color.js (CIELAB-based tonal palettes)."""
+import math
+
+def srgb_to_lin(c):
+ c = c / 255.0
+ return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
+
+def lin_to_srgb(c):
+ c = max(0.0, min(1.0, c))
+ v = 12.92 * c if c <= 0.0031308 else 1.055 * (c ** (1 / 2.4)) - 0.055
+ return round(max(0, min(255, v * 255)))
+
+def hex_to_rgb(h):
+ h = h.lstrip('#')
+ return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
+
+def rgb_to_hex(rgb):
+ return '#%02X%02X%02X' % tuple(rgb)
+
+# sRGB (D65) -> XYZ -> Lab
+def rgb_to_lab(rgb):
+ r, g, b = [srgb_to_lin(c) for c in rgb]
+ x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375
+ y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750
+ z = r * 0.0193339 + g * 0.1191920 + b * 0.9503041
+ xn, yn, zn = 0.95047, 1.0, 1.08883
+ def f(t):
+ return t ** (1/3) if t > 216/24389 else (841/108) * t + 4/29
+ fx, fy, fz = f(x/xn), f(y/yn), f(z/zn)
+ return (116*fy - 16, 500*(fx-fy), 200*(fy-fz))
+
+def lab_to_rgb(lab):
+ L, a, bb = lab
+ fy = (L + 16) / 116
+ fx = fy + a / 500
+ fz = fy - bb / 200
+ def f_inv(t):
+ return t ** 3 if t ** 3 > 216/24389 else (t - 4/29) * (108/841)
+ x = f_inv(fx) * 0.95047
+ y = f_inv(fy) * 1.0
+ z = f_inv(fz) * 1.08883
+ r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314
+ g = x * -0.9692660 + y * 1.8760108 + z * 0.0415560
+ bl = x * 0.0556434 + y * -0.2040259 + z * 1.0572252
+ return (lin_to_srgb(r), lin_to_srgb(g), lin_to_srgb(bl))
+
+def in_gamut(rgb):
+ r, g, b = [srgb_to_lin(c) for c in rgb]
+ x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375
+ y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750
+ z = r * 0.0193339 + g * 0.1191920 + b * 0.9503041
+ xn, yn, zn = 0.95047, 1.0, 1.08883
+ x, y, z = x/xn, y/yn, z/zn
+ return (-1e-4 <= x <= 1.0001) and (-1e-4 <= y <= 1.0001) and (-1e-4 <= z <= 1.0001)
+
+def tone_to_hex(L, a, b):
+ """Return hex for target lightness L keeping (a,b) chroma, clamped into sRGB gamut."""
+ aa, bb = a, b
+ rgb = lab_to_rgb((L, aa, bb))
+ if in_gamut(rgb):
+ return rgb_to_hex(rgb)
+ # binary search chroma reduction
+ lo, hi = 0.0, 1.0
+ best = (255, 255, 255) if L > 50 else (0, 0, 0)
+ for _ in range(24):
+ mid = (lo + hi) / 2
+ rgb = lab_to_rgb((L, aa * mid, bb * mid))
+ if in_gamut(rgb):
+ best = rgb
+ lo = mid
+ else:
+ hi = mid
+ return rgb_to_hex(best)
+
+TONES = [0, 4, 5, 6, 10, 12, 17, 20, 22, 24, 25, 30, 35, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 98, 99, 100]
+
+def palette(seed_hex, chroma_scale=1.0, forced_hue=None):
+ L, a, b = rgb_to_lab(hex_to_rgb(seed_hex))
+ hue = math.atan2(b, a)
+ chroma = math.hypot(a, b) * chroma_scale
+ if forced_hue is not None:
+ hue = math.radians(forced_hue)
+ out = {}
+ for t in TONES:
+ out[t] = tone_to_hex(t, chroma * math.cos(hue), chroma * math.sin(hue))
+ return out, math.degrees(hue), chroma
+
+LIGHT = dict(
+ primary=40, on_primary=100, primary_container=90, on_primary_container=10,
+ primary_fixed=90, primary_fixed_dim=80, on_primary_fixed=10, on_primary_fixed_variant=30,
+ secondary=40, on_secondary=100, secondary_container=90, on_secondary_container=10,
+ tertiary=40, on_tertiary=100, tertiary_container=90, on_tertiary_container=10,
+ error=40, on_error=100, error_container=90, on_error_container=10,
+ background=98, on_background=10,
+ surface=98, on_surface=10, surface_variant=90, on_surface_variant=30,
+ surface_dim=87, surface_bright=98,
+ surface_container_lowest=100, surface_container_low=96, surface_container=94,
+ surface_container_high=92, surface_container_highest=90,
+ outline=50, outline_variant=80,
+ inverse_surface=20, inverse_on_surface=95, inverse_primary=80,
+ scrim=0, shadow=0, surface_tint=40,
+)
+DARK = dict(
+ primary=80, on_primary=20, primary_container=30, on_primary_container=90,
+ primary_fixed=90, primary_fixed_dim=80, on_primary_fixed=10, on_primary_fixed_variant=30,
+ secondary=80, on_secondary=20, secondary_container=30, on_secondary_container=90,
+ tertiary=80, on_tertiary=20, tertiary_container=30, on_tertiary_container=90,
+ error=80, on_error=20, error_container=30, on_error_container=90,
+ background=6, on_background=90,
+ surface=6, on_surface=90, surface_variant=30, on_surface_variant=80,
+ surface_dim=6, surface_bright=24,
+ surface_container_lowest=4, surface_container_low=10, surface_container=12,
+ surface_container_high=17, surface_container_highest=22,
+ outline=60, outline_variant=30,
+ inverse_surface=90, inverse_on_surface=20, inverse_primary=40,
+ scrim=0, shadow=0, surface_tint=80,
+)
+
+ERROR_SEED = '#B3261E' # M3 fixed error palette
+NEUTRAL_CHROMA = 3.2
+NV_CHROMA = 9.0
+
+def build(seed_hex, tertiary_hue_shift=60):
+ p, hue, chroma = palette(seed_hex)
+ # secondary = desaturated version of the seed hue
+ sec, _, _ = palette(seed_hex, chroma_scale=0.34)
+ ter, _, _ = palette(seed_hex, chroma_scale=0.72, forced_hue=hue + tertiary_hue_shift)
+ n_err, _, _ = palette(ERROR_SEED)
+ neu = {}
+ nv = {}
+ for t in TONES:
+ L, a, b = rgb_to_lab(hex_to_rgb(p[t]))
+ neu[t] = tone_to_hex(t, NEUTRAL_CHROMA * math.cos(math.radians(hue)), NEUTRAL_CHROMA * math.sin(math.radians(hue)))
+ nv[t] = tone_to_hex(t, NV_CHROMA * math.cos(math.radians(hue)), NV_CHROMA * math.sin(math.radians(hue)))
+ return dict(primary=p, secondary=sec, tertiary=ter, error=n_err, neutral=neu, neutral_variant=nv)
+
+# role -> (palette key, tone) -- explicit Material 3 role mapping
+ROLE_MAP_LIGHT = {
+ 'primary': ('primary', 40), 'on_primary': ('primary', 100),
+ 'primary_container': ('primary', 90), 'on_primary_container': ('primary', 10),
+ 'primary_fixed': ('primary', 90), 'primary_fixed_dim': ('primary', 80),
+ 'on_primary_fixed': ('primary', 10), 'on_primary_fixed_variant': ('primary', 30),
+ 'secondary': ('secondary', 40), 'on_secondary': ('secondary', 100),
+ 'secondary_container': ('secondary', 90), 'on_secondary_container': ('secondary', 10),
+ 'tertiary': ('tertiary', 40), 'on_tertiary': ('tertiary', 100),
+ 'tertiary_container': ('tertiary', 90), 'on_tertiary_container': ('tertiary', 10),
+ 'error': ('error', 40), 'on_error': ('error', 100),
+ 'error_container': ('error', 90), 'on_error_container': ('error', 10),
+ 'background': ('neutral', 98), 'on_background': ('neutral', 10),
+ 'surface': ('neutral', 98), 'on_surface': ('neutral', 10),
+ 'surface_variant': ('neutral_variant', 90), 'on_surface_variant': ('neutral_variant', 30),
+ 'surface_dim': ('neutral', 87), 'surface_bright': ('neutral', 98),
+ 'surface_container_lowest': ('neutral', 100), 'surface_container_low': ('neutral', 96),
+ 'surface_container': ('neutral', 94), 'surface_container_high': ('neutral', 92),
+ 'surface_container_highest': ('neutral', 90),
+ 'outline': ('neutral_variant', 50), 'outline_variant': ('neutral_variant', 80),
+ 'inverse_surface': ('neutral', 20), 'inverse_on_surface': ('neutral', 95),
+ 'inverse_primary': ('primary', 80),
+ 'scrim': ('neutral', 0), 'shadow': ('neutral', 0), 'surface_tint': ('primary', 40),
+}
+ROLE_MAP_DARK = dict(ROLE_MAP_LIGHT)
+ROLE_MAP_DARK.update({
+ 'primary': ('primary', 80), 'on_primary': ('primary', 20),
+ 'primary_container': ('primary', 30), 'on_primary_container': ('primary', 90),
+ 'secondary': ('secondary', 80), 'on_secondary': ('secondary', 20),
+ 'secondary_container': ('secondary', 30), 'on_secondary_container': ('secondary', 90),
+ 'tertiary': ('tertiary', 80), 'on_tertiary': ('tertiary', 20),
+ 'tertiary_container': ('tertiary', 30), 'on_tertiary_container': ('tertiary', 90),
+ 'error': ('error', 80), 'on_error': ('error', 20),
+ 'error_container': ('error', 30), 'on_error_container': ('error', 90),
+ 'background': ('neutral', 6), 'on_background': ('neutral', 90),
+ 'surface': ('neutral', 6), 'on_surface': ('neutral', 90),
+ 'surface_variant': ('neutral_variant', 30), 'on_surface_variant': ('neutral_variant', 80),
+ 'surface_dim': ('neutral', 6), 'surface_bright': ('neutral', 24),
+ 'surface_container_lowest': ('neutral', 4), 'surface_container_low': ('neutral', 10),
+ 'surface_container': ('neutral', 12), 'surface_container_high': ('neutral', 17),
+ 'surface_container_highest': ('neutral', 22),
+ 'outline': ('neutral_variant', 60), 'outline_variant': ('neutral_variant', 30),
+ 'inverse_surface': ('neutral', 90), 'inverse_on_surface': ('neutral', 20),
+ 'inverse_primary': ('primary', 40), 'surface_tint': ('primary', 80),
+})
+
+def _rel_lum(hex_color):
+ r, g, b = hex_to_rgb(hex_color)
+ def chan(c):
+ c = c / 255.0
+ return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
+ r, g, b = chan(r), chan(g), chan(b)
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b
+
+def contrast(hex_a, hex_b):
+ """WCAG contrast ratio between two hex colours."""
+ la, lb = _rel_lum(hex_a), _rel_lum(hex_b)
+ hi, lo = max(la, lb), min(la, lb)
+ return (hi + 0.05) / (lo + 0.05)
+
+def readable_containers(scheme, maps):
+ """Dark container roles default to tone 30. Bright hues (crimson, amber)
+ can fall just short of 4.5:1 against their tone-90 label, so step the
+ container down the tonal ramp until the pair is accessible."""
+ scheme = dict(scheme)
+ pairs = (('primary_container', 'on_primary_container'),
+ ('secondary_container', 'on_secondary_container'),
+ ('tertiary_container', 'on_tertiary_container'),
+ ('error_container', 'on_error_container'))
+ for role, on_role in pairs:
+ key, tone = scheme[role]
+ on_key, on_tone = scheme[on_role]
+ label = _tone(maps, on_key, on_tone)
+ for candidate in (tone, 25, 22, 20, 17, 12):
+ if candidate not in maps[key]:
+ continue
+ if contrast(_tone(maps, key, candidate), label) >= 4.5:
+ scheme[role] = (key, candidate)
+ break
+ return scheme
+
+def _tone(maps, key, tone):
+ if tone == 100:
+ return '#FFFFFF'
+ if tone == 0:
+ return '#000000'
+ return maps[key][tone]
+
+def roles(scheme, maps):
+ return {role: _tone(maps, *ref) for role, ref in scheme.items()}
+
+def css_block(selector, scheme, maps, indent=' '):
+ r = roles(scheme, maps)
+ lines = [f'{selector} {{']
+ for k in scheme.keys():
+ lines.append(f'{indent}--m3-{k.replace("_", "-")}: {r[k]};')
+ lines.append('}')
+ return '\n'.join(lines)
+
+SEEDS = {
+ '': '#C8102E', # GDIPS red (default / brand)
+ 'indigo': '#6366F1',
+ 'violet': '#8B5CF6',
+ 'crimson': '#DC2626',
+ 'emerald': '#0F9D58',
+ 'amber': '#F59E0B',
+ 'azure': '#2563EB',
+}
+
+blocks = []
+# default seed: light + dark (+ system dark fallback for no-JS)
+maps_default = build(SEEDS[''])
+blocks.append('/* โโ Default dynamic palette: GDIPS red โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */')
+blocks.append(css_block(':root', ROLE_MAP_LIGHT, maps_default))
+blocks.append(css_block(':root[data-theme="dark"]', readable_containers(ROLE_MAP_DARK, maps_default), maps_default))
+blocks.append('@media (prefers-color-scheme: dark) {\n ' +
+ css_block(':root:not([data-theme="light"])', readable_containers(ROLE_MAP_DARK, maps_default), maps_default).replace('\n', '\n ') + '\n}')
+
+for name, seed in SEEDS.items():
+ if not name:
+ continue
+ m = build(seed)
+ blocks.append(f'/* โโ Seed: {name} ({seed}) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */')
+ blocks.append(css_block(f':root[data-seed="{name}"]', ROLE_MAP_LIGHT, m))
+ blocks.append(css_block(f':root[data-seed="{name}"][data-theme="dark"]', readable_containers(ROLE_MAP_DARK, m), m))
+ blocks.append('@media (prefers-color-scheme: dark) {\n ' +
+ css_block(f':root[data-seed="{name}"]:not([data-theme="light"])', readable_containers(ROLE_MAP_DARK, m), m).replace('\n', '\n ') + '\n}')
+
+header = '''/* ============================================================================
+ GDIPS ยท Material You 3 โ Dynamic color palettes
+ ----------------------------------------------------------------------------
+ Material 3 tonal palettes generated from seed colours (CIELAB tone mapping,
+ gamut-clamped). The default seed is the GDIPS brand red; alternate seeds are
+ selected with and the runtime generator in
+ assets/m3/color.js can produce a palette from *any* user-chosen seed.
+ ========================================================================== */
+'''
+open('main/assets/m3/palettes.css', 'w').write(header + '\n' + '\n\n'.join(blocks) + '\n')
+print('wrote palettes.css', len(header + '\n'.join(blocks)))
+print('sample light primary:', roles(ROLE_MAP_LIGHT, maps_default)['primary'], roles(ROLE_MAP_LIGHT, maps_default)['on_primary'])
diff --git a/main/assets/m3/pages.css b/main/assets/m3/pages.css
new file mode 100644
index 0000000..ffad140
--- /dev/null
+++ b/main/assets/m3/pages.css
@@ -0,0 +1,464 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Page level styles
+ ----------------------------------------------------------------------------
+ Layouts that are specific to individual GDIPS pages (entry bootloader,
+ download, rating standards, tools, feedback, 404, redirect). Everything here
+ is built from the shared tokens/components.
+ ========================================================================== */
+
+/* ============================================================================
+ Entry / bootloader page
+ ========================================================================== */
+
+.gd-boot-page {
+ overflow: hidden;
+ height: 100dvh;
+ overscroll-behavior: none;
+}
+
+.gd-boot {
+ position: relative;
+ display: grid;
+ place-items: center;
+ min-height: 100dvh;
+ padding-block: var(--m3-space-6);
+ background: var(--m3-surface);
+ isolation: isolate;
+}
+
+.gd-boot__glow {
+ position: absolute;
+ inset: 0;
+ overflow: hidden;
+ pointer-events: none;
+ z-index: -1;
+}
+
+.gd-boot__orb {
+ position: absolute;
+ display: block;
+ border-radius: 50%;
+ filter: blur(60px);
+ opacity: 0.55;
+ animation: gd-drift 18s var(--m3-ease-standard) infinite alternate;
+}
+
+.gd-boot__orb--primary {
+ width: clamp(240px, 45vw, 520px);
+ aspect-ratio: 1;
+ inset-block-start: -12%;
+ inset-inline-start: -8%;
+ background: var(--m3-primary-container);
+}
+
+.gd-boot__orb--tertiary {
+ width: clamp(200px, 38vw, 440px);
+ aspect-ratio: 1;
+ inset-block-end: -14%;
+ inset-inline-end: -6%;
+ background: var(--m3-tertiary-container);
+ animation-delay: -6s;
+}
+
+.gd-boot__grid {
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(color-mix(in srgb, var(--m3-outline-variant) 45%, transparent) 1px, transparent 1px),
+ linear-gradient(90deg, color-mix(in srgb, var(--m3-outline-variant) 45%, transparent) 1px, transparent 1px);
+ background-size: 56px 56px;
+ mask-image: radial-gradient(circle at 50% 45%, #000 0%, transparent 78%);
+ -webkit-mask-image: radial-gradient(circle at 50% 45%, #000 0%, transparent 78%);
+ opacity: 0.6;
+}
+
+@keyframes gd-drift {
+ from { transform: translate3d(0, 0, 0) scale(1); }
+ to { transform: translate3d(4%, 6%, 0) scale(1.12); }
+}
+
+.gd-boot__inner {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-5);
+ width: 100%;
+ max-width: 640px;
+}
+
+.gd-boot__brand {
+ margin: 0;
+ font-size: clamp(1.5rem, 4vw, 2rem);
+}
+
+.gd-boot__brand-sub {
+ display: block;
+ font-size: var(--m3-label-medium-size);
+ font-weight: 600;
+ letter-spacing: var(--m3-tracking-label);
+ text-transform: uppercase;
+ color: var(--m3-on-surface-variant);
+}
+
+.gd-boot__card {
+ padding: clamp(20px, 4vw, 32px);
+ background: color-mix(in srgb, var(--m3-surface-container-low) 88%, transparent);
+ backdrop-filter: blur(14px);
+ border-radius: var(--m3-shape-xl);
+}
+
+.gd-boot__card-head {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-2);
+ margin-block-end: var(--m3-space-5);
+}
+
+.gd-boot__menu {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-2);
+ transition: opacity var(--m3-duration-medium) var(--m3-ease-standard), transform var(--m3-duration-medium) var(--m3-ease-emphasized);
+}
+
+.gd-boot__menu.is-hidden {
+ opacity: 0;
+ transform: scale(0.98);
+ pointer-events: none;
+}
+
+.gd-boot__item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-3) var(--m3-space-4);
+ border: 1px solid transparent;
+ border-radius: var(--m3-shape-lg);
+ color: var(--m3-on-surface);
+ text-decoration: none;
+ isolation: isolate;
+ overflow: hidden;
+ transition:
+ background-color var(--m3-duration-short-2) var(--m3-ease-standard),
+ border-color var(--m3-duration-short-2) var(--m3-ease-standard),
+ transform var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.gd-boot__item:hover {
+ background: var(--m3-surface-container-high);
+ text-decoration: none;
+ transform: translateX(4px);
+}
+
+.gd-boot__item.is-active {
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+ border-color: color-mix(in srgb, var(--m3-primary) 45%, transparent);
+}
+
+.gd-boot__indicator {
+ display: grid;
+ place-items: center;
+ width: 24px;
+ color: var(--m3-primary);
+ opacity: 0;
+ transform: translateX(-6px);
+ transition: opacity var(--m3-duration-short-2) var(--m3-ease-standard), transform var(--m3-duration-short-2) var(--m3-ease-emphasized);
+}
+
+.gd-boot__item.is-active .gd-boot__indicator { opacity: 1; transform: none; }
+
+.gd-boot__item-icon {
+ display: grid;
+ place-items: center;
+ width: 44px;
+ height: 44px;
+ flex: 0 0 auto;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+ color: var(--m3-on-surface-variant);
+ font-size: 1.1rem;
+}
+
+.gd-boot__item.is-active .gd-boot__item-icon {
+ background: var(--m3-primary);
+ color: var(--m3-on-primary);
+}
+
+.gd-boot__item-text { display: flex; flex-direction: column; min-width: 0; }
+.gd-boot__item-title { font-size: var(--m3-title-medium-size); font-weight: 600; }
+.gd-boot__item-sub { color: inherit; opacity: 0.75; font-size: var(--m3-body-small-size); }
+
+.gd-boot__item-key {
+ margin-inline-start: auto;
+ display: grid;
+ place-items: center;
+ width: 28px;
+ height: 28px;
+ border-radius: var(--m3-shape-sm);
+ background: color-mix(in srgb, currentColor 10%, transparent);
+ font-size: var(--m3-label-medium-size);
+}
+
+.gd-boot__foot {
+ display: flex;
+ align-items: center;
+ gap: var(--m3-space-4);
+ flex-wrap: wrap;
+ margin-block-start: var(--m3-space-5);
+ padding-block-start: var(--m3-space-4);
+ border-block-start: 1px solid var(--m3-outline-variant);
+}
+
+.gd-boot__theme { margin-inline-start: auto; }
+
+.gd-boot__output {
+ position: fixed;
+ inset: 0;
+ display: grid;
+ place-items: center;
+ background: var(--m3-surface);
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity var(--m3-duration-medium) var(--m3-ease-standard);
+ z-index: 5;
+}
+
+.gd-boot__output.is-visible { opacity: 1; }
+
+.gd-boot__output-card {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-4);
+ width: min(420px, 86vw);
+ padding: var(--m3-space-6);
+ border-radius: var(--m3-shape-xl);
+ background: var(--m3-surface-container);
+ box-shadow: var(--m3-elevation-2);
+}
+
+.gd-boot__output-text {
+ font-size: clamp(0.95rem, 2.4vw, 1.15rem);
+ color: var(--m3-primary);
+ min-height: 1.6em;
+}
+
+.gd-boot__output-text::after {
+ content: '';
+ display: inline-block;
+ width: 9px;
+ height: 1.15em;
+ margin-inline-start: 6px;
+ vertical-align: -0.15em;
+ background: currentColor;
+ animation: gd-blink 1s step-end infinite;
+}
+
+.gd-boot__output-text.is-loading::after { animation: gd-dots 1.4s steps(4, end) infinite content; }
+.gd-boot__output-text.is-loading::before { content: ''; }
+
+@keyframes gd-blink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+/* ============================================================================
+ Shared content page pieces
+ ========================================================================== */
+
+.gd-page-head {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-3);
+ padding-block: clamp(24px, 5vw, 48px) var(--m3-space-6);
+}
+
+.gd-page-head__title { font-size: clamp(1.75rem, 4.2vw, 2.75rem); font-weight: 600; }
+.gd-page-head__lead { color: var(--m3-on-surface-variant); max-width: 68ch; }
+
+.gd-card-icon {
+ display: grid;
+ place-items: center;
+ width: 48px;
+ height: 48px;
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ font-size: 1.2rem;
+}
+
+.gd-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--m3-space-4);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-small-size);
+}
+
+.gd-meta span { display: inline-flex; align-items: center; gap: 6px; }
+
+/* Download cards ------------------------------------------------------------ */
+
+.gd-download {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-5);
+ height: 100%;
+}
+
+.gd-download__head { display: flex; align-items: center; gap: var(--m3-space-3); }
+.gd-download__title { font-size: var(--m3-title-large-size); font-weight: 600; }
+.gd-download__size { color: var(--m3-on-surface-variant); font-size: var(--m3-body-small-size); }
+.gd-download__actions { display: flex; gap: var(--m3-space-2); margin-block-start: auto; padding-block-start: var(--m3-space-3); flex-wrap: wrap; }
+
+/* Rating standards ---------------------------------------------------------- */
+
+.gd-rating-card { padding: var(--m3-space-5); display: flex; flex-direction: column; gap: var(--m3-space-4); height: 100%; }
+.gd-rating-card__tier { display: flex; align-items: center; justify-content: space-between; gap: var(--m3-space-3); }
+.gd-rating-card__name { font-size: var(--m3-title-large-size); font-weight: 600; }
+.gd-rating-card__meters { display: flex; flex-direction: column; gap: var(--m3-space-3); }
+
+/* Tools grid ---------------------------------------------------------------- */
+
+.gd-tool {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-5);
+ height: 100%;
+}
+
+.gd-tool__head { display: flex; align-items: center; gap: var(--m3-space-3); }
+.gd-tool__title { font-size: var(--m3-title-medium-size); font-weight: 600; }
+.gd-tool__actions { margin-block-start: auto; padding-block-start: var(--m3-space-2); }
+
+/* Error page ---------------------------------------------------------------- */
+
+.gd-error {
+ display: grid;
+ place-items: center;
+ min-height: 100dvh;
+ padding: var(--m3-space-6);
+ text-align: center;
+ background:
+ radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--m3-error-container) 55%, transparent), transparent 60%),
+ var(--m3-surface);
+}
+
+.gd-error__inner { max-width: 620px; display: flex; flex-direction: column; align-items: center; gap: var(--m3-space-4); }
+.gd-error__code {
+ font-family: var(--m3-font-display);
+ font-size: clamp(4rem, 18vw, 9rem);
+ line-height: 1;
+ color: var(--m3-error);
+ animation: gd-bob 3s var(--m3-ease-standard) infinite;
+}
+.gd-error__actions { display: flex; flex-wrap: wrap; gap: var(--m3-space-3); justify-content: center; margin-block-start: var(--m3-space-2); }
+
+@keyframes gd-bob {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-10px); }
+}
+
+/* Redirect / interstitial page --------------------------------------------- */
+
+.gd-redirect {
+ display: grid;
+ place-items: center;
+ min-height: 100dvh;
+ padding: var(--m3-space-6);
+ text-align: center;
+ background: var(--m3-surface);
+}
+
+.gd-redirect__card {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--m3-space-4);
+ width: min(460px, 100%);
+ padding: clamp(24px, 5vw, 40px);
+ border-radius: var(--m3-shape-xl);
+ background: var(--m3-surface-container-low);
+ box-shadow: var(--m3-elevation-2);
+}
+
+.gd-redirect__logo {
+ width: 96px;
+ height: 96px;
+ border-radius: var(--m3-shape-lg);
+ object-fit: cover;
+ animation: gd-bob 2.6s var(--m3-ease-standard) infinite;
+}
+
+.gd-redirect__count {
+ font-family: var(--m3-font-mono);
+ font-size: 2.5rem;
+ font-weight: 600;
+ color: var(--m3-primary);
+ font-variant-numeric: tabular-nums;
+}
+
+.gd-redirect__ring {
+ --m3-meter-value: 0%;
+ width: 100%;
+}
+
+/* ============================================================================
+ Feedback pages
+ ========================================================================== */
+
+.gd-feedback-grid {
+ display: grid;
+ gap: var(--m3-space-5);
+ align-items: start;
+}
+
+@media (min-width: 1024px) {
+ .gd-feedback-grid { grid-template-columns: minmax(0, 1fr) 340px; }
+}
+
+.gd-feedback-table td:nth-child(1) { white-space: nowrap; color: var(--m3-on-surface-variant); font-size: var(--m3-body-small-size); }
+.gd-feedback-table .gd-feedback-text { max-width: 46ch; }
+.gd-feedback-actions { display: flex; gap: var(--m3-space-2); flex-wrap: wrap; }
+
+.gd-faq-list { display: flex; flex-direction: column; gap: var(--m3-space-3); }
+
+.gd-tabs-wrap {
+ position: sticky;
+ inset-block-start: var(--m3-appbar-height);
+ z-index: 2;
+ background: var(--m3-surface);
+ padding-block: var(--m3-space-2);
+}
+
+.gd-legal section + section { margin-block-start: var(--m3-space-8); }
+
+/* Contact page -------------------------------------------------------------- */
+
+.gd-contact-list { display: grid; gap: var(--m3-space-4); }
+@media (min-width: 720px) { .gd-contact-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+
+.gd-contact-card {
+ display: flex;
+ gap: var(--m3-space-4);
+ padding: var(--m3-space-5);
+ border-radius: var(--m3-shape-lg);
+ background: var(--m3-surface-container-low);
+ border: 1px solid var(--m3-outline-variant);
+ transition: transform var(--m3-duration-short-2) var(--m3-ease-emphasized), box-shadow var(--m3-duration-short-2) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .gd-contact-card:hover { transform: translateY(-3px); box-shadow: var(--m3-elevation-2); }
+}
+
+.gd-forms-grid { display: grid; gap: var(--m3-space-4); }
+@media (min-width: 720px) { .gd-forms-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+
+/* Pulse used when a prediction result updates (kept from the original design) */
+@keyframes pulse {
+ 0%, 100% { transform: scale(1); }
+ 50% { transform: scale(1.04); }
+}
diff --git a/main/assets/m3/palettes.css b/main/assets/m3/palettes.css
new file mode 100644
index 0000000..00862c6
--- /dev/null
+++ b/main/assets/m3/palettes.css
@@ -0,0 +1,960 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Dynamic color palettes
+ ----------------------------------------------------------------------------
+ Material 3 tonal palettes generated from seed colours (CIELAB tone mapping,
+ gamut-clamped). The default seed is the GDIPS brand red; alternate seeds are
+ selected with and the runtime generator in
+ assets/m3/color.js can produce a palette from *any* user-chosen seed.
+ ========================================================================== */
+
+/* โโ Default dynamic palette: GDIPS red โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root {
+ --m3-primary: #C00029;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #FFA9A2;
+ --m3-on-primary-container: #640000;
+ --m3-primary-fixed: #FFA9A2;
+ --m3-primary-fixed-dim: #FF8C88;
+ --m3-on-primary-fixed: #640000;
+ --m3-on-primary-fixed-variant: #A00014;
+ --m3-secondary: #864F4C;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #FFD3CC;
+ --m3-on-secondary-container: #390B08;
+ --m3-tertiary: #745C00;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #FFDE79;
+ --m3-on-tertiary-container: #321800;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #FFF7F6;
+ --m3-on-background: #201A1A;
+ --m3-surface: #FFF7F6;
+ --m3-on-surface: #201A1A;
+ --m3-surface-variant: #F5DDDB;
+ --m3-on-surface-variant: #554240;
+ --m3-surface-dim: #E1D8D7;
+ --m3-surface-bright: #FFF7F6;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #FAF2F1;
+ --m3-surface-container: #F5ECEB;
+ --m3-surface-container-high: #EFE6E5;
+ --m3-surface-container-highest: #E9E0E0;
+ --m3-outline: #877270;
+ --m3-outline-variant: #D9C1BF;
+ --m3-inverse-surface: #352F2E;
+ --m3-inverse-on-surface: #F8EFEE;
+ --m3-inverse-primary: #FF8C88;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #C00029;
+}
+
+:root[data-theme="dark"] {
+ --m3-primary: #FF8C88;
+ --m3-on-primary: #810000;
+ --m3-primary-container: #A00014;
+ --m3-on-primary-container: #FFA9A2;
+ --m3-primary-fixed: #FFA9A2;
+ --m3-primary-fixed-dim: #FF8C88;
+ --m3-on-primary-fixed: #640000;
+ --m3-on-primary-fixed-variant: #A00014;
+ --m3-secondary: #F7B7B1;
+ --m3-on-secondary: #522120;
+ --m3-secondary-container: #6B3835;
+ --m3-on-secondary-container: #FFD3CC;
+ --m3-tertiary: #E7C35F;
+ --m3-on-tertiary: #432E00;
+ --m3-tertiary-container: #5A4400;
+ --m3-on-tertiary-container: #FFDE79;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #181211;
+ --m3-on-background: #E9E0E0;
+ --m3-surface: #181211;
+ --m3-on-surface: #E9E0E0;
+ --m3-surface-variant: #554240;
+ --m3-on-surface-variant: #D9C1BF;
+ --m3-surface-dim: #181211;
+ --m3-surface-bright: #3E3837;
+ --m3-surface-container-lowest: #140C0B;
+ --m3-surface-container-low: #201A1A;
+ --m3-surface-container: #241E1D;
+ --m3-surface-container-high: #2F2828;
+ --m3-surface-container-highest: #3A3332;
+ --m3-outline: #A28C89;
+ --m3-outline-variant: #554240;
+ --m3-inverse-surface: #E9E0E0;
+ --m3-inverse-on-surface: #352F2E;
+ --m3-inverse-primary: #C00029;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FF8C88;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme="light"]) {
+ --m3-primary: #FF8C88;
+ --m3-on-primary: #810000;
+ --m3-primary-container: #A00014;
+ --m3-on-primary-container: #FFA9A2;
+ --m3-primary-fixed: #FFA9A2;
+ --m3-primary-fixed-dim: #FF8C88;
+ --m3-on-primary-fixed: #640000;
+ --m3-on-primary-fixed-variant: #A00014;
+ --m3-secondary: #F7B7B1;
+ --m3-on-secondary: #522120;
+ --m3-secondary-container: #6B3835;
+ --m3-on-secondary-container: #FFD3CC;
+ --m3-tertiary: #E7C35F;
+ --m3-on-tertiary: #432E00;
+ --m3-tertiary-container: #5A4400;
+ --m3-on-tertiary-container: #FFDE79;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #181211;
+ --m3-on-background: #E9E0E0;
+ --m3-surface: #181211;
+ --m3-on-surface: #E9E0E0;
+ --m3-surface-variant: #554240;
+ --m3-on-surface-variant: #D9C1BF;
+ --m3-surface-dim: #181211;
+ --m3-surface-bright: #3E3837;
+ --m3-surface-container-lowest: #140C0B;
+ --m3-surface-container-low: #201A1A;
+ --m3-surface-container: #241E1D;
+ --m3-surface-container-high: #2F2828;
+ --m3-surface-container-highest: #3A3332;
+ --m3-outline: #A28C89;
+ --m3-outline-variant: #554240;
+ --m3-inverse-surface: #E9E0E0;
+ --m3-inverse-on-surface: #352F2E;
+ --m3-inverse-primary: #C00029;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FF8C88;
+ }
+}
+
+/* โโ Seed: indigo (#6366F1) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="indigo"] {
+ --m3-primary: #414ED4;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #DDCFFF;
+ --m3-on-primary-container: #000E81;
+ --m3-primary-fixed: #DDCFFF;
+ --m3-primary-fixed-dim: #BFB4FF;
+ --m3-on-primary-fixed: #000E81;
+ --m3-on-primary-fixed-variant: #0D37B8;
+ --m3-secondary: #5F5985;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #E5DCFF;
+ --m3-on-secondary-container: #18173C;
+ --m3-tertiary: #AE2562;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #FFB5E7;
+ --m3-on-tertiary-container: #58001F;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #FAF8FF;
+ --m3-on-background: #1C1B1F;
+ --m3-surface: #FAF8FF;
+ --m3-on-surface: #1C1B1F;
+ --m3-surface-variant: #E4E0F1;
+ --m3-on-surface-variant: #484553;
+ --m3-surface-dim: #DAD9DF;
+ --m3-surface-bright: #FAF8FF;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #F4F3F9;
+ --m3-surface-container: #EEEDF3;
+ --m3-surface-container-high: #E9E7ED;
+ --m3-surface-container-highest: #E3E2E8;
+ --m3-outline: #787584;
+ --m3-outline-variant: #C8C4D5;
+ --m3-inverse-surface: #313034;
+ --m3-inverse-on-surface: #F1F0F6;
+ --m3-inverse-primary: #BFB4FF;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #414ED4;
+}
+
+:root[data-seed="indigo"][data-theme="dark"] {
+ --m3-primary: #BFB4FF;
+ --m3-on-primary: #00219C;
+ --m3-primary-container: #0D37B8;
+ --m3-on-primary-container: #DDCFFF;
+ --m3-primary-fixed: #DDCFFF;
+ --m3-primary-fixed-dim: #BFB4FF;
+ --m3-on-primary-fixed: #000E81;
+ --m3-on-primary-fixed-variant: #0D37B8;
+ --m3-secondary: #C9C0F3;
+ --m3-on-secondary: #2F2B53;
+ --m3-secondary-container: #47416C;
+ --m3-on-secondary-container: #E5DCFF;
+ --m3-tertiary: #FF98CB;
+ --m3-on-tertiary: #740034;
+ --m3-tertiary-container: #91004B;
+ --m3-on-tertiary-container: #FFB5E7;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #141317;
+ --m3-on-background: #E3E2E8;
+ --m3-surface: #141317;
+ --m3-on-surface: #E3E2E8;
+ --m3-surface-variant: #484553;
+ --m3-on-surface-variant: #C8C4D5;
+ --m3-surface-dim: #141317;
+ --m3-surface-bright: #39383D;
+ --m3-surface-container-lowest: #0F0D13;
+ --m3-surface-container-low: #1C1B1F;
+ --m3-surface-container: #201F23;
+ --m3-surface-container-high: #2A292E;
+ --m3-surface-container-highest: #353439;
+ --m3-outline: #928F9E;
+ --m3-outline-variant: #484553;
+ --m3-inverse-surface: #E3E2E8;
+ --m3-inverse-on-surface: #313034;
+ --m3-inverse-primary: #414ED4;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #BFB4FF;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="indigo"]:not([data-theme="light"]) {
+ --m3-primary: #BFB4FF;
+ --m3-on-primary: #00219C;
+ --m3-primary-container: #0D37B8;
+ --m3-on-primary-container: #DDCFFF;
+ --m3-primary-fixed: #DDCFFF;
+ --m3-primary-fixed-dim: #BFB4FF;
+ --m3-on-primary-fixed: #000E81;
+ --m3-on-primary-fixed-variant: #0D37B8;
+ --m3-secondary: #C9C0F3;
+ --m3-on-secondary: #2F2B53;
+ --m3-secondary-container: #47416C;
+ --m3-on-secondary-container: #E5DCFF;
+ --m3-tertiary: #FF98CB;
+ --m3-on-tertiary: #740034;
+ --m3-tertiary-container: #91004B;
+ --m3-on-tertiary-container: #FFB5E7;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #141317;
+ --m3-on-background: #E3E2E8;
+ --m3-surface: #141317;
+ --m3-on-surface: #E3E2E8;
+ --m3-surface-variant: #484553;
+ --m3-on-surface-variant: #C8C4D5;
+ --m3-surface-dim: #141317;
+ --m3-surface-bright: #39383D;
+ --m3-surface-container-lowest: #0F0D13;
+ --m3-surface-container-low: #1C1B1F;
+ --m3-surface-container: #201F23;
+ --m3-surface-container-high: #2A292E;
+ --m3-surface-container-highest: #353439;
+ --m3-outline: #928F9E;
+ --m3-outline-variant: #484553;
+ --m3-inverse-surface: #E3E2E8;
+ --m3-inverse-on-surface: #313034;
+ --m3-inverse-primary: #414ED4;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #BFB4FF;
+ }
+}
+
+/* โโ Seed: violet (#8B5CF6) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="violet"] {
+ --m3-primary: #683FD4;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #FEC3FF;
+ --m3-on-primary-container: #000082;
+ --m3-primary-fixed: #FEC3FF;
+ --m3-primary-fixed-dim: #E0A7FF;
+ --m3-on-primary-fixed: #000082;
+ --m3-on-primary-fixed-variant: #4925B8;
+ --m3-secondary: #685686;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #F0D9FF;
+ --m3-on-secondary-container: #21133C;
+ --m3-tertiary: #B71455;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #FFAED6;
+ --m3-on-tertiary-container: #5E0014;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #FBF8FE;
+ --m3-on-background: #1D1B1F;
+ --m3-surface: #FBF8FE;
+ --m3-on-surface: #1D1B1F;
+ --m3-surface-variant: #E7E0F0;
+ --m3-on-surface-variant: #4A4452;
+ --m3-surface-dim: #DBD9DF;
+ --m3-surface-bright: #FBF8FE;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #F5F2F8;
+ --m3-surface-container: #EFEDF3;
+ --m3-surface-container-high: #EAE7ED;
+ --m3-surface-container-highest: #E4E1E7;
+ --m3-outline: #7B7483;
+ --m3-outline-variant: #CBC4D4;
+ --m3-inverse-surface: #313034;
+ --m3-inverse-on-surface: #F2F0F6;
+ --m3-inverse-primary: #E0A7FF;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #683FD4;
+}
+
+:root[data-seed="violet"][data-theme="dark"] {
+ --m3-primary: #E0A7FF;
+ --m3-on-primary: #25099C;
+ --m3-primary-container: #4925B8;
+ --m3-on-primary-container: #FEC3FF;
+ --m3-primary-fixed: #FEC3FF;
+ --m3-primary-fixed-dim: #E0A7FF;
+ --m3-on-primary-fixed: #000082;
+ --m3-on-primary-fixed-variant: #4925B8;
+ --m3-secondary: #D3BDF3;
+ --m3-on-secondary: #372854;
+ --m3-secondary-container: #4F3E6C;
+ --m3-on-secondary-container: #F0D9FF;
+ --m3-tertiary: #FF92BB;
+ --m3-on-tertiary: #7B0028;
+ --m3-tertiary-container: #99003E;
+ --m3-on-tertiary-container: #FFAED6;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #151217;
+ --m3-on-background: #E4E1E7;
+ --m3-surface: #151217;
+ --m3-on-surface: #E4E1E7;
+ --m3-surface-variant: #4A4452;
+ --m3-on-surface-variant: #CBC4D4;
+ --m3-surface-dim: #151217;
+ --m3-surface-bright: #3A383D;
+ --m3-surface-container-lowest: #100D13;
+ --m3-surface-container-low: #1D1B1F;
+ --m3-surface-container: #211F23;
+ --m3-surface-container-high: #2B292E;
+ --m3-surface-container-highest: #363438;
+ --m3-outline: #948E9D;
+ --m3-outline-variant: #4A4452;
+ --m3-inverse-surface: #E4E1E7;
+ --m3-inverse-on-surface: #313034;
+ --m3-inverse-primary: #683FD4;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #E0A7FF;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="violet"]:not([data-theme="light"]) {
+ --m3-primary: #E0A7FF;
+ --m3-on-primary: #25099C;
+ --m3-primary-container: #4925B8;
+ --m3-on-primary-container: #FEC3FF;
+ --m3-primary-fixed: #FEC3FF;
+ --m3-primary-fixed-dim: #E0A7FF;
+ --m3-on-primary-fixed: #000082;
+ --m3-on-primary-fixed-variant: #4925B8;
+ --m3-secondary: #D3BDF3;
+ --m3-on-secondary: #372854;
+ --m3-secondary-container: #4F3E6C;
+ --m3-on-secondary-container: #F0D9FF;
+ --m3-tertiary: #FF92BB;
+ --m3-on-tertiary: #7B0028;
+ --m3-tertiary-container: #99003E;
+ --m3-on-tertiary-container: #FFAED6;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #151217;
+ --m3-on-background: #E4E1E7;
+ --m3-surface: #151217;
+ --m3-on-surface: #E4E1E7;
+ --m3-surface-variant: #4A4452;
+ --m3-on-surface-variant: #CBC4D4;
+ --m3-surface-dim: #151217;
+ --m3-surface-bright: #3A383D;
+ --m3-surface-container-lowest: #100D13;
+ --m3-surface-container-low: #1D1B1F;
+ --m3-surface-container: #211F23;
+ --m3-surface-container-high: #2B292E;
+ --m3-surface-container-highest: #363438;
+ --m3-outline: #948E9D;
+ --m3-outline-variant: #4A4452;
+ --m3-inverse-surface: #E4E1E7;
+ --m3-inverse-on-surface: #313034;
+ --m3-inverse-primary: #683FD4;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #E0A7FF;
+ }
+}
+
+/* โโ Seed: crimson (#DC2626) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="crimson"] {
+ --m3-primary: #C20014;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #FFA78D;
+ --m3-on-primary-container: #670000;
+ --m3-primary-fixed: #FFA78D;
+ --m3-primary-fixed-dim: #FF8A73;
+ --m3-on-primary-fixed: #670000;
+ --m3-on-primary-fixed-variant: #A20000;
+ --m3-secondary: #884F45;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #FFD2C5;
+ --m3-on-secondary-container: #3A0A00;
+ --m3-tertiary: #6B5F00;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #FBE26F;
+ --m3-on-tertiary-container: #2E1B00;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #FFF7F6;
+ --m3-on-background: #201A19;
+ --m3-surface: #FFF7F6;
+ --m3-on-surface: #201A19;
+ --m3-surface-variant: #F5DDD9;
+ --m3-on-surface-variant: #55423F;
+ --m3-surface-dim: #E1D8D6;
+ --m3-surface-bright: #FFF7F6;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #FAF2F0;
+ --m3-surface-container: #F5ECEA;
+ --m3-surface-container-high: #EFE6E5;
+ --m3-surface-container-highest: #E9E1DF;
+ --m3-outline: #87726E;
+ --m3-outline-variant: #D8C1BD;
+ --m3-inverse-surface: #352F2E;
+ --m3-inverse-on-surface: #F7EFED;
+ --m3-inverse-primary: #FF8A73;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #C20014;
+}
+
+:root[data-seed="crimson"][data-theme="dark"] {
+ --m3-primary: #FF8A73;
+ --m3-on-primary: #830000;
+ --m3-primary-container: #930000;
+ --m3-on-primary-container: #FFA78D;
+ --m3-primary-fixed: #FFA78D;
+ --m3-primary-fixed-dim: #FF8A73;
+ --m3-on-primary-fixed: #670000;
+ --m3-on-primary-fixed-variant: #A20000;
+ --m3-secondary: #FAB6AA;
+ --m3-on-secondary: #53211A;
+ --m3-secondary-container: #6D372F;
+ --m3-on-secondary-container: #FFD2C5;
+ --m3-tertiary: #DEC654;
+ --m3-on-tertiary: #3C3100;
+ --m3-tertiary-container: #524700;
+ --m3-on-tertiary-container: #FBE26F;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #181210;
+ --m3-on-background: #E9E1DF;
+ --m3-surface: #181210;
+ --m3-on-surface: #E9E1DF;
+ --m3-surface-variant: #55423F;
+ --m3-on-surface-variant: #D8C1BD;
+ --m3-surface-dim: #181210;
+ --m3-surface-bright: #3E3836;
+ --m3-surface-container-lowest: #140C0A;
+ --m3-surface-container-low: #201A19;
+ --m3-surface-container: #241E1D;
+ --m3-surface-container-high: #2F2927;
+ --m3-surface-container-highest: #3A3332;
+ --m3-outline: #A18C88;
+ --m3-outline-variant: #55423F;
+ --m3-inverse-surface: #E9E1DF;
+ --m3-inverse-on-surface: #352F2E;
+ --m3-inverse-primary: #C20014;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FF8A73;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="crimson"]:not([data-theme="light"]) {
+ --m3-primary: #FF8A73;
+ --m3-on-primary: #830000;
+ --m3-primary-container: #930000;
+ --m3-on-primary-container: #FFA78D;
+ --m3-primary-fixed: #FFA78D;
+ --m3-primary-fixed-dim: #FF8A73;
+ --m3-on-primary-fixed: #670000;
+ --m3-on-primary-fixed-variant: #A20000;
+ --m3-secondary: #FAB6AA;
+ --m3-on-secondary: #53211A;
+ --m3-secondary-container: #6D372F;
+ --m3-on-secondary-container: #FFD2C5;
+ --m3-tertiary: #DEC654;
+ --m3-on-tertiary: #3C3100;
+ --m3-tertiary-container: #524700;
+ --m3-on-tertiary-container: #FBE26F;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #181210;
+ --m3-on-background: #E9E1DF;
+ --m3-surface: #181210;
+ --m3-on-surface: #E9E1DF;
+ --m3-surface-variant: #55423F;
+ --m3-on-surface-variant: #D8C1BD;
+ --m3-surface-dim: #181210;
+ --m3-surface-bright: #3E3836;
+ --m3-surface-container-lowest: #140C0A;
+ --m3-surface-container-low: #201A19;
+ --m3-surface-container: #241E1D;
+ --m3-surface-container-high: #2F2927;
+ --m3-surface-container-highest: #3A3332;
+ --m3-outline: #A18C88;
+ --m3-outline-variant: #55423F;
+ --m3-inverse-surface: #E9E1DF;
+ --m3-inverse-on-surface: #352F2E;
+ --m3-inverse-primary: #C20014;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FF8A73;
+ }
+}
+
+/* โโ Seed: emerald (#0F9D58) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="emerald"] {
+ --m3-primary: #007030;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #82FAAD;
+ --m3-on-primary-container: #002900;
+ --m3-primary-fixed: #82FAAD;
+ --m3-primary-fixed-dim: #64DD93;
+ --m3-on-primary-fixed: #002900;
+ --m3-on-primary-fixed-variant: #005619;
+ --m3-secondary: #45664F;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #C6EBD1;
+ --m3-on-secondary-container: #01210D;
+ --m3-tertiary: #006E81;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #59F6FF;
+ --m3-on-tertiary-container: #002839;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #F5FBF6;
+ --m3-on-background: #181D19;
+ --m3-surface: #F5FBF6;
+ --m3-on-surface: #181D19;
+ --m3-surface-variant: #D6E7DA;
+ --m3-on-surface-variant: #3C4A40;
+ --m3-surface-dim: #D5DBD7;
+ --m3-surface-bright: #F5FBF6;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #EFF5F0;
+ --m3-surface-container: #E9EFEB;
+ --m3-surface-container-high: #E4EAE5;
+ --m3-surface-container-highest: #DEE4DF;
+ --m3-outline: #6C7B70;
+ --m3-outline-variant: #BACBBE;
+ --m3-inverse-surface: #2D312E;
+ --m3-inverse-on-surface: #ECF2EE;
+ --m3-inverse-primary: #64DD93;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #007030;
+}
+
+:root[data-seed="emerald"][data-theme="dark"] {
+ --m3-primary: #64DD93;
+ --m3-on-primary: #003E01;
+ --m3-primary-container: #005619;
+ --m3-on-primary-container: #82FAAD;
+ --m3-primary-fixed: #82FAAD;
+ --m3-primary-fixed-dim: #64DD93;
+ --m3-on-primary-fixed: #002900;
+ --m3-on-primary-fixed-variant: #005619;
+ --m3-secondary: #ABCFB5;
+ --m3-on-secondary: #173723;
+ --m3-secondary-container: #2E4D38;
+ --m3-on-secondary-container: #C6EBD1;
+ --m3-tertiary: #2ADAEE;
+ --m3-on-tertiary: #003D50;
+ --m3-tertiary-container: #005568;
+ --m3-on-tertiary-container: #59F6FF;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #0F1511;
+ --m3-on-background: #DEE4DF;
+ --m3-surface: #0F1511;
+ --m3-on-surface: #DEE4DF;
+ --m3-surface-variant: #3C4A40;
+ --m3-on-surface-variant: #BACBBE;
+ --m3-surface-dim: #0F1511;
+ --m3-surface-bright: #363A37;
+ --m3-surface-container-lowest: #09100B;
+ --m3-surface-container-low: #181D19;
+ --m3-surface-container: #1C211D;
+ --m3-surface-container-high: #262B28;
+ --m3-surface-container-highest: #313632;
+ --m3-outline: #859589;
+ --m3-outline-variant: #3C4A40;
+ --m3-inverse-surface: #DEE4DF;
+ --m3-inverse-on-surface: #2D312E;
+ --m3-inverse-primary: #007030;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #64DD93;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="emerald"]:not([data-theme="light"]) {
+ --m3-primary: #64DD93;
+ --m3-on-primary: #003E01;
+ --m3-primary-container: #005619;
+ --m3-on-primary-container: #82FAAD;
+ --m3-primary-fixed: #82FAAD;
+ --m3-primary-fixed-dim: #64DD93;
+ --m3-on-primary-fixed: #002900;
+ --m3-on-primary-fixed-variant: #005619;
+ --m3-secondary: #ABCFB5;
+ --m3-on-secondary: #173723;
+ --m3-secondary-container: #2E4D38;
+ --m3-on-secondary-container: #C6EBD1;
+ --m3-tertiary: #2ADAEE;
+ --m3-on-tertiary: #003D50;
+ --m3-tertiary-container: #005568;
+ --m3-on-tertiary-container: #59F6FF;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #0F1511;
+ --m3-on-background: #DEE4DF;
+ --m3-surface: #0F1511;
+ --m3-on-surface: #DEE4DF;
+ --m3-surface-variant: #3C4A40;
+ --m3-on-surface-variant: #BACBBE;
+ --m3-surface-dim: #0F1511;
+ --m3-surface-bright: #363A37;
+ --m3-surface-container-lowest: #09100B;
+ --m3-surface-container-low: #181D19;
+ --m3-surface-container: #1C211D;
+ --m3-surface-container-high: #262B28;
+ --m3-surface-container-highest: #313632;
+ --m3-outline: #859589;
+ --m3-outline-variant: #3C4A40;
+ --m3-inverse-surface: #DEE4DF;
+ --m3-inverse-on-surface: #2D312E;
+ --m3-inverse-primary: #007030;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #64DD93;
+ }
+}
+
+/* โโ Seed: amber (#F59E0B) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="amber"] {
+ --m3-primary: #924D00;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #FFCF4B;
+ --m3-on-primary-container: #480400;
+ --m3-primary-fixed: #FFCF4B;
+ --m3-primary-fixed-dim: #FFB32C;
+ --m3-on-primary-fixed: #480400;
+ --m3-on-primary-fixed-variant: #763500;
+ --m3-secondary: #775935;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #FFDCB2;
+ --m3-on-secondary-container: #2F1600;
+ --m3-tertiary: #296C0E;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #B1F490;
+ --m3-on-tertiary-container: #002600;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #FEF8F3;
+ --m3-on-background: #1E1B17;
+ --m3-surface: #FEF8F3;
+ --m3-on-surface: #1E1B17;
+ --m3-surface-variant: #EFE0D2;
+ --m3-on-surface-variant: #504539;
+ --m3-surface-dim: #DED9D4;
+ --m3-surface-bright: #FEF8F3;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #F8F3EE;
+ --m3-surface-container: #F2EDE8;
+ --m3-surface-container-high: #EDE7E2;
+ --m3-surface-container-highest: #E7E2DD;
+ --m3-outline: #817569;
+ --m3-outline-variant: #D2C4B7;
+ --m3-inverse-surface: #34302C;
+ --m3-inverse-on-surface: #F5F0EB;
+ --m3-inverse-primary: #FFB32C;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #924D00;
+}
+
+:root[data-seed="amber"][data-theme="dark"] {
+ --m3-primary: #FFB32C;
+ --m3-on-primary: #5D1E00;
+ --m3-primary-container: #763500;
+ --m3-on-primary-container: #FFCF4B;
+ --m3-primary-fixed: #FFCF4B;
+ --m3-primary-fixed-dim: #FFB32C;
+ --m3-on-primary-fixed: #480400;
+ --m3-on-primary-fixed-variant: #763500;
+ --m3-secondary: #E6C097;
+ --m3-on-secondary: #442B08;
+ --m3-secondary-container: #5D411E;
+ --m3-on-secondary-container: #FFDCB2;
+ --m3-tertiary: #96D876;
+ --m3-on-tertiary: #003B00;
+ --m3-tertiary-container: #045300;
+ --m3-on-tertiary-container: #B1F490;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #17130E;
+ --m3-on-background: #E7E2DD;
+ --m3-surface: #17130E;
+ --m3-on-surface: #E7E2DD;
+ --m3-surface-variant: #504539;
+ --m3-on-surface-variant: #D2C4B7;
+ --m3-surface-dim: #17130E;
+ --m3-surface-bright: #3D3835;
+ --m3-surface-container-lowest: #120D07;
+ --m3-surface-container-low: #1E1B17;
+ --m3-surface-container: #231F1B;
+ --m3-surface-container-high: #2D2926;
+ --m3-surface-container-highest: #383430;
+ --m3-outline: #9C8E82;
+ --m3-outline-variant: #504539;
+ --m3-inverse-surface: #E7E2DD;
+ --m3-inverse-on-surface: #34302C;
+ --m3-inverse-primary: #924D00;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FFB32C;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="amber"]:not([data-theme="light"]) {
+ --m3-primary: #FFB32C;
+ --m3-on-primary: #5D1E00;
+ --m3-primary-container: #763500;
+ --m3-on-primary-container: #FFCF4B;
+ --m3-primary-fixed: #FFCF4B;
+ --m3-primary-fixed-dim: #FFB32C;
+ --m3-on-primary-fixed: #480400;
+ --m3-on-primary-fixed-variant: #763500;
+ --m3-secondary: #E6C097;
+ --m3-on-secondary: #442B08;
+ --m3-secondary-container: #5D411E;
+ --m3-on-secondary-container: #FFDCB2;
+ --m3-tertiary: #96D876;
+ --m3-on-tertiary: #003B00;
+ --m3-tertiary-container: #045300;
+ --m3-on-tertiary-container: #B1F490;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #17130E;
+ --m3-on-background: #E7E2DD;
+ --m3-surface: #17130E;
+ --m3-on-surface: #E7E2DD;
+ --m3-surface-variant: #504539;
+ --m3-on-surface-variant: #D2C4B7;
+ --m3-surface-dim: #17130E;
+ --m3-surface-bright: #3D3835;
+ --m3-surface-container-lowest: #120D07;
+ --m3-surface-container-low: #1E1B17;
+ --m3-surface-container: #231F1B;
+ --m3-surface-container-high: #2D2926;
+ --m3-surface-container-highest: #383430;
+ --m3-outline: #9C8E82;
+ --m3-outline-variant: #504539;
+ --m3-inverse-surface: #E7E2DD;
+ --m3-inverse-on-surface: #34302C;
+ --m3-inverse-primary: #924D00;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #FFB32C;
+ }
+}
+
+/* โโ Seed: azure (#2563EB) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+:root[data-seed="azure"] {
+ --m3-primary: #0055D9;
+ --m3-on-primary: #FFFFFF;
+ --m3-primary-container: #C2D6FF;
+ --m3-on-primary-container: #001886;
+ --m3-primary-fixed: #C2D6FF;
+ --m3-primary-fixed-dim: #A3BAFF;
+ --m3-on-primary-fixed: #001886;
+ --m3-on-primary-fixed-variant: #003EBD;
+ --m3-secondary: #595B87;
+ --m3-on-secondary: #FFFFFF;
+ --m3-secondary-container: #DEDEFF;
+ --m3-on-secondary-container: #0F193E;
+ --m3-tertiary: #AB286C;
+ --m3-on-tertiary: #FFFFFF;
+ --m3-tertiary-container: #FFB6F2;
+ --m3-on-tertiary-container: #560027;
+ --m3-error: #B4271F;
+ --m3-on-error: #FFFFFF;
+ --m3-error-container: #FFB598;
+ --m3-on-error-container: #5B0000;
+ --m3-background: #F9F9FF;
+ --m3-on-background: #1B1B1F;
+ --m3-surface: #F9F9FF;
+ --m3-on-surface: #1B1B1F;
+ --m3-surface-variant: #E2E1F2;
+ --m3-on-surface-variant: #464553;
+ --m3-surface-dim: #DAD9DF;
+ --m3-surface-bright: #F9F9FF;
+ --m3-surface-container-lowest: #FFFFFF;
+ --m3-surface-container-low: #F3F3F9;
+ --m3-surface-container: #EEEDF3;
+ --m3-surface-container-high: #E8E7EE;
+ --m3-surface-container-highest: #E2E2E8;
+ --m3-outline: #767685;
+ --m3-outline-variant: #C6C5D6;
+ --m3-inverse-surface: #303035;
+ --m3-inverse-on-surface: #F0F0F6;
+ --m3-inverse-primary: #A3BAFF;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #0055D9;
+}
+
+:root[data-seed="azure"][data-theme="dark"] {
+ --m3-primary: #A3BAFF;
+ --m3-on-primary: #002AA1;
+ --m3-primary-container: #003EBD;
+ --m3-on-primary-container: #C2D6FF;
+ --m3-primary-fixed: #C2D6FF;
+ --m3-primary-fixed-dim: #A3BAFF;
+ --m3-on-primary-fixed: #001886;
+ --m3-on-primary-fixed-variant: #003EBD;
+ --m3-secondary: #C2C2F5;
+ --m3-on-secondary: #282D55;
+ --m3-secondary-container: #40436E;
+ --m3-on-secondary-container: #DEDEFF;
+ --m3-tertiary: #FF9AD6;
+ --m3-on-tertiary: #72003D;
+ --m3-tertiary-container: #8E0054;
+ --m3-on-tertiary-container: #FFB6F2;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #131317;
+ --m3-on-background: #E2E2E8;
+ --m3-surface: #131317;
+ --m3-on-surface: #E2E2E8;
+ --m3-surface-variant: #464553;
+ --m3-on-surface-variant: #C6C5D6;
+ --m3-surface-dim: #131317;
+ --m3-surface-bright: #39393D;
+ --m3-surface-container-lowest: #0E0E13;
+ --m3-surface-container-low: #1B1B1F;
+ --m3-surface-container: #1F1F24;
+ --m3-surface-container-high: #2A292E;
+ --m3-surface-container-highest: #343439;
+ --m3-outline: #908F9F;
+ --m3-outline-variant: #464553;
+ --m3-inverse-surface: #E2E2E8;
+ --m3-inverse-on-surface: #303035;
+ --m3-inverse-primary: #0055D9;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #A3BAFF;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root[data-seed="azure"]:not([data-theme="light"]) {
+ --m3-primary: #A3BAFF;
+ --m3-on-primary: #002AA1;
+ --m3-primary-container: #003EBD;
+ --m3-on-primary-container: #C2D6FF;
+ --m3-primary-fixed: #C2D6FF;
+ --m3-primary-fixed-dim: #A3BAFF;
+ --m3-on-primary-fixed: #001886;
+ --m3-on-primary-fixed-variant: #003EBD;
+ --m3-secondary: #C2C2F5;
+ --m3-on-secondary: #282D55;
+ --m3-secondary-container: #40436E;
+ --m3-on-secondary-container: #DEDEFF;
+ --m3-tertiary: #FF9AD6;
+ --m3-on-tertiary: #72003D;
+ --m3-tertiary-container: #8E0054;
+ --m3-on-tertiary-container: #FFB6F2;
+ --m3-error: #FF987E;
+ --m3-on-error: #770000;
+ --m3-error-container: #950008;
+ --m3-on-error-container: #FFB598;
+ --m3-background: #131317;
+ --m3-on-background: #E2E2E8;
+ --m3-surface: #131317;
+ --m3-on-surface: #E2E2E8;
+ --m3-surface-variant: #464553;
+ --m3-on-surface-variant: #C6C5D6;
+ --m3-surface-dim: #131317;
+ --m3-surface-bright: #39393D;
+ --m3-surface-container-lowest: #0E0E13;
+ --m3-surface-container-low: #1B1B1F;
+ --m3-surface-container: #1F1F24;
+ --m3-surface-container-high: #2A292E;
+ --m3-surface-container-highest: #343439;
+ --m3-outline: #908F9F;
+ --m3-outline-variant: #464553;
+ --m3-inverse-surface: #E2E2E8;
+ --m3-inverse-on-surface: #303035;
+ --m3-inverse-primary: #0055D9;
+ --m3-scrim: #000000;
+ --m3-shadow: #000000;
+ --m3-surface-tint: #A3BAFF;
+ }
+}
diff --git a/main/assets/m3/site.css b/main/assets/m3/site.css
new file mode 100644
index 0000000..1001aa4
--- /dev/null
+++ b/main/assets/m3/site.css
@@ -0,0 +1,449 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Site shell
+ ----------------------------------------------------------------------------
+ Layout + shared page furniture (app bar, drawer, hero, footer, section
+ headers, team/credit cards, download cards, rating tables) built on top of
+ tokens.css and components.css.
+ ========================================================================== */
+
+/* โโ Page shell โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-page {
+ display: flex;
+ flex-direction: column;
+ min-height: 100dvh;
+ background: var(--m3-surface);
+}
+
+.m3-main { flex: 1 1 auto; }
+
+.m3-main--offset {
+ padding-block-end: calc(88px + env(safe-area-inset-bottom));
+}
+
+@media (min-width: 900px) {
+ .m3-main--offset { padding-block-end: 0; }
+}
+
+/* โโ App bar shortcuts โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-app-bar__brand-mark {
+ display: grid;
+ place-items: center;
+ width: 40px;
+ height: 40px;
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ font-size: 1.15rem;
+}
+
+.m3-app-bar__brand-mark img {
+ width: 100%;
+ height: 100%;
+ border-radius: inherit;
+ object-fit: cover;
+}
+
+.m3-theme-toggle .m3-theme-toggle__dark { display: none; }
+:root[data-theme='dark'] .m3-theme-toggle .m3-theme-toggle__dark { display: inline-block; }
+:root[data-theme='dark'] .m3-theme-toggle .m3-theme-toggle__light { display: none; }
+
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme='light']) .m3-theme-toggle .m3-theme-toggle__dark { display: inline-block; }
+ :root:not([data-theme='light']) .m3-theme-toggle .m3-theme-toggle__light { display: none; }
+}
+
+/* โโ Hero โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-hero {
+ position: relative;
+ overflow: hidden;
+ padding-block: clamp(32px, 7vw, 72px);
+ background:
+ radial-gradient(circle at 12% 18%, color-mix(in srgb, var(--m3-primary-container) 70%, transparent) 0%, transparent 45%),
+ radial-gradient(circle at 88% 8%, color-mix(in srgb, var(--m3-tertiary-container) 45%, transparent) 0%, transparent 42%),
+ var(--m3-surface);
+ isolation: isolate;
+}
+
+.m3-hero__grid {
+ display: grid;
+ gap: clamp(24px, 5vw, 48px);
+ align-items: center;
+}
+
+@media (min-width: 900px) {
+ .m3-hero__grid { grid-template-columns: 1.1fr 0.9fr; }
+}
+
+.m3-hero__eyebrow {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 14px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-secondary-container);
+ color: var(--m3-on-secondary-container);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ letter-spacing: var(--m3-tracking-label);
+}
+
+.m3-hero__title {
+ margin-block: var(--m3-space-4) var(--m3-space-3);
+ font-size: clamp(2rem, 5.2vw, 3.5rem);
+ line-height: 1.08;
+ letter-spacing: var(--m3-tracking-display);
+ font-weight: 600;
+}
+
+.m3-hero__title em {
+ font-style: normal;
+ background: linear-gradient(100deg, var(--m3-primary), var(--m3-tertiary));
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+}
+
+.m3-hero__lead {
+ max-width: 60ch;
+ color: var(--m3-on-surface-variant);
+ font-size: clamp(1rem, 1.4vw, 1.125rem);
+ line-height: 1.6;
+}
+
+.m3-hero__actions { margin-block-start: var(--m3-space-6); }
+
+.m3-hero__visual {
+ position: relative;
+ display: grid;
+ place-items: center;
+ min-height: 240px;
+}
+
+.m3-hero__orb {
+ position: relative;
+ display: grid;
+ place-items: center;
+ width: clamp(180px, 40vw, 300px);
+ aspect-ratio: 1;
+ border-radius: var(--m3-shape-full);
+ background: linear-gradient(145deg, var(--m3-primary-container), var(--m3-tertiary-container));
+ box-shadow: var(--m3-elevation-3);
+ animation: m3-float 7s var(--m3-ease-standard) infinite;
+}
+
+.m3-hero__orb img {
+ width: 62%;
+ height: 62%;
+ border-radius: var(--m3-shape-full);
+ object-fit: cover;
+ border: 6px solid color-mix(in srgb, var(--m3-surface) 65%, transparent);
+}
+
+.m3-hero__badge {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 16px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-high);
+ color: var(--m3-on-surface);
+ box-shadow: var(--m3-elevation-2);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+ white-space: nowrap;
+ z-index: 1;
+}
+
+.m3-hero__badge--tl { inset-block-start: 4%; inset-inline-start: 0; }
+.m3-hero__badge--br { inset-block-end: 6%; inset-inline-end: 0; }
+
+@keyframes m3-float {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-14px); }
+}
+
+/* โโ Section header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-section-head {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-end;
+ justify-content: space-between;
+ gap: var(--m3-space-4);
+ margin-block-end: var(--m3-space-6);
+}
+
+.m3-section-head__title { font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 600; }
+.m3-section-head__sub { color: var(--m3-on-surface-variant); margin-block-start: 6px; max-width: 65ch; }
+.m3-section-head--centered { flex-direction: column; align-items: center; text-align: center; }
+
+/* โโ Feature / stat tiles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-tile {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-5);
+ border-radius: var(--m3-shape-lg);
+ background: var(--m3-surface-container-low);
+ border: 1px solid var(--m3-outline-variant);
+ transition: transform var(--m3-duration-medium) var(--m3-ease-emphasized), box-shadow var(--m3-duration-medium) var(--m3-ease-standard), border-color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-tile:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--m3-elevation-2);
+ border-color: transparent;
+ }
+}
+
+.m3-tile__icon {
+ display: grid;
+ place-items: center;
+ width: 48px;
+ height: 48px;
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ font-size: 1.25rem;
+}
+
+.m3-tile__icon--secondary { background: var(--m3-secondary-container); color: var(--m3-on-secondary-container); }
+.m3-tile__icon--tertiary { background: var(--m3-tertiary-container); color: var(--m3-on-tertiary-container); }
+.m3-tile__title { font-size: var(--m3-title-medium-size); font-weight: var(--m3-title-medium-weight); }
+.m3-tile__text { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); }
+
+.m3-stat {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ padding: var(--m3-space-4);
+ border-radius: var(--m3-shape-md);
+ background: var(--m3-surface-container);
+}
+
+.m3-stat__value {
+ font-size: clamp(1.5rem, 3vw, 2rem);
+ font-weight: 600;
+ line-height: 1.15;
+ font-variant-numeric: tabular-nums;
+}
+
+.m3-stat__label { color: var(--m3-on-surface-variant); font-size: var(--m3-label-large-size); font-weight: var(--m3-label-large-weight); letter-spacing: var(--m3-tracking-label); }
+
+/* โโ Person / credit cards (team, contributors) โโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-person {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--m3-space-3);
+ padding: var(--m3-space-6) var(--m3-space-5);
+ border-radius: var(--m3-shape-xl);
+ background: var(--m3-surface-container-low);
+ border: 1px solid var(--m3-outline-variant);
+ text-align: center;
+ height: 100%;
+ transition: transform var(--m3-duration-medium) var(--m3-ease-emphasized), box-shadow var(--m3-duration-medium) var(--m3-ease-standard);
+}
+
+@media (hover: hover) {
+ .m3-person:hover { transform: translateY(-4px); box-shadow: var(--m3-elevation-2); }
+}
+
+.m3-person__avatar {
+ width: 96px;
+ height: 96px;
+ border-radius: var(--m3-shape-full);
+ object-fit: cover;
+ border: 4px solid var(--m3-surface-container-high);
+ background: var(--m3-surface-container-high);
+}
+
+.m3-person__role {
+ padding: 4px 12px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary-container);
+ color: var(--m3-on-primary-container);
+ font-size: var(--m3-label-medium-size);
+ font-weight: var(--m3-label-medium-weight);
+ letter-spacing: var(--m3-tracking-label);
+}
+
+.m3-person__name { font-size: var(--m3-title-large-size); font-weight: 600; }
+.m3-person__bio { color: var(--m3-on-surface-variant); font-size: var(--m3-body-medium-size); }
+.m3-person__actions { margin-block-start: auto; padding-block-start: var(--m3-space-2); }
+
+/* โโ Footer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-footer {
+ margin-block-start: clamp(32px, 6vw, 64px);
+ padding-block: var(--m3-space-8) calc(var(--m3-space-8) + env(safe-area-inset-bottom));
+ background: var(--m3-surface-container);
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-medium-size);
+}
+
+.m3-footer__grid {
+ display: grid;
+ gap: var(--m3-space-8);
+}
+
+@media (min-width: 720px) {
+ .m3-footer__grid { grid-template-columns: 1.4fr 1fr 1fr; }
+}
+
+.m3-footer__brand { display: flex; align-items: center; gap: var(--m3-space-3); color: var(--m3-on-surface); font-size: var(--m3-title-medium-size); font-weight: 600; }
+.m3-footer__brand img { width: 40px; height: 40px; border-radius: var(--m3-shape-sm); }
+.m3-footer__heading { color: var(--m3-on-surface); font-size: var(--m3-label-large-size); font-weight: var(--m3-label-large-weight); letter-spacing: var(--m3-tracking-label); text-transform: uppercase; margin-block-end: var(--m3-space-3); }
+.m3-footer__links { display: flex; flex-direction: column; gap: var(--m3-space-2); }
+.m3-footer__links a { color: var(--m3-on-surface-variant); text-decoration: none; width: fit-content; }
+.m3-footer__links a:hover { color: var(--m3-primary); text-decoration: underline; }
+.m3-footer__bottom {
+ margin-block-start: var(--m3-space-8);
+ padding-block-start: var(--m3-space-4);
+ border-block-start: 1px solid var(--m3-outline-variant);
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--m3-space-3);
+ justify-content: space-between;
+ align-items: center;
+ font-size: var(--m3-body-small-size);
+}
+
+/* โโ Rich text / legal pages โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-prose {
+ max-width: 74ch;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-large-size);
+ line-height: 1.7;
+}
+
+.m3-prose > * + * { margin-block-start: var(--m3-space-4); }
+.m3-prose h2 { color: var(--m3-on-surface); margin-block-start: var(--m3-space-8); }
+.m3-prose h3 { color: var(--m3-on-surface); margin-block-start: var(--m3-space-6); }
+.m3-prose strong { color: var(--m3-on-surface); }
+.m3-prose ul,
+.m3-prose ol { padding-inline-start: 1.5em; display: flex; flex-direction: column; gap: 8px; }
+.m3-prose a { text-decoration: underline; text-underline-offset: 2px; }
+
+/* โโ Progress / rating meters (rating-system page) โโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-meter { display: flex; flex-direction: column; gap: 6px; }
+.m3-meter__head { display: flex; justify-content: space-between; font-size: var(--m3-label-large-size); font-weight: var(--m3-label-large-weight); color: var(--m3-on-surface-variant); }
+.m3-meter__track { height: 8px; border-radius: var(--m3-shape-full); background: var(--m3-surface-container-highest); overflow: hidden; }
+.m3-meter__fill { height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--m3-primary), var(--m3-tertiary)); width: var(--m3-meter-value, 0%); transition: width var(--m3-duration-long) var(--m3-ease-emphasized-decel); }
+
+.m3-rating-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 14px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-surface-container-highest);
+ color: var(--m3-on-surface);
+ font-size: var(--m3-label-large-size);
+ font-weight: var(--m3-label-large-weight);
+}
+
+.m3-rating-chip i { color: var(--m3-tertiary); }
+
+/* Difficulty accents reused by the demon list cards */
+:root {
+ --m3-diff-easy: #2e7d32;
+ --m3-diff-medium: #ef6c00;
+ --m3-diff-hard: #c62828;
+ --m3-diff-insane: #6a1b9a;
+ --m3-diff-extreme: #1565c0;
+ --m3-diff-impossible: #37474f;
+}
+
+:root[data-theme='dark'] {
+ --m3-diff-easy: #81c995;
+ --m3-diff-medium: #ffb74d;
+ --m3-diff-hard: #f28b82;
+ --m3-diff-insane: #d7aefb;
+ --m3-diff-extreme: #8ab4f8;
+ --m3-diff-impossible: #cfd8dc;
+}
+
+/* โโ Utility: two-column split used by several pages โโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-split {
+ display: grid;
+ gap: clamp(20px, 4vw, 40px);
+ align-items: start;
+}
+
+@media (min-width: 1024px) {
+ .m3-split { grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); }
+ .m3-split--reverse { grid-template-columns: minmax(280px, 360px) minmax(0, 1fr); }
+}
+
+.m3-aside {
+ display: flex;
+ flex-direction: column;
+ gap: var(--m3-space-4);
+ position: sticky;
+ inset-block-start: calc(var(--m3-appbar-height) + 16px);
+}
+
+.m3-panel {
+ padding: var(--m3-space-5);
+ border-radius: var(--m3-shape-lg);
+ background: var(--m3-surface-container-low);
+ border: 1px solid var(--m3-outline-variant);
+}
+
+.m3-panel--filled { background: var(--m3-surface-container-high); border-color: transparent; }
+
+/* โโ Print โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+@media print {
+ .m3-app-bar,
+ .m3-drawer,
+ .m3-nav-bar,
+ .m3-footer,
+ .m3-scrim,
+ .m3-fab { display: none !important; }
+
+ body { background: #fff; color: #000; }
+}
+
+/* โโ Scroll reveal โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.m3-reveal {
+ opacity: 0;
+ transform: translateY(18px);
+ transition:
+ opacity var(--m3-duration-long) var(--m3-ease-emphasized-decel),
+ transform var(--m3-duration-long) var(--m3-ease-emphasized-decel);
+ will-change: opacity, transform;
+}
+
+.m3-reveal.is-visible { opacity: 1; transform: none; }
+
+@media (prefers-reduced-motion: reduce) {
+ .m3-reveal { opacity: 1; transform: none; }
+}
+
+/* โโ Small shared helpers used across the redesigned pages โโโโโโโโโโโโโโโโโโโ */
+
+.m3-meta {
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-body-small-size);
+}
+
+.m3-drawer__meta {
+ color: var(--m3-on-surface-variant);
+ font-size: 0.75rem;
+ line-height: 1;
+}
+
+.gd-year { font-variant-numeric: tabular-nums; }
diff --git a/main/assets/m3/tokens.css b/main/assets/m3/tokens.css
new file mode 100644
index 0000000..4e9da65
--- /dev/null
+++ b/main/assets/m3/tokens.css
@@ -0,0 +1,503 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Design tokens
+ ----------------------------------------------------------------------------
+ Non-colour tokens (type scale, shape, elevation, motion, spacing) shared by
+ every page. Colour roles live in palettes.css and are generated from a seed
+ colour, so themes are fully dynamic.
+ ========================================================================== */
+
+/* Self-hosted UI faces (no third-party font requests). Variable weight axes. */
+@font-face {
+ font-family: 'Roboto Flex';
+ src: url('../vendor/fonts/roboto-flex-latin-wght-normal.woff2') format('woff2');
+ font-style: normal;
+ font-weight: 100 1000;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'JetBrains Mono';
+ src: url('../vendor/fonts/jetbrains-mono-latin-wght-normal.woff2') format('woff2');
+ font-style: normal;
+ font-weight: 100 800;
+ font-display: swap;
+}
+
+/* Local display face used for GDIPS "game style" headlines (404, bootloader) */
+@font-face {
+ font-family: 'Pusab';
+ src: url('../Pusab.ttf') format('truetype');
+ font-display: swap;
+ font-weight: 400;
+}
+
+:root {
+ /* โโ Typography โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ Material 3 expressive scale. Roboto Flex is the variable M3 face; the
+ Grotesk stack keeps the "GDIPS" personality in display sizes. */
+ --m3-font-brand: 'Roboto Flex', 'Google Sans', 'Roboto', 'Segoe UI', system-ui, sans-serif;
+ --m3-font-plain: 'Roboto Flex', 'Roboto', 'Segoe UI', system-ui, -apple-system, sans-serif;
+ --m3-font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', 'Cascadia Code', Consolas, monospace;
+ --m3-font-display: 'Pusab', 'Roboto Flex', 'Roboto', system-ui, sans-serif;
+
+ --m3-display-large-size: 3.5625rem; /* 57 */
+ --m3-display-medium-size: 2.8125rem; /* 45 */
+ --m3-display-small-size: 2.25rem; /* 36 */
+ --m3-headline-large-size: 2rem; /* 32 */
+ --m3-headline-medium-size: 1.75rem; /* 28 */
+ --m3-headline-small-size: 1.5rem; /* 24 */
+ --m3-title-large-size: 1.375rem; /* 22 */
+ --m3-title-medium-size: 1rem; /* 16 */
+ --m3-title-small-size: 0.875rem; /* 14 */
+ --m3-body-large-size: 1rem; /* 16 */
+ --m3-body-medium-size: 0.875rem; /* 14 */
+ --m3-body-small-size: 0.75rem; /* 12 */
+ --m3-label-large-size: 0.875rem; /* 14 */
+ --m3-label-medium-size: 0.75rem; /* 12 */
+ --m3-label-small-size: 0.6875rem; /* 11 */
+
+ --m3-display-large-line: 4rem;
+ --m3-display-medium-line: 3.25rem;
+ --m3-display-small-line: 2.75rem;
+ --m3-headline-large-line: 2.5rem;
+ --m3-headline-medium-line: 2.25rem;
+ --m3-headline-small-line: 2rem;
+ --m3-title-large-line: 1.75rem;
+ --m3-title-medium-line: 1.5rem;
+ --m3-title-small-line: 1.25rem;
+ --m3-body-large-line: 1.5rem;
+ --m3-body-medium-line: 1.25rem;
+ --m3-body-small-line: 1rem;
+ --m3-label-large-line: 1.25rem;
+ --m3-label-medium-line: 1rem;
+ --m3-label-small-line: 1rem;
+
+ --m3-display-large-weight: 500;
+ --m3-display-small-weight: 500;
+ --m3-headline-weight: 500;
+ --m3-title-large-weight: 500;
+ --m3-title-medium-weight: 600;
+ --m3-title-small-weight: 600;
+ --m3-body-weight: 400;
+ --m3-label-large-weight: 600;
+ --m3-label-medium-weight: 600;
+
+ --m3-tracking-display: -0.02em;
+ --m3-tracking-headline: -0.012em;
+ --m3-tracking-title: 0.006em;
+ --m3-tracking-body: 0.015em;
+ --m3-tracking-label: 0.035em;
+
+ /* โโ Shape (corner radii) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-shape-none: 0;
+ --m3-shape-xs: 4px;
+ --m3-shape-sm: 8px;
+ --m3-shape-md: 12px;
+ --m3-shape-lg: 16px;
+ --m3-shape-xl: 28px;
+ --m3-shape-2xl: 32px;
+ --m3-shape-full: 999px;
+
+ /* โโ Elevation (M3 key + ambient shadows) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-elevation-0: none;
+ --m3-elevation-1: 0 1px 2px 0 rgb(0 0 0 / 0.30), 0 1px 3px 1px rgb(0 0 0 / 0.15);
+ --m3-elevation-2: 0 1px 2px 0 rgb(0 0 0 / 0.30), 0 2px 6px 2px rgb(0 0 0 / 0.15);
+ --m3-elevation-3: 0 1px 3px 0 rgb(0 0 0 / 0.30), 0 4px 8px 3px rgb(0 0 0 / 0.15);
+ --m3-elevation-4: 0 2px 3px 0 rgb(0 0 0 / 0.30), 0 6px 10px 4px rgb(0 0 0 / 0.15);
+ --m3-elevation-5: 0 4px 4px 0 rgb(0 0 0 / 0.30), 0 8px 12px 6px rgb(0 0 0 / 0.15);
+
+ /* โโ Spacing (4dp grid) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-space-1: 4px;
+ --m3-space-2: 8px;
+ --m3-space-3: 12px;
+ --m3-space-4: 16px;
+ --m3-space-5: 20px;
+ --m3-space-6: 24px;
+ --m3-space-7: 28px;
+ --m3-space-8: 32px;
+ --m3-space-10: 40px;
+ --m3-space-12: 48px;
+ --m3-space-16: 64px;
+ --m3-space-20: 80px;
+
+ --m3-page-gutter: clamp(16px, 4vw, 32px);
+ --m3-content-max: 1200px;
+ --m3-content-wide: 1440px;
+ --m3-appbar-height: 64px;
+
+ /* โโ Motion โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-ease-standard: cubic-bezier(0.2, 0, 0, 1);
+ --m3-ease-standard-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
+ --m3-ease-standard-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
+ --m3-ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
+ --m3-ease-emphasized-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
+ --m3-ease-emphasized-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
+ --m3-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
+ --m3-duration-short: 150ms;
+ --m3-duration-short-2: 200ms;
+ --m3-duration-medium: 300ms;
+ --m3-duration-long: 500ms;
+ --m3-duration-extra-long: 700ms;
+
+ /* โโ State layers (M3 interaction opacities) โโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-state-hover: 0.08;
+ --m3-state-focus: 0.10;
+ --m3-state-pressed: 0.10;
+ --m3-state-drag: 0.16;
+ --m3-state-disabled-content: 0.38;
+ --m3-state-disabled-container: 0.12;
+
+ /* โโ Misc โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+ --m3-focus-ring: 3px;
+ --m3-z-drawer: 1000;
+ --m3-z-appbar: 900;
+ --m3-z-dialog: 1200;
+ --m3-z-menu: 1100;
+ --m3-z-snackbar: 1300;
+ --m3-z-tooltip: 1400;
+
+ color-scheme: light;
+}
+
+:root[data-theme='dark'] {
+ color-scheme: dark;
+ --m3-elevation-1: 0 1px 3px 1px rgb(0 0 0 / 0.55), 0 1px 2px 0 rgb(0 0 0 / 0.7);
+ --m3-elevation-2: 0 2px 6px 2px rgb(0 0 0 / 0.55), 0 1px 2px 0 rgb(0 0 0 / 0.7);
+ --m3-elevation-3: 0 4px 8px 3px rgb(0 0 0 / 0.55), 0 1px 3px 0 rgb(0 0 0 / 0.7);
+ --m3-elevation-4: 0 6px 10px 4px rgb(0 0 0 / 0.55), 0 2px 3px 0 rgb(0 0 0 / 0.7);
+ --m3-elevation-5: 0 8px 12px 6px rgb(0 0 0 / 0.55), 0 4px 4px 0 rgb(0 0 0 / 0.7);
+}
+
+/* ============================================================================
+ Base / reset
+ ========================================================================== */
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+html {
+ -webkit-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+ scroll-behavior: smooth;
+ scroll-padding-top: calc(var(--m3-appbar-height) + 16px);
+}
+
+body {
+ margin: 0;
+ min-height: 100dvh;
+ font-family: var(--m3-font-plain);
+ font-size: var(--m3-body-large-size);
+ line-height: var(--m3-body-large-line);
+ letter-spacing: var(--m3-tracking-body);
+ font-weight: var(--m3-body-weight);
+ color: var(--m3-on-surface);
+ background-color: var(--m3-surface);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
+ font-variant-ligatures: common-ligatures;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+figure,
+blockquote,
+dl,
+dd {
+ margin: 0;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: var(--m3-font-brand);
+ font-weight: var(--m3-headline-weight);
+ letter-spacing: var(--m3-tracking-headline);
+ line-height: 1.25;
+ text-wrap: balance;
+}
+
+h1 { font-size: var(--m3-headline-large-size); }
+h2 { font-size: var(--m3-headline-medium-size); }
+h3 { font-size: var(--m3-title-large-size); font-weight: var(--m3-title-large-weight); }
+h4 { font-size: var(--m3-title-medium-size); font-weight: var(--m3-title-medium-weight); }
+h5 { font-size: var(--m3-title-small-size); }
+
+p { text-wrap: pretty; }
+
+ul,
+ol {
+ margin: 0;
+ padding-inline-start: 1.35em;
+}
+
+img,
+svg,
+video,
+canvas,
+iframe {
+ max-width: 100%;
+ display: block;
+}
+
+img { height: auto; }
+
+a {
+ color: var(--m3-primary);
+ text-decoration: none;
+ border-radius: var(--m3-shape-xs);
+ transition: color var(--m3-duration-short) var(--m3-ease-standard);
+}
+
+a:hover { color: var(--m3-primary); text-decoration: underline; }
+a:visited { color: var(--m3-tertiary); }
+
+button,
+input,
+select,
+textarea {
+ font: inherit;
+ letter-spacing: inherit;
+ color: inherit;
+}
+
+button { cursor: pointer; }
+button:disabled { cursor: not-allowed; }
+
+hr {
+ border: 0;
+ border-top: 1px solid var(--m3-outline-variant);
+ margin-block: var(--m3-space-5);
+}
+
+code,
+kbd,
+samp,
+pre {
+ font-family: var(--m3-font-mono);
+ font-size: 0.9em;
+}
+
+kbd {
+ display: inline-block;
+ padding: 0.1em 0.45em;
+ border-radius: var(--m3-shape-xs);
+ background: var(--m3-surface-container-high);
+ border: 1px solid var(--m3-outline-variant);
+ border-bottom-width: 2px;
+ color: var(--m3-on-surface-variant);
+ font-size: var(--m3-label-medium-size);
+ line-height: 1.5;
+}
+
+strong,
+b { font-weight: 650; }
+
+small { font-size: var(--m3-body-small-size); }
+
+/* โโ Focus โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
+.m3-focus-ring:focus-visible {
+ outline: var(--m3-focus-ring) solid var(--m3-secondary);
+ outline-offset: 2px;
+}
+
+:focus:not(:focus-visible) { outline: none; }
+
+/* โโ Selection & scrollbars โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+::selection {
+ background: var(--m3-primary);
+ color: var(--m3-on-primary);
+}
+
+* {
+ scrollbar-color: var(--m3-outline) transparent;
+ scrollbar-width: thin;
+}
+
+::-webkit-scrollbar { width: 10px; height: 10px; }
+::-webkit-scrollbar-track { background: transparent; }
+::-webkit-scrollbar-thumb {
+ background: var(--m3-outline-variant);
+ border-radius: var(--m3-shape-full);
+ border: 3px solid transparent;
+ background-clip: content-box;
+}
+::-webkit-scrollbar-thumb:hover { background-clip: content-box; background-color: var(--m3-outline); }
+
+/* ============================================================================
+ Typography utilities
+ ========================================================================== */
+
+.m3-display-large,
+.m3-display-medium,
+.m3-display-small,
+.m3-headline-large,
+.m3-headline-medium,
+.m3-headline-small,
+.m3-title-large,
+.m3-title-medium,
+.m3-title-small,
+.m3-body-large,
+.m3-body-medium,
+.m3-body-small,
+.m3-label-large,
+.m3-label-medium,
+.m3-label-small {
+ font-family: var(--m3-font-brand);
+ margin: 0;
+}
+
+.m3-display-large { font-size: var(--m3-display-large-size); line-height: var(--m3-display-large-line); font-weight: var(--m3-display-large-weight); letter-spacing: var(--m3-tracking-display); }
+.m3-display-medium { font-size: var(--m3-display-medium-size); line-height: var(--m3-display-medium-line); font-weight: var(--m3-display-large-weight); letter-spacing: var(--m3-tracking-display); }
+.m3-display-small { font-size: var(--m3-display-small-size); line-height: var(--m3-display-small-line); font-weight: var(--m3-display-small-weight); letter-spacing: var(--m3-tracking-display); }
+.m3-headline-large { font-size: var(--m3-headline-large-size); line-height: var(--m3-headline-large-line); letter-spacing: var(--m3-tracking-headline); }
+.m3-headline-medium { font-size: var(--m3-headline-medium-size); line-height: var(--m3-headline-medium-line); letter-spacing: var(--m3-tracking-headline); }
+.m3-headline-small { font-size: var(--m3-headline-small-size); line-height: var(--m3-headline-small-line); letter-spacing: var(--m3-tracking-headline); }
+.m3-title-large { font-size: var(--m3-title-large-size); line-height: var(--m3-title-large-line); font-weight: var(--m3-title-large-weight); letter-spacing: var(--m3-tracking-title); }
+.m3-title-medium { font-size: var(--m3-title-medium-size); line-height: var(--m3-title-medium-line); font-weight: var(--m3-title-medium-weight); letter-spacing: var(--m3-tracking-title); }
+.m3-title-small { font-size: var(--m3-title-small-size); line-height: var(--m3-title-small-line); font-weight: var(--m3-title-small-weight); letter-spacing: var(--m3-tracking-title); }
+
+.m3-body-large { font-family: var(--m3-font-plain); font-size: var(--m3-body-large-size); line-height: var(--m3-body-large-line); letter-spacing: var(--m3-tracking-body); }
+.m3-body-medium { font-family: var(--m3-font-plain); font-size: var(--m3-body-medium-size); line-height: var(--m3-body-medium-line); letter-spacing: var(--m3-tracking-body); }
+.m3-body-small { font-family: var(--m3-font-plain); font-size: var(--m3-body-small-size); line-height: var(--m3-body-small-line); letter-spacing: var(--m3-tracking-body); }
+.m3-label-large { font-family: var(--m3-font-plain); font-size: var(--m3-label-large-size); line-height: var(--m3-label-large-line); font-weight: var(--m3-label-large-weight); letter-spacing: var(--m3-tracking-label); }
+.m3-label-medium { font-family: var(--m3-font-plain); font-size: var(--m3-label-medium-size); line-height: var(--m3-label-medium-line); font-weight: var(--m3-label-medium-weight); letter-spacing: var(--m3-tracking-label); }
+.m3-label-small { font-family: var(--m3-font-plain); font-size: var(--m3-label-small-size); line-height: var(--m3-label-small-line); font-weight: var(--m3-label-medium-weight); letter-spacing: var(--m3-tracking-label); }
+
+.m3-mono { font-family: var(--m3-font-mono); font-variant-numeric: tabular-nums; }
+.m3-display-font { font-family: var(--m3-font-display); letter-spacing: 0.01em; }
+.m3-text-primary { color: var(--m3-primary); }
+.m3-text-muted { color: var(--m3-on-surface-variant); }
+.m3-text-error { color: var(--m3-error); }
+.m3-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.m3-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
+.m3-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
+
+/* ============================================================================
+ Layout helpers
+ ========================================================================== */
+
+.m3-container {
+ width: 100%;
+ max-width: var(--m3-content-max);
+ margin-inline: auto;
+ padding-inline: var(--m3-page-gutter);
+}
+
+.m3-container--wide { max-width: var(--m3-content-wide); }
+
+.m3-section { padding-block: clamp(24px, 6vw, 56px); }
+
+.m3-stack { display: flex; flex-direction: column; gap: var(--m3-space-4); }
+.m3-row { display: flex; flex-wrap: wrap; gap: var(--m3-space-3); align-items: center; }
+.m3-spacer { flex: 1 1 auto; }
+
+.m3-grid { display: grid; gap: var(--m3-space-5); }
+.m3-grid--auto { grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); }
+.m3-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }
+.m3-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
+
+.m3-shape-none { border-radius: 0; }
+.m3-shape-xs { border-radius: var(--m3-shape-xs); }
+.m3-shape-sm { border-radius: var(--m3-shape-sm); }
+.m3-shape-md { border-radius: var(--m3-shape-md); }
+.m3-shape-lg { border-radius: var(--m3-shape-lg); }
+.m3-shape-xl { border-radius: var(--m3-shape-xl); }
+.m3-shape-full { border-radius: var(--m3-shape-full); }
+
+.m3-elevation-0 { box-shadow: var(--m3-elevation-0); }
+.m3-elevation-1 { box-shadow: var(--m3-elevation-1); }
+.m3-elevation-2 { box-shadow: var(--m3-elevation-2); }
+.m3-elevation-3 { box-shadow: var(--m3-elevation-3); }
+.m3-elevation-4 { box-shadow: var(--m3-elevation-4); }
+.m3-elevation-5 { box-shadow: var(--m3-elevation-5); }
+
+.m3-hidden { display: none !important; }
+.m3-visually-hidden,
+.sr-only {
+ position: absolute !important;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0 0 0 0);
+ clip-path: inset(50%);
+ white-space: nowrap;
+ border: 0;
+}
+
+.m3-skip-link {
+ position: absolute;
+ inset-inline-start: var(--m3-space-4);
+ top: -80px;
+ z-index: calc(var(--m3-z-snackbar) + 1);
+ padding: 12px 20px;
+ border-radius: var(--m3-shape-full);
+ background: var(--m3-primary);
+ color: var(--m3-on-primary);
+ font-weight: 650;
+ box-shadow: var(--m3-elevation-3);
+ transition: top var(--m3-duration-short-2) var(--m3-ease-emphasized-decel);
+}
+
+.m3-skip-link:focus { top: var(--m3-space-4); text-decoration: none; }
+
+/* ============================================================================
+ Motion
+ ========================================================================== */
+
+@media (prefers-reduced-motion: reduce) {
+ html { scroll-behavior: auto; }
+
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.001ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.001ms !important;
+ scroll-behavior: auto !important;
+ }
+}
+
+@media (prefers-contrast: more) {
+ :root {
+ --m3-outline-variant: var(--m3-outline);
+ }
+
+ .m3-card,
+ .m3-button,
+ .m3-text-field,
+ .m3-navigation-drawer {
+ border-color: currentColor;
+ }
+}
+
+/* โโ Responsive visibility helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+@media (max-width: 599px) {
+ .m3-hide-sm { display: none !important; }
+}
+
+@media (min-width: 600px) and (max-width: 899px) {
+ .m3-hide-md { display: none !important; }
+}
+
+@media (max-width: 899px) {
+ .m3-hide-below-md { display: none !important; }
+}
+
+@media (min-width: 900px) {
+ .m3-show-below-md { display: none !important; }
+}
diff --git a/main/assets/m3/ui.js b/main/assets/m3/ui.js
new file mode 100644
index 0000000..1d2fbda
--- /dev/null
+++ b/main/assets/m3/ui.js
@@ -0,0 +1,583 @@
+/* ============================================================================
+ GDIPS ยท Material You 3 โ Interaction layer
+ ----------------------------------------------------------------------------
+ Progressive enhancement for the M3 components: ripples, app-bar elevation,
+ navigation drawers + scrims, menus, dialogs (with focus trap), tabs,
+ segmented buttons, text-field state, sliders, snackbars, copy-to-clipboard
+ and scroll reveals. Every behaviour is declarative โ pages only add data
+ attributes, no per-page scripting required.
+
+ Public API
+ M3UI.snackbar(message, opts) transient message with optional action
+ M3UI.openDialog(elOrId) / close() dialog helpers
+ M3UI.openDrawer(elOrId, open) drawer helpers
+ M3UI.setLoading(el, bool) button loading state
+ M3UI.copy(text) clipboard helper
+ ========================================================================== */
+
+(function (global) {
+ 'use strict';
+
+ var REDUCED = global.matchMedia && global.matchMedia('(prefers-reduced-motion: reduce)').matches;
+ var FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
+
+ function $(sel, scope) { return (scope || document).querySelector(sel); }
+ function $$(sel, scope) { return Array.prototype.slice.call((scope || document).querySelectorAll(sel)); }
+ function byId(id) { return typeof id === 'string' ? document.getElementById(id.replace(/^#/, '')) : id; }
+
+ /* โโ Scroll lock โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ var lockCount = 0;
+ function lockScroll() {
+ if (lockCount++ === 0) {
+ var gap = global.innerWidth - document.documentElement.clientWidth;
+ document.body.style.overflow = 'hidden';
+ if (gap > 0) document.body.style.paddingInlineEnd = gap + 'px';
+ }
+ }
+ function unlockScroll() {
+ if (lockCount > 0 && --lockCount === 0) {
+ document.body.style.overflow = '';
+ document.body.style.paddingInlineEnd = '';
+ }
+ }
+
+ /* โโ Ripple โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ var RIPPLE_SELECTOR = [
+ '.m3-button', '.m3-icon-button', '.m3-fab', '.m3-chip', '.m3-tab',
+ '.m3-list-item', '.m3-menu-item', '.m3-page-btn', '.m3-nav-bar__item',
+ '.m3-drawer__item', '.m3-segmented__item', '.m3-card--interactive',
+ '.sidebar-link', '.card-action-btn', '.view-btn', '.action-btn', '.filter-option'
+ ].join(',');
+
+ function attachRipple(el) {
+ if (REDUCED || el.dataset.m3Ripple === 'off') return;
+ el.addEventListener('pointerdown', function (event) {
+ var rect = el.getBoundingClientRect();
+ var size = Math.max(rect.width, rect.height) * 2;
+ var ripple = document.createElement('span');
+ ripple.className = 'm3-ripple';
+ ripple.style.width = ripple.style.height = size + 'px';
+ ripple.style.left = (event.clientX - rect.left - size / 2) + 'px';
+ ripple.style.top = (event.clientY - rect.top - size / 2) + 'px';
+ if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
+ el.appendChild(ripple);
+ setTimeout(function () { ripple.remove(); }, 600);
+ });
+ }
+
+ /* โโ App bar elevation on scroll โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setupAppBars(scope) {
+ $$('.m3-app-bar', scope).forEach(function (bar) {
+ if (bar.dataset.m3Bound) return;
+ bar.dataset.m3Bound = '1';
+ var sentinel = document.createElement('div');
+ sentinel.setAttribute('aria-hidden', 'true');
+ sentinel.style.cssText = 'position:absolute;top:0;left:0;height:1px;width:1px;';
+ bar.parentNode.insertBefore(sentinel, bar);
+ if ('IntersectionObserver' in global) {
+ new IntersectionObserver(function (entries) {
+ bar.classList.toggle('is-scrolled', !entries[0].isIntersecting);
+ }, { threshold: 0 }).observe(sentinel);
+ }
+ });
+ }
+
+ /* โโ Drawers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setDrawer(drawer, open) {
+ if (!drawer) return;
+ var wasOpen = drawer.classList.contains('is-open') || drawer.classList.contains('active');
+ drawer.classList.toggle('is-open', open);
+ drawer.classList.toggle('active', open);
+ drawer.setAttribute('aria-hidden', open ? 'false' : 'true');
+ var scrim = $('.m3-scrim[data-m3-scrim-for="#' + drawer.id + '"]') || $('.m3-scrim.is-paired');
+ if (scrim) scrim.classList.toggle('is-open', open);
+ if (open && !wasOpen) {
+ lockScroll();
+ var focusable = $(FOCUSABLE, drawer);
+ if (focusable) setTimeout(function () { focusable.focus(); }, 220);
+ } else if (!open && wasOpen) {
+ unlockScroll();
+ }
+ if (!open) {
+ var toggle = $('[data-m3-drawer-toggle="#' + drawer.id + '"]');
+ if (toggle) toggle.focus();
+ }
+ }
+
+ function setupDrawers(scope) {
+ $$('[data-m3-drawer-toggle]', scope).forEach(function (toggle) {
+ if (toggle.dataset.m3Bound) return;
+ toggle.dataset.m3Bound = '1';
+ toggle.addEventListener('click', function (event) {
+ event.preventDefault();
+ var drawer = byId(toggle.getAttribute('data-m3-drawer-toggle'));
+ if (!drawer) return;
+ setDrawer(drawer, !(drawer.classList.contains('is-open') || drawer.classList.contains('active')));
+ });
+ });
+
+ $$('[data-m3-drawer-close]', scope).forEach(function (btn) {
+ if (btn.dataset.m3Bound) return;
+ btn.dataset.m3Bound = '1';
+ btn.addEventListener('click', function () { setDrawer(btn.closest('.m3-drawer, .sidebar'), false); });
+ });
+
+ // Bridge for drawers whose open/close state is owned by legacy scripts
+ // (the demon list toggles `.active` itself โ we only mirror it).
+ $$('[data-m3-scrim-for]', scope).forEach(function (scrim) {
+ var drawer = byId(scrim.getAttribute('data-m3-scrim-for'));
+ if (!drawer || scrim.dataset.m3Bound) return;
+ scrim.dataset.m3Bound = '1';
+ var sync = function () {
+ var open = drawer.classList.contains('is-open') || drawer.classList.contains('active');
+ scrim.classList.toggle('is-open', open);
+ if (open) { lockScroll(); } else { unlockScroll(); }
+ };
+ new MutationObserver(sync).observe(drawer, { attributes: true, attributeFilter: ['class'] });
+ scrim.addEventListener('click', function () {
+ drawer.classList.remove('is-open', 'active');
+ if (typeof global.DemonListApp !== 'undefined') { /* legacy app keeps its own state */ }
+ setDrawer(drawer, false);
+ });
+ sync();
+ });
+ }
+
+ /* โโ Menus โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function closeMenus(except) {
+ $$('.m3-menu.is-open').forEach(function (menu) {
+ if (menu === except) return;
+ menu.classList.remove('is-open');
+ var trigger = $('[data-m3-menu-trigger="#' + menu.id + '"]');
+ if (trigger) trigger.setAttribute('aria-expanded', 'false');
+ });
+ }
+
+ function setupMenus(scope) {
+ $$('[data-m3-menu-trigger]', scope).forEach(function (trigger) {
+ if (trigger.dataset.m3Bound) return;
+ trigger.dataset.m3Bound = '1';
+ trigger.setAttribute('aria-haspopup', 'true');
+ trigger.setAttribute('aria-expanded', 'false');
+ trigger.addEventListener('click', function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ var menu = byId(trigger.getAttribute('data-m3-menu-trigger'));
+ if (!menu) return;
+ var willOpen = !menu.classList.contains('is-open');
+ closeMenus(menu);
+ menu.classList.toggle('is-open', willOpen);
+ trigger.setAttribute('aria-expanded', String(willOpen));
+ });
+ });
+
+ $$('.m3-menu', scope).forEach(function (menu) {
+ if (menu.dataset.m3Bound) return;
+ menu.dataset.m3Bound = '1';
+ menu.addEventListener('click', function (event) {
+ if (event.target.closest('[data-m3-menu-keep]')) return;
+ if (event.target.closest('.m3-menu-item')) closeMenus();
+ });
+ });
+ }
+
+ /* โโ Dialogs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ var openDialogs = [];
+
+ function openDialog(target) {
+ var dialog = byId(target);
+ if (!dialog) return;
+ dialog.classList.add('is-open');
+ dialog.setAttribute('aria-hidden', 'false');
+ openDialogs.push(dialog);
+ lockScroll();
+ var focusable = $(FOCUSABLE, dialog);
+ if (focusable) setTimeout(function () { focusable.focus(); }, 180);
+ dialog.dispatchEvent(new CustomEvent('m3dialog:open', { bubbles: true }));
+ }
+
+ function closeDialog(target) {
+ var dialog = target ? byId(target) : openDialogs[openDialogs.length - 1];
+ if (!dialog) return;
+ dialog.classList.remove('is-open');
+ dialog.setAttribute('aria-hidden', 'true');
+ openDialogs = openDialogs.filter(function (d) { return d !== dialog; });
+ unlockScroll();
+ var trigger = $('[data-m3-dialog-open="#' + dialog.id + '"]');
+ if (trigger) trigger.focus();
+ dialog.dispatchEvent(new CustomEvent('m3dialog:close', { bubbles: true }));
+ }
+
+ function trapFocus(dialog, event) {
+ var items = $$(FOCUSABLE, dialog).filter(function (el) { return el.offsetParent !== null || el === document.activeElement; });
+ if (!items.length) return;
+ var first = items[0];
+ var last = items[items.length - 1];
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
+ }
+
+ function setupDialogs(scope) {
+ $$('[data-m3-dialog-open]', scope).forEach(function (trigger) {
+ if (trigger.dataset.m3Bound) return;
+ trigger.dataset.m3Bound = '1';
+ trigger.addEventListener('click', function (event) {
+ event.preventDefault();
+ openDialog(trigger.getAttribute('data-m3-dialog-open'));
+ });
+ });
+
+ $$('.m3-dialog', scope).forEach(function (dialog) {
+ if (dialog.dataset.m3Bound) return;
+ dialog.dataset.m3Bound = '1';
+ dialog.setAttribute('role', 'dialog');
+ dialog.setAttribute('aria-modal', 'true');
+ dialog.setAttribute('aria-hidden', 'true');
+ dialog.addEventListener('click', function (event) {
+ if (event.target === dialog) closeDialog(dialog);
+ });
+ });
+
+ document.addEventListener('click', function (event) {
+ var closer = event.target.closest('[data-m3-dialog-close]');
+ if (closer) {
+ event.preventDefault();
+ closeDialog(closer.closest('.m3-dialog'));
+ }
+ });
+
+ document.addEventListener('keydown', function (event) {
+ if (event.key === 'Escape') {
+ if (openDialogs.length) { closeDialog(); return; }
+ if ($('.m3-menu.is-open')) { closeMenus(); return; }
+ var drawer = $('.m3-scrim.is-open');
+ if (drawer) {
+ var target = byId(drawer.getAttribute('data-m3-scrim-for'));
+ if (target) setDrawer(target, false);
+ }
+ }
+ if (event.key === 'Tab' && openDialogs.length) trapFocus(openDialogs[openDialogs.length - 1], event);
+ });
+
+ document.addEventListener('click', function (event) {
+ if (!event.target.closest('.m3-menu') && !event.target.closest('[data-m3-menu-trigger]')) closeMenus();
+ });
+ }
+
+ /* โโ Snackbar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function region() {
+ var el = $('.m3-snackbar-region');
+ if (!el) {
+ el = document.createElement('div');
+ el.className = 'm3-snackbar-region';
+ el.setAttribute('role', 'status');
+ el.setAttribute('aria-live', 'polite');
+ document.body.appendChild(el);
+ }
+ return el;
+ }
+
+ function snackbar(message, options) {
+ var opts = options || {};
+ var bar = document.createElement('div');
+ bar.className = 'm3-snackbar' + (opts.variant === 'error' ? ' m3-snackbar--error' : '');
+ var icon = opts.variant === 'error' ? 'fa-circle-exclamation' : (opts.icon || null);
+ bar.innerHTML = (icon ? ' ' : '') +
+ '' + message + ' ';
+ if (opts.actionLabel) {
+ var action = document.createElement('button');
+ action.type = 'button';
+ action.className = 'm3-snackbar__action';
+ action.textContent = opts.actionLabel;
+ action.addEventListener('click', function () {
+ if (typeof opts.onAction === 'function') opts.onAction();
+ dismiss();
+ });
+ bar.appendChild(action);
+ }
+ region().appendChild(bar);
+ var timer = setTimeout(dismiss, opts.duration || 4000);
+ function dismiss() {
+ clearTimeout(timer);
+ bar.classList.add('is-leaving');
+ setTimeout(function () { bar.remove(); }, 200);
+ }
+ return dismiss;
+ }
+
+ /* โโ Tabs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function activateTab(tab) {
+ var group = tab.closest('[data-m3-tabs]');
+ if (!group) return;
+ var tabs = $$('[role="tab"]', group);
+ tabs.forEach(function (t) {
+ var selected = t === tab;
+ t.setAttribute('aria-selected', String(selected));
+ t.classList.toggle('is-active', selected);
+ t.tabIndex = selected ? 0 : -1;
+ var panelId = t.getAttribute('aria-controls') || (t.getAttribute('href') || '').replace(/^.*#/, '');
+ var panel = panelId ? byId(panelId) : null;
+ if (panel) {
+ panel.hidden = !selected;
+ panel.classList.toggle('is-active', selected);
+ }
+ });
+ }
+
+ function setupTabs(scope) {
+ $$('[data-m3-tabs]', scope).forEach(function (group) {
+ if (group.dataset.m3Bound) return;
+ group.dataset.m3Bound = '1';
+ group.setAttribute('role', 'tablist');
+ var tabs = $$('[role="tab"]', group);
+ tabs.forEach(function (tab, index) {
+ if (!tab.hasAttribute('aria-controls')) {
+ var href = (tab.getAttribute('href') || '').replace(/^.*#/, '');
+ if (href) tab.setAttribute('aria-controls', href);
+ }
+ tab.addEventListener('click', function (event) {
+ event.preventDefault();
+ activateTab(tab);
+ if (global.history && tab.getAttribute('href') && tab.getAttribute('href').charAt(0) === '#') {
+ global.history.replaceState(null, '', tab.getAttribute('href'));
+ }
+ });
+ tab.addEventListener('keydown', function (event) {
+ var step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;
+ if (!step) return;
+ event.preventDefault();
+ var next = tabs[(index + step + tabs.length) % tabs.length];
+ next.focus();
+ activateTab(next);
+ });
+ });
+ var initial = tabs.filter(function (t) { return t.getAttribute('aria-selected') === 'true' || t.classList.contains('is-active'); })[0] || tabs[0];
+ if (initial) activateTab(initial);
+ });
+ }
+
+ /* โโ Segmented buttons & chips โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setupSegmented(scope) {
+ $$('[data-m3-segmented]', scope).forEach(function (group) {
+ if (group.dataset.m3Bound) return;
+ group.dataset.m3Bound = '1';
+ group.setAttribute('role', 'tablist');
+ var items = $$('.m3-segmented__item', group);
+ items.forEach(function (item) {
+ item.setAttribute('role', 'tab');
+ item.setAttribute('aria-selected', String(item.classList.contains('is-selected')));
+ item.addEventListener('click', function () {
+ items.forEach(function (other) {
+ other.classList.toggle('is-selected', other === item);
+ other.setAttribute('aria-selected', String(other === item));
+ });
+ group.dispatchEvent(new CustomEvent('m3segment:change', { detail: { value: item.dataset.value, item: item }, bubbles: true }));
+ });
+ });
+ });
+
+ $$('[data-m3-chip-toggle]', scope).forEach(function (chip) {
+ if (chip.dataset.m3Bound) return;
+ chip.dataset.m3Bound = '1';
+ chip.addEventListener('click', function () {
+ var pressed = chip.getAttribute('aria-pressed') === 'true';
+ chip.setAttribute('aria-pressed', String(!pressed));
+ chip.classList.toggle('m3-chip--selected', !pressed);
+ });
+ });
+ }
+
+ /* โโ Fields, sliders, switches โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setupFields(scope) {
+ $$('.m3-field__box', scope).forEach(function (box) {
+ var field = box.closest('.m3-field');
+ var input = $('.m3-field__input', box);
+ if (!input || box.dataset.m3Bound) return;
+ box.dataset.m3Bound = '1';
+ var sync = function () {
+ box.classList.toggle('has-value', !!input.value);
+ if (field) field.classList.toggle('m3-field--filled', !!input.value);
+ };
+ input.addEventListener('input', sync);
+ input.addEventListener('change', sync);
+ input.addEventListener('blur', function () {
+ if (field && field.dataset.m3Validate === 'required' && !input.value) {
+ field.classList.add('m3-field--error');
+ }
+ });
+ sync();
+ });
+
+ var syncRange = function (input) {
+ var min = parseFloat(input.min || 0);
+ var max = parseFloat(input.max || 100);
+ var value = parseFloat(input.value);
+ var pct = ((value - min) / (max - min)) * 100;
+ input.style.setProperty('--m3-slider-fill', pct + '%');
+ };
+
+ $$('.m3-slider', scope).forEach(function (input) {
+ if (input.dataset.m3Bound) return;
+ input.dataset.m3Bound = '1';
+ input.addEventListener('input', function () { syncRange(input); });
+ syncRange(input);
+ });
+
+ $$('[data-m3-range-output]', scope).forEach(function (input) {
+ var output = byId(input.getAttribute('data-m3-range-output'));
+ if (!output) return;
+ var update = function () { output.textContent = input.value; };
+ input.addEventListener('input', update);
+ update();
+ });
+ }
+
+ /* โโ Theme toggles & copy buttons โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setupThemeToggles(scope) {
+ $$('.m3-theme-toggle', scope).forEach(function (btn) {
+ if (btn.dataset.m3Bound) return;
+ btn.dataset.m3Bound = '1';
+ btn.addEventListener('click', function (event) {
+ event.preventDefault();
+ if (global.M3Color) {
+ var theme = global.M3Color.toggleTheme();
+ btn.setAttribute('aria-label', theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme');
+ }
+ });
+ });
+ }
+
+ function copy(text) {
+ if (navigator.clipboard && global.isSecureContext) return navigator.clipboard.writeText(text);
+ return new Promise(function (resolve, reject) {
+ try {
+ var area = document.createElement('textarea');
+ area.value = text;
+ area.setAttribute('readonly', '');
+ area.style.cssText = 'position:absolute;left:-9999px;';
+ document.body.appendChild(area);
+ area.select();
+ document.execCommand('copy');
+ area.remove();
+ resolve();
+ } catch (error) { reject(error); }
+ });
+ }
+
+ function setupCopy(scope) {
+ $$('[data-m3-copy]', scope).forEach(function (btn) {
+ if (btn.dataset.m3Bound) return;
+ btn.dataset.m3Bound = '1';
+ btn.addEventListener('click', function (event) {
+ event.preventDefault();
+ var source = btn.getAttribute('data-m3-copy');
+ var field = source ? $(source) : null;
+ var value = field ? (field.value || field.textContent) : source;
+ copy(value.trim()).then(function () {
+ snackbar(btn.getAttribute('data-m3-copy-message') || 'Copied to clipboard');
+ }).catch(function () {
+ snackbar('Could not copy โ copy manually: ' + value, { variant: 'error' });
+ });
+ });
+ });
+ }
+
+ /* โโ Reveal on scroll โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setupReveals(scope) {
+ var items = $$('.m3-reveal', scope);
+ if (!items.length) return;
+ if (REDUCED || !('IntersectionObserver' in global)) {
+ items.forEach(function (el) { el.classList.add('is-visible'); });
+ return;
+ }
+ var observer = new IntersectionObserver(function (entries) {
+ entries.forEach(function (entry) {
+ if (!entry.isIntersecting) return;
+ var delay = parseInt(entry.target.getAttribute('data-m3-reveal-delay') || '0', 10);
+ setTimeout(function () { entry.target.classList.add('is-visible'); }, delay);
+ observer.unobserve(entry.target);
+ });
+ }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
+ items.forEach(function (el) { observer.observe(el); });
+ }
+
+ /* โโ Loading state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function setLoading(el, loading, label) {
+ if (!el) return;
+ var target = el.classList.contains('m3-button') ? el : el.closest('.m3-button') || el;
+ target.classList.toggle('is-loading', !!loading);
+ target.setAttribute('aria-busy', String(!!loading));
+ if (loading) {
+ target.dataset.m3Label = target.dataset.m3Label || target.textContent.trim();
+ if (!target.querySelector('.sr-only')) {
+ var sr = document.createElement('span');
+ sr.className = 'sr-only';
+ sr.textContent = label || 'Loading';
+ target.appendChild(sr);
+ }
+ } else {
+ var sr = target.querySelector('.sr-only.sr-only--auto');
+ if (sr) sr.remove();
+ }
+ target.disabled = !!loading;
+ }
+
+ /* โโ Boot โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+ function init(scope) {
+ scope = scope || document;
+ $$(RIPPLE_SELECTOR, scope).forEach(attachRipple);
+ setupAppBars(scope);
+ setupDrawers(scope);
+ setupMenus(scope);
+ setupDialogs(scope);
+ setupTabs(scope);
+ setupSegmented(scope);
+ setupFields(scope);
+ setupThemeToggles(scope);
+ setupCopy(scope);
+ setupReveals(scope);
+ }
+
+ global.M3UI = {
+ init: init,
+ snackbar: snackbar,
+ openDialog: openDialog,
+ closeDialog: closeDialog,
+ openDrawer: function (target, open) { setDrawer(byId(target), open); },
+ setLoading: setLoading,
+ copy: copy,
+ lockScroll: lockScroll,
+ unlockScroll: unlockScroll
+ };
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', function () { init(); });
+ } else {
+ init();
+ }
+
+ // Re-scan when pages inject markup dynamically (e.g. the demon list grids).
+ global.addEventListener('m3ui:refresh', function () { init(); });
+
+ // Legacy bridge: elements that toggle drawers via plain classes.
+ document.addEventListener('click', function (event) {
+ var toggle = event.target.closest('[data-m3-drawer-legacy]');
+ if (!toggle) return;
+ var drawer = byId(toggle.getAttribute('data-m3-drawer-legacy'));
+ if (drawer) setTimeout(function () { setDrawer(drawer, drawer.classList.contains('active') || drawer.classList.contains('is-open')); }, 0);
+ });
+})(window);
diff --git a/main/assets/people/alonebg.svg b/main/assets/people/alonebg.svg
new file mode 100644
index 0000000..f535e96
--- /dev/null
+++ b/main/assets/people/alonebg.svg
@@ -0,0 +1,4 @@
+
+
+ AB
+
diff --git a/main/assets/people/blazen.svg b/main/assets/people/blazen.svg
new file mode 100644
index 0000000..9631bdb
--- /dev/null
+++ b/main/assets/people/blazen.svg
@@ -0,0 +1,4 @@
+
+
+ BL
+
diff --git a/main/assets/people/danzgame.svg b/main/assets/people/danzgame.svg
new file mode 100644
index 0000000..c3decb2
--- /dev/null
+++ b/main/assets/people/danzgame.svg
@@ -0,0 +1,4 @@
+
+
+ DG
+
diff --git a/main/assets/people/denyzr.svg b/main/assets/people/denyzr.svg
new file mode 100644
index 0000000..1761b7a
--- /dev/null
+++ b/main/assets/people/denyzr.svg
@@ -0,0 +1,4 @@
+
+
+ DZ
+
diff --git a/main/assets/people/fless.svg b/main/assets/people/fless.svg
new file mode 100644
index 0000000..c5e54d5
--- /dev/null
+++ b/main/assets/people/fless.svg
@@ -0,0 +1,4 @@
+
+
+ FL
+
diff --git a/main/assets/people/giffarirmx.svg b/main/assets/people/giffarirmx.svg
new file mode 100644
index 0000000..13c6081
--- /dev/null
+++ b/main/assets/people/giffarirmx.svg
@@ -0,0 +1,4 @@
+
+
+ GR
+
diff --git a/main/assets/people/mathieuar.svg b/main/assets/people/mathieuar.svg
new file mode 100644
index 0000000..0062e57
--- /dev/null
+++ b/main/assets/people/mathieuar.svg
@@ -0,0 +1,4 @@
+
+
+ MA
+
diff --git a/main/assets/people/megasaint.svg b/main/assets/people/megasaint.svg
new file mode 100644
index 0000000..329a2bd
--- /dev/null
+++ b/main/assets/people/megasaint.svg
@@ -0,0 +1,4 @@
+
+
+ MS
+
diff --git a/main/assets/people/migmatos.svg b/main/assets/people/migmatos.svg
new file mode 100644
index 0000000..16540e6
--- /dev/null
+++ b/main/assets/people/migmatos.svg
@@ -0,0 +1,4 @@
+
+
+ MI
+
diff --git a/main/assets/people/robtop.svg b/main/assets/people/robtop.svg
new file mode 100644
index 0000000..24ed725
--- /dev/null
+++ b/main/assets/people/robtop.svg
@@ -0,0 +1,4 @@
+
+
+ RT
+
diff --git a/main/assets/people/zeroxygd.svg b/main/assets/people/zeroxygd.svg
new file mode 100644
index 0000000..8aa0927
--- /dev/null
+++ b/main/assets/people/zeroxygd.svg
@@ -0,0 +1,4 @@
+
+
+ ZG
+
diff --git a/main/assets/vendor/fontawesome/LICENSE.txt b/main/assets/vendor/fontawesome/LICENSE.txt
new file mode 100644
index 0000000..39e18e3
--- /dev/null
+++ b/main/assets/vendor/fontawesome/LICENSE.txt
@@ -0,0 +1,165 @@
+Fonticons, Inc. (https://fontawesome.com)
+
+--------------------------------------------------------------------------------
+
+Font Awesome Free License
+
+Font Awesome Free is free, open source, and GPL friendly. You can use it for
+commercial projects, open source projects, or really almost whatever you want.
+Full Font Awesome Free license: https://fontawesome.com/license/free.
+
+--------------------------------------------------------------------------------
+
+# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
+
+The Font Awesome Free download is licensed under a Creative Commons
+Attribution 4.0 International License and applies to all icons packaged
+as SVG and JS file types.
+
+--------------------------------------------------------------------------------
+
+# Fonts: SIL OFL 1.1 License
+
+In the Font Awesome Free download, the SIL OFL license applies to all icons
+packaged as web and desktop font files.
+
+Copyright (c) 2023 Fonticons, Inc. (https://fontawesome.com)
+with Reserved Font Name: "Font Awesome".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+SIL OPEN FONT LICENSE
+Version 1.1 - 26 February 2007
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting โ in part or in whole โ any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+# Code: MIT License (https://opensource.org/licenses/MIT)
+
+In the Font Awesome Free download, the MIT license applies to all non-font and
+non-icon files.
+
+Copyright 2023 Fonticons, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+# Attribution
+
+Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
+Awesome Free files already contain embedded comments with sufficient
+attribution, so you shouldn't need to do anything additional when using these
+files normally.
+
+We've kept attribution comments terse, so we ask that you do not actively work
+to remove them from files, especially code. They're a great way for folks to
+learn about Font Awesome.
+
+--------------------------------------------------------------------------------
+
+# Brand Icons
+
+All brand icons are trademarks of their respective owners. The use of these
+trademarks does not indicate endorsement of the trademark holder by Font
+Awesome, nor vice versa. **Please do not use brand logos for any purpose except
+to represent the company, product, or service to which they refer.**
diff --git a/main/assets/vendor/fontawesome/css/all.min.css b/main/assets/vendor/fontawesome/css/all.min.css
new file mode 100644
index 0000000..a18b779
--- /dev/null
+++ b/main/assets/vendor/fontawesome/css/all.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}
+
+.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"}
+.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2")}.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2")}.fa-regular,.far{font-weight:400}:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2")}.fa-solid,.fas{font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
\ No newline at end of file
diff --git a/main/assets/vendor/fontawesome/webfonts/fa-brands-400.woff2 b/main/assets/vendor/fontawesome/webfonts/fa-brands-400.woff2
new file mode 100644
index 0000000..71e3185
Binary files /dev/null and b/main/assets/vendor/fontawesome/webfonts/fa-brands-400.woff2 differ
diff --git a/main/assets/vendor/fontawesome/webfonts/fa-regular-400.woff2 b/main/assets/vendor/fontawesome/webfonts/fa-regular-400.woff2
new file mode 100644
index 0000000..7f02168
Binary files /dev/null and b/main/assets/vendor/fontawesome/webfonts/fa-regular-400.woff2 differ
diff --git a/main/assets/vendor/fontawesome/webfonts/fa-solid-900.woff2 b/main/assets/vendor/fontawesome/webfonts/fa-solid-900.woff2
new file mode 100644
index 0000000..5c16cd3
Binary files /dev/null and b/main/assets/vendor/fontawesome/webfonts/fa-solid-900.woff2 differ
diff --git a/main/assets/vendor/fontawesome/webfonts/fa-v4compatibility.woff2 b/main/assets/vendor/fontawesome/webfonts/fa-v4compatibility.woff2
new file mode 100644
index 0000000..9027e38
Binary files /dev/null and b/main/assets/vendor/fontawesome/webfonts/fa-v4compatibility.woff2 differ
diff --git a/main/assets/vendor/fonts/LICENSE-jetbrains-mono.txt b/main/assets/vendor/fonts/LICENSE-jetbrains-mono.txt
new file mode 100644
index 0000000..8f7ed67
--- /dev/null
+++ b/main/assets/vendor/fonts/LICENSE-jetbrains-mono.txt
@@ -0,0 +1,93 @@
+Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) JetBrainsMono-Italic[wght].ttf: Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/main/assets/vendor/fonts/LICENSE-roboto-flex.txt b/main/assets/vendor/fonts/LICENSE-roboto-flex.txt
new file mode 100644
index 0000000..2750ff6
--- /dev/null
+++ b/main/assets/vendor/fonts/LICENSE-roboto-flex.txt
@@ -0,0 +1,93 @@
+Copyright 2017 The Roboto Flex Project Authors (https://github.com/googlefonts/roboto-flex)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/main/assets/vendor/fonts/jetbrains-mono-latin-wght-normal.woff2 b/main/assets/vendor/fonts/jetbrains-mono-latin-wght-normal.woff2
new file mode 100644
index 0000000..cd5102a
Binary files /dev/null and b/main/assets/vendor/fonts/jetbrains-mono-latin-wght-normal.woff2 differ
diff --git a/main/assets/vendor/fonts/roboto-flex-latin-wght-normal.woff2 b/main/assets/vendor/fonts/roboto-flex-latin-wght-normal.woff2
new file mode 100644
index 0000000..88bbf49
Binary files /dev/null and b/main/assets/vendor/fonts/roboto-flex-latin-wght-normal.woff2 differ
diff --git a/main/assets/vendor/papaparse/LICENSE b/main/assets/vendor/papaparse/LICENSE
new file mode 100644
index 0000000..12f5b35
--- /dev/null
+++ b/main/assets/vendor/papaparse/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Matthew Holt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/main/assets/vendor/papaparse/papaparse.min.js b/main/assets/vendor/papaparse/papaparse.min.js
new file mode 100644
index 0000000..edfdb37
--- /dev/null
+++ b/main/assets/vendor/papaparse/papaparse.min.js
@@ -0,0 +1,7 @@
+/* @license
+Papa Parse
+v5.3.2
+https://github.com/mholt/PapaParse
+License: MIT
+*/
+!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&"undefined"!=typeof exports?module.exports=t():e.Papa=t()}(this,function s(){"use strict";var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,b={parse:function(e,t){var i=(t=t||{}).dynamicTyping||!1;M(i)&&(t.dynamicTypingFunction=i,i={});if(t.dynamicTyping=i,t.transform=!!M(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var r=function(){if(!b.WORKERS_SUPPORTED)return!1;var e=(i=f.URL||f.webkitURL||null,r=s.toString(),b.BLOB_URL||(b.BLOB_URL=i.createObjectURL(new Blob(["(",r,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var i,r;return t.onmessage=_,t.id=h++,a[t.id]=t}();return r.userStep=t.step,r.userChunk=t.chunk,r.userComplete=t.complete,r.userError=t.error,t.step=M(t.step),t.chunk=M(t.chunk),t.complete=M(t.complete),t.error=M(t.error),delete t.worker,void r.postMessage({input:e,config:t,workerId:r.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&M(e.read)&&M(e.on)?n=new g(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var n=!1,_=!0,m=",",y="\r\n",s='"',a=s+s,i=!1,r=null,o=!1;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return-1!==t.delimiter.indexOf(e)}).length||(m=t.delimiter);("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(n=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(i=t.skipEmptyLines);"string"==typeof t.newline&&(y=t.newline);"string"==typeof t.quoteChar&&(s=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");r=t.columns}void 0!==t.escapeChar&&(a=t.escapeChar+s);("boolean"==typeof t.escapeFormulae||t.escapeFormulae instanceof RegExp)&&(o=t.escapeFormulae instanceof RegExp?t.escapeFormulae:/^[=+\-@\t\r].*$/)}();var h=new RegExp(j(s),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return u(null,e,i);if("object"==typeof e[0])return u(r||Object.keys(e[0]),e,i)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields||r),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:"object"==typeof e.data[0]?Object.keys(e.data[0]):[]),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),u(e.fields||[],e.data||[],i);throw new Error("Unable to serialize unrecognized input");function u(e,t,i){var r="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(M(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!M(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){M(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1})}}function l(e){var r;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(r=new XMLHttpRequest,this._config.withCredentials&&(r.withCredentials=this._config.withCredentials),n||(r.onload=v(this._chunkLoaded,this),r.onerror=v(this._chunkError,this)),r.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)r.setRequestHeader(t,e[t])}if(this._config.chunkSize){var i=this._start+this._config.chunkSize-1;r.setRequestHeader("Range","bytes="+this._start+"-"+i)}try{r.send(this._config.downloadRequestBody)}catch(e){this._chunkError(e.message)}n&&0===r.status&&this._chunkError()}},this._chunkLoaded=function(){4===r.readyState&&(r.status<200||400<=r.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:r.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(r),this.parseChunk(r.responseText)))},this._chunkError=function(e){var t=r.statusText||e;this._sendError(new Error(t))}}function c(e){var r,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((r=new FileReader).onload=v(this._chunkLoaded,this),r.onerror=v(this._chunkError,this)):r=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(r.error)}}function p(e){var i;u.call(this,e=e||{}),this.stream=function(e){return i=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=i.substring(0,t),i=i.substring(t)):(e=i,i=""),this._finished=!i,this.parseChunk(e)}}}function g(e){u.call(this,e=e||{});var t=[],i=!0,r=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){r&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):i=!0},this._streamData=v(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),i&&(i=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=v(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=v(function(){this._streamCleanUp(),r=!0,this._streamData("")},this),this._streamCleanUp=v(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function i(m){var a,o,h,r=Math.pow(2,53),n=-r,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,u=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))$/,t=this,i=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(M(m.step)){var p=m.step;m.step=function(e){if(c=e,_())g();else{if(g(),0===c.data.length)return;i+=e.data.length,m.preview&&i>m.preview?o.abort():(c.data=c.data[0],p(c,t))}}}function y(e){return"greedy"===m.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){return c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),m.skipEmptyLines&&(c.data=c.data.filter(function(e){return!y(e)})),_()&&function(){if(!c)return;function e(e,t){M(m.transformHeader)&&(e=m.transformHeader(e,t)),l.push(e)}if(Array.isArray(c.data[0])){for(var t=0;_()&&t=l.length?"__parsed_extra":l[i]),m.transform&&(s=m.transform(s,n)),s=v(n,s),"__parsed_extra"===n?(r[n]=r[n]||[],r[n].push(s)):r[n]=s}return m.header&&(i>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+i,f+t):i=r.length/2?"\r\n":"\r"}(e,r)),h=!1,m.delimiter)M(m.delimiter)&&(m.delimiter=m.delimiter(e),c.meta.delimiter=m.delimiter);else{var n=function(e,t,i,r,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=D)return C(!0)}else for(m=F,F++;;){if(-1===(m=r.indexOf(S,m+1)))return i||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:F}),E();if(m===n-1)return E(r.substring(F,m).replace(_,S));if(S!==L||r[m+1]!==L){if(S===L||0===m||r[m-1]!==L){-1!==p&&p=D)return C(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:F}),m++}}else m++}return E();function k(e){h.push(e),d=F}function b(e){var t=0;if(-1!==e){var i=r.substring(m+1,e);i&&""===i.trim()&&(t=i.length)}return t}function E(e){return i||(void 0===e&&(e=r.substring(F)),f.push(e),F=n,k(f),o&&R()),C()}function w(e){F=e,k(f),f=[],g=r.indexOf(x,F)}function C(e){return{data:h,errors:u,meta:{delimiter:O,linebreak:x,aborted:z,truncated:!!e,cursor:d+(t||0)}}}function R(){T(C()),h=[],u=[]}},this.abort=function(){z=!0},this.getCharIndex=function(){return F}}function _(e){var t=e.data,i=a[t.workerId],r=!1;if(t.error)i.userError(t.error,t.file);else if(t.results&&t.results.data){var n={abort:function(){r=!0,m(t.workerId,{data:[],errors:[],meta:{aborted:!0}})},pause:y,resume:y};if(M(i.userStep)){for(var s=0;s
-
+
Leaderboard - GDIPS Demonlist
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-