From 3ff49209d67348a9194c3f860326b90ee26a60b6 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 21:57:34 +0100 Subject: [PATCH 01/13] docs: spec for NB-1 password visibility toggle Template-only design adding an accessible show/hide toggle to all four auth password surfaces. Records the resolved scope decision to build a branded password_reset_confirm.html (currently the admin fallback) and the choice of Material Symbols + a single delegated script over per- template duplication. --- ...05-16-password-visibility-toggle-design.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md diff --git a/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md b/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md new file mode 100644 index 0000000..7428091 --- /dev/null +++ b/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md @@ -0,0 +1,153 @@ +# Password visibility toggle on auth forms — design + +- **Ticket:** NB-1 (Notion: NyasaBlog Tickets) +- **Date:** 2026-05-16 +- **Type:** Improvement · Priority P3 · Effort S +- **Constraint:** Template-only. No backend, form, or model changes. + +## Problem + +Every NyasaBlog auth password field renders a plain `` +with no way to reveal what was typed. On mobile, where mistyping is common, +users cannot verify a password before submitting. + +## Goal + +Add an accessible show/hide toggle to every password input across the four +auth surfaces, masked by default on every load, with no persistence and no +exposure of the password value beyond a client-side DOM attribute flip. + +## Affected surfaces + +| Surface | Template | Password fields | +| --- | --- | --- | +| Login | `account/templates/account/partials/login_form.html` | password (1, loop-rendered) | +| Register | `account/templates/account/partials/register_form.html` | password + confirm (loop-rendered) | +| Change password | `templates/registration/password_change.html` | old / new / confirm (3, hardcoded) | +| Reset confirm | `templates/registration/password_reset_confirm.html` | new / confirm (**template does not exist yet**) | + +### Reset-confirm scope note + +`mysite/urls.py:101` wires `PasswordResetConfirmView.as_view()` with **no +`template_name`**, so the "set a new password" page currently renders Django +admin's unstyled `registration/password_reset_confirm.html` fallback (off-brand, +no `base.html`). `TEMPLATES.DIRS` lists the project `templates/` dir ahead of +`APP_DIRS`, so creating `templates/registration/password_reset_confirm.html` +overrides the admin fallback with **no `urls.py` change**. Per ticket owner +decision (2026-05-16), NB-1 includes building this branded page, modelled on +`password_change.html`. This remains template-only. + +## Decisions (resolved, not open) + +1. **Icon set:** Material Symbols (`visibility` / `visibility_off`), not + Bootstrap Icons. Already loaded in `base.html`; `password_change.html` and + `design_reference/` mockups use it. Overrides the ticket's "Bootstrap Icons + or inline SVG" suggestion for project consistency. +2. **Toggle markup:** Lifted verbatim from `design_reference/login_mobile.html` + — an absolutely-positioned `type="button"` inside a `relative` wrapper, with + `pr-12` on the input to reserve space. +3. **Shared mechanism (approach A1):** one markup include + one delegated + script, rather than pure-JS injection (A2, risks the no-height-shift AC and + is fragile across HTMX swaps) or per-template duplication (A3, violates DRY). +4. **No-JS behaviour:** the button renders as static markup and is inert + without JS. The password stays masked and the form stays fully functional — + the toggle is a progressive enhancement, not required for the core flow. + +## Architecture + +### New files + +**`templates/snippets/password_toggle.html`** — button markup only: + +```html + +``` + +**`templates/snippets/password_toggle_js.html`** — one ` +``` + +- [ ] **Step 4: Wire the login form partial** + +In `account/templates/account/partials/login_form.html`, replace the entire field loop block. The CURRENT block is: + +```django + {% for field in login_form %} +
+ + + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} +
+ {% endfor %} +``` + +Replace it with: + +```django + {% for field in login_form %} +
+ + {% if field.field.widget.input_type == 'password' %} +
+ + {% include 'snippets/password_toggle.html' %} +
+ {% else %} + + {% endif %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} +
+ {% endfor %} +``` + +Then add the script include as the LAST line of the file, after the closing ``: + +```django +{% include 'snippets/password_toggle_js.html' %} +``` + +- [ ] **Step 5: Run test to verify it passes** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_login_page_has_exactly_one_password_toggle -v 2` +Expected: PASS (1 test OK). + +- [ ] **Step 6: Commit** + +```bash +cd ~/PycharmProjects/nyasablog +git add templates/snippets/password_toggle.html templates/snippets/password_toggle_js.html account/templates/account/partials/login_form.html account/tests.py +git commit -m "feat: password visibility toggle on login form + +Shared toggle include + delegated script; login password field +wrapped with the toggle. NB-1." +``` + +--- + +### Task 2: Register form toggle + +**Files:** +- Modify: `account/templates/account/partials/register_form.html` +- Test: `account/tests.py` (add method to `PasswordToggleTests`) + +- [ ] **Step 1: Write the failing test** + +Add this method to `PasswordToggleTests` in `account/tests.py`: + +```python + def test_register_page_has_two_password_toggles(self): + resp = self.client.get(reverse('register')) + self.assertEqual(resp.status_code, 200) + body = resp.content.decode() + # RegistrationForm exposes password1 + password2 + self.assertEqual(body.count('data-pw-toggle'), 2) +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_register_page_has_two_password_toggles -v 2` +Expected: FAIL — `0 != 2`. + +- [ ] **Step 3: Wire the register form partial** + +In `account/templates/account/partials/register_form.html`, replace the CURRENT field loop block: + +```django + {% for field in registration_form %} +
+ + + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} +
+ {% endfor %} +``` + +with: + +```django + {% for field in registration_form %} +
+ + {% if field.field.widget.input_type == 'password' %} +
+ + {% include 'snippets/password_toggle.html' %} +
+ {% else %} + + {% endif %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} +
+ {% endfor %} +``` + +Then add as the LAST line of the file, after the closing ``: + +```django +{% include 'snippets/password_toggle_js.html' %} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_register_page_has_two_password_toggles -v 2` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +cd ~/PycharmProjects/nyasablog +git add account/templates/account/partials/register_form.html account/tests.py +git commit -m "feat: password visibility toggle on register form + +Both password fields wrapped with the shared toggle. NB-1." +``` + +--- + +### Task 3: Password change toggle + +**Files:** +- Modify: `templates/registration/password_change.html` +- Test: `account/tests.py` (add method to `PasswordToggleTests`) + +- [ ] **Step 1: Write the failing test** + +Add this method to `PasswordToggleTests`: + +```python + def test_password_change_page_has_three_toggles(self): + self.client.force_login(self.user) + resp = self.client.get(reverse('password_change')) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content.decode().count('data-pw-toggle'), 3) +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_password_change_page_has_three_toggles -v 2` +Expected: FAIL — `0 != 3`. + +- [ ] **Step 3: Wire the password change template** + +In `templates/registration/password_change.html`, replace the three field `
` blocks. The CURRENT markup is: + +```django +
+ + +
+
+ + +
+
+ + +
+``` + +Replace with: + +```django +
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+``` + +Then add the script include just before the `{% endblock content %}` line at the bottom of the file: + +```django +{% include 'snippets/password_toggle_js.html' %} +{% endblock content %} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_password_change_page_has_three_toggles -v 2` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +cd ~/PycharmProjects/nyasablog +git add templates/registration/password_change.html account/tests.py +git commit -m "feat: password visibility toggle on change-password form + +All three password fields wrapped with the shared toggle. NB-1." +``` + +--- + +### Task 4: Branded password_reset_confirm page with toggle + +**Files:** +- Create: `templates/registration/password_reset_confirm.html` +- Test: `account/tests.py` (add method to `PasswordToggleTests`) + +Context: `mysite/urls.py:101` wires `PasswordResetConfirmView.as_view()` with no `template_name`; `TEMPLATES.DIRS` lists `templates/` before `APP_DIRS`, so creating this file overrides the Django-admin fallback with no `urls.py` change. The view redirects a valid `reset///` link (302) to a session URL that renders this template with `validlink=True` and `form` (`SetPasswordForm`: `new_password1`, `new_password2`). + +- [ ] **Step 1: Write the failing test** + +Add this method to `PasswordToggleTests`: + +```python + def test_password_reset_confirm_is_branded_with_two_toggles(self): + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + token = default_token_generator.make_token(self.user) + resp = self.client.get( + reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token}), + follow=True, + ) + self.assertEqual(resp.status_code, 200) + self.assertTemplateUsed(resp, 'registration/password_reset_confirm.html') + body = resp.content.decode() + # Branded: extends base.html, so the site name is present (admin + # fallback would not contain it). + self.assertIn('NyasaBlog', body) + self.assertEqual(body.count('data-pw-toggle'), 2) +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_password_reset_confirm_is_branded_with_two_toggles -v 2` +Expected: FAIL — currently renders Django admin's template: `assertTemplateUsed` fails, or `'NyasaBlog'` / `data-pw-toggle` count assertion fails. + +- [ ] **Step 3: Create the branded template** + +Create `templates/registration/password_reset_confirm.html` (2-space indentation), modelled on `password_change.html`: + +```django +{% extends 'base.html' %} + +{% block title %}Set New Password | NyasaBlog{% endblock %} + +{% block content %} +
+
+
+ lock_reset +

Set a new password

+
+ + {% if validlink %} +
+ {% csrf_token %} +
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+ + {% for field in form %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} + + +
+ {% else %} +

+ This password reset link is invalid or has expired. Please + request a new one. +

