diff --git a/package-lock.json b/package-lock.json index 0d695aa..ed32d6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@opentelemetry/sdk-node": "0.52.1", "@prisma/client": "5.17.0", "@quixo3/prisma-session-store": "3.1.13", + "bcrypt": "5.1.1", "class-transformer": "0.5.1", "class-validator": "0.14.1", "cookie-parser": "1.4.6", @@ -61,6 +62,7 @@ "@nestjs/testing": "10.3.10", "@swc/cli": "0.4.0", "@swc/core": "1.7.0", + "@types/bcrypt": "5.0.2", "@types/cookie-parser": "1.4.7", "@types/express": "4.17.21", "@types/jest": "29.5.12", @@ -2200,6 +2202,75 @@ "node": ">=8" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@microsoft/tsdoc": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", @@ -4928,6 +4999,16 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -5741,6 +5822,12 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -5968,6 +6055,12 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -5989,6 +6082,34 @@ ], "license": "MIT" }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -6206,6 +6327,26 @@ "node": ">=6.0.0" } }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcrypt/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, "node_modules/bignumber.js": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", @@ -6801,6 +6942,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -6993,6 +7143,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -7137,6 +7296,12 @@ "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", "license": "MIT" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -7459,6 +7624,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -7478,6 +7649,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -8779,6 +8959,36 @@ "node": ">=12" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/fs-monkey": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", @@ -8815,6 +9025,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/gaxios": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.0.tgz", @@ -9101,6 +9338,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -10982,6 +11225,37 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -11331,6 +11605,21 @@ "integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==", "license": "MIT" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11365,6 +11654,19 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/oauth": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.0.tgz", @@ -13015,7 +13317,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -13031,7 +13332,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -13043,7 +13343,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -13064,7 +13363,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -13358,6 +13656,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -13994,6 +14298,50 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/terser": { "version": "5.31.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", @@ -14942,6 +15290,15 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index f45ae9e..19048a3 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@opentelemetry/sdk-node": "0.52.1", "@prisma/client": "5.17.0", "@quixo3/prisma-session-store": "3.1.13", + "bcrypt": "5.1.1", "class-transformer": "0.5.1", "class-validator": "0.14.1", "cookie-parser": "1.4.6", @@ -81,6 +82,7 @@ "@nestjs/testing": "10.3.10", "@swc/cli": "0.4.0", "@swc/core": "1.7.0", + "@types/bcrypt": "5.0.2", "@types/cookie-parser": "1.4.7", "@types/express": "4.17.21", "@types/jest": "29.5.12", diff --git a/public/styles.css b/public/styles.css index afc330d..233d223 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1 +1,3390 @@ -/*! tailwindcss v3.4.8 | MIT License | https://tailwindcss.com*/*,:after,:before{-webkit-box-sizing:border-box;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;-webkit-font-feature-settings:normal;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;-webkit-font-feature-settings:normal;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;-webkit-font-feature-settings: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::-webkit-input-placeholder,textarea::-webkit-input-placeholder{opacity:1;color:#9ca3af}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input:-ms-input-placeholder,textarea:-ms-input-placeholder{opacity:1;color:#9ca3af}input::-ms-input-placeholder,textarea::-ms-input-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]{display:none}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;-webkit-transform:rotate(45deg);transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;-webkit-transform:rotate(45deg);transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,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}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select: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:#1c64f2;--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);-webkit-box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#1c64f2}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#6b7280;opacity:1}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#6b7280;opacity:1}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}input[type=time]::-webkit-calendar-picker-indicator{background:none}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' aria-hidden='true' viewBox='0 0 10 6'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 1 4 4 4-4'/%3E%3C/svg%3E");background-position:right .75rem center;background-repeat:no-repeat;background-size:.75em .75em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}:is([dir=rtl]) select:not([size]){background-position:left .75rem center;padding-right:.75rem;padding-left:0}[multiple]{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}[type=checkbox],[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;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0;height:1rem;width:1rem;color:#1c64f2;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[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:#1c64f2;--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);-webkit-box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:.55em .55em;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' aria-hidden='true' viewBox='0 0 16 12'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M1 5.917 5.724 10.5 15 1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:.55em .55em;-webkit-print-color-adjust:exact;print-color-adjust:exact}.dark [type=radio]:checked,[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");background-size:1em 1em}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' aria-hidden='true' viewBox='0 0 16 12'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M.5 6h14'/%3E%3C/svg%3E");background-color:currentColor;border-color:transparent;background-position:50%;background-repeat:no-repeat;background-size:.55em .55em;-webkit-print-color-adjust:exact;print-color-adjust:exact}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::-webkit-file-upload-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::-webkit-file-upload-button:hover{background:#374151}input[type=file]::file-selector-button:hover{background:#374151}:is([dir=rtl]) input[type=file]::-webkit-file-upload-button{padding-right:2rem;padding-left:1rem}:is([dir=rtl]) input[type=file]::file-selector-button{padding-right:2rem;padding-left:1rem}.dark input[type=file]::-webkit-file-upload-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::-webkit-file-upload-button:hover{background:#6b7280}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#1c64f2;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid transparent;outline-offset:2px;--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(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);-webkit-box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#1c64f2;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#3f83f8}input[type=range]::-ms-fill-lower{background:#3f83f8}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;-webkit-transition-duration:.15s;transition-duration:.15s;-webkit-box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{-webkit-transform:translateX(100%);;transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#1c64f2;border-color:#1c64f2}*,: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(63,131,248,.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: }::-webkit-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(63,131,248,.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(63,131,248,.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: }.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}}.format{color:var(--tw-format-body);max-width:65ch}.format :where([class~=lead]):not(:where([class~=not-format] *)){color:var(--tw-format-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.format :where(a):not(:where([class~=not-format] *)){color:var(--tw-format-links);text-decoration:underline;font-weight:500}.format :where(a):not(:where([class~=not-format] *)):hover{text-decoration:none}.format :where(strong):not(:where([class~=not-format] *)){color:var(--tw-format-bold);font-weight:700}.format :where(a strong):not(:where([class~=not-format] *)){color:inherit}.format :where(blockquote strong):not(:where([class~=not-format] *)){color:inherit}.format :where(thead th strong):not(:where([class~=not-format] *)){color:inherit}.format :where(ol):not(:where([class~=not-format] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.format :where(ol[type=A]):not(:where([class~=not-format] *)){list-style-type:upper-alpha}.format :where(ol[type=a]):not(:where([class~=not-format] *)){list-style-type:lower-alpha}.format :where(ol[type=A s]):not(:where([class~=not-format] *)){list-style-type:upper-alpha}.format :where(ol[type=a s]):not(:where([class~=not-format] *)){list-style-type:lower-alpha}.format :where(ol[type=I]):not(:where([class~=not-format] *)){list-style-type:upper-roman}.format :where(ol[type=i]):not(:where([class~=not-format] *)){list-style-type:lower-roman}.format :where(ol[type=I s]):not(:where([class~=not-format] *)){list-style-type:upper-roman}.format :where(ol[type=i s]):not(:where([class~=not-format] *)){list-style-type:lower-roman}.format :where(ol[type="1"]):not(:where([class~=not-format] *)){list-style-type:decimal}.format :where(ul):not(:where([class~=not-format] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.format :where(ol>li):not(:where([class~=not-format] *))::marker{font-weight:400;color:var(--tw-format-counters)}.format :where(ul>li):not(:where([class~=not-format] *))::marker{color:var(--tw-format-bullets)}.format :where(hr):not(:where([class~=not-format] *)){border-color:var(--tw-format-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.format :where(blockquote):not(:where([class~=not-format] *)){font-size:1.1111111em;font-weight:700;font-style:italic;color:var(--tw-format-quotes);quotes:"\201C""\201D""\2018""\2019";margin-bottom:1.6em}.format :where(blockquote):not(:where([class~=not-format] *)):before{content:"";background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='24' fill='none'%3E%3Cpath fill='%239CA3AF' d='M18.69 24v-9.855C18.69 6.54 23.663 1.385 30.666 0l1.326 2.868c-3.242 1.223-5.326 4.85-5.326 7.799H32V24zM0 24v-9.855C0 6.54 4.997 1.384 12 0l1.328 2.868C10.084 4.091 8 7.718 8 10.667h5.31V24z'/%3E%3C/svg%3E");background-repeat:no-repeat;color:var(--tw-format-quotes);width:1.7777778em;height:1.3333333em;display:block;margin-top:1.6em}.format :where(blockquote p:first-of-type):not(:where([class~=not-format] *)):before{content:open-quote}.format :where(blockquote p:last-of-type):not(:where([class~=not-format] *)):after{content:close-quote}.format :where(h1):not(:where([class~=not-format] *)){color:var(--tw-format-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.format :where(h1 strong):not(:where([class~=not-format] *)){font-weight:900;color:inherit}.format :where(h2):not(:where([class~=not-format] *)){color:var(--tw-format-headings);font-weight:700;font-size:1.5em;margin-top:0;margin-bottom:1em;line-height:1.3333333}.format :where(h2 strong):not(:where([class~=not-format] *)){font-weight:800;color:inherit}.format :where(h3):not(:where([class~=not-format] *)){color:var(--tw-format-headings);font-weight:700;font-size:1.25em;margin-top:0;margin-bottom:.6em;line-height:1.6}.format :where(h3 strong):not(:where([class~=not-format] *)){font-weight:800;color:inherit}.format :where(h4):not(:where([class~=not-format] *)){color:var(--tw-format-headings);font-weight:600;margin-top:0;margin-bottom:.5em;line-height:1.5}.format :where(h4 strong):not(:where([class~=not-format] *)){font-weight:700;color:inherit}.format :where(img):not(:where([class~=not-format] *)){margin-top:2em;margin-bottom:2em}.format :where(figure>*):not(:where([class~=not-format] *)){margin-top:0;margin-bottom:0}.format :where(figcaption):not(:where([class~=not-format] *)){color:var(--tw-format-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.format :where(code):not(:where([class~=not-format] *)){color:var(--tw-format-code);font-weight:600;background-color:var(--tw-format-code-bg);padding:.3333333em .5555556em;border-radius:.2222222em;font-size:.875em}.format :where(a code):not(:where([class~=not-format] *)){color:inherit}.format :where(h1 code):not(:where([class~=not-format] *)){color:inherit}.format :where(h2 code):not(:where([class~=not-format] *)){color:inherit;font-size:.875em}.format :where(h3 code):not(:where([class~=not-format] *)){color:inherit;font-size:.9em}.format :where(h4 code):not(:where([class~=not-format] *)){color:inherit}.format :where(blockquote code):not(:where([class~=not-format] *)){color:inherit}.format :where(thead th code):not(:where([class~=not-format] *)){color:inherit}.format :where(pre):not(:where([class~=not-format] *)){color:var(--tw-format-pre-code);background-color:var(--tw-format-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:.8571429em 1.1428571em}.format :where(pre code):not(:where([class~=not-format] *)){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}.format :where(pre code):not(:where([class~=not-format] *)):before{content:none}.format :where(pre code):not(:where([class~=not-format] *)):after{content:none}.format :where(table):not(:where([class~=not-format] *)){width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.format :where(thead):not(:where([class~=not-format] *)){background-color:var(--tw-format-th-bg);border-radius:.2777778em}.format :where(thead th):not(:where([class~=not-format] *)){color:var(--tw-format-headings);font-weight:600;vertical-align:bottom;padding:.5555556em .5714286em .5714286em}.format :where(tbody tr):not(:where([class~=not-format] *)){border-bottom-width:1px;border-bottom-color:var(--tw-format-td-borders)}.format :where(tbody tr:last-child):not(:where([class~=not-format] *)){border-bottom-width:0}.format :where(tbody td):not(:where([class~=not-format] *)){vertical-align:baseline}.format :where(tfoot):not(:where([class~=not-format] *)){border-top-width:1px;border-top-color:var(--tw-format-th-borders)}.format :where(tfoot td):not(:where([class~=not-format] *)){vertical-align:top}.format{--tw-format-body:#6b7280;--tw-format-headings:#111827;--tw-format-lead:#6b7280;--tw-format-links:#4b5563;--tw-format-bold:#111827;--tw-format-counters:#6b7280;--tw-format-bullets:#6b7280;--tw-format-hr:#e5e7eb;--tw-format-quotes:#111827;--tw-format-quote-borders:#e5e7eb;--tw-format-captions:#6b7280;--tw-format-code:#111827;--tw-format-code-bg:#f3f4f6;--tw-format-pre-code:#4b5563;--tw-format-pre-bg:#f3f4f6;--tw-format-th-borders:#e5e7eb;--tw-format-th-bg:#f9fafb;--tw-format-td-borders:#e5e7eb;--tw-format-invert-body:#9ca3af;--tw-format-invert-headings:#fff;--tw-format-invert-lead:#9ca3af;--tw-format-invert-links:#fff;--tw-format-invert-bold:#fff;--tw-format-invert-counters:#9ca3af;--tw-format-invert-bullets:#4b5563;--tw-format-invert-hr:#374151;--tw-format-invert-quotes:#f3f4f6;--tw-format-invert-quote-borders:#374151;--tw-format-invert-captions:#9ca3af;--tw-format-invert-code:#fff;--tw-format-invert-code-bg:#1f2937;--tw-format-invert-pre-code:#d1d5db;--tw-format-invert-pre-bg:#374151;--tw-format-invert-th-borders:#4b5563;--tw-format-invert-td-borders:#374151;--tw-format-invert-th-bg:#374151;font-size:1rem;line-height:1.75}.format :where(p):not(:where([class~=not-format] *)){margin-top:1.25em;margin-bottom:1.25em}.format :where(blockquote>p:first-child):not(:where([class~=not-format] *)){margin-top:0}.format :where(video):not(:where([class~=not-format] *)){margin-top:2em;margin-bottom:2em}.format :where(figure):not(:where([class~=not-format] *)){margin-top:2em;margin-bottom:2em}.format :where(li):not(:where([class~=not-format] *)){margin-top:.5em;margin-bottom:.5em}.format :where(ol>li):not(:where([class~=not-format] *)){padding-left:.375em}.format :where(ul>li):not(:where([class~=not-format] *)){padding-left:.375em}.format :where(.format>ul>li p):not(:where([class~=not-format] *)){margin-top:.75em;margin-bottom:.75em}.format :where(.format>ul>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.25em}.format :where(.format>ul>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.25em}.format :where(.format>ol>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.25em}.format :where(.format>ol>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.25em}.format :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-format] *)){margin-top:.75em;margin-bottom:.75em}.format :where(hr+*):not(:where([class~=not-format] *)){margin-top:0}.format :where(h2+*):not(:where([class~=not-format] *)){margin-top:0}.format :where(h3+*):not(:where([class~=not-format] *)){margin-top:0}.format :where(h4+*):not(:where([class~=not-format] *)){margin-top:0}.format :where(thead th:last-child):not(:where([class~=not-format] *)){padding-right:0}.format :where(tbody td,tfoot td):not(:where([class~=not-format] *)){padding:.5714286em}.format :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-format] *)){padding-right:0}.format :where(.format>:first-child):not(:where([class~=not-format] *)){margin-top:0}.format :where(.format>:last-child):not(:where([class~=not-format] *)){margin-bottom:0}.format-sm :where(.format>ul>li p):not(:where([class~=not-format] *)){margin-top:.5em;margin-bottom:.5em}.format-sm :where(.format>ul>li>:first-child):not(:where([class~=not-format] *)){margin-top:1em}.format-sm :where(.format>ul>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1em}.format-sm :where(.format>ol>li>:first-child):not(:where([class~=not-format] *)){margin-top:1em}.format-sm :where(.format>ol>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1em}.format-sm :where(.format>:first-child):not(:where([class~=not-format] *)){margin-top:0}.format-sm :where(.format>:last-child):not(:where([class~=not-format] *)){margin-bottom:0}.format-base :where(.format>ul>li p):not(:where([class~=not-format] *)){margin-top:.75em;margin-bottom:.75em}.format-base :where(.format>ul>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.25em}.format-base :where(.format>ul>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.25em}.format-base :where(.format>ol>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.25em}.format-base :where(.format>ol>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.25em}.format-base :where(.format>:first-child):not(:where([class~=not-format] *)){margin-top:0}.format-base :where(.format>:last-child):not(:where([class~=not-format] *)){margin-bottom:0}.format-lg :where(.format>ul>li p):not(:where([class~=not-format] *)){margin-top:.8888889em;margin-bottom:.8888889em}.format-lg :where(.format>ul>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.3333333em}.format-lg :where(.format>ul>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.3333333em}.format-lg :where(.format>ol>li>:first-child):not(:where([class~=not-format] *)){margin-top:1.3333333em}.format-lg :where(.format>ol>li>:last-child):not(:where([class~=not-format] *)){margin-bottom:1.3333333em}.format-lg :where(.format>:first-child):not(:where([class~=not-format] *)){margin-top:0}.format-lg :where(.format>:last-child):not(:where([class~=not-format] *)){margin-bottom:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.right-0{right:0}.top-0{top:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.me-2{-webkit-margin-end:.5rem;margin-inline-end:.5rem}.me-4{-webkit-margin-end:1rem;margin-inline-end:1rem}.ml-1{margin-left:.25rem}.ml-8{margin-left:2rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mr-8{margin-right:2rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-6{height:1.5rem}.h-9{height:2.25rem}.h-full{height:100%}.min-h-8{min-height:2rem}.w-1\/2{width:50%}.w-4{width:1rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-full{width:100%}.max-w-screen-xl{max-width:1280px}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.flex-shrink{-ms-flex-negative:1;flex-shrink:1}.flex-grow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.-translate-y-full{-webkit-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));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))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{-webkit-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));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))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{-webkit-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));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))}.rotate-180{--tw-rotate:180deg}.transform{-webkit-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));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))}.transform-none{-webkit-transform:none;transform:none}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-col,.flex-row{-webkit-box-direction:normal}.flex-col{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-end{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.self-center{-ms-flex-item-align:center;align-self:center}.justify-self-end{justify-self:end}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded-lg{border-radius:.5rem}.rounded-e-lg{border-start-end-radius:.5rem;border-end-end-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-s-lg{border-start-start-radius:.5rem;border-end-start-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-b{border-bottom-width:1px}.border-s-4{border-inline-start-width:4px}.border-blue-600{--tw-border-opacity:1;border-color:rgb(28 100 242/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(26 86 219/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity))}.border-green-500{--tw-border-opacity:1;border-color:rgb(14 159 110/var(--tw-border-opacity))}.border-green-700{--tw-border-opacity:1;border-color:rgb(4 108 78/var(--tw-border-opacity))}.border-purple-700{--tw-border-opacity:1;border-color:rgb(108 43 217/var(--tw-border-opacity))}.border-red-500{--tw-border-opacity:1;border-color:rgb(240 82 82/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(200 30 30/var(--tw-border-opacity))}.border-yellow-400{--tw-border-opacity:1;border-color:rgb(227 160 8/var(--tw-border-opacity))}.\!bg-gray-50{--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(26 86 219/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900\/50{background-color:rgba(17,24,39,.5)}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(243 250 247/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(4 108 78/var(--tw-bg-opacity))}.bg-purple-700{--tw-bg-opacity:1;background-color:rgb(108 43 217/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(253 242 242/var(--tw-bg-opacity))}.bg-red-700{--tw-bg-opacity:1;background-color:rgb(200 30 30/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:hsla(0,0%,100%,.5)}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(227 160 8/var(--tw-bg-opacity))}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-16{padding-bottom:4rem}.pl-3{padding-left:.75rem}.pr-4{padding-right:1rem}.pt-2{padding-top:.5rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.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-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}.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-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.text-blue-500{--tw-text-opacity:1;color:rgb(63 131 248/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(28 100 242/var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity:1;color:rgb(26 86 219/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-600{--tw-text-opacity:1;color:rgb(5 122 85/var(--tw-text-opacity))}.text-green-700{--tw-text-opacity:1;color:rgb(4 108 78/var(--tw-text-opacity))}.text-green-900{--tw-text-opacity:1;color:rgb(1 71 55/var(--tw-text-opacity))}.text-purple-700{--tw-text-opacity:1;color:rgb(108 43 217/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(224 36 36/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(200 30 30/var(--tw-text-opacity))}.text-red-900{--tw-text-opacity:1;color:rgb(119 29 29/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-400{--tw-text-opacity:1;color:rgb(227 160 8/var(--tw-text-opacity))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.placeholder-green-700::-webkit-input-placeholder{--tw-placeholder-opacity:1;color:rgb(4 108 78/var(--tw-placeholder-opacity))}.placeholder-green-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(4 108 78/var(--tw-placeholder-opacity))}.placeholder-green-700:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(4 108 78/var(--tw-placeholder-opacity))}.placeholder-green-700::-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(4 108 78/var(--tw-placeholder-opacity))}.placeholder-green-700::placeholder{--tw-placeholder-opacity:1;color:rgb(4 108 78/var(--tw-placeholder-opacity))}.placeholder-red-700::-webkit-input-placeholder{--tw-placeholder-opacity:1;color:rgb(200 30 30/var(--tw-placeholder-opacity))}.placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(200 30 30/var(--tw-placeholder-opacity))}.placeholder-red-700:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(200 30 30/var(--tw-placeholder-opacity))}.placeholder-red-700::-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(200 30 30/var(--tw-placeholder-opacity))}.placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(200 30 30/var(--tw-placeholder-opacity))}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{-webkit-box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px)}.blur,.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{-webkit-transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform,-webkit-filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform,-webkit-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-box-shadow,-webkit-transform,-webkit-filter,-webkit-backdrop-filter;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.transition-opacity{-webkit-transition-property:opacity;transition-property:opacity;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.transition-transform{-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.ease-out{-webkit-transition-timing-function:cubic-bezier(0,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(30 66 159/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.hover\:bg-gray-900:hover{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.hover\:bg-green-800:hover{--tw-bg-opacity:1;background-color:rgb(3 84 63/var(--tw-bg-opacity))}.hover\:bg-purple-800:hover{--tw-bg-opacity:1;background-color:rgb(85 33 181/var(--tw-bg-opacity))}.hover\:bg-red-800:hover{--tw-bg-opacity:1;background-color:rgb(155 28 28/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:bg-yellow-500:hover{--tw-bg-opacity:1;background-color:rgb(194 120 3/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(28 100 242/var(--tw-text-opacity))}.hover\:text-blue-700:hover{--tw-text-opacity:1;color:rgb(26 86 219/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(63 131 248/var(--tw-border-opacity))}.focus\:border-green-500:focus{--tw-border-opacity:1;border-color:rgb(14 159 110/var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(240 82 82/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.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-2:focus,.focus\:ring-4:focus{-webkit-box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4: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(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(63 131 248/var(--tw-ring-opacity))}.focus\:ring-gray-100:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(243 244 246/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(132 225 188/var(--tw-ring-opacity))}.focus\:ring-green-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(14 159 110/var(--tw-ring-opacity))}.focus\:ring-purple-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(202 191 253/var(--tw-ring-opacity))}.focus\:ring-red-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(248 180 180/var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(240 82 82/var(--tw-ring-opacity))}.focus\:ring-yellow-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(250 202 21/var(--tw-ring-opacity))}@media (min-width:640px){.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:mb-0{margin-bottom:0}.sm\:block{display:block}.sm\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.sm\:items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sm\:justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.sm\:text-center{text-align:center}}@media (min-width:768px){.md\:me-6{-webkit-margin-end:1.5rem;margin-inline-end:1.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1024px){.lg\:order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.lg\:order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.lg\:my-6{margin-top:1.5rem;margin-bottom:1.5rem}.lg\:mt-0{margin-top:0}.lg\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.lg\:hidden{display:none}.lg\:w-auto{width:auto}.lg\:flex-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.lg\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.lg\:border-0{border-width:0}.lg\:p-0{padding:0}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}.lg\:py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.lg\:pb-24{padding-bottom:6rem}.lg\:pt-16{padding-top:4rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}.lg\:hover\:bg-transparent:hover{background-color:transparent}}.rtl\:rotate-180:where([dir=rtl],[dir=rtl] *){--tw-rotate:180deg;-webkit-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));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))}.rtl\:space-x-reverse:where([dir=rtl],[dir=rtl] *)>:not([hidden])~:not([hidden]){--tw-space-x-reverse:1}@media (prefers-color-scheme:dark){.dark\:border-blue-500{--tw-border-opacity:1;border-color:rgb(63 131 248/var(--tw-border-opacity))}.dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}.dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}.dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}.dark\:border-green-500{--tw-border-opacity:1;border-color:rgb(14 159 110/var(--tw-border-opacity))}.dark\:border-purple-400{--tw-border-opacity:1;border-color:rgb(172 148 250/var(--tw-border-opacity))}.dark\:border-red-500{--tw-border-opacity:1;border-color:rgb(240 82 82/var(--tw-border-opacity))}.dark\:border-transparent{border-color:transparent}.dark\:border-yellow-300{--tw-border-opacity:1;border-color:rgb(250 202 21/var(--tw-border-opacity))}.dark\:\!bg-gray-700{--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.dark\:bg-blue-600{--tw-bg-opacity:1;background-color:rgb(28 100 242/var(--tw-bg-opacity))}.dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.dark\:bg-gray-800\/50{background-color:rgba(31,41,55,.5)}.dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.dark\:bg-gray-900\/80{background-color:rgba(17,24,39,.8)}.dark\:bg-green-600{--tw-bg-opacity:1;background-color:rgb(5 122 85/var(--tw-bg-opacity))}.dark\:bg-purple-600{--tw-bg-opacity:1;background-color:rgb(126 58 242/var(--tw-bg-opacity))}.dark\:bg-red-600{--tw-bg-opacity:1;background-color:rgb(224 36 36/var(--tw-bg-opacity))}.dark\:text-blue-500{--tw-text-opacity:1;color:rgb(63 131 248/var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.dark\:text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.dark\:text-green-400{--tw-text-opacity:1;color:rgb(49 196 141/var(--tw-text-opacity))}.dark\:text-green-500{--tw-text-opacity:1;color:rgb(14 159 110/var(--tw-text-opacity))}.dark\:text-purple-400{--tw-text-opacity:1;color:rgb(172 148 250/var(--tw-text-opacity))}.dark\:text-red-500{--tw-text-opacity:1;color:rgb(240 82 82/var(--tw-text-opacity))}.dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:text-yellow-300{--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}.dark\:placeholder-gray-400::-webkit-input-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}.dark\:placeholder-green-500::-webkit-input-placeholder{--tw-placeholder-opacity:1;color:rgb(14 159 110/var(--tw-placeholder-opacity))}.dark\:placeholder-green-500::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(14 159 110/var(--tw-placeholder-opacity))}.dark\:placeholder-green-500:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(14 159 110/var(--tw-placeholder-opacity))}.dark\:placeholder-green-500::-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(14 159 110/var(--tw-placeholder-opacity))}.dark\:placeholder-green-500::placeholder{--tw-placeholder-opacity:1;color:rgb(14 159 110/var(--tw-placeholder-opacity))}.dark\:placeholder-red-500::-webkit-input-placeholder{--tw-placeholder-opacity:1;color:rgb(240 82 82/var(--tw-placeholder-opacity))}.dark\:placeholder-red-500::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(240 82 82/var(--tw-placeholder-opacity))}.dark\:placeholder-red-500:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(240 82 82/var(--tw-placeholder-opacity))}.dark\:placeholder-red-500::-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(240 82 82/var(--tw-placeholder-opacity))}.dark\:placeholder-red-500::placeholder{--tw-placeholder-opacity:1;color:rgb(240 82 82/var(--tw-placeholder-opacity))}.dark\:hover\:border-gray-600:hover{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}.dark\:hover\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(63 131 248/var(--tw-bg-opacity))}.dark\:hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(26 86 219/var(--tw-bg-opacity))}.dark\:hover\:bg-gray-600:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.dark\:hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.dark\:hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(5 122 85/var(--tw-bg-opacity))}.dark\:hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(4 108 78/var(--tw-bg-opacity))}.dark\:hover\:bg-purple-500:hover{--tw-bg-opacity:1;background-color:rgb(144 97 249/var(--tw-bg-opacity))}.dark\:hover\:bg-purple-700:hover{--tw-bg-opacity:1;background-color:rgb(108 43 217/var(--tw-bg-opacity))}.dark\:hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(224 36 36/var(--tw-bg-opacity))}.dark\:hover\:bg-red-700:hover{--tw-bg-opacity:1;background-color:rgb(200 30 30/var(--tw-bg-opacity))}.dark\:hover\:bg-yellow-400:hover{--tw-bg-opacity:1;background-color:rgb(227 160 8/var(--tw-bg-opacity))}.dark\:hover\:text-blue-500:hover{--tw-text-opacity:1;color:rgb(63 131 248/var(--tw-text-opacity))}.dark\:hover\:text-gray-300:hover{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.dark\:hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(63 131 248/var(--tw-border-opacity))}.dark\:focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(63 131 248/var(--tw-ring-opacity))}.dark\:focus\:ring-blue-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(30 66 159/var(--tw-ring-opacity))}.dark\:focus\:ring-gray-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}.dark\:focus\:ring-gray-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(55 65 81/var(--tw-ring-opacity))}.dark\:focus\:ring-gray-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(31 41 55/var(--tw-ring-opacity))}.dark\:focus\:ring-green-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(3 84 63/var(--tw-ring-opacity))}.dark\:focus\:ring-purple-900:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(74 29 150/var(--tw-ring-opacity))}.dark\:focus\:ring-red-900:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(119 29 29/var(--tw-ring-opacity))}.dark\:focus\:ring-yellow-900:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 49 18/var(--tw-ring-opacity))}}@media (min-width:1024px){@media (prefers-color-scheme:dark){.lg\:dark\:hover\:bg-transparent:hover{background-color:transparent}.lg\:dark\:hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}}} \ No newline at end of file +/* +! tailwindcss v3.4.8 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + -webkit-box-sizing: border-box; + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #E5E7EB; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + -webkit-font-feature-settings: normal; + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + -webkit-font-feature-settings: normal; + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + -webkit-font-feature-settings: inherit; + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { + opacity: 1; + /* 1 */ + color: #9CA3AF; + /* 2 */ +} + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9CA3AF; + /* 2 */ +} + +input:-ms-input-placeholder, textarea:-ms-input-placeholder { + opacity: 1; + /* 1 */ + color: #9CA3AF; + /* 2 */ +} + +input::-ms-input-placeholder, textarea::-ms-input-placeholder { + opacity: 1; + /* 1 */ + color: #9CA3AF; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9CA3AF; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +.tooltip-arrow,.tooltip-arrow:before { + position: absolute; + width: 8px; + height: 8px; + background: inherit; +} + +.tooltip-arrow { + visibility: hidden; +} + +.tooltip-arrow:before { + content: ""; + visibility: visible; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +[data-tooltip-style^='light'] + .tooltip > .tooltip-arrow:before { + border-style: solid; + border-color: #e5e7eb; +} + +[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='top'] > .tooltip-arrow:before { + border-bottom-width: 1px; + border-right-width: 1px; +} + +[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='right'] > .tooltip-arrow:before { + border-bottom-width: 1px; + border-left-width: 1px; +} + +[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='bottom'] > .tooltip-arrow:before { + border-top-width: 1px; + border-left-width: 1px; +} + +[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='left'] > .tooltip-arrow:before { + border-top-width: 1px; + border-right-width: 1px; +} + +.tooltip[data-popper-placement^='top'] > .tooltip-arrow { + bottom: -4px; +} + +.tooltip[data-popper-placement^='bottom'] > .tooltip-arrow { + top: -4px; +} + +.tooltip[data-popper-placement^='left'] > .tooltip-arrow { + right: -4px; +} + +.tooltip[data-popper-placement^='right'] > .tooltip-arrow { + left: -4px; +} + +.tooltip.invisible > .tooltip-arrow:before { + visibility: hidden; +} + +[data-popper-arrow],[data-popper-arrow]:before { + position: absolute; + width: 8px; + height: 8px; + background: inherit; +} + +[data-popper-arrow] { + visibility: hidden; +} + +[data-popper-arrow]:before { + content: ""; + visibility: visible; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +[data-popper-arrow]:after { + content: ""; + visibility: visible; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + position: absolute; + width: 9px; + height: 9px; + background: inherit; +} + +[role="tooltip"] > [data-popper-arrow]:before { + border-style: solid; + border-color: #e5e7eb; +} + +.dark [role="tooltip"] > [data-popper-arrow]:before { + border-style: solid; + border-color: #4b5563; +} + +[role="tooltip"] > [data-popper-arrow]:after { + border-style: solid; + border-color: #e5e7eb; +} + +.dark [role="tooltip"] > [data-popper-arrow]:after { + border-style: solid; + border-color: #4b5563; +} + +[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow]:before { + border-bottom-width: 1px; + border-right-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow]:after { + border-bottom-width: 1px; + border-right-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow]:before { + border-bottom-width: 1px; + border-left-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow]:after { + border-bottom-width: 1px; + border-left-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow]:before { + border-top-width: 1px; + border-left-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow]:after { + border-top-width: 1px; + border-left-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow]:before { + border-top-width: 1px; + border-right-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow]:after { + border-top-width: 1px; + border-right-width: 1px; +} + +[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow] { + bottom: -5px; +} + +[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow] { + top: -5px; +} + +[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow] { + right: -5px; +} + +[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow] { + left: -5px; +} + +[role="tooltip"].invisible > [data-popper-arrow]:before { + visibility: hidden; +} + +[role="tooltip"].invisible > [data-popper-arrow]:after { + visibility: hidden; +} + +[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6B7280; + border-width: 1px; + border-radius: 0px; + padding-top: 0.5rem; + padding-right: 0.75rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 1rem; + line-height: 1.5rem; + --tw-shadow: 0 0 #0000; +} + +[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select: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: #1C64F2; + --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); + -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + border-color: #1C64F2; +} + +input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { + color: #6B7280; + opacity: 1; +} + +input::-moz-placeholder, textarea::-moz-placeholder { + color: #6B7280; + opacity: 1; +} + +input:-ms-input-placeholder, textarea:-ms-input-placeholder { + color: #6B7280; + opacity: 1; +} + +input::-ms-input-placeholder, textarea::-ms-input-placeholder { + color: #6B7280; + opacity: 1; +} + +input::placeholder,textarea::placeholder { + color: #6B7280; + opacity: 1; +} + +::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +input[type="time"]::-webkit-calendar-picker-indicator { + background: none; +} + +select:not([size]) { + background-image: url("data:image/svg+xml,%3csvg aria-hidden='true' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 10 6'%3e %3cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 1 4 4 4-4'/%3e %3c/svg%3e"); + background-position: right 0.75rem center; + background-repeat: no-repeat; + background-size: 0.75em 0.75em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} + +:is([dir=rtl]) select:not([size]) { + background-position: left 0.75rem center; + padding-right: 0.75rem; + padding-left: 0; +} + +[multiple] { + background-image: initial; + background-position: initial; + background-repeat: unset; + background-size: initial; + padding-right: 0.75rem; + -webkit-print-color-adjust: unset; + print-color-adjust: unset; +} + +[type='checkbox'],[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; + -ms-user-select: none; + user-select: none; + -ms-flex-negative: 0; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #1C64F2; + background-color: #fff; + border-color: #6B7280; + border-width: 1px; + --tw-shadow: 0 0 #0000; +} + +[type='checkbox'] { + border-radius: 0px; +} + +[type='radio'] { + border-radius: 100%; +} + +[type='checkbox']:focus,[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: #1C64F2; + --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); + -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); +} + +[type='checkbox']:checked,[type='radio']:checked,.dark [type='checkbox']:checked,.dark [type='radio']:checked { + border-color: transparent; + background-color: currentColor; + background-size: 0.55em 0.55em; + background-position: center; + background-repeat: no-repeat; +} + +[type='checkbox']:checked { + background-image: url("data:image/svg+xml,%3csvg aria-hidden='true' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 12'%3e %3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M1 5.917 5.724 10.5 15 1.5'/%3e %3c/svg%3e"); + background-repeat: no-repeat; + background-size: 0.55em 0.55em; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} + +[type='radio']:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + background-size: 1em 1em; +} + +.dark [type='radio']:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + background-size: 1em 1em; +} + +[type='checkbox']:indeterminate { + background-image: url("data:image/svg+xml,%3csvg aria-hidden='true' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 12'%3e %3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M0.5 6h14'/%3e %3c/svg%3e"); + background-color: currentColor; + border-color: transparent; + background-position: center; + background-repeat: no-repeat; + background-size: 0.55em 0.55em; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} + +[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { + border-color: transparent; + background-color: currentColor; +} + +[type='file'] { + background: unset; + border-color: inherit; + border-width: 0; + border-radius: 0; + padding: 0; + font-size: unset; + line-height: inherit; +} + +[type='file']:focus { + outline: 1px auto inherit; +} + +input[type=file]::-webkit-file-upload-button { + color: white; + background: #1F2937; + border: 0; + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + padding-top: 0.625rem; + padding-bottom: 0.625rem; + padding-left: 2rem; + padding-right: 1rem; + -webkit-margin-start: -1rem; + margin-inline-start: -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} + +input[type=file]::file-selector-button { + color: white; + background: #1F2937; + border: 0; + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + padding-top: 0.625rem; + padding-bottom: 0.625rem; + padding-left: 2rem; + padding-right: 1rem; + -webkit-margin-start: -1rem; + margin-inline-start: -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} + +input[type=file]::-webkit-file-upload-button:hover { + background: #374151; +} + +input[type=file]::file-selector-button:hover { + background: #374151; +} + +:is([dir=rtl]) input[type=file]::-webkit-file-upload-button { + padding-right: 2rem; + padding-left: 1rem; +} + +:is([dir=rtl]) input[type=file]::file-selector-button { + padding-right: 2rem; + padding-left: 1rem; +} + +.dark input[type=file]::-webkit-file-upload-button { + color: white; + background: #4B5563; +} + +.dark input[type=file]::file-selector-button { + color: white; + background: #4B5563; +} + +.dark input[type=file]::-webkit-file-upload-button:hover { + background: #6B7280; +} + +.dark input[type=file]::file-selector-button:hover { + background: #6B7280; +} + +input[type="range"]::-webkit-slider-thumb { + height: 1.25rem; + width: 1.25rem; + background: #1C64F2; + border-radius: 9999px; + border: 0; + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + cursor: pointer; +} + +input[type="range"]:disabled::-webkit-slider-thumb { + background: #9CA3AF; +} + +.dark input[type="range"]:disabled::-webkit-slider-thumb { + background: #6B7280; +} + +input[type="range"]:focus::-webkit-slider-thumb { + outline: 2px solid transparent; + outline-offset: 2px; + --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(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-opacity: 1px; + --tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity)); +} + +input[type="range"]::-moz-range-thumb { + height: 1.25rem; + width: 1.25rem; + background: #1C64F2; + border-radius: 9999px; + border: 0; + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + cursor: pointer; +} + +input[type="range"]:disabled::-moz-range-thumb { + background: #9CA3AF; +} + +.dark input[type="range"]:disabled::-moz-range-thumb { + background: #6B7280; +} + +input[type="range"]::-moz-range-progress { + background: #3F83F8; +} + +input[type="range"]::-ms-fill-lower { + background: #3F83F8; +} + +.toggle-bg:after { + content: ""; + position: absolute; + top: 0.125rem; + left: 0.125rem; + background: white; + border-color: #D1D5DB; + border-width: 1px; + border-radius: 9999px; + height: 1.25rem; + width: 1.25rem; + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter; + -webkit-transition-duration: .15s; + transition-duration: .15s; + -webkit-box-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); +} + +input:checked + .toggle-bg:after { + -webkit-transform: translateX(100%);; + transform: translateX(100%);; + border-color: white; +} + +input:checked + .toggle-bg { + background: #1C64F2; + border-color: #1C64F2; +} + +*, ::before, ::after { + --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: rgb(63 131 248 / 0.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: ; +} + +::-webkit-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: rgb(63 131 248 / 0.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: rgb(63 131 248 / 0.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: ; +} + +.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; + } +} + +.format { + color: var(--tw-format-body); + max-width: 65ch; +} + +.format :where([class~="lead"]):not(:where([class~="not-format"] *)) { + color: var(--tw-format-lead); + font-size: 1.25em; + line-height: 1.6; + margin-top: 1.2em; + margin-bottom: 1.2em; +} + +.format :where(a):not(:where([class~="not-format"] *)) { + color: var(--tw-format-links); + text-decoration: underline; + font-weight: 500; +} + +.format :where(a):not(:where([class~="not-format"] *)):hover { + text-decoration: none; +} + +.format :where(strong):not(:where([class~="not-format"] *)) { + color: var(--tw-format-bold); + font-weight: 700; +} + +.format :where(a strong):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(blockquote strong):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(thead th strong):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(ol):not(:where([class~="not-format"] *)) { + list-style-type: decimal; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-left: 1.625em; +} + +.format :where(ol[type="A"]):not(:where([class~="not-format"] *)) { + list-style-type: upper-alpha; +} + +.format :where(ol[type="a"]):not(:where([class~="not-format"] *)) { + list-style-type: lower-alpha; +} + +.format :where(ol[type="A" s]):not(:where([class~="not-format"] *)) { + list-style-type: upper-alpha; +} + +.format :where(ol[type="a" s]):not(:where([class~="not-format"] *)) { + list-style-type: lower-alpha; +} + +.format :where(ol[type="I"]):not(:where([class~="not-format"] *)) { + list-style-type: upper-roman; +} + +.format :where(ol[type="i"]):not(:where([class~="not-format"] *)) { + list-style-type: lower-roman; +} + +.format :where(ol[type="I" s]):not(:where([class~="not-format"] *)) { + list-style-type: upper-roman; +} + +.format :where(ol[type="i" s]):not(:where([class~="not-format"] *)) { + list-style-type: lower-roman; +} + +.format :where(ol[type="1"]):not(:where([class~="not-format"] *)) { + list-style-type: decimal; +} + +.format :where(ul):not(:where([class~="not-format"] *)) { + list-style-type: disc; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-left: 1.625em; +} + +.format :where(ol > li):not(:where([class~="not-format"] *))::marker { + font-weight: 400; + color: var(--tw-format-counters); +} + +.format :where(ul > li):not(:where([class~="not-format"] *))::marker { + color: var(--tw-format-bullets); +} + +.format :where(hr):not(:where([class~="not-format"] *)) { + border-color: var(--tw-format-hr); + border-top-width: 1px; + margin-top: 3em; + margin-bottom: 3em; +} + +.format :where(blockquote):not(:where([class~="not-format"] *)) { + font-size: 1.1111111em; + font-weight: 700; + font-style: italic; + color: var(--tw-format-quotes); + quotes: "\201C""\201D""\2018""\2019"; + margin-bottom: 1.6em; +} + +.format :where(blockquote):not(:where([class~="not-format"] *))::before { + content: ""; + background-image: url("data:image/svg+xml,%0A%3Csvg width='32' height='24' viewBox='0 0 32 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.6893 24V14.1453C18.6893 6.54 23.664 1.38533 30.6667 -7.15256e-07L31.9933 2.868C28.7507 4.09066 26.6667 7.71867 26.6667 10.6667H32V24H18.6893ZM-9.53674e-07 24V14.1453C-9.53674e-07 6.54 4.99733 1.384 12 -7.15256e-07L13.328 2.868C10.084 4.09066 8 7.71867 8 10.6667L13.3107 10.6667V24H-9.53674e-07Z' fill='%239CA3AF'/%3E%3C/svg%3E%0A"); + background-repeat: no-repeat; + color: var(--tw-format-quotes); + width: 1.7777778em; + height: 1.3333333em; + display: block; + margin-top: 1.6em; +} + +.format :where(blockquote p:first-of-type):not(:where([class~="not-format"] *))::before { + content: open-quote; +} + +.format :where(blockquote p:last-of-type):not(:where([class~="not-format"] *))::after { + content: close-quote; +} + +.format :where(h1):not(:where([class~="not-format"] *)) { + color: var(--tw-format-headings); + font-weight: 800; + font-size: 2.25em; + margin-top: 0; + margin-bottom: 0.8888889em; + line-height: 1.1111111; +} + +.format :where(h1 strong):not(:where([class~="not-format"] *)) { + font-weight: 900; + color: inherit; +} + +.format :where(h2):not(:where([class~="not-format"] *)) { + color: var(--tw-format-headings); + font-weight: 700; + font-size: 1.5em; + margin-top: 0; + margin-bottom: 1em; + line-height: 1.3333333; +} + +.format :where(h2 strong):not(:where([class~="not-format"] *)) { + font-weight: 800; + color: inherit; +} + +.format :where(h3):not(:where([class~="not-format"] *)) { + color: var(--tw-format-headings); + font-weight: 700; + font-size: 1.25em; + margin-top: 0; + margin-bottom: 0.6em; + line-height: 1.6; +} + +.format :where(h3 strong):not(:where([class~="not-format"] *)) { + font-weight: 800; + color: inherit; +} + +.format :where(h4):not(:where([class~="not-format"] *)) { + color: var(--tw-format-headings); + font-weight: 600; + margin-top: 0; + margin-bottom: 0.5em; + line-height: 1.5; +} + +.format :where(h4 strong):not(:where([class~="not-format"] *)) { + font-weight: 700; + color: inherit; +} + +.format :where(img):not(:where([class~="not-format"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.format :where(figure > *):not(:where([class~="not-format"] *)) { + margin-top: 0; + margin-bottom: 0; +} + +.format :where(figcaption):not(:where([class~="not-format"] *)) { + color: var(--tw-format-captions); + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; +} + +.format :where(code):not(:where([class~="not-format"] *)) { + color: var(--tw-format-code); + font-weight: 600; + background-color: var(--tw-format-code-bg); + padding-top: 0.3333333em; + padding-bottom: 0.3333333em; + padding-left: 0.5555556em; + padding-right: 0.5555556em; + border-radius: 0.2222222em; + font-size: 0.875em; +} + +.format :where(a code):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(h1 code):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(h2 code):not(:where([class~="not-format"] *)) { + color: inherit; + font-size: 0.875em; +} + +.format :where(h3 code):not(:where([class~="not-format"] *)) { + color: inherit; + font-size: 0.9em; +} + +.format :where(h4 code):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(blockquote code):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(thead th code):not(:where([class~="not-format"] *)) { + color: inherit; +} + +.format :where(pre):not(:where([class~="not-format"] *)) { + color: var(--tw-format-pre-code); + background-color: var(--tw-format-pre-bg); + overflow-x: auto; + font-weight: 400; + font-size: 0.875em; + line-height: 1.7142857; + margin-top: 1.7142857em; + margin-bottom: 1.7142857em; + border-radius: 0.375rem; + padding-top: 0.8571429em; + padding-right: 1.1428571em; + padding-bottom: 0.8571429em; + padding-left: 1.1428571em; +} + +.format :where(pre code):not(:where([class~="not-format"] *)) { + 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; +} + +.format :where(pre code):not(:where([class~="not-format"] *))::before { + content: none; +} + +.format :where(pre code):not(:where([class~="not-format"] *))::after { + content: none; +} + +.format :where(table):not(:where([class~="not-format"] *)) { + width: 100%; + table-layout: auto; + text-align: left; + margin-top: 2em; + margin-bottom: 2em; + font-size: 0.875em; + line-height: 1.7142857; +} + +.format :where(thead):not(:where([class~="not-format"] *)) { + background-color: var(--tw-format-th-bg); + border-radius: 0.2777778em; +} + +.format :where(thead th):not(:where([class~="not-format"] *)) { + color: var(--tw-format-headings); + font-weight: 600; + vertical-align: bottom; + padding: 0.5555556em; + padding-right: 0.5714286em; + padding-bottom: 0.5714286em; + padding-left: 0.5714286em; +} + +.format :where(tbody tr):not(:where([class~="not-format"] *)) { + border-bottom-width: 1px; + border-bottom-color: var(--tw-format-td-borders); +} + +.format :where(tbody tr:last-child):not(:where([class~="not-format"] *)) { + border-bottom-width: 0; +} + +.format :where(tbody td):not(:where([class~="not-format"] *)) { + vertical-align: baseline; +} + +.format :where(tfoot):not(:where([class~="not-format"] *)) { + border-top-width: 1px; + border-top-color: var(--tw-format-th-borders); +} + +.format :where(tfoot td):not(:where([class~="not-format"] *)) { + vertical-align: top; +} + +.format { + --tw-format-body: #6b7280; + --tw-format-headings: #111827; + --tw-format-lead: #6b7280; + --tw-format-links: #4b5563; + --tw-format-bold: #111827; + --tw-format-counters: #6b7280; + --tw-format-bullets: #6b7280; + --tw-format-hr: #e5e7eb; + --tw-format-quotes: #111827; + --tw-format-quote-borders: #e5e7eb; + --tw-format-captions: #6b7280; + --tw-format-code: #111827; + --tw-format-code-bg: #f3f4f6; + --tw-format-pre-code: #4b5563; + --tw-format-pre-bg: #f3f4f6; + --tw-format-th-borders: #e5e7eb; + --tw-format-th-bg: #f9fafb; + --tw-format-td-borders: #e5e7eb; + --tw-format-invert-body: #9ca3af; + --tw-format-invert-headings: #fff; + --tw-format-invert-lead: #9ca3af; + --tw-format-invert-links: #fff; + --tw-format-invert-bold: #fff; + --tw-format-invert-counters: #9ca3af; + --tw-format-invert-bullets: #4b5563; + --tw-format-invert-hr: #374151; + --tw-format-invert-quotes: #f3f4f6; + --tw-format-invert-quote-borders: #374151; + --tw-format-invert-captions: #9ca3af; + --tw-format-invert-code: #fff; + --tw-format-invert-code-bg: #1f2937; + --tw-format-invert-pre-code: #d1d5db; + --tw-format-invert-pre-bg: #374151; + --tw-format-invert-th-borders: #4b5563; + --tw-format-invert-td-borders: #374151; + --tw-format-invert-th-bg: #374151; + font-size: 1rem; + line-height: 1.75; +} + +.format :where(p):not(:where([class~="not-format"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; +} + +.format :where(blockquote > p:first-child):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(video):not(:where([class~="not-format"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.format :where(figure):not(:where([class~="not-format"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.format :where(li):not(:where([class~="not-format"] *)) { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.format :where(ol > li):not(:where([class~="not-format"] *)) { + padding-left: 0.375em; +} + +.format :where(ul > li):not(:where([class~="not-format"] *)) { + padding-left: 0.375em; +} + +.format :where(.format > ul > li p):not(:where([class~="not-format"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +.format :where(.format > ul > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.25em; +} + +.format :where(.format > ul > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.25em; +} + +.format :where(.format > ol > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.25em; +} + +.format :where(.format > ol > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.25em; +} + +.format :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-format"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +.format :where(hr + *):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(h2 + *):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(h3 + *):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(h4 + *):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(thead th:last-child):not(:where([class~="not-format"] *)) { + padding-right: 0; +} + +.format :where(tbody td, tfoot td):not(:where([class~="not-format"] *)) { + padding-top: 0.5714286em; + padding-right: 0.5714286em; + padding-bottom: 0.5714286em; + padding-left: 0.5714286em; +} + +.format :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-format"] *)) { + padding-right: 0; +} + +.format :where(.format > :first-child):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format :where(.format > :last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 0; +} + +.format-sm :where(.format > ul > li p):not(:where([class~="not-format"] *)) { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.format-sm :where(.format > ul > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1em; +} + +.format-sm :where(.format > ul > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1em; +} + +.format-sm :where(.format > ol > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1em; +} + +.format-sm :where(.format > ol > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1em; +} + +.format-sm :where(.format > :first-child):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format-sm :where(.format > :last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 0; +} + +.format-base :where(.format > ul > li p):not(:where([class~="not-format"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +.format-base :where(.format > ul > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.25em; +} + +.format-base :where(.format > ul > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.25em; +} + +.format-base :where(.format > ol > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.25em; +} + +.format-base :where(.format > ol > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.25em; +} + +.format-base :where(.format > :first-child):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format-base :where(.format > :last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 0; +} + +.format-lg :where(.format > ul > li p):not(:where([class~="not-format"] *)) { + margin-top: 0.8888889em; + margin-bottom: 0.8888889em; +} + +.format-lg :where(.format > ul > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.3333333em; +} + +.format-lg :where(.format > ul > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.3333333em; +} + +.format-lg :where(.format > ol > li > *:first-child):not(:where([class~="not-format"] *)) { + margin-top: 1.3333333em; +} + +.format-lg :where(.format > ol > li > *:last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 1.3333333em; +} + +.format-lg :where(.format > :first-child):not(:where([class~="not-format"] *)) { + margin-top: 0; +} + +.format-lg :where(.format > :last-child):not(:where([class~="not-format"] *)) { + margin-bottom: 0; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.visible { + visibility: visible; +} + +.invisible { + visibility: hidden; +} + +.collapse { + visibility: collapse; +} + +.static { + position: static; +} + +.fixed { + position: fixed; +} + +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.inset-0 { + inset: 0px; +} + +.bottom-0 { + bottom: 0px; +} + +.bottom-\[60px\] { + bottom: 60px; +} + +.left-0 { + left: 0px; +} + +.right-0 { + right: 0px; +} + +.top-0 { + top: 0px; +} + +.z-10 { + z-index: 10; +} + +.z-20 { + z-index: 20; +} + +.z-30 { + z-index: 30; +} + +.z-40 { + z-index: 40; +} + +.z-50 { + z-index: 50; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.my-4 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.me-2 { + -webkit-margin-end: 0.5rem; + margin-inline-end: 0.5rem; +} + +.me-4 { + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} + +.ml-1 { + margin-left: 0.25rem; +} + +.ml-8 { + margin-left: 2rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.mr-4 { + margin-right: 1rem; +} + +.mr-8 { + margin-right: 2rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.inline { + display: inline; +} + +.flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.inline-flex { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.table { + display: table; +} + +.grid { + display: grid; +} + +.hidden { + display: none; +} + +.h-4 { + height: 1rem; +} + +.h-6 { + height: 1.5rem; +} + +.h-9 { + height: 2.25rem; +} + +.h-full { + height: 100%; +} + +.min-h-8 { + min-height: 2rem; +} + +.w-1\/2 { + width: 50%; +} + +.w-4 { + width: 1rem; +} + +.w-6 { + width: 1.5rem; +} + +.w-64 { + width: 16rem; +} + +.w-full { + width: 100%; +} + +.max-w-screen-xl { + max-width: 1280px; +} + +.flex-1 { + -webkit-box-flex: 1; + -ms-flex: 1 1 0%; + flex: 1 1 0%; +} + +.flex-shrink { + -ms-flex-negative: 1; + flex-shrink: 1; +} + +.flex-grow { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.-translate-x-full { + --tw-translate-x: -100%; + -webkit-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)); + 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)); +} + +.-translate-y-full { + --tw-translate-y: -100%; + -webkit-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)); + 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)); +} + +.translate-x-0 { + --tw-translate-x: 0px; + -webkit-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)); + 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)); +} + +.translate-x-full { + --tw-translate-x: 100%; + -webkit-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)); + 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)); +} + +.translate-y-full { + --tw-translate-y: 100%; + -webkit-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)); + 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)); +} + +.rotate-180 { + --tw-rotate: 180deg; + -webkit-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)); + 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)); +} + +.transform { + -webkit-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)); + 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)); +} + +.transform-none { + -webkit-transform: none; + transform: none; +} + +.cursor-default { + cursor: default; +} + +.cursor-not-allowed { + cursor: not-allowed; +} + +.cursor-pointer { + cursor: pointer; +} + +.resize { + resize: both; +} + +.list-none { + list-style-type: none; +} + +.grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.grid-cols-7 { + grid-template-columns: repeat(7, minmax(0, 1fr)); +} + +.flex-row { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.flex-col { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.flex-wrap { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.items-start { + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; +} + +.items-end { + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; +} + +.items-center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.justify-start { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.justify-end { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.justify-center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.justify-between { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-x-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.75rem * var(--tw-space-x-reverse)); + margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); +} + +.self-center { + -ms-flex-item-align: center; + align-self: center; +} + +.justify-self-end { + justify-self: end; +} + +.overflow-hidden { + overflow: hidden; +} + +.whitespace-nowrap { + white-space: nowrap; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-e-lg { + border-start-end-radius: 0.5rem; + border-end-end-radius: 0.5rem; +} + +.rounded-l-lg { + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; +} + +.rounded-r-lg { + border-top-right-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; +} + +.rounded-s-lg { + border-start-start-radius: 0.5rem; + border-end-start-radius: 0.5rem; +} + +.border { + border-width: 1px; +} + +.border-0 { + border-width: 0px; +} + +.border-b { + border-bottom-width: 1px; +} + +.border-s-4 { + border-inline-start-width: 4px; +} + +.border-blue-600 { + --tw-border-opacity: 1; + border-color: rgb(28 100 242 / var(--tw-border-opacity)); +} + +.border-blue-700 { + --tw-border-opacity: 1; + border-color: rgb(26 86 219 / var(--tw-border-opacity)); +} + +.border-gray-100 { + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); +} + +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.border-gray-800 { + --tw-border-opacity: 1; + border-color: rgb(31 41 55 / var(--tw-border-opacity)); +} + +.border-green-500 { + --tw-border-opacity: 1; + border-color: rgb(14 159 110 / var(--tw-border-opacity)); +} + +.border-green-700 { + --tw-border-opacity: 1; + border-color: rgb(4 108 78 / var(--tw-border-opacity)); +} + +.border-purple-700 { + --tw-border-opacity: 1; + border-color: rgb(108 43 217 / var(--tw-border-opacity)); +} + +.border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(240 82 82 / var(--tw-border-opacity)); +} + +.border-red-700 { + --tw-border-opacity: 1; + border-color: rgb(200 30 30 / var(--tw-border-opacity)); +} + +.border-yellow-400 { + --tw-border-opacity: 1; + border-color: rgb(227 160 8 / var(--tw-border-opacity)); +} + +.\!bg-gray-50 { + --tw-bg-opacity: 1 !important; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)) !important; +} + +.bg-blue-700 { + --tw-bg-opacity: 1; + background-color: rgb(26 86 219 / var(--tw-bg-opacity)); +} + +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.bg-gray-800 { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); +} + +.bg-gray-900\/50 { + background-color: rgb(17 24 39 / 0.5); +} + +.bg-green-50 { + --tw-bg-opacity: 1; + background-color: rgb(243 250 247 / var(--tw-bg-opacity)); +} + +.bg-green-700 { + --tw-bg-opacity: 1; + background-color: rgb(4 108 78 / var(--tw-bg-opacity)); +} + +.bg-purple-700 { + --tw-bg-opacity: 1; + background-color: rgb(108 43 217 / var(--tw-bg-opacity)); +} + +.bg-red-50 { + --tw-bg-opacity: 1; + background-color: rgb(253 242 242 / var(--tw-bg-opacity)); +} + +.bg-red-700 { + --tw-bg-opacity: 1; + background-color: rgb(200 30 30 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.bg-white\/50 { + background-color: rgb(255 255 255 / 0.5); +} + +.bg-yellow-400 { + --tw-bg-opacity: 1; + background-color: rgb(227 160 8 / var(--tw-bg-opacity)); +} + +.p-0 { + padding: 0px; +} + +.p-1 { + padding: 0.25rem; +} + +.p-2 { + padding: 0.5rem; +} + +.p-2\.5 { + padding: 0.625rem; +} + +.p-4 { + padding: 1rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-2\.5 { + padding-top: 0.625rem; + padding-bottom: 0.625rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.pb-16 { + padding-bottom: 4rem; +} + +.pl-3 { + padding-left: 0.75rem; +} + +.pr-4 { + padding-right: 1rem; +} + +.pt-2 { + padding-top: 0.5rem; +} + +.pt-8 { + padding-top: 2rem; +} + +.text-center { + text-align: center; +} + +.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-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.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-6 { + line-height: 1.5rem; +} + +.leading-9 { + line-height: 2.25rem; +} + +.leading-none { + line-height: 1; +} + +.leading-relaxed { + line-height: 1.625; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + +.text-blue-500 { + --tw-text-opacity: 1; + color: rgb(63 131 248 / var(--tw-text-opacity)); +} + +.text-blue-600 { + --tw-text-opacity: 1; + color: rgb(28 100 242 / var(--tw-text-opacity)); +} + +.text-blue-700 { + --tw-text-opacity: 1; + color: rgb(26 86 219 / var(--tw-text-opacity)); +} + +.text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.text-gray-800 { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-green-600 { + --tw-text-opacity: 1; + color: rgb(5 122 85 / var(--tw-text-opacity)); +} + +.text-green-700 { + --tw-text-opacity: 1; + color: rgb(4 108 78 / var(--tw-text-opacity)); +} + +.text-green-900 { + --tw-text-opacity: 1; + color: rgb(1 71 55 / var(--tw-text-opacity)); +} + +.text-purple-700 { + --tw-text-opacity: 1; + color: rgb(108 43 217 / var(--tw-text-opacity)); +} + +.text-red-600 { + --tw-text-opacity: 1; + color: rgb(224 36 36 / var(--tw-text-opacity)); +} + +.text-red-700 { + --tw-text-opacity: 1; + color: rgb(200 30 30 / var(--tw-text-opacity)); +} + +.text-red-900 { + --tw-text-opacity: 1; + color: rgb(119 29 29 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-yellow-400 { + --tw-text-opacity: 1; + color: rgb(227 160 8 / var(--tw-text-opacity)); +} + +.antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.placeholder-green-700::-webkit-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(4 108 78 / var(--tw-placeholder-opacity)); +} + +.placeholder-green-700::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(4 108 78 / var(--tw-placeholder-opacity)); +} + +.placeholder-green-700:-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(4 108 78 / var(--tw-placeholder-opacity)); +} + +.placeholder-green-700::-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(4 108 78 / var(--tw-placeholder-opacity)); +} + +.placeholder-green-700::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(4 108 78 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-700::-webkit-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(200 30 30 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-700::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(200 30 30 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-700:-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(200 30 30 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-700::-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(200 30 30 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-700::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(200 30 30 / var(--tw-placeholder-opacity)); +} + +.opacity-0 { + opacity: 0; +} + +.opacity-100 { + opacity: 1; +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-lg { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.outline { + outline-style: solid; +} + +.blur { + --tw-blur: blur(8px); + -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.filter { + -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.transition { + -webkit-transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, -webkit-transform, -webkit-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-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; + -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + -webkit-transition-duration: 150ms; + transition-duration: 150ms; +} + +.transition-opacity { + -webkit-transition-property: opacity; + transition-property: opacity; + -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + -webkit-transition-duration: 150ms; + transition-duration: 150ms; +} + +.transition-transform { + -webkit-transition-property: -webkit-transform; + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + -webkit-transition-duration: 150ms; + transition-duration: 150ms; +} + +.ease-out { + -webkit-transition-timing-function: cubic-bezier(0, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); +} + +.hover\:border-gray-300:hover { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.hover\:bg-blue-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(30 66 159 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-50:hover { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.hover\:bg-green-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(3 84 63 / var(--tw-bg-opacity)); +} + +.hover\:bg-purple-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(85 33 181 / var(--tw-bg-opacity)); +} + +.hover\:bg-red-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(155 28 28 / var(--tw-bg-opacity)); +} + +.hover\:bg-white:hover { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.hover\:bg-yellow-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(194 120 3 / var(--tw-bg-opacity)); +} + +.hover\:text-blue-600:hover { + --tw-text-opacity: 1; + color: rgb(28 100 242 / var(--tw-text-opacity)); +} + +.hover\:text-blue-700:hover { + --tw-text-opacity: 1; + color: rgb(26 86 219 / var(--tw-text-opacity)); +} + +.hover\:text-gray-600:hover { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.hover\:text-gray-900:hover { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.hover\:underline:hover { + text-decoration-line: underline; +} + +.focus\:z-10:focus { + z-index: 10; +} + +.focus\:border-blue-500:focus { + --tw-border-opacity: 1; + border-color: rgb(63 131 248 / var(--tw-border-opacity)); +} + +.focus\:border-green-500:focus { + --tw-border-opacity: 1; + border-color: rgb(14 159 110 / var(--tw-border-opacity)); +} + +.focus\:border-red-500:focus { + --tw-border-opacity: 1; + border-color: rgb(240 82 82 / var(--tw-border-opacity)); +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.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); + -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-4: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(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-blue-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity)); +} + +.focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(63 131 248 / var(--tw-ring-opacity)); +} + +.focus\:ring-gray-100:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(243 244 246 / var(--tw-ring-opacity)); +} + +.focus\:ring-gray-200:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity)); +} + +.focus\:ring-gray-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); +} + +.focus\:ring-green-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(132 225 188 / var(--tw-ring-opacity)); +} + +.focus\:ring-green-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(14 159 110 / var(--tw-ring-opacity)); +} + +.focus\:ring-purple-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(202 191 253 / var(--tw-ring-opacity)); +} + +.focus\:ring-red-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(248 180 180 / var(--tw-ring-opacity)); +} + +.focus\:ring-red-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(240 82 82 / var(--tw-ring-opacity)); +} + +.focus\:ring-yellow-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(250 202 21 / var(--tw-ring-opacity)); +} + +@media (min-width: 640px) { + .sm\:mx-auto { + margin-left: auto; + margin-right: auto; + } + + .sm\:mb-0 { + margin-bottom: 0px; + } + + .sm\:block { + display: block; + } + + .sm\:flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + .sm\:items-center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } + + .sm\:justify-between { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + } + + .sm\:text-center { + text-align: center; + } +} + +@media (min-width: 768px) { + .md\:me-6 { + -webkit-margin-end: 1.5rem; + margin-inline-end: 1.5rem; + } + + .md\:text-5xl { + font-size: 3rem; + line-height: 1; + } + + .md\:text-xl { + font-size: 1.25rem; + line-height: 1.75rem; + } +} + +@media (min-width: 1024px) { + .lg\:order-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + + .lg\:order-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + + .lg\:my-6 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + .lg\:mt-0 { + margin-top: 0px; + } + + .lg\:flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + .lg\:hidden { + display: none; + } + + .lg\:w-auto { + width: auto; + } + + .lg\:flex-row { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + + .lg\:space-x-8 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(2rem * var(--tw-space-x-reverse)); + margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); + } + + .lg\:border-0 { + border-width: 0px; + } + + .lg\:p-0 { + padding: 0px; + } + + .lg\:px-4 { + padding-left: 1rem; + padding-right: 1rem; + } + + .lg\:px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; + } + + .lg\:px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + .lg\:py-2\.5 { + padding-top: 0.625rem; + padding-bottom: 0.625rem; + } + + .lg\:pb-24 { + padding-bottom: 6rem; + } + + .lg\:pt-16 { + padding-top: 4rem; + } + + .lg\:text-6xl { + font-size: 3.75rem; + line-height: 1; + } + + .lg\:hover\:bg-transparent:hover { + background-color: transparent; + } +} + +.rtl\:rotate-180:where([dir="rtl"], [dir="rtl"] *) { + --tw-rotate: 180deg; + -webkit-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)); + 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)); +} + +.rtl\:space-x-reverse:where([dir="rtl"], [dir="rtl"] *) > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 1; +} + +@media (prefers-color-scheme: dark) { + .dark\:border-blue-500 { + --tw-border-opacity: 1; + border-color: rgb(63 131 248 / var(--tw-border-opacity)); + } + + .dark\:border-gray-500 { + --tw-border-opacity: 1; + border-color: rgb(107 114 128 / var(--tw-border-opacity)); + } + + .dark\:border-gray-600 { + --tw-border-opacity: 1; + border-color: rgb(75 85 99 / var(--tw-border-opacity)); + } + + .dark\:border-gray-700 { + --tw-border-opacity: 1; + border-color: rgb(55 65 81 / var(--tw-border-opacity)); + } + + .dark\:border-green-500 { + --tw-border-opacity: 1; + border-color: rgb(14 159 110 / var(--tw-border-opacity)); + } + + .dark\:border-purple-400 { + --tw-border-opacity: 1; + border-color: rgb(172 148 250 / var(--tw-border-opacity)); + } + + .dark\:border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(240 82 82 / var(--tw-border-opacity)); + } + + .dark\:border-transparent { + border-color: transparent; + } + + .dark\:border-yellow-300 { + --tw-border-opacity: 1; + border-color: rgb(250 202 21 / var(--tw-border-opacity)); + } + + .dark\:\!bg-gray-700 { + --tw-bg-opacity: 1 !important; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; + } + + .dark\:bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(28 100 242 / var(--tw-bg-opacity)); + } + + .dark\:bg-gray-600 { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); + } + + .dark\:bg-gray-700 { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); + } + + .dark\:bg-gray-800 { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); + } + + .dark\:bg-gray-800\/50 { + background-color: rgb(31 41 55 / 0.5); + } + + .dark\:bg-gray-900 { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); + } + + .dark\:bg-gray-900\/80 { + background-color: rgb(17 24 39 / 0.8); + } + + .dark\:bg-green-600 { + --tw-bg-opacity: 1; + background-color: rgb(5 122 85 / var(--tw-bg-opacity)); + } + + .dark\:bg-purple-600 { + --tw-bg-opacity: 1; + background-color: rgb(126 58 242 / var(--tw-bg-opacity)); + } + + .dark\:bg-red-600 { + --tw-bg-opacity: 1; + background-color: rgb(224 36 36 / var(--tw-bg-opacity)); + } + + .dark\:text-blue-500 { + --tw-text-opacity: 1; + color: rgb(63 131 248 / var(--tw-text-opacity)); + } + + .dark\:text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); + } + + .dark\:text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); + } + + .dark\:text-green-400 { + --tw-text-opacity: 1; + color: rgb(49 196 141 / var(--tw-text-opacity)); + } + + .dark\:text-green-500 { + --tw-text-opacity: 1; + color: rgb(14 159 110 / var(--tw-text-opacity)); + } + + .dark\:text-purple-400 { + --tw-text-opacity: 1; + color: rgb(172 148 250 / var(--tw-text-opacity)); + } + + .dark\:text-red-500 { + --tw-text-opacity: 1; + color: rgb(240 82 82 / var(--tw-text-opacity)); + } + + .dark\:text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + + .dark\:text-yellow-300 { + --tw-text-opacity: 1; + color: rgb(250 202 21 / var(--tw-text-opacity)); + } + + .dark\:placeholder-gray-400::-webkit-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-gray-400::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-gray-400:-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-gray-400::-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-gray-400::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-green-500::-webkit-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(14 159 110 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-green-500::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(14 159 110 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-green-500:-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(14 159 110 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-green-500::-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(14 159 110 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-green-500::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(14 159 110 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-red-500::-webkit-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(240 82 82 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-red-500::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(240 82 82 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-red-500:-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(240 82 82 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-red-500::-ms-input-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(240 82 82 / var(--tw-placeholder-opacity)); + } + + .dark\:placeholder-red-500::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(240 82 82 / var(--tw-placeholder-opacity)); + } + + .dark\:hover\:border-gray-600:hover { + --tw-border-opacity: 1; + border-color: rgb(75 85 99 / var(--tw-border-opacity)); + } + + .dark\:hover\:bg-blue-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(63 131 248 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(26 86 219 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-gray-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-gray-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-gray-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-green-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(5 122 85 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-green-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(4 108 78 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-purple-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(144 97 249 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-purple-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(108 43 217 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-red-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(224 36 36 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-red-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(200 30 30 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-yellow-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(227 160 8 / var(--tw-bg-opacity)); + } + + .dark\:hover\:text-blue-500:hover { + --tw-text-opacity: 1; + color: rgb(63 131 248 / var(--tw-text-opacity)); + } + + .dark\:hover\:text-gray-300:hover { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); + } + + .dark\:hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + + .dark\:focus\:border-blue-500:focus { + --tw-border-opacity: 1; + border-color: rgb(63 131 248 / var(--tw-border-opacity)); + } + + .dark\:focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(63 131 248 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-blue-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(30 66 159 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-gray-600:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-gray-700:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-gray-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(31 41 55 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-green-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(3 84 63 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-purple-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(74 29 150 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-red-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(119 29 29 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-yellow-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(99 49 18 / var(--tw-ring-opacity)); + } +} + +@media (min-width: 1024px) { + @media (prefers-color-scheme: dark) { + .lg\:dark\:hover\:bg-transparent:hover { + background-color: transparent; + } + + .lg\:dark\:hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + } +} \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index c8fdec9..593c8b1 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -13,6 +13,7 @@ import i18n_opts from './config/i18n'; import { LoggerModule } from 'nestjs-pino'; import pinoOpts from './config/pino'; import { OpenTelemetryModule } from 'nestjs-otel'; +import { CredentialsService } from './credentials/credentials.service'; @Module({ controllers: [AppController], @@ -38,5 +39,6 @@ import { OpenTelemetryModule } from 'nestjs-otel'; UsersModule, ValidationModule, ], + providers: [CredentialsService], }) export class AppModule {} diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts index bf6e85e..51a7c6b 100644 --- a/src/auth/auth.controller.spec.ts +++ b/src/auth/auth.controller.spec.ts @@ -9,6 +9,7 @@ import { prismaMock } from '../../prisma/singleton'; import { I18nModule } from 'nestjs-i18n'; import i18n_opts from '@core/config/i18n'; import opts from '@core/config/app'; +import { CredentialsService } from '@core/credentials/credentials.service'; describe('AuthController', () => { let module: TestingModule; @@ -27,6 +28,7 @@ describe('AuthController', () => { providers: [ AuthService, UsersService, + CredentialsService, { provide: PrismaService, useValue: prismaMock }, ], controllers: [AuthController], diff --git a/src/auth/auth.controller.tsx b/src/auth/auth.controller.tsx index 30917a8..354852d 100644 --- a/src/auth/auth.controller.tsx +++ b/src/auth/auth.controller.tsx @@ -1,11 +1,11 @@ -import { Body, Controller } from '@nestjs/common'; +import { Body, Controller, Logger } from '@nestjs/common'; import { AuthService } from './auth.service'; import { ConfigService } from '@nestjs/config'; import { Config } from '@core/config/app'; import { CurrentSession } from './current-session.decorator'; -import { SessionWithUserPii } from '@core/users/users.service'; + import { UserAvatar } from './components/user-avatar'; import { AuthLinks } from './components/auth-links'; import { Base } from '@core/base/base.controller'; @@ -17,11 +17,14 @@ import * as P from '@core/auth/pages'; import { SignInDto } from './schemas/sign-in'; import { EmailDto } from '@core/validation/schemas'; import { MainContent } from '@core/components'; +import { SessionWithUserPii } from '@core/users/users.service'; + const PREFIX = 'auth' as const; const prefix = `/${PREFIX}` as const; @Controller(PREFIX) export class AuthController extends Base { + logger = new Logger(AuthController.name); constructor( private readonly configService: ConfigService, private readonly authService: AuthService, @@ -66,7 +69,8 @@ export class AuthController extends Base { description: 'sign in', }) async sigInPost(@Body() signInDto: SignInDto) { - console.log(signInDto); + const user = await this.authService.localSignIn(signInDto); + this.logger.log(user); } @Route({ @@ -89,7 +93,8 @@ export class AuthController extends Base { description: 'register', }) async registerPost(@Body() signInDto: SignInDto) { - console.log(signInDto); + const user = await this.authService.localRegister(signInDto); + this.logger.log(user); } @Route({ diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 522e53f..6c67984 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -4,10 +4,12 @@ import { AuthService } from './auth.service'; import { UsersModule } from '@core/users/users.module'; import { JwtModule } from '@nestjs/jwt'; import { GoogleController } from './auth.google.controller'; +import { CredentialsService } from '@core/credentials/credentials.service'; +import { PrismaModule } from 'nestjs-prisma'; @Module({ - imports: [JwtModule, UsersModule], + imports: [JwtModule, UsersModule, PrismaModule], controllers: [AuthController, GoogleController], - providers: [AuthService], + providers: [AuthService, CredentialsService], }) export class AuthModule {} diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index d736839..38711ed 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -4,6 +4,7 @@ import { JwtModule } from '@nestjs/jwt'; import { UsersService } from '@core/users/users.service'; import { PrismaService } from 'nestjs-prisma'; import { prismaMock } from '../../prisma/singleton'; +import { CredentialsService } from '@core/credentials/credentials.service'; describe('AuthService', () => { let module: TestingModule; @@ -15,6 +16,7 @@ describe('AuthService', () => { providers: [ AuthService, UsersService, + CredentialsService, { provide: PrismaService, useValue: prismaMock }, ], }).compile(); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 367af5d..c752eb7 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -3,12 +3,19 @@ import { JwtService } from '@nestjs/jwt'; import { SessionWithUserPii, UsersService } from '@core/users/users.service'; import { ValidGoogleOauthData } from './google-oauth.strategy'; import { JwtPayload } from './jwt.strategy'; +import bcrypt from 'bcrypt'; +import { + CredentialsService, + CredentialWithUserPii, +} from '@core/credentials/credentials.service'; +import { SignInDto } from './schemas/sign-in'; @Injectable() export class AuthService { constructor( private jwtService: JwtService, private readonly usersService: UsersService, + private readonly credentialsService: CredentialsService, ) {} generateJwt(payload: JwtPayload) { @@ -20,6 +27,31 @@ export class AuthService { throw new BadRequestException('Invalid user data'); } - return this.usersService.upsertOauthCredentialUser(data); + return this.credentialsService.upsertOauthCredentialUser(data); + } + + async localSignIn({ + email, + password, + }: SignInDto): Promise { + const credential = + await this.credentialsService.findLocalUserByEmail(email); + const valid = await bcrypt.compare(password, credential?.value || ''); + if (!valid || !credential) { + throw new BadRequestException('Invalid email or password'); + } + return credential; + } + + async localRegister({ + email, + password, + }: SignInDto): Promise { + const existing = await this.credentialsService.findLocalUserByEmail(email); + if (existing) { + throw new BadRequestException('User already exists'); + } + + return this.credentialsService.createLocalUser(email, password); } } diff --git a/src/auth/components/user-avatar.tsx b/src/auth/components/user-avatar.tsx index 58b1768..d5b70fe 100644 --- a/src/auth/components/user-avatar.tsx +++ b/src/auth/components/user-avatar.tsx @@ -1,6 +1,7 @@ import { Link } from '@core/components'; +import { PiiType } from '@core/credentials/credentials.service'; import { Translations } from '@core/i18n/i18n.utils'; -import { PiiType, SessionWithUserPii } from '@core/users/users.service'; +import { SessionWithUserPii } from '@core/users/users.service'; export type UserAvatarProps = Translations & { session: SessionWithUserPii; diff --git a/src/auth/google-oauth.strategy.ts b/src/auth/google-oauth.strategy.ts index 2d92095..29d8ee3 100644 --- a/src/auth/google-oauth.strategy.ts +++ b/src/auth/google-oauth.strategy.ts @@ -1,5 +1,6 @@ import { Config } from '@core/config/app'; -import { PiiType } from '@core/users/users.service'; +import { PiiType } from '@core/credentials/credentials.service'; + import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { PassportStrategy } from '@nestjs/passport'; diff --git a/src/auth/local.strategy.ts b/src/auth/local.strategy.ts new file mode 100644 index 0000000..c6b7950 --- /dev/null +++ b/src/auth/local.strategy.ts @@ -0,0 +1,19 @@ +import { Strategy } from 'passport-local'; +import { PassportStrategy } from '@nestjs/passport'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { AuthService } from './auth.service'; + +@Injectable() +export class LocalStrategy extends PassportStrategy(Strategy) { + constructor(private authService: AuthService) { + super(); + } + + async validate(email: string, password: string): Promise { + const user = await this.authService.localSignIn({ email, password }); + if (!user) { + throw new UnauthorizedException(); + } + return user; + } +} diff --git a/src/credentials/credentials.service.spec.ts b/src/credentials/credentials.service.spec.ts new file mode 100644 index 0000000..9c2bc10 --- /dev/null +++ b/src/credentials/credentials.service.spec.ts @@ -0,0 +1,185 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { + CredentialsService, + CredentialWithUserPii, + UserAndPiiInclude, +} from './credentials.service'; +import { PrismaService } from 'nestjs-prisma'; +import { ValidGoogleOauthData } from '@core/auth/google-oauth.strategy'; +import { faker } from '@faker-js/faker'; +import { User, Pii, Credential, Prisma } from '@prisma/client'; +import { pick } from 'lodash'; +import { prismaMock } from '../../prisma/singleton'; + +describe('CredentialsService', () => { + let service: CredentialsService; + let module: TestingModule; + + const data: ValidGoogleOauthData = { + credential: { + type: 'google', + value: 'google_id', + external_id: 'google_id', + refresh_token: 'refresh_token', + expires_at: faker.date.future(), + }, + pii: [{ type: 'email', value: faker.internet.exampleEmail() }], + }; + const user: User = { + id: faker.string.uuid(), + created_at: faker.date.past(), + updated_at: faker.date.recent(), + status: 'verified', + }; + const pii: Pii[] = [ + { + id: faker.string.uuid(), + type: 'email', + value: data.pii[0].value, + user_id: user.id, + created_at: faker.date.past(), + updated_at: faker.date.recent(), + }, + ]; + const credential: Credential = { + id: faker.string.uuid(), + type: data.credential.type, + value: data.credential.value, + external_id: data.credential.external_id, + refresh_token: data.credential.refresh_token, + expires_at: data.credential.expires_at, + user_id: user.id, + created_at: faker.date.past(), + updated_at: faker.date.recent(), + }; + const credentialWithUserPii: CredentialWithUserPii = { + ...credential, + user: { + ...user, + pii, + }, + } as const; + + beforeAll(async () => { + module = await Test.createTestingModule({ + providers: [ + CredentialsService, + { + provide: PrismaService, + useValue: prismaMock, + }, + ], + }).compile(); + + service = module.get(CredentialsService); + }); + afterAll(async () => { + await module.close(); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + describe('createCredentialedUser', () => { + it('should create a new user', async () => { + prismaMock.credential.create.mockResolvedValue(credentialWithUserPii); + + const args = { + data: { + ...pick(credential, [ + 'type', + 'value', + 'external_id', + 'refresh_token', + 'expires_at', + ]), + user: { + create: { + pii: { + createMany: { + data: pii.map((p) => pick(p, ['type', 'value'])), + }, + }, + }, + }, + }, + ...UserAndPiiInclude, + } satisfies Prisma.CredentialCreateArgs; + + const result = await service.createCredentialedUser(data); + + expect(prismaMock.credential.create).toHaveBeenCalledWith(args); + + expect(result).toEqual(credentialWithUserPii); + }); + }); + describe('updateCredentialedUser', () => { + it('should update a user', async () => { + const newPii: Pii = { + id: faker.string.uuid(), + created_at: faker.date.past(), + updated_at: faker.date.recent(), + type: 'phone', + value: faker.phone.number(), + user_id: user.id, + }; + const newCredentialWithPii: CredentialWithUserPii = { + ...credentialWithUserPii, + user: { + ...credentialWithUserPii.user, + pii: [...pii, newPii], + }, + }; + prismaMock.credential.upsert.mockResolvedValue(newCredentialWithPii); + const gPii = pick(newPii, [ + 'type', + 'value', + ]) as ValidGoogleOauthData['pii'][number]; + const result = await service.updateCredentialedUser(user, { + ...data, + pii: [...data.pii, gPii], + }); + + expect(prismaMock.pii.upsert).toHaveBeenNthCalledWith(1, { + where: { + type_user_id: { type: 'email', user_id: user.id }, + }, + create: { + ...data.pii[0], + user: { + connect: { id: user.id }, + }, + }, + update: data.pii[0], + }); + expect(prismaMock.pii.upsert).toHaveBeenNthCalledWith(2, { + where: { + type_user_id: { type: 'phone', user_id: user.id }, + }, + create: { + ...gPii, + user: { + connect: { id: user.id }, + }, + }, + update: gPii, + }); + + expect(prismaMock.credential.upsert).toHaveBeenCalledWith({ + where: { + type_external_id: pick(data.credential, ['type', 'external_id']), + }, + create: { + ...data.credential, + user: { + connect: { id: user.id }, + }, + }, + update: data.credential, + ...UserAndPiiInclude, + }); + + expect(result).toEqual(newCredentialWithPii); + }); + }); +}); diff --git a/src/credentials/credentials.service.ts b/src/credentials/credentials.service.ts new file mode 100644 index 0000000..b2d330b --- /dev/null +++ b/src/credentials/credentials.service.ts @@ -0,0 +1,196 @@ +import { ValidGoogleOauthData } from '@core/auth/google-oauth.strategy'; +import { Injectable } from '@nestjs/common'; +import { Prisma, User } from '@prisma/client'; +import { PrismaService } from 'nestjs-prisma'; +import * as bcrypt from 'bcrypt'; +import { addDays } from 'date-fns'; +import { pick } from 'lodash'; + +export const VerifiablePiiTypes = ['email', 'phone'] as const; +export type VerifiablePiiType = (typeof VerifiablePiiTypes)[number]; + +export const PII_TYPES = [ + ...VerifiablePiiTypes, + 'first_name', + 'last_name', + 'display_name', + 'address', + 'profile_photo_url', +] as const; + +export type PiiType = (typeof PII_TYPES)[number]; +export const PiiType: Record = PII_TYPES.reduce( + (acc, type) => ({ ...acc, [type]: type }), + {} as Record, +); + +export const UserAndPiiInclude = { + include: { + user: { include: { pii: true } }, + }, +} satisfies Prisma.CredentialDefaultArgs; + +export type CredentialWithUserPii = Prisma.CredentialGetPayload< + typeof UserAndPiiInclude +>; + +const SALT_ROUNDS = 10; + +const PASSWORD_ROTATION_DAYS = 90; + +@Injectable() +export class CredentialsService { + constructor(private readonly db: PrismaService) {} + /** + * Finds an existing user by external_id or email + * @param {ValidGoogleOauthData} data - The data to search for + * @returns {Promise} The user if found, otherwise null + */ + private async findExistingUser( + data: ValidGoogleOauthData, + ): Promise { + const OR: Prisma.UserWhereInput['OR'] = [ + { + credentials: { + some: { + external_id: data.credential.external_id, + type: data.credential.type, + }, + }, + }, + ]; + const email = data.pii.find((pii) => pii.type === 'email'); + if (email) { + OR.push({ pii: { some: email } }); + } + return this.db.user.findFirst({ + where: { + OR, + }, + }); + } + + /** + * Create a new user with the given data + * @param {ValidGoogleOauthData} data - The data to create the user with + * @returns {Promise} The user session with associated User and PII + */ + async createCredentialedUser(data: ValidGoogleOauthData) { + const { credential, pii } = data; + return this.db.credential.create({ + data: { + ...credential, + user: { + create: { + pii: { + createMany: { data: pii }, + }, + }, + }, + }, + ...UserAndPiiInclude, + }); + } + + /** + * Update a user with the given data + * @param {User} user - The user to update + * @param {ValidGoogleOauthData} data - The data to update the user with + * @returns {Promise} The user session with associated User and PII + */ + async updateCredentialedUser(user: User, data: ValidGoogleOauthData) { + const { credential, pii } = data; + await this.db.$transaction( + pii.map((pii) => + this.db.pii.upsert({ + where: { + type_user_id: { type: pii.type, user_id: user.id }, + }, + create: { + ...pii, + user: { + connect: { id: user.id }, + }, + }, + update: pii, + }), + ), + ); + return this.db.credential.upsert({ + where: { + type_external_id: pick(credential, ['type', 'external_id']), + }, + create: { + ...credential, + user: { + connect: { id: user.id }, + }, + }, + update: credential, + ...UserAndPiiInclude, + }); + } + + /** + * Upsert a user with the given data + * @param {ValidGoogleOauthData} data - The data to upsert the user with + * @returns {Promise} The user session with associated User and PII + */ + async upsertOauthCredentialUser( + data: ValidGoogleOauthData, + ): Promise { + const existing = await this.findExistingUser(data); + + if (existing) { + return this.updateCredentialedUser(existing, data); + } + return this.createCredentialedUser(data); + } + + /** + * + * @param email + * @returns + */ + async findLocalUserByEmail( + email: string, + ): Promise { + return this.db.credential.findUnique({ + where: { + user: { pii: { some: { type: 'email', value: email } } }, + type_external_id: { type: 'password', external_id: email }, + }, + ...UserAndPiiInclude, + }); + } + + private async createCredential(data: Prisma.CredentialCreateInput) { + return this.db.credential.create({ data, ...UserAndPiiInclude }); + } + + /** + * Create a new user with the given email and password + * @param email + * @param password + * @returns + */ + async createLocalUser(email: string, password: string) { + const hashed = await bcrypt.hash(password, SALT_ROUNDS); + return this.createCredential({ + type: 'password', + value: hashed, + external_id: email, + expires_at: addDays(new Date(), PASSWORD_ROTATION_DAYS), + user: { + create: { + pii: { + create: { + type: 'email', + value: email, + }, + }, + }, + }, + }); + } +} diff --git a/src/users/users.controller.spec.ts b/src/users/users.controller.spec.ts deleted file mode 100644 index 90d34da..0000000 --- a/src/users/users.controller.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { UsersController } from './users.controller'; -import { UsersService } from './users.service'; -import { PrismaService } from 'nestjs-prisma'; -import { prismaMock } from '../../prisma/singleton'; - -describe('UsersController', () => { - let module: TestingModule; - let controller: UsersController; - - beforeAll(async () => { - module = await Test.createTestingModule({ - controllers: [UsersController], - providers: [ - UsersService, - { - provide: PrismaService, - useValue: prismaMock, - }, - ], - }).compile(); - - controller = module.get(UsersController); - }); - - afterAll(async () => { - await module.close(); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts deleted file mode 100644 index 527b7a7..0000000 --- a/src/users/users.controller.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Controller } from '@nestjs/common'; -import { UsersService } from './users.service'; - -@Controller('users') -export class UsersController { - constructor(private readonly usersService: UsersService) {} -} diff --git a/src/users/users.service.spec.ts b/src/users/users.service.spec.ts index f8baecb..b9c595e 100644 --- a/src/users/users.service.spec.ts +++ b/src/users/users.service.spec.ts @@ -1,16 +1,11 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { - CredentialWithUserPii, - SessionWithUserPii, - UserAndPiiInclude, - UsersService, -} from './users.service'; +import { SessionWithUserPii, UsersService } from './users.service'; import { PrismaService } from 'nestjs-prisma'; import { prismaMock } from '../../prisma/singleton'; import { faker } from '@faker-js/faker'; -import { Pii, User, Credential, Prisma } from '@prisma/client'; +import { Pii, User } from '@prisma/client'; import { ValidGoogleOauthData } from '@core/auth/google-oauth.strategy'; -import { pick } from 'lodash'; +import { UserAndPiiInclude } from '@core/credentials/credentials.service'; describe('UsersService', () => { let module: TestingModule; @@ -42,25 +37,6 @@ describe('UsersService', () => { updated_at: faker.date.recent(), }, ]; - const credential: Credential = { - id: faker.string.uuid(), - type: data.credential.type, - value: data.credential.value, - external_id: data.credential.external_id, - refresh_token: data.credential.refresh_token, - expires_at: data.credential.expires_at, - user_id: user.id, - created_at: faker.date.past(), - updated_at: faker.date.recent(), - }; - const credentialWithUserPii: CredentialWithUserPii = { - ...credential, - user: { - ...user, - pii, - }, - } as const; - const session: SessionWithUserPii = { id: faker.string.uuid(), created_at: faker.date.past(), @@ -83,99 +59,14 @@ describe('UsersService', () => { service = module.get(UsersService); }); - // afterAll(async () => { - // await module.close(); - // }); + afterAll(async () => { + await module.close(); + }); it('should be defined', () => { expect(service).toBeDefined(); }); - describe('findExistingUser', () => { - it('should find a user by external_id', async () => { - prismaMock.user.findFirst.mockResolvedValue(user); - - const result = await service.findExistingUser(data); - - expect(prismaMock.user.findFirst).toHaveBeenCalledWith({ - where: { - OR: [ - { - credentials: { - some: { - external_id: data.credential.external_id, - type: data.credential.type, - }, - }, - }, - { - pii: { - some: { - value: data.pii[0].value, - type: data.pii[0].type, - }, - }, - }, - ], - }, - }); - - expect(result).toEqual(user); - - const result2 = await service.findExistingUser({ - ...data, - pii: [], - }); - - expect(prismaMock.user.findFirst).toHaveBeenCalledWith({ - where: { - OR: [ - { - credentials: { - some: { - external_id: data.credential.external_id, - type: data.credential.type, - }, - }, - }, - ], - }, - }); - - expect(result2).toEqual(user); - }); - it('should return null if no user is found', async () => { - prismaMock.user.findFirst.mockResolvedValue(null); - - const result = await service.findExistingUser(data); - - expect(prismaMock.user.findFirst).toHaveBeenCalledWith({ - where: { - OR: [ - { - credentials: { - some: { - external_id: data.credential.external_id, - type: data.credential.type, - }, - }, - }, - { - pii: { - some: { - value: data.pii[0].value, - type: data.pii[0].type, - }, - }, - }, - ], - }, - }); - - expect(result).toBeNull(); - }); - }); - describe('getUserByJwt', () => { it('should get a user by jwt', async () => { const payload = { sub: session.id }; @@ -207,108 +98,4 @@ describe('UsersService', () => { expect(result).toBeNull(); }); }); - - describe('createCredentialedUser', () => { - it('should create a new user', async () => { - prismaMock.credential.create.mockResolvedValue(credentialWithUserPii); - - const args = { - data: { - ...pick(credential, [ - 'type', - 'value', - 'external_id', - 'refresh_token', - 'expires_at', - ]), - user: { - create: { - pii: { - createMany: { - data: pii.map((p) => pick(p, ['type', 'value'])), - }, - }, - }, - }, - }, - ...UserAndPiiInclude, - } satisfies Prisma.CredentialCreateArgs; - - const result = await service.createCredentialedUser(data); - - expect(prismaMock.credential.create).toHaveBeenCalledWith(args); - - expect(result).toEqual(credentialWithUserPii); - }); - }); - - describe('updateCredentialedUser', () => { - it('should update a user', async () => { - const newPii: Pii = { - id: faker.string.uuid(), - created_at: faker.date.past(), - updated_at: faker.date.recent(), - type: 'phone', - value: faker.phone.number(), - user_id: user.id, - }; - const newCredentialWithPii: CredentialWithUserPii = { - ...credentialWithUserPii, - user: { - ...credentialWithUserPii.user, - pii: [...pii, newPii], - }, - }; - prismaMock.credential.upsert.mockResolvedValue(newCredentialWithPii); - const gPii = pick(newPii, [ - 'type', - 'value', - ]) as ValidGoogleOauthData['pii'][number]; - const result = await service.updateCredentialedUser(user, { - ...data, - pii: [...data.pii, gPii], - }); - - expect(prismaMock.pii.upsert).toHaveBeenNthCalledWith(1, { - where: { - type_user_id: { type: 'email', user_id: user.id }, - }, - create: { - ...data.pii[0], - user: { - connect: { id: user.id }, - }, - }, - update: data.pii[0], - }); - expect(prismaMock.pii.upsert).toHaveBeenNthCalledWith(2, { - where: { - type_user_id: { type: 'phone', user_id: user.id }, - }, - create: { - ...gPii, - user: { - connect: { id: user.id }, - }, - }, - update: gPii, - }); - - expect(prismaMock.credential.upsert).toHaveBeenCalledWith({ - where: { - type_external_id: pick(data.credential, ['type', 'external_id']), - }, - create: { - ...data.credential, - user: { - connect: { id: user.id }, - }, - }, - update: data.credential, - ...UserAndPiiInclude, - }); - - expect(result).toEqual(newCredentialWithPii); - }); - }); }); diff --git a/src/users/users.service.ts b/src/users/users.service.ts index d0f8ff8..d1e13d9 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -1,71 +1,19 @@ -import { ValidGoogleOauthData } from '@core/auth/google-oauth.strategy'; import { JwtPayload } from '@core/auth/jwt.strategy'; +import { UserAndPiiInclude } from '@core/credentials/credentials.service'; import { Injectable, Logger } from '@nestjs/common'; -import { Prisma, User } from '@prisma/client'; -import { pick } from 'lodash'; -import { PrismaService } from 'nestjs-prisma'; - -export const PII_TYPES = [ - 'first_name', - 'last_name', - 'display_name', - 'email', - 'phone', - 'address', - 'profile_photo_url', -] as const; -export type PiiType = (typeof PII_TYPES)[number]; -export const PiiType: Record = PII_TYPES.reduce( - (acc, type) => ({ ...acc, [type]: type }), - {} as Record, -); +import { Prisma } from '@prisma/client'; -export const UserAndPiiInclude = { - include: { - user: { include: { pii: true } }, - }, -} satisfies Prisma.SessionDefaultArgs; +import { PrismaService } from 'nestjs-prisma'; export type SessionWithUserPii = Prisma.SessionGetPayload< typeof UserAndPiiInclude >; -export type CredentialWithUserPii = Prisma.CredentialGetPayload< - typeof UserAndPiiInclude ->; - @Injectable() export class UsersService { #log = new Logger(UsersService.name); constructor(private readonly db: PrismaService) {} - /** - * Finds an existing user by external_id or email - * @param {ValidGoogleOauthData} data - The data to search for - * @returns {Promise} The user if found, otherwise null - */ - async findExistingUser(data: ValidGoogleOauthData): Promise { - const OR: Prisma.UserWhereInput['OR'] = [ - { - credentials: { - some: { - external_id: data.credential.external_id, - type: data.credential.type, - }, - }, - }, - ]; - const email = data.pii.find((pii) => pii.type === 'email'); - if (email) { - OR.push({ pii: { some: email } }); - } - return this.db.user.findFirst({ - where: { - OR, - }, - }); - } - /** * Get a user by their JWT payload * @param {JwtPayload} jwt - The JWT payload @@ -79,81 +27,4 @@ export class UsersService { }); return session; } - - /** - * Create a new user with the given data - * @param {ValidGoogleOauthData} data - The data to create the user with - * @returns {Promise} The user session with associated User and PII - */ - async createCredentialedUser(data: ValidGoogleOauthData) { - const { credential, pii } = data; - return this.db.credential.create({ - data: { - ...credential, - user: { - create: { - pii: { - createMany: { data: pii }, - }, - }, - }, - }, - ...UserAndPiiInclude, - }); - } - - /** - * Update a user with the given data - * @param {User} user - The user to update - * @param {ValidGoogleOauthData} data - The data to update the user with - * @returns {Promise} The user session with associated User and PII - */ - async updateCredentialedUser(user: User, data: ValidGoogleOauthData) { - const { credential, pii } = data; - await this.db.$transaction( - pii.map((pii) => - this.db.pii.upsert({ - where: { - type_user_id: { type: pii.type, user_id: user.id }, - }, - create: { - ...pii, - user: { - connect: { id: user.id }, - }, - }, - update: pii, - }), - ), - ); - return this.db.credential.upsert({ - where: { - type_external_id: pick(credential, ['type', 'external_id']), - }, - create: { - ...credential, - user: { - connect: { id: user.id }, - }, - }, - update: credential, - ...UserAndPiiInclude, - }); - } - - /** - * Upsert a user with the given data - * @param {ValidGoogleOauthData} data - The data to upsert the user with - * @returns {Promise} The user session with associated User and PII - */ - async upsertOauthCredentialUser( - data: ValidGoogleOauthData, - ): Promise { - const existing = await this.findExistingUser(data); - - if (existing) { - return this.updateCredentialedUser(existing, data); - } - return this.createCredentialedUser(data); - } }