+ {% endif %} + + {% include 'snippets/password_toggle_js.html' %} +
+
+{% endblock content %} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_password_reset_confirm_is_branded_with_two_toggles -v 2` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +cd ~/PycharmProjects/nyasablog +git add templates/registration/password_reset_confirm.html account/tests.py +git commit -m "feat: branded password_reset_confirm page with toggle + +Replaces the Django-admin fallback with a base.html-styled page; +both new-password fields wrapped with the shared toggle. NB-1." +``` + +--- + +### Task 5: Full-suite regression, lint, and manual verification + +**Files:** none modified (verification only; commit any lint fix if needed) + +- [ ] **Step 1: Run the full account + blog suite** + +Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account blog -v 1` +Expected: all tests pass, including the pre-existing `blog.tests.test_password_reset_loads` and the 4 new `PasswordToggleTests`. If `test_password_reset_loads` or any auth test fails, stop and investigate before proceeding. + +- [ ] **Step 2: Lint the changed Python** + +Run: `cd ~/PycharmProjects/nyasablog && ruff check account/tests.py` +Expected: no errors. If ruff reports issues introduced by the new test class, fix them and re-run. (Templates are not linted by ruff.) + +- [ ] **Step 3: Manual in-browser verification** + +Run the dev server: `cd ~/PycharmProjects/nyasablog && python manage.py runserver` and, at a viewport width of 320px and a normal desktop width, verify on `/login/`, `/register/`, `/password_change/` (logged in), and a live password-reset-confirm link: + +- Clicking the eye icon flips the field between dots and plaintext; icon swaps `visibility` ↔ `visibility_off`. +- Tabbing reaches the button; Enter and Space both toggle it. +- `aria-label` flips between "Show password" and "Hide password" (inspect element / screen reader). +- The button does NOT submit the form. +- Field height does not change when toggled; layout holds at 320px. +- On `/login/` and `/register/`, submit with a bad value to force the HTMX partial re-render, then confirm the toggle still works on the swapped-in form (delegated handler survives the swap). +- Reload each page: every field is masked again (no persisted visible state). + +Document the outcome of each check in the task notes. There is no JS test runner in the suite, so this manual pass is the verification of record for the JS behavior. + +- [ ] **Step 4: Final commit (only if Step 2 required a lint fix)** + +```bash +cd ~/PycharmProjects/nyasablog +git add account/tests.py +git commit -m "chore: lint fixes for password toggle tests" +``` + +If Step 2 reported no issues, skip this step — no empty commit. + +--- + +## Self-Review + +**Spec coverage:** +- Toggle on all 4 surfaces → Tasks 1 (login), 2 (register), 3 (change), 4 (reset confirm). ✓ +- Shared markup include + single delegated script (A1) → created in Task 1, reused thereafter. ✓ +- Branded `password_reset_confirm.html` overriding admin fallback, no `urls.py` change → Task 4. ✓ +- Material Symbols `visibility`/`visibility_off` → in `password_toggle.html` + JS swap. ✓ +- Masked default / no persistence → server always renders `type="password"`; state only in transient DOM (verified Step 3, Task 5). ✓ +- `type="button"`, keyboard reachable, `aria-label` flip → asserted in Task 1 test + manual Task 5. ✓ +- No height shift at ≥320px → absolute overlay + `pr-12`; manual Task 5. ✓ +- Nothing logged/stored/transmitted → pure client attribute flip; no backend touched. ✓ +- `window`-scoped idempotency guard, HTMX-swap safe → `password_toggle_js.html` + manual swap check Task 5. ✓ +- Existing `test_password_reset_loads` still green → Task 5 Step 1. ✓ + +**Placeholder scan:** No TBD/TODO/"handle edge cases"/uncoded steps. Every code step shows complete, runnable code; every command step shows the exact command and expected output. ✓ + +**Type/name consistency:** `data-pw-toggle`, `.relative` wrapper, `pr-12`, `window.__pwToggleBound`, icon text `visibility`/`visibility_off`, `aria-label` "Show password"/"Hide password", class `PasswordToggleTests`, and `snippets/password_toggle.html` / `snippets/password_toggle_js.html` paths are identical across every task. ✓ From 1fcb5b9fb483572144d32169d79e97800d361375 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 22:24:38 +0100 Subject: [PATCH 03/13] feat: password visibility toggle on login form Shared toggle include + delegated script; login password field wrapped with the toggle. NB-1. --- .../account/partials/login_form.html | 12 ++++++++++++ account/tests.py | 18 ++++++++++++++++++ templates/snippets/password_toggle.html | 4 ++++ templates/snippets/password_toggle_js.html | 19 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 templates/snippets/password_toggle.html create mode 100644 templates/snippets/password_toggle_js.html diff --git a/account/templates/account/partials/login_form.html b/account/templates/account/partials/login_form.html index dc45b2f..b0a51e9 100644 --- a/account/templates/account/partials/login_form.html +++ b/account/templates/account/partials/login_form.html @@ -17,11 +17,22 @@ {% for field in login_form %}
+ {% if field.field.widget.input_type == 'password' %} +
+ + {% include 'snippets/password_toggle.html' %} +
+ {% else %} + {% endif %} {% for error in field.errors %}

{{ error }}

{% endfor %} @@ -37,3 +48,4 @@ +{% include 'snippets/password_toggle_js.html' %} diff --git a/account/tests.py b/account/tests.py index 6c4ebfd..ca5e34f 100644 --- a/account/tests.py +++ b/account/tests.py @@ -13,6 +13,7 @@ from django.urls import reverse from django.utils import timezone from django.utils.encoding import force_bytes +from django.contrib.auth.tokens import default_token_generator from django.utils.http import urlsafe_base64_encode from rest_framework.authtoken.models import Token from rest_framework.test import APIClient, APIRequestFactory, APITestCase @@ -1219,3 +1220,20 @@ def test_verification_email_from_address_is_a_nyasablog_address(self): send_verification_email(self.user) sent = mail.outbox[0] self.assertIn('@nyasablog.com', sent.from_email) + + +class PasswordToggleTests(TestCase): + def setUp(self): + self.user = Account.objects.create_user( + email='toggle@nyasablog.com', username='toggleuser', password='Str0ngPass!9' + ) + self.user.email_verified = True + self.user.save() + + def test_login_page_has_exactly_one_password_toggle(self): + resp = self.client.get(reverse('login')) + self.assertEqual(resp.status_code, 200) + body = resp.content.decode() + self.assertEqual(body.count('data-pw-toggle'), 1) + self.assertIn('type="button"', body) + self.assertIn('aria-label="Show password"', body) diff --git a/templates/snippets/password_toggle.html b/templates/snippets/password_toggle.html new file mode 100644 index 0000000..06f7b51 --- /dev/null +++ b/templates/snippets/password_toggle.html @@ -0,0 +1,4 @@ + diff --git a/templates/snippets/password_toggle_js.html b/templates/snippets/password_toggle_js.html new file mode 100644 index 0000000..0e5153b --- /dev/null +++ b/templates/snippets/password_toggle_js.html @@ -0,0 +1,19 @@ + From bfbecc3caa29c8c21b87bf02b0e2d28863adebfb Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 22:28:43 +0100 Subject: [PATCH 04/13] fix: count toggle by aria-label, drop JS selector hack The login toggle test counted the data-pw-toggle literal, which also appears in the delegated script's selector (double-count). Count the markup-only aria-label token instead and restore the clean selector. NB-1. --- account/tests.py | 10 ++++++++-- templates/snippets/password_toggle_js.html | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/account/tests.py b/account/tests.py index ca5e34f..231688f 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1234,6 +1234,12 @@ def test_login_page_has_exactly_one_password_toggle(self): resp = self.client.get(reverse('login')) self.assertEqual(resp.status_code, 200) body = resp.content.decode() - self.assertEqual(body.count('data-pw-toggle'), 1) + # Count the rendered toggle button by its aria-label attribute. + # NOT `data-pw-toggle`: that literal also appears inside the + # delegated script's `closest('[data-pw-toggle]')` selector, so + # counting it would double-count. The JS sets the label via + # setAttribute with bare 'Show password' (no `aria-label="` + # prefix), so this token only matches rendered markup. + self.assertEqual(body.count('aria-label="Show password"'), 1) + self.assertIn('data-pw-toggle', body) self.assertIn('type="button"', body) - self.assertIn('aria-label="Show password"', body) diff --git a/templates/snippets/password_toggle_js.html b/templates/snippets/password_toggle_js.html index 0e5153b..fb17f3c 100644 --- a/templates/snippets/password_toggle_js.html +++ b/templates/snippets/password_toggle_js.html @@ -3,7 +3,7 @@ if (window.__pwToggleBound) return; window.__pwToggleBound = true; document.body.addEventListener('click', function (e) { - var btn = e.target.closest('[data-pw' + '-toggle]'); + var btn = e.target.closest('[data-pw-toggle]'); if (!btn) return; var wrapper = btn.closest('.relative'); if (!wrapper) return; From 7a40ea7d7a53a870f47674f9c935c01db4d2d866 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 22:44:22 +0100 Subject: [PATCH 05/13] docs: harden NB-1 plan/spec from code review Move default_token_generator import to Task 4 (avoids F401/I001), switch the JS wrapper contract from .relative to data-pw-wrapper, add an HTMX partial-swap test, and record the compiled-Tailwind build step. --- .../2026-05-16-password-visibility-toggle.md | 144 +++++++++++++----- ...05-16-password-visibility-toggle-design.md | 18 ++- 2 files changed, 123 insertions(+), 39 deletions(-) diff --git a/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md b/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md index a468867..0c22bd3 100644 --- a/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md +++ b/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md @@ -13,8 +13,10 @@ **Conventions observed:** - `account/tests.py` uses **4-space** indentation — match it. - Templates use **2-space** indentation — match it. -- CI runs `python manage.py test blog account personal`. New tests go in `account/tests.py`. +- Run all test/manage commands with the venv interpreter: **`.venv/bin/python manage.py ...`** (every `python manage.py` below means `.venv/bin/python manage.py`). +- CI runs `python manage.py test blog account personal` + `ruff check .`. New tests go in `account/tests.py`. Keep the test class lint-clean (no unused imports — F401/I001 fail CI). - User model: `account.models.Account`, `create_user(email, username, password)`, `email_verified` flag, `USERNAME_FIELD='email'`. +- **Tailwind is compiled, not CDN** (`CLAUDE.md`). New utility classes (`pr-12`, the toggle button's positioning classes) only take effect in the built CSS after `npm run build:css`. The `data-pw-wrapper` attribute and Django logic work without it, but the feature renders unstyled until the CSS is rebuilt — see Task 5. --- @@ -26,13 +28,9 @@ - Modify: `account/templates/account/partials/login_form.html` - Test: `account/tests.py` (append new class; add one import) -- [ ] **Step 1: Write the failing test** - -Add this import to the existing import block at the top of `account/tests.py` (the other names used below — `TestCase`, `reverse`, `force_bytes`, `urlsafe_base64_encode`, `Account` — are already imported there): +- [ ] **Step 1: Write the failing tests** -```python -from django.contrib.auth.tokens import default_token_generator -``` +Do NOT add any new import in this task. `TestCase`, `reverse`, and `Account` are already imported at the top of `account/tests.py`. (`default_token_generator` is added later, in Task 4, where it is first used — adding it here would be an unused import and fail `ruff` F401/I001.) Append this class to the end of `account/tests.py` (4-space indentation): @@ -49,15 +47,39 @@ class PasswordToggleTests(TestCase): resp = self.client.get(reverse('login')) self.assertEqual(resp.status_code, 200) body = resp.content.decode() - self.assertEqual(body.count('data-pw-toggle'), 1) + # Count the rendered toggle button by its aria-label attribute. + # NOT `data-pw-toggle`: that literal also appears inside the + # delegated script's `closest('[data-pw-toggle]')` selector, so + # counting it would double-count. The JS sets the label via + # setAttribute with bare 'Show password' (no `aria-label="` + # prefix), so this token only matches rendered markup. + self.assertEqual(body.count('aria-label="Show password"'), 1) + self.assertIn('data-pw-toggle', body) self.assertIn('type="button"', body) - self.assertIn('aria-label="Show password"', body) + + def test_login_htmx_partial_swap_has_toggle_and_script(self): + # Failed credentials with the HX-Request header make login_view + # return the swapped-in partial (account/partials/login_form.html), + # not the full page. This is the path where the script's + # window.__pwToggleBound guard matters, so assert the toggle AND + # the script are present in the fragment. (If django-htmx is not + # active the full page is returned instead — the assertions still + # hold, since the page includes the same partial.) + resp = self.client.post( + reverse('login'), + {'email': 'toggle@nyasablog.com', 'password': 'wrong-password'}, + HTTP_HX_REQUEST='true', + ) + self.assertEqual(resp.status_code, 200) + body = resp.content.decode() + self.assertEqual(body.count('aria-label="Show password"'), 1) + self.assertIn('__pwToggleBound', body) ``` -- [ ] **Step 2: Run test to verify it fails** +- [ ] **Step 2: Run tests to verify they fail** -Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_login_page_has_exactly_one_password_toggle -v 2` -Expected: FAIL — `0 != 1` (no `data-pw-toggle` in the rendered login page yet). +Run: `cd ~/PycharmProjects/nyasablog && .venv/bin/python manage.py test account.tests.PasswordToggleTests -v 2` +Expected: FAIL — both tests fail (no toggle markup / no script in the rendered login page or partial yet). - [ ] **Step 3: Create the shared snippets** @@ -80,7 +102,7 @@ Create `templates/snippets/password_toggle_js.html`: document.body.addEventListener('click', function (e) { var btn = e.target.closest('[data-pw-toggle]'); if (!btn) return; - var wrapper = btn.closest('.relative'); + var wrapper = btn.closest('[data-pw-wrapper]'); if (!wrapper) return; var input = wrapper.querySelector('input'); if (!input) return; @@ -121,7 +143,7 @@ Replace it with:
{% if field.field.widget.input_type == 'password' %} -
+
`: ```django {% include 'snippets/password_toggle_js.html' %} ``` -- [ ] **Step 5: Run test to verify it passes** +- [ ] **Step 5: Run tests to verify they pass** -Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account.tests.PasswordToggleTests.test_login_page_has_exactly_one_password_toggle -v 2` -Expected: PASS (1 test OK). +Run: `cd ~/PycharmProjects/nyasablog && .venv/bin/python manage.py test account.tests.PasswordToggleTests -v 2` +Expected: PASS (2 tests OK). - [ ] **Step 6: Commit** @@ -182,8 +211,10 @@ Add this method to `PasswordToggleTests` in `account/tests.py`: resp = self.client.get(reverse('register')) self.assertEqual(resp.status_code, 200) body = resp.content.decode() - # RegistrationForm exposes password1 + password2 - self.assertEqual(body.count('data-pw-toggle'), 2) + # RegistrationForm exposes password1 + password2. Count by + # aria-label (markup-only token), not `data-pw-toggle` which + # also appears in the delegated script's selector. + self.assertEqual(body.count('aria-label="Show password"'), 2) ``` - [ ] **Step 2: Run test to verify it fails** @@ -218,7 +249,7 @@ with:
{% if field.field.widget.input_type == 'password' %} -
+
-
+
{% include 'snippets/password_toggle.html' %} @@ -321,7 +354,7 @@ Replace with:
-
+
{% include 'snippets/password_toggle.html' %} @@ -329,7 +362,7 @@ Replace with:
-
+
{% include 'snippets/password_toggle.html' %} @@ -337,6 +370,10 @@ Replace with:
``` +(Each password input is in its own `
` — +`data-pw-wrapper` is the contract the shared script uses to find the input; +`relative` provides positioning for the absolute button.) + Then add the script include just before the `{% endblock content %}` line at the bottom of the file: ```django @@ -371,6 +408,14 @@ Context: `mysite/urls.py:101` wires `PasswordResetConfirmView.as_view()` with no - [ ] **Step 1: Write the failing test** +First add the `default_token_generator` import. It must be **isort-ordered**: `django.contrib` sorts after `django.conf` and before `django.core`. Insert it immediately after the `from django.conf import settings` line (and before `from django.core ...`): + +```python +from django.contrib.auth.tokens import default_token_generator +``` + +`urlsafe_base64_encode` (`django.utils.http`) and `force_bytes` (`django.utils.encoding`) are already imported at the top of `account/tests.py`. After adding the import, run `ruff check account/tests.py` and confirm zero errors (no F401 — it is now used by the test below; no I001 — it is correctly sorted). + Add this method to `PasswordToggleTests`: ```python @@ -387,7 +432,8 @@ Add this method to `PasswordToggleTests`: # Branded: extends base.html, so the site name is present (admin # fallback would not contain it). self.assertIn('NyasaBlog', body) - self.assertEqual(body.count('data-pw-toggle'), 2) + # Count by aria-label (markup-only token), not `data-pw-toggle`. + self.assertEqual(body.count('aria-label="Show password"'), 2) ``` - [ ] **Step 2: Run test to verify it fails** @@ -417,7 +463,7 @@ Create `templates/registration/password_reset_confirm.html` (2-space indentation {% csrf_token %}
-
+
{% include 'snippets/password_toggle.html' %} @@ -425,7 +471,7 @@ Create `templates/registration/password_reset_confirm.html` (2-space indentation
-
+
{% include 'snippets/password_toggle.html' %} @@ -477,17 +523,34 @@ both new-password fields wrapped with the shared toggle. NB-1." - [ ] **Step 1: Run the full account + blog suite** -Run: `cd ~/PycharmProjects/nyasablog && python manage.py test account blog -v 1` -Expected: all tests pass, including the pre-existing `blog.tests.test_password_reset_loads` and the 4 new `PasswordToggleTests`. If `test_password_reset_loads` or any auth test fails, stop and investigate before proceeding. +Run: `cd ~/PycharmProjects/nyasablog && .venv/bin/python manage.py test account blog -v 1` +Expected: all tests pass, including the pre-existing `blog.tests.test_password_reset_loads` and the 5 new `PasswordToggleTests` (login ×1, login-HTMX-partial ×1, register, password-change, reset-confirm). Baseline before this branch was 251 passing. If `test_password_reset_loads` or any auth test fails, stop and investigate before proceeding. + +- [ ] **Step 2: Lint (must be CI-clean)** + +Run: `cd ~/PycharmProjects/nyasablog && ruff check .` +Expected: the lint job passes with no NEW findings attributable to this branch. In particular `account/tests.py` must have zero F401 (unused import) and zero I001 (import order) — the `default_token_generator` import is added in Task 4 where it is used and must be isort-ordered (after `django.conf`, before `django.core`). Templates are not linted. If ruff reports a NEW issue from this branch, fix it and re-run; do not "fix" pre-existing repo findings unrelated to this change. + +- [ ] **Step 3: Rebuild the compiled Tailwind CSS** -- [ ] **Step 2: Lint the changed Python** +The new utility classes (`pr-12` on password inputs, the toggle button's `absolute right-3 top-1/2 -translate-y-1/2 w-10 h-10 ...`) only exist in the production stylesheet after a rebuild — Tailwind is compiled, not CDN (`CLAUDE.md`). `data-pw-wrapper` is an attribute, not a class, so it needs no CSS. -Run: `cd ~/PycharmProjects/nyasablog && ruff check account/tests.py` -Expected: no errors. If ruff reports issues introduced by the new test class, fix them and re-run. (Templates are not linted by ruff.) +Run: `cd ~/PycharmProjects/nyasablog && npm run build:css` +Then `git status` — if `static/css/tailwind.min.css` (or the project's built CSS output) changed, stage and commit it: -- [ ] **Step 3: Manual in-browser verification** +```bash +git add static/css/tailwind.min.css +git commit -m "chore: rebuild Tailwind CSS for password toggle classes + +NB-1 adds pr-12 and the toggle button positioning utilities; compile +them into the built stylesheet so the feature is styled in prod." +``` + +If `npm run build:css` is unavailable in this environment, STOP and report it — note explicitly that the CSS rebuild + `collectstatic` to DO Spaces is a required deploy step for this feature (per `CLAUDE.md`), so a reviewer/deployer does not ship an unstyled toggle. -Run the dev server: `cd ~/PycharmProjects/nyasablog && python manage.py runserver` and, at a viewport width of 320px and a normal desktop width, verify on `/login/`, `/register/`, `/password_change/` (logged in), and a live password-reset-confirm link: +- [ ] **Step 4: Manual in-browser verification** + +Run the dev server: `cd ~/PycharmProjects/nyasablog && .venv/bin/python manage.py runserver` and, at a viewport width of 320px and a normal desktop width, verify on `/login/`, `/register/`, `/password_change/` (logged in), and a live password-reset-confirm link: - Clicking the eye icon flips the field between dots and plaintext; icon swaps `visibility` ↔ `visibility_off`. - Tabbing reaches the button; Enter and Space both toggle it. @@ -499,7 +562,9 @@ Run the dev server: `cd ~/PycharmProjects/nyasablog && python manage.py runserve Document the outcome of each check in the task notes. There is no JS test runner in the suite, so this manual pass is the verification of record for the JS behavior. -- [ ] **Step 4: Final commit (only if Step 2 required a lint fix)** +- [ ] **Step 5: Final commit (only if Step 2 produced a lint fix)** + +If Step 2 required editing `account/tests.py` to clear a NEW ruff finding: ```bash cd ~/PycharmProjects/nyasablog @@ -507,7 +572,7 @@ git add account/tests.py git commit -m "chore: lint fixes for password toggle tests" ``` -If Step 2 reported no issues, skip this step — no empty commit. +If Step 2 was clean, skip — no empty commit. (The CSS commit, if any, was already made in Step 3.) --- @@ -522,9 +587,12 @@ If Step 2 reported no issues, skip this step — no empty commit. - `type="button"`, keyboard reachable, `aria-label` flip → asserted in Task 1 test + manual Task 5. ✓ - No height shift at ≥320px → absolute overlay + `pr-12`; manual Task 5. ✓ - Nothing logged/stored/transmitted → pure client attribute flip; no backend touched. ✓ -- `window`-scoped idempotency guard, HTMX-swap safe → `password_toggle_js.html` + manual swap check Task 5. ✓ +- `window`-scoped idempotency guard, HTMX-swap safe → `password_toggle_js.html` + `test_login_htmx_partial_swap_has_toggle_and_script` (Task 1) + manual swap check Task 5. ✓ +- Compiled-Tailwind constraint (`pr-12` etc. need a CSS rebuild for prod) → Task 5 Step 3 (`npm run build:css`). ✓ - Existing `test_password_reset_loads` still green → Task 5 Step 1. ✓ **Placeholder scan:** No TBD/TODO/"handle edge cases"/uncoded steps. Every code step shows complete, runnable code; every command step shows the exact command and expected output. ✓ -**Type/name consistency:** `data-pw-toggle`, `.relative` wrapper, `pr-12`, `window.__pwToggleBound`, icon text `visibility`/`visibility_off`, `aria-label` "Show password"/"Hide password", class `PasswordToggleTests`, and `snippets/password_toggle.html` / `snippets/password_toggle_js.html` paths are identical across every task. ✓ +**Type/name consistency:** `data-pw-toggle` (button marker), `data-pw-wrapper` (wrapper marker the script keys off — NOT the `.relative` class), `relative` + `pr-12` (presentation only), `window.__pwToggleBound`, icon text `visibility`/`visibility_off`, `aria-label` "Show password"/"Hide password", class `PasswordToggleTests`, and `snippets/password_toggle.html` / `snippets/password_toggle_js.html` paths are identical across every task. The `default_token_generator` import is introduced once, in Task 4, isort-ordered. ✓ + +**Test-token note (correction):** Toggle-count assertions count `aria-label="Show password"`, NOT `data-pw-toggle`. The `data-pw-toggle` literal also appears inside the delegated script's `closest('[data-pw-toggle]')` selector, so counting it double-counts. The JS sets the label via `setAttribute('aria-label', ... 'Show password')` — bare string, no `aria-label="` prefix — so the chosen token matches only rendered button markup. The JS keeps the clean spec selector `closest('[data-pw-toggle]')`; do NOT split that string as a test workaround. diff --git a/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md b/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md index 7428091..d33a373 100644 --- a/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md +++ b/docs/superpowers/specs/2026-05-16-password-visibility-toggle-design.md @@ -70,7 +70,13 @@ decision (2026-05-16), NB-1 includes building this branded page, modelled on `document.body`-delegated `click` listener for `[data-pw-toggle]`: - Resolve the target input as the `` within the button's closest - `.relative` wrapper (no IDs — robust for loop-rendered and hardcoded markup). + `[data-pw-wrapper]` element (no IDs — robust for loop-rendered and + hardcoded markup). The wrapper carries both `class="relative"` (presentation: + positioning context for the absolute button) and the `data-pw-wrapper` + attribute (the explicit behavioral contract the script keys off). Keying + off the `data-` attribute rather than the `.relative` utility class keeps + behavior decoupled from presentation, so a later layout change can't break + the toggle silently. - Flip `input.type` between `password` and `text`. - Swap the icon text `visibility` ↔ `visibility_off`. - Swap `aria-label` "Show password" ↔ "Hide password". @@ -147,6 +153,16 @@ type flip, icon swap, `aria-label` swap, Enter/Space activation, no field height shift, and that toggling does not submit the form. Verify the HTMX-swapped login/register partials still toggle after a failed submit. +## Build / deploy constraint + +Tailwind is **compiled, not CDN** (`CLAUDE.md`). The new utility classes +(`pr-12` on password inputs and the toggle button's positioning utilities) +must be compiled into the built stylesheet via `npm run build:css`, and in +production the rebuilt CSS must reach DO Spaces via `collectstatic` — a +template/`rsync`-only change ships an unstyled toggle otherwise. `data-pw-*` +are attributes, not classes, so they need no CSS. This is an implementation +step (plan Task 5), recorded here so the constraint isn't lost. + ## Out of scope Password strength meter; "remember password" UI; biometric/autofill changes; From c21820f61e01d55282aaab970c26f14410b52d06 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 22:46:47 +0100 Subject: [PATCH 06/13] refactor: harden toggle contract + drop premature import Key the script off a semantic data-pw-wrapper attribute instead of the .relative presentation class (silent-failure risk), remove the unused default_token_generator import (F401/I001), and add a test for the HTMX partial-swap path. NB-1. --- .../account/partials/login_form.html | 2 +- account/tests.py | 19 ++++++++++++++++++- templates/snippets/password_toggle_js.html | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/account/templates/account/partials/login_form.html b/account/templates/account/partials/login_form.html index b0a51e9..5a28462 100644 --- a/account/templates/account/partials/login_form.html +++ b/account/templates/account/partials/login_form.html @@ -18,7 +18,7 @@
{% if field.field.widget.input_type == 'password' %} -
+
Date: Sat, 16 May 2026 22:52:10 +0100 Subject: [PATCH 07/13] feat: password visibility toggle on register form Both password fields wrapped with the shared toggle. NB-1. --- .../templates/account/partials/register_form.html | 12 ++++++++++++ account/tests.py | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/account/templates/account/partials/register_form.html b/account/templates/account/partials/register_form.html index 2455dcf..f82a8d9 100644 --- a/account/templates/account/partials/register_form.html +++ b/account/templates/account/partials/register_form.html @@ -13,11 +13,22 @@ {% for field in registration_form %}
+ {% if field.field.widget.input_type == 'password' %} +
+ + {% include 'snippets/password_toggle.html' %} +
+ {% else %} + {% endif %} {% for error in field.errors %}

{{ error }}

{% endfor %} @@ -28,3 +39,4 @@

By creating an account, you agree to our Terms and Privacy Policy

+{% include 'snippets/password_toggle_js.html' %} diff --git a/account/tests.py b/account/tests.py index 3039b6f..8a9d416 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1260,3 +1260,12 @@ def test_login_htmx_partial_swap_has_toggle_and_script(self): body = resp.content.decode() self.assertEqual(body.count('aria-label="Show password"'), 1) self.assertIn('__pwToggleBound', body) + + def test_register_page_has_two_password_toggles(self): + resp = self.client.get(reverse('register')) + self.assertEqual(resp.status_code, 200) + body = resp.content.decode() + # RegistrationForm exposes password1 + password2. Count by + # aria-label (markup-only token), not `data-pw-toggle` which + # also appears in the delegated script's selector. + self.assertEqual(body.count('aria-label="Show password"'), 2) From 634383866ffa42e44ae25a99d70c7c7744c551bb Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 16 May 2026 23:56:18 +0100 Subject: [PATCH 08/13] feat: password visibility toggle on change-password form All three password fields wrapped with the shared toggle. NB-1. --- account/tests.py | 8 ++++++++ templates/registration/password_change.html | 22 +++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/account/tests.py b/account/tests.py index 8a9d416..15e3d6a 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1269,3 +1269,11 @@ def test_register_page_has_two_password_toggles(self): # aria-label (markup-only token), not `data-pw-toggle` which # also appears in the delegated script's selector. self.assertEqual(body.count('aria-label="Show password"'), 2) + + def test_password_change_page_has_three_toggles(self): + self.client.force_login(self.user) + resp = self.client.get(reverse('password_change')) + self.assertEqual(resp.status_code, 200) + body = resp.content.decode() + # Count by aria-label (markup-only token), not `data-pw-toggle`. + self.assertEqual(body.count('aria-label="Show password"'), 3) diff --git a/templates/registration/password_change.html b/templates/registration/password_change.html index 80e289e..7ff80a9 100644 --- a/templates/registration/password_change.html +++ b/templates/registration/password_change.html @@ -14,18 +14,27 @@

Change Password

{% csrf_token %}
- +
+ + {% include 'snippets/password_toggle.html' %} +
- +
+ + {% include 'snippets/password_toggle.html' %} +
- +
+ + {% include 'snippets/password_toggle.html' %} +
{% for field in form %} @@ -38,4 +47,5 @@

Change Password

+{% include 'snippets/password_toggle_js.html' %} {% endblock content %} From 1b77c34155f2dfc01e8b5c442b7a8a0e048a3cf4 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 May 2026 00:05:22 +0100 Subject: [PATCH 09/13] feat: branded password_reset_confirm page with toggle Replaces the Django-admin fallback with a base.html-styled page; both new-password fields wrapped with the shared toggle. NB-1. --- account/tests.py | 17 +++++++ .../registration/password_reset_confirm.html | 51 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 templates/registration/password_reset_confirm.html diff --git a/account/tests.py b/account/tests.py index 15e3d6a..015b0b9 100644 --- a/account/tests.py +++ b/account/tests.py @@ -3,6 +3,7 @@ from unittest.mock import patch from django.conf import settings +from django.contrib.auth.tokens import default_token_generator from django.core import mail from django.core.cache import cache from django.core.mail import get_connection @@ -1277,3 +1278,19 @@ def test_password_change_page_has_three_toggles(self): body = resp.content.decode() # Count by aria-label (markup-only token), not `data-pw-toggle`. self.assertEqual(body.count('aria-label="Show password"'), 3) + + def test_password_reset_confirm_is_branded_with_two_toggles(self): + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + token = default_token_generator.make_token(self.user) + resp = self.client.get( + reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token}), + follow=True, + ) + self.assertEqual(resp.status_code, 200) + self.assertTemplateUsed(resp, 'registration/password_reset_confirm.html') + body = resp.content.decode() + # Branded: extends base.html, so the site name is present (admin + # fallback would not contain it). + self.assertIn('NyasaBlog', body) + # Count by aria-label (markup-only token), not `data-pw-toggle`. + self.assertEqual(body.count('aria-label="Show password"'), 2) diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html new file mode 100644 index 0000000..8e7b038 --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,51 @@ +{% extends 'base.html' %} + +{% block title %}Set New Password | NyasaBlog{% endblock %} + +{% block content %} +
+
+
+ lock_reset +

Set a new password

+
+ + {% if validlink %} +
+ {% csrf_token %} +
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+
+ +
+ + {% include 'snippets/password_toggle.html' %} +
+
+ + {% for field in form %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} + + +
+ {% else %} +

+ This password reset link is invalid or has expired. Please + request a new one. +

+ {% endif %} + + {% include 'snippets/password_toggle_js.html' %} +
+
+{% endblock content %} From 4cda12882e57e1ead30dde796f6c707804e9e013 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 May 2026 00:13:22 +0100 Subject: [PATCH 10/13] style: move JS include outside card to match password_change Mirrors templates/registration/password_change.html structure; no behavioral change. NB-1. --- templates/registration/password_reset_confirm.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html index 8e7b038..9665262 100644 --- a/templates/registration/password_reset_confirm.html +++ b/templates/registration/password_reset_confirm.html @@ -45,7 +45,7 @@

Set a new password

{% endif %} - {% include 'snippets/password_toggle_js.html' %}
+{% include 'snippets/password_toggle_js.html' %} {% endblock content %} From 49f536754f8bfb0c02e0932dc95aeac495832e85 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 May 2026 00:21:10 +0100 Subject: [PATCH 11/13] chore: rebuild Tailwind CSS for password toggle classes NB-1 adds pr-12 and the toggle button positioning utilities; compile them into the built stylesheet so the feature is styled in prod. --- static/css/tailwind.min.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/tailwind.min.css b/static/css/tailwind.min.css index 52581a9..028d8ec 100644 --- a/static/css/tailwind.min.css +++ b/static/css/tailwind.min.css @@ -1 +1 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}input:where(:not([type])),input:where([type=date]),input:where([type=datetime-local]),input:where([type=email]),input:where([type=month]),input:where([type=number]),input:where([type=password]),input:where([type=search]),input:where([type=tel]),input:where([type=text]),input:where([type=time]),input:where([type=url]),input:where([type=week]),select,select:where([multiple]),textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}input:where(:not([type])):focus,input:where([type=date]):focus,input:where([type=datetime-local]):focus,input:where([type=email]):focus,input:where([type=month]):focus,input:where([type=number]):focus,input:where([type=password]):focus,input:where([type=search]):focus,input:where([type=tel]):focus,input:where([type=text]):focus,input:where([type=time]):focus,input:where([type=url]):focus,input:where([type=week]):focus,select:focus,select:where([multiple]):focus,textarea:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}select:where([multiple]),select:where([size]:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}input:where([type=checkbox]),input:where([type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}input:where([type=checkbox]){border-radius:0}input:where([type=radio]){border-radius:100%}input:where([type=checkbox]):focus,input:where([type=radio]):focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}input:where([type=checkbox]):checked,input:where([type=radio]):checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}input:where([type=checkbox]):checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0'/%3E%3C/svg%3E")}@media (forced-colors:active) {input:where([type=checkbox]):checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=radio]):checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}@media (forced-colors:active) {input:where([type=radio]):checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=checkbox]):checked:focus,input:where([type=checkbox]):checked:hover,input:where([type=radio]):checked:focus,input:where([type=radio]):checked:hover{border-color:transparent;background-color:currentColor}input:where([type=checkbox]):indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media (forced-colors:active) {input:where([type=checkbox]):indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=checkbox]):indeterminate:focus,input:where([type=checkbox]):indeterminate:hover{border-color:transparent;background-color:currentColor}input:where([type=file]){background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}input:where([type=file]):focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:var(--color-on-surface);--tw-prose-headings:var(--color-on-surface);--tw-prose-lead:var(--color-on-surface-variant);--tw-prose-links:var(--color-primary);--tw-prose-bold:var(--color-on-surface);--tw-prose-counters:var(--color-on-surface-variant);--tw-prose-bullets:var(--color-outline);--tw-prose-hr:var(--color-outline-variant);--tw-prose-quotes:var(--color-on-surface);--tw-prose-quote-borders:var(--color-primary);--tw-prose-captions:var(--color-on-surface-variant);--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:var(--color-on-surface);--tw-prose-pre-code:var(--color-on-surface);--tw-prose-pre-bg:var(--color-surface-container);--tw-prose-th-borders:var(--color-outline);--tw-prose-td-borders:var(--color-outline-variant);--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-lg{font-size:1.125rem;line-height:1.6}.prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-top:1.0909091em;margin-bottom:1.0909091em}.prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6666667em;margin-bottom:1.6666667em;padding-inline-start:1em}.prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.6666667em;margin-top:0;margin-bottom:.8333333em;line-height:1}.prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.6666667em;margin-top:1.6em;margin-bottom:.8em;line-height:1.3333333}.prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.3333333em;margin-top:1.4em;margin-bottom:.5em;line-height:1.5}.prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:.4444444em;line-height:1.5555556}.prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-lg :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;border-radius:.3125rem;padding-top:.2222222em;padding-inline-end:.4444444em;padding-bottom:.2222222em;padding-inline-start:.4444444em}.prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8666667em}.prose-lg :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-lg :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.75;margin-top:2em;margin-bottom:2em;border-radius:.375rem;padding-top:1em;padding-inline-end:1.5em;padding-bottom:1em;padding-inline-start:1.5em}.prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;margin-bottom:.6666667em}.prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(.prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.prose-lg :where(.prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;padding-inline-start:1.5555556em}.prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3.1111111em;margin-bottom:3.1111111em}.prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.prose-lg :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.75em;padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-lg :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.prose-lg :where(.prose-lg>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(.prose-lg>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-bottom-3{bottom:-.75rem}.bottom-0{bottom:0}.bottom-24{bottom:6rem}.left-0{left:0}.left-3{left:.75rem}.right-0{right:0}.right-3{right:.75rem}.right-6{right:1.5rem}.top-0{top:0}.top-1\/2{top:50%}.top-20{top:5rem}.top-28{top:7rem}.top-3{top:.75rem}.top-full{top:100%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.col-span-1{grid-column:span 1/span 1}.col-span-full{grid-column:1/-1}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-mt-16{margin-top:-4rem}.-mt-24{margin-top:-6rem}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-8{margin-left:2rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-1{-webkit-line-clamp:1}.line-clamp-1,.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.line-clamp-2{-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-\[21\/9\]{aspect-ratio:21/9}.aspect-video{aspect-ratio:16/9}.h-1{height:.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2\.5{height:.625rem}.h-24{height:6rem}.h-3{height:.75rem}.h-32{height:8rem}.h-48{height:12rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[120px\]{height:120px}.h-\[200px\]{height:200px}.h-\[2px\]{height:2px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-px{height:1px}.max-h-0{max-height:0}.max-h-48{max-height:12rem}.max-h-96{max-height:24rem}.min-h-\[500px\]{min-height:500px}.min-h-\[50vh\]{min-height:50vh}.min-h-\[60vh\]{min-height:60vh}.min-h-\[70vh\]{min-height:70vh}.min-h-screen{min-height:100vh}.w-0{width:0}.w-1{width:.25rem}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-48{width:12rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[1px\]{width:1px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[280px\]{min-width:280px}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[1280px\]{max-width:1280px}.max-w-\[1440px\]{max-width:1440px}.max-w-\[65ch\]{max-width:65ch}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.scroll-mt-28{scroll-margin-top:7rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-10{gap:2.5rem}.gap-12{gap:3rem}.gap-16{gap:4rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem*var(--tw-space-y-reverse))}.space-y-12>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(3rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.rounded-t-\[10px\]{border-top-left-radius:10px;border-top-right-radius:10px}.border{border-width:1px}.border-2{border-width:2px}.border-4{border-width:4px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-error{border-color:var(--color-error)}.border-primary-container{border-color:var(--color-primary-container)}.border-surface-container-lowest{border-color:var(--color-surface-container-lowest)}.bg-\[\#002627\]{--tw-bg-opacity:1;background-color:rgb(0 38 39/var(--tw-bg-opacity,1))}.bg-\[\#0f3d3e\]{--tw-bg-opacity:1;background-color:rgb(15 61 62/var(--tw-bg-opacity,1))}.bg-\[\#1877F2\]{--tw-bg-opacity:1;background-color:rgb(24 119 242/var(--tw-bg-opacity,1))}.bg-\[\#1DA1F2\]{--tw-bg-opacity:1;background-color:rgb(29 161 242/var(--tw-bg-opacity,1))}.bg-\[\#25D366\]{--tw-bg-opacity:1;background-color:rgb(37 211 102/var(--tw-bg-opacity,1))}.bg-\[\#beebeb\]{--tw-bg-opacity:1;background-color:rgb(190 235 235/var(--tw-bg-opacity,1))}.bg-background{background-color:var(--color-background)}.bg-error{background-color:var(--color-error)}.bg-error-container{background-color:var(--color-error-container)}.bg-outline-variant{background-color:var(--color-outline-variant)}.bg-primary{background-color:var(--color-primary)}.bg-primary-container{background-color:var(--color-primary-container)}.bg-primary-fixed{background-color:var(--color-primary-fixed)}.bg-secondary{background-color:var(--color-secondary)}.bg-surface-container{background-color:var(--color-surface-container)}.bg-surface-container-high{background-color:var(--color-surface-container-high)}.bg-surface-container-low{background-color:var(--color-surface-container-low)}.bg-surface-container-lowest{background-color:var(--color-surface-container-lowest)}.bg-tertiary-container{background-color:var(--color-tertiary-container)}.bg-tertiary-fixed-dim{background-color:var(--color-tertiary-fixed-dim)}.bg-transparent{background-color:transparent}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-\[\#002627\]{--tw-gradient-from:#002627 var(--tw-gradient-from-position);--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#002627\]\/90{--tw-gradient-from:rgba(0,38,39,.9) var(--tw-gradient-from-position);--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-black\/20{--tw-gradient-from:rgba(0,0,0,.2) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-black\/40{--tw-gradient-from:rgba(0,0,0,.4) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-\[\#002627\]\/20{--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(0,38,39,.2) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-\[\#0f3d3e\]{--tw-gradient-to:#0f3d3e var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-12{padding-bottom:3rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pl-4{padding-left:1rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-12{padding-top:3rem}.pt-2{padding-top:.5rem}.pt-24{padding-top:6rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-body{font-family:Inter,sans-serif}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-6xl{font-size:3.75rem;line-height:1}.text-7xl{font-size:4.5rem;line-height:1}.text-\[10px\]{font-size:10px}.text-\[10rem\]{font-size:10rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[\#002627\]{--tw-text-opacity:1;color:rgb(0 38 39/var(--tw-text-opacity,1))}.text-\[\#25D366\]{--tw-text-opacity:1;color:rgb(37 211 102/var(--tw-text-opacity,1))}.text-\[\#a3cfcf\]{--tw-text-opacity:1;color:rgb(163 207 207/var(--tw-text-opacity,1))}.text-error{color:var(--color-error)}.text-on-error{color:var(--color-on-error)}.text-on-error-container{color:var(--color-on-error-container)}.text-on-primary{color:var(--color-on-primary)}.text-on-primary-container{color:var(--color-on-primary-container)}.text-on-primary-fixed{--tw-text-opacity:1;color:rgb(0 32 32/var(--tw-text-opacity,1))}.text-on-secondary{color:var(--color-on-secondary)}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-variant{color:var(--color-on-surface-variant)}.text-on-tertiary{color:var(--color-on-tertiary)}.text-on-tertiary-fixed{color:var(--color-on-tertiary-fixed)}.text-outline{color:var(--color-outline)}.text-outline-variant{color:var(--color-outline-variant)}.text-primary{color:var(--color-primary)}.text-secondary{color:var(--color-secondary)}.text-surface-container-high{color:var(--color-surface-container-high)}.text-surface-container-highest{color:var(--color-surface-container-highest)}.text-tertiary{color:var(--color-tertiary)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-white\/80{color:hsla(0,0%,100%,.8)}.text-white\/90{color:hsla(0,0%,100%,.9)}.underline{text-decoration-line:underline}.decoration-2{text-decoration-thickness:2px}.underline-offset-4{text-underline-offset:4px}.placeholder-outline-variant::-moz-placeholder{color:var(--color-outline-variant)}.placeholder-outline-variant::placeholder{color:var(--color-outline-variant)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-xl{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur:blur(24px)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.selection\:bg-secondary-container ::-moz-selection{background-color:var(--color-secondary-container)}.selection\:bg-secondary-container ::selection{background-color:var(--color-secondary-container)}.selection\:text-on-secondary-container ::-moz-selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:text-on-secondary-container ::selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:bg-secondary-container::-moz-selection{background-color:var(--color-secondary-container)}.selection\:bg-secondary-container::selection{background-color:var(--color-secondary-container)}.selection\:text-on-secondary-container::-moz-selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:text-on-secondary-container::selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.placeholder\:text-outline-variant::-moz-placeholder{color:var(--color-outline-variant)}.placeholder\:text-outline-variant::placeholder{color:var(--color-outline-variant)}.placeholder\:text-white\/50::-moz-placeholder{color:hsla(0,0%,100%,.5)}.placeholder\:text-white\/50::placeholder{color:hsla(0,0%,100%,.5)}.empty\:hidden:empty{display:none}.hover\:-translate-y-1:hover{--tw-translate-y:-0.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-primary:hover{background-color:var(--color-primary)}.hover\:bg-secondary-container:hover{background-color:var(--color-secondary-container)}.hover\:bg-surface-container:hover{background-color:var(--color-surface-container)}.hover\:bg-surface-container-highest:hover{background-color:var(--color-surface-container-highest)}.hover\:bg-surface-container-low:hover{background-color:var(--color-surface-container-low)}.hover\:text-error:hover{color:var(--color-error)}.hover\:text-on-primary:hover{color:var(--color-on-primary)}.hover\:text-primary:hover{color:var(--color-primary)}.hover\:text-primary-container:hover{color:var(--color-primary-container)}.hover\:text-secondary:hover{color:var(--color-secondary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.focus\:border-secondary:focus{border-color:var(--color-secondary)}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-tertiary-fixed-dim:focus{--tw-ring-color:var(--color-tertiary-fixed-dim)}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-within .group-focus-within\:w-full{width:100%}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-primary{color:var(--color-primary)}.group:hover .group-hover\:text-primary-container{color:var(--color-primary-container)}.group:hover .group-hover\:text-secondary{color:var(--color-secondary)}.group:hover .group-hover\:text-tertiary-fixed-dim{color:var(--color-tertiary-fixed-dim)}.aria-selected\:bg-surface-container-low[aria-selected=true]{background-color:var(--color-surface-container-low)}@media (prefers-reduced-motion:no-preference){.motion-safe\:transition-\[max-height\2c opacity\]{transition-property:max-height,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.motion-safe\:transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.motion-safe\:duration-300{transition-duration:.3s}.motion-safe\:ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.motion-safe\:hover\:rotate-12:hover{--tw-rotate:12deg}.motion-safe\:hover\:rotate-12:hover,.motion-safe\:hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.motion-safe\:active\:scale-90:active{--tw-scale-x:.9;--tw-scale-y:.9}.motion-safe\:active\:scale-90:active,.motion-safe\:active\:scale-95:active{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95}.motion-safe\:active\:scale-\[0\.97\]:active{--tw-scale-x:0.97;--tw-scale-y:0.97}.motion-safe\:active\:scale-\[0\.97\]:active,.motion-safe\:active\:scale-\[0\.98\]:active{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:active\:scale-\[0\.98\]:active{--tw-scale-x:0.98;--tw-scale-y:0.98}}@media (min-width:768px){.md\:col-span-2{grid-column:span 2/span 2}.md\:mb-16{margin-bottom:4rem}.md\:ml-auto{margin-left:auto}.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-20{height:5rem}.md\:h-32{height:8rem}.md\:h-40{height:10rem}.md\:h-\[180px\]{height:180px}.md\:h-\[320px\]{height:320px}.md\:h-full{height:100%}.md\:w-32{width:8rem}.md\:w-40{width:10rem}.md\:w-64{width:16rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:gap-12{gap:3rem}.md\:gap-6{gap:1.5rem}.md\:gap-8{gap:2rem}.md\:p-10{padding:2.5rem}.md\:p-12{padding:3rem}.md\:p-8{padding:2rem}.md\:px-12{padding-left:3rem;padding-right:3rem}.md\:text-left{text-align:left}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-7xl{font-size:4.5rem;line-height:1}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:top-28{top:7rem}.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-4{grid-column:span 4/span 4}.lg\:col-span-8{grid-column:span 8/span 8}.lg\:col-span-9{grid-column:span 9/span 9}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-2\/3{width:66.666667%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:text-5xl{font-size:3rem;line-height:1}} \ No newline at end of file +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}input:where(:not([type])),input:where([type=date]),input:where([type=datetime-local]),input:where([type=email]),input:where([type=month]),input:where([type=number]),input:where([type=password]),input:where([type=search]),input:where([type=tel]),input:where([type=text]),input:where([type=time]),input:where([type=url]),input:where([type=week]),select,select:where([multiple]),textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}input:where(:not([type])):focus,input:where([type=date]):focus,input:where([type=datetime-local]):focus,input:where([type=email]):focus,input:where([type=month]):focus,input:where([type=number]):focus,input:where([type=password]):focus,input:where([type=search]):focus,input:where([type=tel]):focus,input:where([type=text]):focus,input:where([type=time]):focus,input:where([type=url]):focus,input:where([type=week]):focus,select:focus,select:where([multiple]):focus,textarea:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}select:where([multiple]),select:where([size]:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}input:where([type=checkbox]),input:where([type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}input:where([type=checkbox]){border-radius:0}input:where([type=radio]){border-radius:100%}input:where([type=checkbox]):focus,input:where([type=radio]):focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}input:where([type=checkbox]):checked,input:where([type=radio]):checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}input:where([type=checkbox]):checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0'/%3E%3C/svg%3E")}@media (forced-colors:active) {input:where([type=checkbox]):checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=radio]):checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}@media (forced-colors:active) {input:where([type=radio]):checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=checkbox]):checked:focus,input:where([type=checkbox]):checked:hover,input:where([type=radio]):checked:focus,input:where([type=radio]):checked:hover{border-color:transparent;background-color:currentColor}input:where([type=checkbox]):indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media (forced-colors:active) {input:where([type=checkbox]):indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}input:where([type=checkbox]):indeterminate:focus,input:where([type=checkbox]):indeterminate:hover{border-color:transparent;background-color:currentColor}input:where([type=file]){background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}input:where([type=file]):focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:var(--color-on-surface);--tw-prose-headings:var(--color-on-surface);--tw-prose-lead:var(--color-on-surface-variant);--tw-prose-links:var(--color-primary);--tw-prose-bold:var(--color-on-surface);--tw-prose-counters:var(--color-on-surface-variant);--tw-prose-bullets:var(--color-outline);--tw-prose-hr:var(--color-outline-variant);--tw-prose-quotes:var(--color-on-surface);--tw-prose-quote-borders:var(--color-primary);--tw-prose-captions:var(--color-on-surface-variant);--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:var(--color-on-surface);--tw-prose-pre-code:var(--color-on-surface);--tw-prose-pre-bg:var(--color-surface-container);--tw-prose-th-borders:var(--color-outline);--tw-prose-td-borders:var(--color-outline-variant);--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-lg{font-size:1.125rem;line-height:1.6}.prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-top:1.0909091em;margin-bottom:1.0909091em}.prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6666667em;margin-bottom:1.6666667em;padding-inline-start:1em}.prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.6666667em;margin-top:0;margin-bottom:.8333333em;line-height:1}.prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.6666667em;margin-top:1.6em;margin-bottom:.8em;line-height:1.3333333}.prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.3333333em;margin-top:1.4em;margin-bottom:.5em;line-height:1.5}.prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:.4444444em;line-height:1.5555556}.prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-lg :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;border-radius:.3125rem;padding-top:.2222222em;padding-inline-end:.4444444em;padding-bottom:.2222222em;padding-inline-start:.4444444em}.prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8666667em}.prose-lg :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-lg :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.75;margin-top:2em;margin-bottom:2em;border-radius:.375rem;padding-top:1em;padding-inline-end:1.5em;padding-bottom:1em;padding-inline-start:1.5em}.prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;margin-bottom:.6666667em}.prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(.prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.prose-lg :where(.prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;padding-inline-start:1.5555556em}.prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3.1111111em;margin-bottom:3.1111111em}.prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.prose-lg :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.75em;padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.prose-lg :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-lg :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.prose-lg :where(.prose-lg>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(.prose-lg>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-bottom-3{bottom:-.75rem}.bottom-0{bottom:0}.bottom-24{bottom:6rem}.left-0{left:0}.left-3{left:.75rem}.right-0{right:0}.right-3{right:.75rem}.right-6{right:1.5rem}.top-0{top:0}.top-1\/2{top:50%}.top-20{top:5rem}.top-28{top:7rem}.top-3{top:.75rem}.top-full{top:100%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.col-span-1{grid-column:span 1/span 1}.col-span-full{grid-column:1/-1}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-mt-16{margin-top:-4rem}.-mt-24{margin-top:-6rem}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-8{margin-left:2rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-1{-webkit-line-clamp:1}.line-clamp-1,.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.line-clamp-2{-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-\[21\/9\]{aspect-ratio:21/9}.aspect-video{aspect-ratio:16/9}.h-1{height:.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2\.5{height:.625rem}.h-24{height:6rem}.h-3{height:.75rem}.h-32{height:8rem}.h-48{height:12rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[120px\]{height:120px}.h-\[200px\]{height:200px}.h-\[2px\]{height:2px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-px{height:1px}.max-h-0{max-height:0}.max-h-48{max-height:12rem}.max-h-96{max-height:24rem}.min-h-\[500px\]{min-height:500px}.min-h-\[50vh\]{min-height:50vh}.min-h-\[60vh\]{min-height:60vh}.min-h-\[70vh\]{min-height:70vh}.min-h-screen{min-height:100vh}.w-0{width:0}.w-1{width:.25rem}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-48{width:12rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[1px\]{width:1px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[280px\]{min-width:280px}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[1280px\]{max-width:1280px}.max-w-\[1440px\]{max-width:1440px}.max-w-\[65ch\]{max-width:65ch}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.scroll-mt-28{scroll-margin-top:7rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-10{gap:2.5rem}.gap-12{gap:3rem}.gap-16{gap:4rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem*var(--tw-space-y-reverse))}.space-y-12>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(3rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.rounded-t-\[10px\]{border-top-left-radius:10px;border-top-right-radius:10px}.border{border-width:1px}.border-2{border-width:2px}.border-4{border-width:4px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-error{border-color:var(--color-error)}.border-primary-container{border-color:var(--color-primary-container)}.border-surface-container-lowest{border-color:var(--color-surface-container-lowest)}.bg-\[\#002627\]{--tw-bg-opacity:1;background-color:rgb(0 38 39/var(--tw-bg-opacity,1))}.bg-\[\#0f3d3e\]{--tw-bg-opacity:1;background-color:rgb(15 61 62/var(--tw-bg-opacity,1))}.bg-\[\#1877F2\]{--tw-bg-opacity:1;background-color:rgb(24 119 242/var(--tw-bg-opacity,1))}.bg-\[\#1DA1F2\]{--tw-bg-opacity:1;background-color:rgb(29 161 242/var(--tw-bg-opacity,1))}.bg-\[\#25D366\]{--tw-bg-opacity:1;background-color:rgb(37 211 102/var(--tw-bg-opacity,1))}.bg-\[\#beebeb\]{--tw-bg-opacity:1;background-color:rgb(190 235 235/var(--tw-bg-opacity,1))}.bg-background{background-color:var(--color-background)}.bg-error{background-color:var(--color-error)}.bg-error-container{background-color:var(--color-error-container)}.bg-outline-variant{background-color:var(--color-outline-variant)}.bg-primary{background-color:var(--color-primary)}.bg-primary-container{background-color:var(--color-primary-container)}.bg-primary-fixed{background-color:var(--color-primary-fixed)}.bg-secondary{background-color:var(--color-secondary)}.bg-surface-container{background-color:var(--color-surface-container)}.bg-surface-container-high{background-color:var(--color-surface-container-high)}.bg-surface-container-low{background-color:var(--color-surface-container-low)}.bg-surface-container-lowest{background-color:var(--color-surface-container-lowest)}.bg-tertiary-container{background-color:var(--color-tertiary-container)}.bg-tertiary-fixed-dim{background-color:var(--color-tertiary-fixed-dim)}.bg-transparent{background-color:transparent}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-\[\#002627\]{--tw-gradient-from:#002627 var(--tw-gradient-from-position);--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#002627\]\/90{--tw-gradient-from:rgba(0,38,39,.9) var(--tw-gradient-from-position);--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-black\/20{--tw-gradient-from:rgba(0,0,0,.2) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-black\/40{--tw-gradient-from:rgba(0,0,0,.4) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-\[\#002627\]\/20{--tw-gradient-to:rgba(0,38,39,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(0,38,39,.2) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-\[\#0f3d3e\]{--tw-gradient-to:#0f3d3e var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-12{padding-bottom:3rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pl-4{padding-left:1rem}.pr-12{padding-right:3rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-12{padding-top:3rem}.pt-2{padding-top:.5rem}.pt-24{padding-top:6rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-body{font-family:Inter,sans-serif}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-6xl{font-size:3.75rem;line-height:1}.text-7xl{font-size:4.5rem;line-height:1}.text-\[10px\]{font-size:10px}.text-\[10rem\]{font-size:10rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[\#002627\]{--tw-text-opacity:1;color:rgb(0 38 39/var(--tw-text-opacity,1))}.text-\[\#25D366\]{--tw-text-opacity:1;color:rgb(37 211 102/var(--tw-text-opacity,1))}.text-\[\#a3cfcf\]{--tw-text-opacity:1;color:rgb(163 207 207/var(--tw-text-opacity,1))}.text-error{color:var(--color-error)}.text-on-error{color:var(--color-on-error)}.text-on-error-container{color:var(--color-on-error-container)}.text-on-primary{color:var(--color-on-primary)}.text-on-primary-container{color:var(--color-on-primary-container)}.text-on-primary-fixed{--tw-text-opacity:1;color:rgb(0 32 32/var(--tw-text-opacity,1))}.text-on-secondary{color:var(--color-on-secondary)}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-variant{color:var(--color-on-surface-variant)}.text-on-tertiary{color:var(--color-on-tertiary)}.text-on-tertiary-fixed{color:var(--color-on-tertiary-fixed)}.text-outline{color:var(--color-outline)}.text-outline-variant{color:var(--color-outline-variant)}.text-primary{color:var(--color-primary)}.text-secondary{color:var(--color-secondary)}.text-surface-container-high{color:var(--color-surface-container-high)}.text-surface-container-highest{color:var(--color-surface-container-highest)}.text-tertiary{color:var(--color-tertiary)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-white\/80{color:hsla(0,0%,100%,.8)}.text-white\/90{color:hsla(0,0%,100%,.9)}.underline{text-decoration-line:underline}.decoration-2{text-decoration-thickness:2px}.underline-offset-4{text-underline-offset:4px}.placeholder-outline-variant::-moz-placeholder{color:var(--color-outline-variant)}.placeholder-outline-variant::placeholder{color:var(--color-outline-variant)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-xl{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur:blur(24px)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.selection\:bg-secondary-container ::-moz-selection{background-color:var(--color-secondary-container)}.selection\:bg-secondary-container ::selection{background-color:var(--color-secondary-container)}.selection\:text-on-secondary-container ::-moz-selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:text-on-secondary-container ::selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:bg-secondary-container::-moz-selection{background-color:var(--color-secondary-container)}.selection\:bg-secondary-container::selection{background-color:var(--color-secondary-container)}.selection\:text-on-secondary-container::-moz-selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.selection\:text-on-secondary-container::selection{--tw-text-opacity:1;color:rgb(29 57 137/var(--tw-text-opacity,1))}.placeholder\:text-outline-variant::-moz-placeholder{color:var(--color-outline-variant)}.placeholder\:text-outline-variant::placeholder{color:var(--color-outline-variant)}.placeholder\:text-white\/50::-moz-placeholder{color:hsla(0,0%,100%,.5)}.placeholder\:text-white\/50::placeholder{color:hsla(0,0%,100%,.5)}.empty\:hidden:empty{display:none}.hover\:-translate-y-1:hover{--tw-translate-y:-0.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-primary:hover{background-color:var(--color-primary)}.hover\:bg-secondary-container:hover{background-color:var(--color-secondary-container)}.hover\:bg-surface-container:hover{background-color:var(--color-surface-container)}.hover\:bg-surface-container-highest:hover{background-color:var(--color-surface-container-highest)}.hover\:bg-surface-container-low:hover{background-color:var(--color-surface-container-low)}.hover\:text-error:hover{color:var(--color-error)}.hover\:text-on-primary:hover{color:var(--color-on-primary)}.hover\:text-primary:hover{color:var(--color-primary)}.hover\:text-primary-container:hover{color:var(--color-primary-container)}.hover\:text-secondary:hover{color:var(--color-secondary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.focus\:border-secondary:focus{border-color:var(--color-secondary)}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-tertiary-fixed-dim:focus{--tw-ring-color:var(--color-tertiary-fixed-dim)}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-within .group-focus-within\:w-full{width:100%}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-primary{color:var(--color-primary)}.group:hover .group-hover\:text-primary-container{color:var(--color-primary-container)}.group:hover .group-hover\:text-secondary{color:var(--color-secondary)}.group:hover .group-hover\:text-tertiary-fixed-dim{color:var(--color-tertiary-fixed-dim)}.aria-selected\:bg-surface-container-low[aria-selected=true]{background-color:var(--color-surface-container-low)}@media (prefers-reduced-motion:no-preference){.motion-safe\:transition-\[max-height\2c opacity\]{transition-property:max-height,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.motion-safe\:transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.motion-safe\:duration-300{transition-duration:.3s}.motion-safe\:ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.motion-safe\:hover\:rotate-12:hover{--tw-rotate:12deg}.motion-safe\:hover\:rotate-12:hover,.motion-safe\:hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.motion-safe\:active\:scale-90:active{--tw-scale-x:.9;--tw-scale-y:.9}.motion-safe\:active\:scale-90:active,.motion-safe\:active\:scale-95:active{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95}.motion-safe\:active\:scale-\[0\.97\]:active{--tw-scale-x:0.97;--tw-scale-y:0.97}.motion-safe\:active\:scale-\[0\.97\]:active,.motion-safe\:active\:scale-\[0\.98\]:active{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.motion-safe\:active\:scale-\[0\.98\]:active{--tw-scale-x:0.98;--tw-scale-y:0.98}}@media (min-width:768px){.md\:col-span-2{grid-column:span 2/span 2}.md\:mb-16{margin-bottom:4rem}.md\:ml-auto{margin-left:auto}.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-20{height:5rem}.md\:h-32{height:8rem}.md\:h-40{height:10rem}.md\:h-\[180px\]{height:180px}.md\:h-\[320px\]{height:320px}.md\:h-full{height:100%}.md\:w-32{width:8rem}.md\:w-40{width:10rem}.md\:w-64{width:16rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:gap-12{gap:3rem}.md\:gap-6{gap:1.5rem}.md\:gap-8{gap:2rem}.md\:p-10{padding:2.5rem}.md\:p-12{padding:3rem}.md\:p-8{padding:2rem}.md\:px-12{padding-left:3rem;padding-right:3rem}.md\:text-left{text-align:left}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-7xl{font-size:4.5rem;line-height:1}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:top-28{top:7rem}.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-4{grid-column:span 4/span 4}.lg\:col-span-8{grid-column:span 8/span 8}.lg\:col-span-9{grid-column:span 9/span 9}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-2\/3{width:66.666667%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:text-5xl{font-size:3rem;line-height:1}} \ No newline at end of file From df376669671fa7ff0c2acb8f0f76d1010b6dde30 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 May 2026 00:36:29 +0100 Subject: [PATCH 12/13] fix: stop reflecting submitted password; tighten toggle review nits Drop value= on the password input branch so a failed login/register Post no longer echoes the cleartext password into the response HTML (email/username still prefill). Correct the HTMX-partial test docstring and assert a fragment was returned. Render the toggle script only on the valid-link reset-confirm branch. NB-1. --- .../templates/account/partials/login_form.html | 1 - .../account/partials/register_form.html | 1 - account/tests.py | 16 +++++++++------- .../registration/password_reset_confirm.html | 3 +-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/account/templates/account/partials/login_form.html b/account/templates/account/partials/login_form.html index 5a28462..2ec48d2 100644 --- a/account/templates/account/partials/login_form.html +++ b/account/templates/account/partials/login_form.html @@ -21,7 +21,6 @@
{% include 'snippets/password_toggle.html' %} diff --git a/account/templates/account/partials/register_form.html b/account/templates/account/partials/register_form.html index f82a8d9..4ff1800 100644 --- a/account/templates/account/partials/register_form.html +++ b/account/templates/account/partials/register_form.html @@ -17,7 +17,6 @@
{% include 'snippets/password_toggle.html' %} diff --git a/account/tests.py b/account/tests.py index 015b0b9..cd92b5b 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1245,13 +1245,14 @@ def test_login_page_has_exactly_one_password_toggle(self): self.assertIn('type="button"', body) def test_login_htmx_partial_swap_has_toggle_and_script(self): - # Failed credentials with the HX-Request header make login_view - # return the swapped-in partial (account/partials/login_form.html), - # not the full page. This is the path where the script's - # window.__pwToggleBound guard matters, so assert the toggle AND - # the script are present in the fragment. (If django-htmx is not - # active the full page is returned instead — the assertions still - # hold, since the page includes the same partial.) + # Failed credentials + the HX-Request header make login_view return + # the swapped-in partial (account/partials/login_form.html), a bare + # fragment, not the full page. Assert the fragment carries both the + # toggle button and the idempotency-guard script, so an HTMX swap + # delivers everything the delegated handler needs. (assertNotIn + # 'Set a new password + {% include 'snippets/password_toggle_js.html' %} {% else %}

This password reset link is invalid or has expired. Please request a new one.

{% endif %} -
-{% include 'snippets/password_toggle_js.html' %} {% endblock content %} From 4d070e33eba5fa7211cbd59aa54fb9993ede9e54 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 May 2026 00:56:34 +0100 Subject: [PATCH 13/13] fix: allowlist test-fixture passwords for detect-secrets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PasswordToggleTests fixtures (Str0ngPass!9, wrong-password) tripped the detect-secrets pre-commit/CI hook. Mark them with inline `pragma: allowlist secret` (repo convention, as in base.html) rather than baselining them, and commit the hook's refreshed .secrets.baseline (line-number/timestamp bookkeeping only — no new or removed secrets). NB-1. --- .secrets.baseline | 16 ++++++++-------- account/tests.py | 5 +++-- .../2026-05-16-password-visibility-toggle.md | 5 +++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 6000923..8dc1819 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -152,49 +152,49 @@ "filename": "account/tests.py", "hashed_secret": "1c58bd92003bbaa0538e249fff6ee19a270dec5f", "is_verified": false, - "line_number": 74 + "line_number": 75 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "1816851d10187b57a93235b52495e615629f906d", "is_verified": false, - "line_number": 103 + "line_number": 104 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "0fa86f7cd4925d1bc1f299fefdaeb3cede77592f", "is_verified": false, - "line_number": 146 + "line_number": 147 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "d8ecf7db8fc9ec9c31bc5c9ae2929cc599c75f8d", "is_verified": false, - "line_number": 176 + "line_number": 177 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "0d8b28805975effded2c628b96d75cd3b47bbdcf", "is_verified": false, - "line_number": 257 + "line_number": 258 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "1151a8c33d6ae2daf21ad0d466488e707c1c7f8d", "is_verified": false, - "line_number": 281 + "line_number": 282 }, { "type": "Secret Keyword", "filename": "account/tests.py", "hashed_secret": "bdb8465ce041d94a0e490564f2162dcc87d4a46a", "is_verified": false, - "line_number": 289 + "line_number": 290 } ], "blog/tests.py": [ @@ -225,5 +225,5 @@ } ] }, - "generated_at": "2026-05-14T23:21:05Z" + "generated_at": "2026-05-16T23:54:17Z" } diff --git a/account/tests.py b/account/tests.py index cd92b5b..8dd963b 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1225,7 +1225,8 @@ def test_verification_email_from_address_is_a_nyasablog_address(self): class PasswordToggleTests(TestCase): def setUp(self): self.user = Account.objects.create_user( - email='toggle@nyasablog.com', username='toggleuser', password='Str0ngPass!9' + email='toggle@nyasablog.com', username='toggleuser', + password='Str0ngPass!9', # pragma: allowlist secret ) self.user.email_verified = True self.user.save() @@ -1255,7 +1256,7 @@ def test_login_htmx_partial_swap_has_toggle_and_script(self): # inactive.) resp = self.client.post( reverse('login'), - {'email': 'toggle@nyasablog.com', 'password': 'wrong-password'}, + {'email': 'toggle@nyasablog.com', 'password': 'wrong-password'}, # pragma: allowlist secret HTTP_HX_REQUEST='true', ) self.assertEqual(resp.status_code, 200) diff --git a/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md b/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md index 0c22bd3..698295e 100644 --- a/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md +++ b/docs/superpowers/plans/2026-05-16-password-visibility-toggle.md @@ -38,7 +38,8 @@ Append this class to the end of `account/tests.py` (4-space indentation): class PasswordToggleTests(TestCase): def setUp(self): self.user = Account.objects.create_user( - email='toggle@nyasablog.com', username='toggleuser', password='Str0ngPass!9' + email='toggle@nyasablog.com', username='toggleuser', + password='Str0ngPass!9', # pragma: allowlist secret ) self.user.email_verified = True self.user.save() @@ -67,7 +68,7 @@ class PasswordToggleTests(TestCase): # hold, since the page includes the same partial.) resp = self.client.post( reverse('login'), - {'email': 'toggle@nyasablog.com', 'password': 'wrong-password'}, + {'email': 'toggle@nyasablog.com', 'password': 'wrong-password'}, # pragma: allowlist secret HTTP_HX_REQUEST='true', ) self.assertEqual(resp.status_code, 200)