Spaces:
Running
Running
Mark Duppenthaler
commited on
Commit
·
ca345b7
1
Parent(s):
81574bd
Updated with sorting rows and columns
Browse files- README.md +7 -14
- backend/mk_leaderboard.py +0 -0
- frontend/dist/assets/index-BWZpYvtq.css +1 -0
- frontend/dist/assets/index-CwrBXUIs.css +0 -1
- frontend/dist/assets/{index-RC6rN_Gk.js → index-D2ksG3qQ.js} +0 -0
- frontend/dist/index.html +2 -2
- frontend/src/components/DatasetSelector.tsx +2 -2
- frontend/src/components/IndependentMetricsTable.tsx +69 -0
- frontend/src/components/LeaderboardFilter.tsx +186 -152
- frontend/src/components/LeaderboardTable.tsx +559 -243
- frontend/src/components/ModelFilter.tsx +2 -2
README.md
CHANGED
@@ -1,15 +1,13 @@
|
|
1 |
---
|
2 |
-
title: Omniseal
|
3 |
emoji: 🦀
|
4 |
colorFrom: red
|
5 |
colorTo: green
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
-
short_description:
|
9 |
---
|
10 |
|
11 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
12 |
-
|
13 |
## Docker Build Instructions
|
14 |
|
15 |
### Prerequisites
|
@@ -24,9 +22,10 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
24 |
```bash
|
25 |
cd backend
|
26 |
conda env create -f environment.yml -y
|
|
|
27 |
```
|
28 |
|
29 |
-
2. Build frontend (outputs html, js, css into frontend/dist)
|
30 |
|
31 |
```bash
|
32 |
cd frontend
|
@@ -34,7 +33,7 @@ npm install
|
|
34 |
npm run build
|
35 |
```
|
36 |
|
37 |
-
3. Run backend server
|
38 |
|
39 |
```bash
|
40 |
gunicorn --chdir backend -b 0.0.0.0:7860 app:app --reload
|
@@ -44,13 +43,7 @@ gunicorn --chdir backend -b 0.0.0.0:7860 app:app --reload
|
|
44 |
|
45 |
### Build Steps (Docker, huggingface)
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
```bash
|
50 |
-
cd /path/to/omniseal_dev
|
51 |
-
```
|
52 |
-
|
53 |
-
2. Build the Docker image:
|
54 |
|
55 |
```bash
|
56 |
docker build -t omniseal-benchmark .
|
@@ -74,7 +67,7 @@ docker run -p 7860:7860 -v $(pwd)/backend:/app/backend omniseal-benchmark
|
|
74 |
|
75 |
When updating the backend, you can run it in whichever build steps above to take advantage of hot-reload so you don't have to restart the server.
|
76 |
|
77 |
-
For the frontend
|
78 |
|
79 |
1. Create a `.env.local` file in the frontend directory. Set `VITE_API_SERVER_URL` to where your backend server is running. When running locally it will be `VITE_API_SERVER_URL=http://localhost:7860`. This overrides the configuration in `.env` so the frontend will connect with your backend URL of choice.
|
80 |
|
|
|
1 |
---
|
2 |
+
title: Omniseal Leaderboard
|
3 |
emoji: 🦀
|
4 |
colorFrom: red
|
5 |
colorTo: green
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
+
short_description: Leaderboard for watermarking models
|
9 |
---
|
10 |
|
|
|
|
|
11 |
## Docker Build Instructions
|
12 |
|
13 |
### Prerequisites
|
|
|
22 |
```bash
|
23 |
cd backend
|
24 |
conda env create -f environment.yml -y
|
25 |
+
conda activate omniseal-benchmark-backend
|
26 |
```
|
27 |
|
28 |
+
2. Build frontend (outputs html, js, css into frontend/dist). Note you only need this if you are updating the frontend, the repository would already have a build checked in at frontend/dist
|
29 |
|
30 |
```bash
|
31 |
cd frontend
|
|
|
33 |
npm run build
|
34 |
```
|
35 |
|
36 |
+
3. Run backend server from project root. This would serve frontend files from port http://localhost:7860
|
37 |
|
38 |
```bash
|
39 |
gunicorn --chdir backend -b 0.0.0.0:7860 app:app --reload
|
|
|
43 |
|
44 |
### Build Steps (Docker, huggingface)
|
45 |
|
46 |
+
2. Build the Docker image from project root:
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
```bash
|
49 |
docker build -t omniseal-benchmark .
|
|
|
67 |
|
68 |
When updating the backend, you can run it in whichever build steps above to take advantage of hot-reload so you don't have to restart the server.
|
69 |
|
70 |
+
For the frontend:
|
71 |
|
72 |
1. Create a `.env.local` file in the frontend directory. Set `VITE_API_SERVER_URL` to where your backend server is running. When running locally it will be `VITE_API_SERVER_URL=http://localhost:7860`. This overrides the configuration in `.env` so the frontend will connect with your backend URL of choice.
|
73 |
|
backend/mk_leaderboard.py
DELETED
File without changes
|
frontend/dist/assets/index-BWZpYvtq.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
/*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-700:oklch(37.3% .034 259.733);--color-black:#000;--spacing:.25rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--ease-in:cubic-bezier(.4,0,1,1);--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light]{color-scheme:light;--color-base-100:oklch(100% 0 0);--color-base-200:oklch(98% 0 0);--color-base-300:oklch(95% 0 0);--color-base-content:oklch(21% .006 285.885);--color-primary:oklch(45% .24 277.023);--color-primary-content:oklch(93% .034 272.788);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}@media (prefers-color-scheme:dark){:root{color-scheme:dark;--color-base-100:oklch(25.33% .016 252.42);--color-base-200:oklch(23.26% .014 253.1);--color-base-300:oklch(21.15% .012 254.09);--color-base-content:oklch(97.807% .029 256.847);--color-primary:oklch(58% .233 277.117);--color-primary-content:oklch(96% .018 272.314);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}}:root:has(input.theme-controller[value=light]:checked),[data-theme=light]{color-scheme:light;--color-base-100:oklch(100% 0 0);--color-base-200:oklch(98% 0 0);--color-base-300:oklch(95% 0 0);--color-base-content:oklch(21% .006 285.885);--color-primary:oklch(45% .24 277.023);--color-primary-content:oklch(93% .034 272.788);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}:root:has(input.theme-controller[value=dark]:checked),[data-theme=dark]{color-scheme:dark;--color-base-100:oklch(25.33% .016 252.42);--color-base-200:oklch(23.26% .014 253.1);--color-base-300:oklch(21.15% .012 254.09);--color-base-content:oklch(97.807% .029 256.847);--color-primary:oklch(58% .233 277.117);--color-primary-content:oklch(96% .018 272.314);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}@property --radialprogress{syntax: "<percentage>"; inherits: true; initial-value: 0%;}:root{scrollbar-color:currentColor #0000}@supports (color:color-mix(in lab,red,red)){:root{scrollbar-color:color-mix(in oklch,currentColor 35%,#0000)#0000}}:root{--fx-noise:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.34' numOctaves='4' stitchTiles='stitch'%3E%3C/feTurbulence%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)' opacity='0.2'%3E%3C/rect%3E%3C/svg%3E")}:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not([class*=drawer-open])>.drawer-toggle:checked){overflow:hidden}:where(:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not(.drawer-open)>.drawer-toggle:checked)){scrollbar-gutter:stable;background-image:linear-gradient(var(--color-base-100),var(--color-base-100));--root-bg:var(--color-base-100)}@supports (color:color-mix(in lab,red,red)){:where(:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not(.drawer-open)>.drawer-toggle:checked)){--root-bg:color-mix(in srgb,var(--color-base-100),oklch(0% 0 0) 40%)}}:where(.modal[open],.modal-open,.modal-toggle:checked+.modal):not(.modal-start,.modal-end){scrollbar-gutter:stable}:root,[data-theme]{background-color:var(--root-bg,var(--color-base-100));color:var(--color-base-content)}}@layer components;@layer utilities{.diff{webkit-user-select:none;-webkit-user-select:none;user-select:none;direction:ltr;grid-template-columns:auto 1fr;width:100%;display:grid;position:relative;overflow:hidden;container-type:inline-size}.diff:focus-visible,.diff:has(.diff-item-1:focus-visible){outline-style:var(--tw-outline-style);outline-offset:1px;outline-width:2px;outline-color:var(--color-base-content)}.diff:focus-visible .diff-resizer{min-width:90cqi;max-width:90cqi}.diff:has(.diff-item-2:focus-visible){outline-style:var(--tw-outline-style);outline-offset:1px;outline-width:2px}.diff:has(.diff-item-2:focus-visible) .diff-resizer{min-width:10cqi;max-width:10cqi}@supports (-webkit-overflow-scrolling:touch) and (overflow:-webkit-paged-x){.diff:focus .diff-resizer{min-width:10cqi;max-width:10cqi}.diff:has(.diff-item-1:focus) .diff-resizer{min-width:90cqi;max-width:90cqi}}.tab{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-align:center;webkit-user-select:none;-webkit-user-select:none;user-select:none;flex-wrap:wrap;justify-content:center;align-items:center;display:inline-flex;position:relative}@media (hover:hover){.tab:hover{color:var(--color-base-content)}}.tab{--tab-p:1rem;--tab-bg:var(--color-base-100);--tab-border-color:var(--color-base-300);--tab-radius-ss:0;--tab-radius-se:0;--tab-radius-es:0;--tab-radius-ee:0;--tab-order:0;--tab-radius-min:calc(.75rem - var(--border));order:var(--tab-order);height:var(--tab-height);border-color:#0000;padding-inline-start:var(--tab-p);padding-inline-end:var(--tab-p);font-size:.875rem}.tab:is(input[type=radio]){min-width:fit-content}.tab:is(input[type=radio]):after{content:attr(aria-label)}.tab:is(label){position:relative}.tab:is(label) input{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0;position:absolute;top:0;right:0;bottom:0;left:0}:is(.tab:checked,.tab:is(label:has(:checked)),.tab:is(.tab-active,[aria-selected=true]))+.tab-content{height:calc(100% - var(--tab-height) + var(--border));display:block}.tab:not(:checked,label:has(:checked),:hover,.tab-active,[aria-selected=true]){color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.tab:not(:checked,label:has(:checked),:hover,.tab-active,[aria-selected=true]){color:color-mix(in oklab,var(--color-base-content)50%,transparent)}}.tab:not(input):empty{cursor:default;flex-grow:1}.tab:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.tab:focus{outline-offset:2px;outline:2px solid #0000}}.tab:focus-visible,.tab:is(label:has(:checked:focus-visible)){outline-offset:-5px;outline:2px solid}.tab[disabled]{pointer-events:none;opacity:.4}.collapse-arrow>.collapse-title:after{content:"";transform-origin:75% 75%;pointer-events:none;top:1.9rem;width:.5rem;height:.5rem;transition-property:all;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:block;position:absolute;inset-inline-end:1.4rem;transform:translateY(-100%)rotate(45deg);box-shadow:2px 2px}.loading{pointer-events:none;aspect-ratio:1;vertical-align:middle;width:calc(var(--size-selector,.25rem)*6);background-color:currentColor;display:inline-block;-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:100%;mask-size:100%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.pointer-events-none{pointer-events:none}.collapse:not(td,tr,colgroup){visibility:visible}.collapse{border-radius:var(--radius-box,1rem);isolation:isolate;grid-template-rows:max-content 0fr;width:100%;transition:grid-template-rows .2s;display:grid;position:relative;overflow:hidden}.collapse>input:is([type=checkbox],[type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0;z-index:1;grid-row-start:1;grid-column-start:1;width:100%;min-height:1lh;padding:1rem;padding-inline-end:3rem;transition:background-color .2s ease-out}.collapse:is([open],:focus:not(.collapse-close)),.collapse:not(.collapse-close):has(>input:is([type=checkbox],[type=radio]):checked){grid-template-rows:max-content 1fr}.collapse:is([open],:focus:not(.collapse-close))>.collapse-content,.collapse:not(.collapse-close)>:where(input:is([type=checkbox],[type=radio]):checked~.collapse-content){visibility:visible;min-height:fit-content}.collapse:focus-visible,.collapse:has(>input:is([type=checkbox],[type=radio]):focus-visible){outline-color:var(--color-base-content);outline-offset:2px;outline-width:2px;outline-style:solid}.collapse:not(.collapse-close)>input[type=checkbox],.collapse:not(.collapse-close)>input[type=radio]:not(:checked),.collapse:not(.collapse-close)>.collapse-title{cursor:pointer}.collapse:focus:not(.collapse-close,.collapse[open])>.collapse-title{cursor:unset}.collapse:is([open],:focus:not(.collapse-close))>:where(.collapse-content),.collapse:not(.collapse-close)>:where(input:is([type=checkbox],[type=radio]):checked~.collapse-content){padding-bottom:1rem;transition:padding .2s ease-out,background-color .2s ease-out}.collapse[open].collapse-arrow>.collapse-title:after,.collapse.collapse-open.collapse-arrow>.collapse-title:after{transform:translateY(-50%)rotate(225deg)}.collapse.collapse-open.collapse-plus>.collapse-title:after{content:"−"}.collapse.collapse-arrow:focus:not(.collapse-close)>.collapse-title:after,.collapse.collapse-arrow:not(.collapse-close)>input:is([type=checkbox],[type=radio]):checked~.collapse-title:after{transform:translateY(-50%)rotate(225deg)}.collapse[open].collapse-plus>.collapse-title:after,.collapse.collapse-plus:focus:not(.collapse-close)>.collapse-title:after,.collapse.collapse-plus:not(.collapse-close)>input:is([type=checkbox],[type=radio]):checked~.collapse-title:after{content:"−"}.collapse:is(details){width:100%}.collapse:is(details) summary{display:block;position:relative}.collapse:is(details) summary::-webkit-details-marker{display:none}.collapse:is(details) summary{outline:none}.collapse-content{visibility:hidden;min-height:0;cursor:unset;grid-row-start:2;grid-column-start:1;padding-left:1rem;padding-right:1rem;transition:visibility .2s,padding .2s ease-out,background-color .2s ease-out}.collapse{visibility:collapse}.visible{visibility:visible}.toggle{border:var(--border)solid currentColor;color:var(--input-color);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;vertical-align:middle;webkit-user-select:none;-webkit-user-select:none;user-select:none;--radius-selector-max:calc(var(--radius-selector) + var(--radius-selector) + var(--radius-selector));border-radius:calc(var(--radius-selector) + min(var(--toggle-p),var(--radius-selector-max)) + min(var(--border),var(--radius-selector-max)));padding:var(--toggle-p);flex-shrink:0;grid-template-columns:0fr 1fr 1fr;place-content:center;display:inline-grid;position:relative;box-shadow:inset 0 1px}@supports (color:color-mix(in lab,red,red)){.toggle{box-shadow:0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000) inset}}.toggle{--input-color:var(--color-base-content);transition:color .3s,grid-template-columns .2s}@supports (color:color-mix(in lab,red,red)){.toggle{--input-color:color-mix(in oklab,var(--color-base-content)50%,#0000)}}.toggle{--toggle-p:calc(var(--size)*.125);--size:calc(var(--size-selector,.25rem)*6);width:calc((var(--size)*2) - (var(--border) + var(--toggle-p))*2);height:var(--size)}.toggle>*{z-index:1;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#0000;border:none;grid-column:2/span 1;grid-row-start:1;height:100%;padding:.125rem;transition:opacity .2s,rotate .4s}.toggle>:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.toggle>:focus{outline-offset:2px;outline:2px solid #0000}}.toggle>:nth-child(2){color:var(--color-base-100);rotate:none}.toggle>:nth-child(3){color:var(--color-base-100);opacity:0;rotate:-15deg}.toggle:has(:checked)>:nth-child(2){opacity:0;rotate:15deg}.toggle:has(:checked)>:nth-child(3){opacity:1;rotate:none}.toggle:before{aspect-ratio:1;border-radius:var(--radius-selector);--tw-content:"";content:var(--tw-content);height:100%;box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor;background-color:currentColor;grid-row-start:1;grid-column-start:2;transition:background-color .1s,translate .2s,inset-inline-start .2s;position:relative;inset-inline-start:0;translate:0}@supports (color:color-mix(in lab,red,red)){.toggle:before{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000)}}.toggle:before{background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise)}@media (forced-colors:active){.toggle:before{outline-style:var(--tw-outline-style);outline-offset:-1px;outline-width:1px}}@media print{.toggle:before{outline-offset:-1rem;outline:.25rem solid}}.toggle:focus-visible,.toggle:has(:focus-visible){outline-offset:2px;outline:2px solid}.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked){background-color:var(--color-base-100);--input-color:var(--color-base-content);grid-template-columns:1fr 1fr 0fr}:is(.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked)):before{background-color:currentColor}@starting-style{:is(.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked)):before{opacity:0}}.toggle:indeterminate{grid-template-columns:.5fr 1fr .5fr}.toggle:disabled{cursor:not-allowed;opacity:.3}.toggle:disabled:before{border:var(--border)solid currentColor;background-color:#0000}.input{cursor:text;border:var(--border)solid #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--color-base-100);vertical-align:middle;white-space:nowrap;width:clamp(3rem,20rem,100%);height:var(--size);touch-action:manipulation;border-color:var(--input-color);box-shadow:0 1px var(--input-color) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset;border-start-start-radius:var(--join-ss,var(--radius-field));border-start-end-radius:var(--join-se,var(--radius-field));border-end-end-radius:var(--join-ee,var(--radius-field));border-end-start-radius:var(--join-es,var(--radius-field));flex-shrink:1;align-items:center;gap:.5rem;padding-inline:.75rem;font-size:.875rem;display:inline-flex;position:relative}@supports (color:color-mix(in lab,red,red)){.input{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset}}.input{--size:calc(var(--size-field,.25rem)*10);--input-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.input{--input-color:color-mix(in oklab,var(--color-base-content)20%,#0000)}}.input:where(input){display:inline-flex}.input :where(input){-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#0000;border:none;width:100%;height:100%;display:inline-flex}.input :where(input):focus,.input :where(input):focus-within{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.input :where(input):focus,.input :where(input):focus-within{outline-offset:2px;outline:2px solid #0000}}.input :where(input[type=url]),.input :where(input[type=email]){direction:ltr}.input :where(input[type=date]){display:inline-block}.input:focus,.input:focus-within{--input-color:var(--color-base-content);box-shadow:0 1px var(--input-color)}@supports (color:color-mix(in lab,red,red)){.input:focus,.input:focus-within{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000)}}.input:focus,.input:focus-within{outline:2px solid var(--input-color);outline-offset:2px;isolation:isolate;z-index:1}.input:has(>input[disabled]),.input:is(:disabled,[disabled]){cursor:not-allowed;border-color:var(--color-base-200);background-color:var(--color-base-200);color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.input:has(>input[disabled]),.input:is(:disabled,[disabled]){color:color-mix(in oklab,var(--color-base-content)40%,transparent)}}:is(.input:has(>input[disabled]),.input:is(:disabled,[disabled]))::placeholder{color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){:is(.input:has(>input[disabled]),.input:is(:disabled,[disabled]))::placeholder{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.input:has(>input[disabled]),.input:is(:disabled,[disabled]){box-shadow:none}.input:has(>input[disabled])>input[disabled]{cursor:not-allowed}.input::-webkit-date-and-time-value{text-align:inherit}.input[type=number]::-webkit-inner-spin-button{margin-block:-.75rem;margin-inline-end:-.75rem}.input::-webkit-calendar-picker-indicator{position:absolute;inset-inline-end:.75em}.table{border-radius:var(--radius-box);text-align:left;width:100%;font-size:.875rem;position:relative}.table:where(:dir(rtl),[dir=rtl],[dir=rtl] *){text-align:right}@media (hover:hover){:is(.table tr.row-hover,.table tr.row-hover:nth-child(2n)):hover{background-color:var(--color-base-200)}}.table :where(th,td){vertical-align:middle;padding-block:.75rem;padding-inline:1rem}.table :where(thead,tfoot){white-space:nowrap;color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(thead,tfoot){color:color-mix(in oklab,var(--color-base-content)60%,transparent)}}.table :where(thead,tfoot){font-size:.875rem;font-weight:600}.table :where(tfoot){border-top:var(--border)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(tfoot){border-top:var(--border)solid color-mix(in oklch,var(--color-base-content)5%,#0000)}}.table :where(.table-pin-rows thead tr){z-index:1;background-color:var(--color-base-100);position:sticky;top:0}.table :where(.table-pin-rows tfoot tr){z-index:1;background-color:var(--color-base-100);position:sticky;bottom:0}.table :where(.table-pin-cols tr th){background-color:var(--color-base-100);position:sticky;left:0;right:0}.table :where(thead tr,tbody tr:not(:last-child)){border-bottom:var(--border)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(thead tr,tbody tr:not(:last-child)){border-bottom:var(--border)solid color-mix(in oklch,var(--color-base-content)5%,#0000)}}.steps{counter-reset:step;grid-auto-columns:1fr;grid-auto-flow:column;display:inline-grid;overflow:auto hidden}.steps .step{text-align:center;--step-bg:var(--color-base-300);--step-fg:var(--color-base-content);grid-template-rows:40px 1fr;grid-template-columns:auto;place-items:center;min-width:4rem;display:grid}.steps .step:before{width:100%;height:.5rem;color:var(--step-bg);background-color:var(--step-bg);--tw-content:"";content:var(--tw-content);border:1px solid;grid-row-start:1;grid-column-start:1;margin-inline-start:-100%;top:0}.steps .step>.step-icon,.steps .step:not(:has(.step-icon)):after{content:counter(step);counter-increment:step;z-index:1;color:var(--step-fg);background-color:var(--step-bg);border:1px solid var(--step-bg);border-radius:3.40282e38px;grid-row-start:1;grid-column-start:1;place-self:center;place-items:center;width:2rem;height:2rem;display:grid;position:relative}.steps .step:first-child:before{content:none}.steps .step[data-content]:after{content:attr(data-content)}.steps .step-neutral+.step-neutral:before,.steps .step-neutral:after,.steps .step-neutral>.step-icon{--step-bg:var(--color-neutral);--step-fg:var(--color-neutral-content)}.steps .step-primary+.step-primary:before,.steps .step-primary:after,.steps .step-primary>.step-icon{--step-bg:var(--color-primary);--step-fg:var(--color-primary-content)}.steps .step-secondary+.step-secondary:before,.steps .step-secondary:after,.steps .step-secondary>.step-icon{--step-bg:var(--color-secondary);--step-fg:var(--color-secondary-content)}.steps .step-accent+.step-accent:before,.steps .step-accent:after,.steps .step-accent>.step-icon{--step-bg:var(--color-accent);--step-fg:var(--color-accent-content)}.steps .step-info+.step-info:before,.steps .step-info:after,.steps .step-info>.step-icon{--step-bg:var(--color-info);--step-fg:var(--color-info-content)}.steps .step-success+.step-success:before,.steps .step-success:after,.steps .step-success>.step-icon{--step-bg:var(--color-success);--step-fg:var(--color-success-content)}.steps .step-warning+.step-warning:before,.steps .step-warning:after,.steps .step-warning>.step-icon{--step-bg:var(--color-warning);--step-fg:var(--color-warning-content)}.steps .step-error+.step-error:before,.steps .step-error:after,.steps .step-error>.step-icon{--step-bg:var(--color-error);--step-fg:var(--color-error-content)}.range{-webkit-appearance:none;-moz-appearance:none;appearance:none;webkit-appearance:none;--range-thumb:var(--color-base-100);--range-thumb-size:calc(var(--size-selector,.25rem)*6);--range-progress:currentColor;--range-fill:1;--range-p:.25rem;--range-bg:currentColor}@supports (color:color-mix(in lab,red,red)){.range{--range-bg:color-mix(in oklab,currentColor 10%,#0000)}}.range{cursor:pointer;vertical-align:middle;--radius-selector-max:calc(var(--radius-selector) + var(--radius-selector) + var(--radius-selector));border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)));width:clamp(3rem,20rem,100%);height:var(--range-thumb-size);background-color:#0000;border:none;overflow:hidden}[dir=rtl] .range{--range-dir:-1}.range:focus{outline:none}.range:focus-visible{outline-offset:2px;outline:2px solid}.range::-webkit-slider-runnable-track{background-color:var(--range-bg);border-radius:var(--radius-selector);width:100%;height:calc(var(--range-thumb-size)*.5)}@media (forced-colors:active){.range::-webkit-slider-runnable-track{border:1px solid}.range::-moz-range-track{border:1px solid}}.range::-webkit-slider-thumb{box-sizing:border-box;border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)));height:var(--range-thumb-size);width:var(--range-thumb-size);border:var(--range-p)solid;-webkit-appearance:none;-moz-appearance:none;appearance:none;webkit-appearance:none;color:var(--range-progress);box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor,0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill));background-color:currentColor;position:relative;top:50%;transform:translateY(-50%)}@supports (color:color-mix(in lab,red,red)){.range::-webkit-slider-thumb{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000),0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))}}.range::-moz-range-track{background-color:var(--range-bg);border-radius:var(--radius-selector);width:100%;height:calc(var(--range-thumb-size)*.5)}.range::-moz-range-thumb{box-sizing:border-box;border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)));height:var(--range-thumb-size);width:var(--range-thumb-size);border:var(--range-p)solid;color:var(--range-progress);box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor,0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill));background-color:currentColor;position:relative;top:50%}@supports (color:color-mix(in lab,red,red)){.range::-moz-range-thumb{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000),0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))}}.range:disabled{cursor:not-allowed;opacity:.3}.range\!{-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;webkit-appearance:none!important;--range-thumb:var(--color-base-100)!important;--range-thumb-size:calc(var(--size-selector,.25rem)*6)!important;--range-progress:currentColor!important;--range-fill:1!important;--range-p:.25rem!important;--range-bg:currentColor!important}@supports (color:color-mix(in lab,red,red)){.range\!{--range-bg:color-mix(in oklab,currentColor 10%,#0000)!important}}.range\!{cursor:pointer!important;vertical-align:middle!important;--radius-selector-max:calc(var(--radius-selector) + var(--radius-selector) + var(--radius-selector))!important;border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)))!important;width:clamp(3rem,20rem,100%)!important;height:var(--range-thumb-size)!important;background-color:#0000!important;border:none!important;overflow:hidden!important}[dir=rtl] .range\!{--range-dir:-1!important}.range\!:focus{outline:none!important}.range\!:focus-visible{outline-offset:2px!important;outline:2px solid!important}.range\!::-webkit-slider-runnable-track{background-color:var(--range-bg)!important;border-radius:var(--radius-selector)!important;width:100%!important;height:calc(var(--range-thumb-size)*.5)!important}@media (forced-colors:active){.range\!::-webkit-slider-runnable-track{border:1px solid!important}.range\!::-moz-range-track{border:1px solid!important}}.range\!::-webkit-slider-thumb{box-sizing:border-box!important;border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)))!important;height:var(--range-thumb-size)!important;width:var(--range-thumb-size)!important;border:var(--range-p)solid!important;-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;webkit-appearance:none!important;color:var(--range-progress)!important;box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor,0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))!important;background-color:currentColor!important;position:relative!important;top:50%!important;transform:translateY(-50%)!important}@supports (color:color-mix(in lab,red,red)){.range\!::-webkit-slider-thumb{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000),0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))!important}}.range\!::-moz-range-track{background-color:var(--range-bg)!important;border-radius:var(--radius-selector)!important;width:100%!important;height:calc(var(--range-thumb-size)*.5)!important}.range\!::-moz-range-thumb{box-sizing:border-box!important;border-radius:calc(var(--radius-selector) + min(var(--range-p),var(--radius-selector-max)))!important;height:var(--range-thumb-size)!important;width:var(--range-thumb-size)!important;border:var(--range-p)solid!important;color:var(--range-progress)!important;box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor,0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))!important;background-color:currentColor!important;position:relative!important;top:50%!important}@supports (color:color-mix(in lab,red,red)){.range\!::-moz-range-thumb{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000),0 0 0 2rem var(--range-thumb) inset,calc((var(--range-dir,1)*-100rem) - (var(--range-dir,1)*var(--range-thumb-size)/2)) 0 0 calc(100rem*var(--range-fill))!important}}.range\!:disabled{cursor:not-allowed!important;opacity:.3!important}.tabs-border .tab{--tab-border-color:#0000 #0000 var(--tab-border-color)#0000;border-radius:var(--radius-field);position:relative}.tabs-border .tab:before{--tw-content:"";content:var(--tw-content);background-color:var(--tab-border-color);border-radius:var(--radius-field);width:80%;height:3px;transition:background-color .2s;position:absolute;bottom:0;left:10%}:is(.tabs-border .tab:is(.tab-active,[aria-selected=true]):not(.tab-disabled,[disabled]),.tabs-border .tab:is(input:checked),.tabs-border .tab:is(label:has(:checked))):before{--tab-border-color:currentColor;border-top:3px solid}.select{border:var(--border)solid #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--color-base-100);vertical-align:middle;width:clamp(3rem,20rem,100%);height:var(--size);touch-action:manipulation;text-overflow:ellipsis;box-shadow:0 1px var(--input-color) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:calc(100% - 20px) calc(1px + 50%),calc(100% - 16.1px) calc(1px + 50%);background-repeat:no-repeat;background-size:4px 4px,4px 4px;border-start-start-radius:var(--join-ss,var(--radius-field));border-start-end-radius:var(--join-se,var(--radius-field));border-end-end-radius:var(--join-ee,var(--radius-field));border-end-start-radius:var(--join-es,var(--radius-field));flex-shrink:1;align-items:center;gap:.375rem;padding-inline:1rem 1.75rem;font-size:.875rem;display:inline-flex;position:relative}@supports (color:color-mix(in lab,red,red)){.select{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset}}.select{border-color:var(--input-color);--input-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.select{--input-color:color-mix(in oklab,var(--color-base-content)20%,#0000)}}.select{--size:calc(var(--size-field,.25rem)*10)}[dir=rtl] .select{background-position:12px calc(1px + 50%),16px calc(1px + 50%)}.select select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:inherit;border-radius:inherit;border-style:none;width:calc(100% + 2.75rem);height:calc(100% - 2px);margin-inline:-1rem -1.75rem;padding-inline:1rem 1.75rem}.select select:focus,.select select:focus-within{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.select select:focus,.select select:focus-within{outline-offset:2px;outline:2px solid #0000}}.select select:not(:last-child){background-image:none;margin-inline-end:-1.375rem}.select:focus,.select:focus-within{--input-color:var(--color-base-content);box-shadow:0 1px var(--input-color)}@supports (color:color-mix(in lab,red,red)){.select:focus,.select:focus-within{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000)}}.select:focus,.select:focus-within{outline:2px solid var(--input-color);outline-offset:2px;isolation:isolate;z-index:1}.select:has(>select[disabled]),.select:is(:disabled,[disabled]){cursor:not-allowed;border-color:var(--color-base-200);background-color:var(--color-base-200);color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.select:has(>select[disabled]),.select:is(:disabled,[disabled]){color:color-mix(in oklab,var(--color-base-content)40%,transparent)}}:is(.select:has(>select[disabled]),.select:is(:disabled,[disabled]))::placeholder{color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){:is(.select:has(>select[disabled]),.select:is(:disabled,[disabled]))::placeholder{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.select:has(>select[disabled])>select[disabled]{cursor:not-allowed}.timeline{display:flex;position:relative}.timeline>li{grid-template-rows:var(--timeline-row-start,minmax(0,1fr))auto var(--timeline-row-end,minmax(0,1fr));grid-template-columns:var(--timeline-col-start,minmax(0,1fr))auto var(--timeline-col-end,minmax(0,1fr));flex-shrink:0;align-items:center;display:grid;position:relative}.timeline>li>hr{border:none;width:100%}.timeline>li>hr:first-child{grid-row-start:2;grid-column-start:1}.timeline>li>hr:last-child{grid-area:2/3/auto/none}@media print{.timeline>li>hr{border:.1px solid var(--color-base-300)}}.timeline :where(hr){background-color:var(--color-base-300);height:.25rem}.timeline:has(.timeline-middle hr):first-child{border-start-start-radius:0;border-start-end-radius:var(--radius-selector);border-end-end-radius:var(--radius-selector);border-end-start-radius:0}.timeline:has(.timeline-middle hr):last-child,.timeline:not(:has(.timeline-middle)) :first-child hr:last-child{border-start-start-radius:var(--radius-selector);border-start-end-radius:0;border-end-end-radius:0;border-end-start-radius:var(--radius-selector)}.timeline:not(:has(.timeline-middle)) :last-child hr:first-child{border-start-start-radius:0;border-start-end-radius:var(--radius-selector);border-end-end-radius:var(--radius-selector);border-end-start-radius:0}.collapse-title{grid-row-start:1;grid-column-start:1;width:100%;min-height:1lh;padding:1rem;padding-inline-end:3rem;transition:background-color .2s ease-out;position:relative}.checkbox{border:var(--border)solid var(--input-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.checkbox{border:var(--border)solid var(--input-color,color-mix(in oklab,var(--color-base-content)20%,#0000))}}.checkbox{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--radius-selector);vertical-align:middle;color:var(--color-base-content);box-shadow:0 1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 0 #0000 inset,0 0 #0000;--size:calc(var(--size-selector,.25rem)*6);width:var(--size);height:var(--size);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);flex-shrink:0;padding:.25rem;transition:background-color .2s,box-shadow .2s;display:inline-block;position:relative}.checkbox:before{--tw-content:"";content:var(--tw-content);opacity:0;clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 80%,70% 80%,70% 100%);width:100%;height:100%;box-shadow:0 3px oklch(100% 0 0/calc(var(--depth)*.1)) inset;background-color:currentColor;font-size:1rem;line-height:.75;transition:clip-path .3s .1s,opacity .1s .1s,rotate .3s .1s,translate .3s .1s;display:block;rotate:45deg}.checkbox:focus-visible{outline:2px solid var(--input-color,currentColor);outline-offset:2px}.checkbox:checked,.checkbox[aria-checked=true]{background-color:var(--input-color,#0000);box-shadow:0 0 #0000 inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px oklch(0% 0 0/calc(var(--depth)*.1))}:is(.checkbox:checked,.checkbox[aria-checked=true]):before{clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 0%,70% 0%,70% 100%);opacity:1}@media (forced-colors:active){:is(.checkbox:checked,.checkbox[aria-checked=true]):before{--tw-content:"✔︎";clip-path:none;background-color:#0000;rotate:none}}@media print{:is(.checkbox:checked,.checkbox[aria-checked=true]):before{--tw-content:"✔︎";clip-path:none;background-color:#0000;rotate:none}}.checkbox:indeterminate:before{opacity:1;clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 80%,80% 80%,80% 100%);translate:0 -35%;rotate:none}.checkbox:disabled{cursor:not-allowed;opacity:.2}.radio{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;vertical-align:middle;border:var(--border)solid var(--input-color,currentColor);border-radius:3.40282e38px;flex-shrink:0;padding:.25rem;display:inline-block;position:relative}@supports (color:color-mix(in lab,red,red)){.radio{border:var(--border)solid var(--input-color,color-mix(in srgb,currentColor 20%,#0000))}}.radio{box-shadow:0 1px oklch(0% 0 0/calc(var(--depth)*.1)) inset;--size:calc(var(--size-selector,.25rem)*6);width:var(--size);height:var(--size);color:var(--input-color,currentColor)}.radio:before{--tw-content:"";content:var(--tw-content);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);border-radius:3.40282e38px;width:100%;height:100%;display:block}.radio:focus-visible{outline:2px solid}.radio:checked,.radio[aria-checked=true]{background-color:var(--color-base-100);border-color:currentColor;animation:.2s ease-out radio}:is(.radio:checked,.radio[aria-checked=true]):before{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px oklch(0% 0 0/calc(var(--depth)*.1));background-color:currentColor}@media (forced-colors:active){:is(.radio:checked,.radio[aria-checked=true]):before{outline-style:var(--tw-outline-style);outline-offset:-1px;outline-width:1px}}@media print{:is(.radio:checked,.radio[aria-checked=true]):before{outline-offset:-1rem;outline:.25rem solid}}.radio:disabled{cursor:not-allowed;opacity:.2}.stats{border-radius:var(--radius-box);grid-auto-flow:column;display:inline-grid;position:relative;overflow-x:auto}.progress{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--radius-box);background-color:currentColor;width:100%;height:.5rem;position:relative;overflow:hidden}@supports (color:color-mix(in lab,red,red)){.progress{background-color:color-mix(in oklab,currentColor 20%,transparent)}}.progress{color:var(--color-base-content)}.progress:indeterminate{background-image:repeating-linear-gradient(90deg,currentColor -1% 10%,#0000 10% 90%);background-position-x:15%;background-size:200%;animation:5s ease-in-out infinite progress}@supports ((-moz-appearance:none)){.progress:indeterminate::-moz-progress-bar{background-color:#0000;background-image:repeating-linear-gradient(90deg,currentColor -1% 10%,#0000 10% 90%);background-position-x:15%;background-size:200%;animation:5s ease-in-out infinite progress}.progress::-moz-progress-bar{border-radius:var(--radius-box);background-color:currentColor}}@supports ((-webkit-appearance:none)){.progress::-webkit-progress-bar{border-radius:var(--radius-box);background-color:#0000}.progress::-webkit-progress-value{border-radius:var(--radius-box);background-color:currentColor}}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.top-0{top:calc(var(--spacing)*0)}.top-1\/2{top:50%}.top-12{top:calc(var(--spacing)*12)}.right-2{right:calc(var(--spacing)*2)}.left-0{left:calc(var(--spacing)*0)}.textarea{border:var(--border)solid #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--radius-field);background-color:var(--color-base-100);vertical-align:middle;touch-action:manipulation;border-color:var(--input-color);width:clamp(3rem,20rem,100%);min-height:5rem;box-shadow:0 1px var(--input-color) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset;flex-shrink:1;padding-block:.5rem;padding-inline:.75rem;font-size:.875rem}@supports (color:color-mix(in lab,red,red)){.textarea{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset}}.textarea{--input-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.textarea{--input-color:color-mix(in oklab,var(--color-base-content)20%,#0000)}}.textarea textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#0000;border:none}.textarea textarea:focus,.textarea textarea:focus-within{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.textarea textarea:focus,.textarea textarea:focus-within{outline-offset:2px;outline:2px solid #0000}}.textarea:focus,.textarea:focus-within{--input-color:var(--color-base-content);box-shadow:0 1px var(--input-color)}@supports (color:color-mix(in lab,red,red)){.textarea:focus,.textarea:focus-within{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000)}}.textarea:focus,.textarea:focus-within{outline:2px solid var(--input-color);outline-offset:2px;isolation:isolate}.textarea:has(>textarea[disabled]),.textarea:is(:disabled,[disabled]){cursor:not-allowed;border-color:var(--color-base-200);background-color:var(--color-base-200);color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.textarea:has(>textarea[disabled]),.textarea:is(:disabled,[disabled]){color:color-mix(in oklab,var(--color-base-content)40%,transparent)}}:is(.textarea:has(>textarea[disabled]),.textarea:is(:disabled,[disabled]))::placeholder{color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){:is(.textarea:has(>textarea[disabled]),.textarea:is(:disabled,[disabled]))::placeholder{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.textarea:has(>textarea[disabled]),.textarea:is(:disabled,[disabled]){box-shadow:none}.textarea:has(>textarea[disabled])>textarea[disabled]{cursor:not-allowed}.stack{grid-template-rows:3px 4px 1fr 4px 3px;grid-template-columns:3px 4px 1fr 4px 3px;display:inline-grid}.stack>*{width:100%;height:100%}.stack>:nth-child(n+2){opacity:.7;width:100%}.stack>:nth-child(2){z-index:2;opacity:.9}.stack>:first-child{z-index:3;width:100%}:is(.stack,.stack.stack-bottom)>*{grid-area:3/3/6/4}:is(.stack,.stack.stack-bottom)>:nth-child(2){grid-area:2/2/5/5}:is(.stack,.stack.stack-bottom)>:first-child{grid-area:1/1/4/6}.stack.stack-top>*{grid-area:1/3/4/4}.stack.stack-top>:nth-child(2){grid-area:2/2/5/5}.stack.stack-top>:first-child{grid-area:3/1/6/6}.stack.stack-start>*{grid-area:3/1/4/4}.stack.stack-start>:nth-child(2){grid-area:2/2/5/5}.stack.stack-start>:first-child{grid-area:1/3/6/6}.stack.stack-end>*{grid-area:3/3/4/6}.stack.stack-end>:nth-child(2){grid-area:2/2/5/5}.stack.stack-end>:first-child{grid-area:1/1/6/4}.z-10{z-index:10}.z-20{z-index:20}.tab-content{order:var(--tabcontent-order);--tabcontent-radius-ss:0;--tabcontent-radius-se:0;--tabcontent-radius-es:0;--tabcontent-radius-ee:0;--tabcontent-order:1;width:100%;margin:var(--tabcontent-margin);border-color:#0000;border-width:var(--border);border-start-start-radius:var(--tabcontent-radius-ss);border-start-end-radius:var(--tabcontent-radius-se);border-end-end-radius:var(--tabcontent-radius-ee);border-end-start-radius:var(--tabcontent-radius-es);display:none}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.container\!{width:100%!important}@media (min-width:40rem){.container\!{max-width:40rem!important}}@media (min-width:48rem){.container\!{max-width:48rem!important}}@media (min-width:64rem){.container\!{max-width:64rem!important}}@media (min-width:80rem){.container\!{max-width:80rem!important}}@media (min-width:96rem){.container\!{max-width:96rem!important}}.filter{flex-wrap:wrap;display:flex}.filter input[type=radio]{width:auto}.filter input{opacity:1;transition:margin .1s,opacity .3s,padding .3s,border-width .1s;overflow:hidden;scale:1}.filter input:not(:last-child){margin-inline-end:.25rem}.filter input.filter-reset{aspect-ratio:1}.filter input.filter-reset:after{content:"×"}.filter:not(:has(input:checked:not(.filter-reset))) .filter-reset,.filter:not(:has(input:checked:not(.filter-reset))) input[type=reset],.filter:has(input:checked:not(.filter-reset)) input:not(:checked,.filter-reset,input[type=reset]){opacity:0;border-width:0;width:0;margin-inline:0;padding-inline:0;scale:0}.mx-auto{margin-inline:auto}.input-sm{--size:calc(var(--size-field,.25rem)*8);font-size:.75rem}.input-sm[type=number]::-webkit-inner-spin-button{margin-block:-.5rem;margin-inline-end:-.75rem}.my-4{margin-block:calc(var(--spacing)*4)}.label{white-space:nowrap;color:currentColor;align-items:center;gap:.375rem;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.label{color:color-mix(in oklab,currentColor 60%,transparent)}}.label:has(input){cursor:pointer}.label:is(.input>*,.select>*){white-space:nowrap;height:calc(100% - .5rem);font-size:inherit;align-items:center;padding-inline:.75rem;display:flex}.label:is(.input>*,.select>*):first-child{border-inline-end:var(--border)solid currentColor;margin-inline:-.75rem .75rem}@supports (color:color-mix(in lab,red,red)){.label:is(.input>*,.select>*):first-child{border-inline-end:var(--border)solid color-mix(in oklab,currentColor 10%,#0000)}}.label:is(.input>*,.select>*):last-child{border-inline-start:var(--border)solid currentColor;margin-inline:.75rem -.75rem}@supports (color:color-mix(in lab,red,red)){.label:is(.input>*,.select>*):last-child{border-inline-start:var(--border)solid color-mix(in oklab,currentColor 10%,#0000)}}.mt-8{margin-top:calc(var(--spacing)*8)}.mr-2{margin-right:calc(var(--spacing)*2)}.fieldset-legend{color:var(--color-base-content);justify-content:space-between;align-items:center;gap:.5rem;margin-bottom:-.25rem;padding-block:.5rem;font-weight:600;display:flex}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.status{aspect-ratio:1;border-radius:var(--radius-selector);background-color:var(--color-base-content);width:.5rem;height:.5rem;display:inline-block}@supports (color:color-mix(in lab,red,red)){.status{background-color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.status{vertical-align:middle;color:#0000004d;background-position:50%;background-repeat:no-repeat}@supports (color:color-mix(in lab,red,red)){.status{color:#0000004d}@supports (color:color-mix(in lab,red,red)){.status{color:color-mix(in oklab,var(--color-black)30%,transparent)}}}.status{background-image:radial-gradient(circle at 35% 30%,oklch(1 0 0/calc(var(--depth)*.5)),#0000);box-shadow:0 2px 3px -1px}@supports (color:color-mix(in lab,red,red)){.status{box-shadow:0 2px 3px -1px color-mix(in oklab,currentColor calc(var(--depth)*100%),#0000)}}.tabs{--tabs-height:auto;--tabs-direction:row;--tab-height:calc(var(--size-field,.25rem)*10);height:var(--tabs-height);flex-wrap:wrap;flex-direction:var(--tabs-direction);display:flex}.fieldset{grid-template-columns:1fr;grid-auto-rows:max-content;gap:.375rem;padding-block:.25rem;font-size:.75rem;display:grid}.card-title{font-size:var(--cardtitle-fs,1.125rem);align-items:center;gap:.5rem;font-weight:600;display:flex}.join{--join-ss:0;--join-se:0;--join-es:0;--join-ee:0;align-items:stretch;display:inline-flex}.join :where(.join-item){border-start-start-radius:var(--join-ss,0);border-start-end-radius:var(--join-se,0);border-end-end-radius:var(--join-ee,0);border-end-start-radius:var(--join-es,0)}.join :where(.join-item) *{--join-ss:var(--radius-field);--join-se:var(--radius-field);--join-es:var(--radius-field);--join-ee:var(--radius-field)}.join>.join-item:where(:first-child),.join :first-child:not(:last-child) :where(.join-item){--join-ss:var(--radius-field);--join-se:0;--join-es:var(--radius-field);--join-ee:0}.join>.join-item:where(:last-child),.join :last-child:not(:first-child) :where(.join-item){--join-ss:0;--join-se:var(--radius-field);--join-es:0;--join-ee:var(--radius-field)}.join>.join-item:where(:only-child),.join :only-child :where(.join-item){--join-ss:var(--radius-field);--join-se:var(--radius-field);--join-es:var(--radius-field);--join-ee:var(--radius-field)}.mask{vertical-align:middle;display:inline-block;-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.h-4{height:calc(var(--spacing)*4)}.h-64{height:calc(var(--spacing)*64)}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-\[80vh\]{max-height:80vh}.min-h-screen{min-height:100vh}.loading-lg{width:calc(var(--size-selector,.25rem)*7)}.w-4{width:calc(var(--spacing)*4)}.w-11\/12{width:91.6667%}.w-48{width:calc(var(--spacing)*48)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-full{max-width:100%}.min-w-\[220px\]{min-width:220px}.min-w-max{min-width:max-content}.flex-1{flex:1}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.link{cursor:pointer;text-decoration-line:underline}.link:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.link:focus{outline-offset:2px;outline:2px solid #0000}}.link:focus-visible{outline-offset:2px;outline:2px solid}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*8)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*8)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b-3{border-bottom-style:var(--tw-border-style);border-bottom-width:3px}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-700{border-color:var(--color-gray-700)}.border-b-gray-700{border-bottom-color:var(--color-gray-700)}.bg-base-100{background-color:var(--color-base-100)}.bg-base-200{background-color:var(--color-base-200)}.loading-spinner{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E")}.radio-sm{padding:.1875rem}.radio-sm[type=radio]{--size:calc(var(--size-selector,.25rem)*5)}.p-4{padding:calc(var(--spacing)*4)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.py-1{padding-block:calc(var(--spacing)*1)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-6{padding-left:calc(var(--spacing)*6)}.pl-10{padding-left:calc(var(--spacing)*10)}.text-center{text-align:center}.text-left{text-align:left}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-gray-400{color:var(--color-gray-400)}.text-primary{color:var(--color-primary)}.text-red-500{color:var(--color-red-500)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.blur{--tw-blur:blur(8px);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,)}.invert{--tw-invert:invert(100%);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{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{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,visibility,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition\!{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,visibility,content-visibility,overlay,pointer-events!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:bg-base-100:hover{background-color:var(--color-base-100)}.hover\:bg-base-200:hover{background-color:var(--color-base-200)}.hover\:bg-base-300:hover{background-color:var(--color-base-300)}}@media (min-width:48rem){.md\:w-1\/2{width:50%}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-x-4{column-gap:calc(var(--spacing)*4)}}@media (min-width:64rem){.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}}@keyframes radio{0%{padding:5px}50%{padding:3px}}@keyframes skeleton{0%{background-position:150%}to{background-position:-50%}}@keyframes progress{50%{background-position-x:-115%}}@keyframes toast{0%{opacity:0;scale:.9}to{opacity:1;scale:1}}@keyframes dropdown{0%{opacity:0}}@keyframes rating{0%,40%{filter:brightness(1.05)contrast(1.05);scale:1.1}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
frontend/dist/assets/index-CwrBXUIs.css
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
/*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-700:oklch(37.3% .034 259.733);--spacing:.25rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light]{color-scheme:light;--color-base-100:oklch(100% 0 0);--color-base-200:oklch(98% 0 0);--color-base-300:oklch(95% 0 0);--color-base-content:oklch(21% .006 285.885);--color-primary:oklch(45% .24 277.023);--color-primary-content:oklch(93% .034 272.788);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}@media (prefers-color-scheme:dark){:root{color-scheme:dark;--color-base-100:oklch(25.33% .016 252.42);--color-base-200:oklch(23.26% .014 253.1);--color-base-300:oklch(21.15% .012 254.09);--color-base-content:oklch(97.807% .029 256.847);--color-primary:oklch(58% .233 277.117);--color-primary-content:oklch(96% .018 272.314);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}}:root:has(input.theme-controller[value=light]:checked),[data-theme=light]{color-scheme:light;--color-base-100:oklch(100% 0 0);--color-base-200:oklch(98% 0 0);--color-base-300:oklch(95% 0 0);--color-base-content:oklch(21% .006 285.885);--color-primary:oklch(45% .24 277.023);--color-primary-content:oklch(93% .034 272.788);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}:root:has(input.theme-controller[value=dark]:checked),[data-theme=dark]{color-scheme:dark;--color-base-100:oklch(25.33% .016 252.42);--color-base-200:oklch(23.26% .014 253.1);--color-base-300:oklch(21.15% .012 254.09);--color-base-content:oklch(97.807% .029 256.847);--color-primary:oklch(58% .233 277.117);--color-primary-content:oklch(96% .018 272.314);--color-secondary:oklch(65% .241 354.308);--color-secondary-content:oklch(94% .028 342.258);--color-accent:oklch(77% .152 181.912);--color-accent-content:oklch(38% .063 188.416);--color-neutral:oklch(14% .005 285.823);--color-neutral-content:oklch(92% .004 286.32);--color-info:oklch(74% .16 232.661);--color-info-content:oklch(29% .066 243.157);--color-success:oklch(76% .177 163.223);--color-success-content:oklch(37% .077 168.94);--color-warning:oklch(82% .189 84.429);--color-warning-content:oklch(41% .112 45.904);--color-error:oklch(71% .194 13.428);--color-error-content:oklch(27% .105 12.094);--radius-selector:.5rem;--radius-field:.25rem;--radius-box:.5rem;--size-selector:.25rem;--size-field:.25rem;--border:1px;--depth:1;--noise:0}@property --radialprogress{syntax: "<percentage>"; inherits: true; initial-value: 0%;}:root{scrollbar-color:currentColor #0000}@supports (color:color-mix(in lab,red,red)){:root{scrollbar-color:color-mix(in oklch,currentColor 35%,#0000)#0000}}:root{--fx-noise:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.34' numOctaves='4' stitchTiles='stitch'%3E%3C/feTurbulence%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)' opacity='0.2'%3E%3C/rect%3E%3C/svg%3E")}:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not([class*=drawer-open])>.drawer-toggle:checked){overflow:hidden}:where(:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not(.drawer-open)>.drawer-toggle:checked)){scrollbar-gutter:stable;background-image:linear-gradient(var(--color-base-100),var(--color-base-100));--root-bg:var(--color-base-100)}@supports (color:color-mix(in lab,red,red)){:where(:root:has(.modal-open,.modal[open],.modal:target,.modal-toggle:checked,.drawer:not(.drawer-open)>.drawer-toggle:checked)){--root-bg:color-mix(in srgb,var(--color-base-100),oklch(0% 0 0) 40%)}}:where(.modal[open],.modal-open,.modal-toggle:checked+.modal):not(.modal-start,.modal-end){scrollbar-gutter:stable}:root,[data-theme]{background-color:var(--root-bg,var(--color-base-100));color:var(--color-base-content)}}@layer components;@layer utilities{.diff{webkit-user-select:none;-webkit-user-select:none;user-select:none;direction:ltr;grid-template-columns:auto 1fr;width:100%;display:grid;position:relative;overflow:hidden;container-type:inline-size}.diff:focus-visible,.diff:has(.diff-item-1:focus-visible){outline-style:var(--tw-outline-style);outline-offset:1px;outline-width:2px;outline-color:var(--color-base-content)}.diff:focus-visible .diff-resizer{min-width:90cqi;max-width:90cqi}.diff:has(.diff-item-2:focus-visible){outline-style:var(--tw-outline-style);outline-offset:1px;outline-width:2px}.diff:has(.diff-item-2:focus-visible) .diff-resizer{min-width:10cqi;max-width:10cqi}@supports (-webkit-overflow-scrolling:touch) and (overflow:-webkit-paged-x){.diff:focus .diff-resizer{min-width:10cqi;max-width:10cqi}.diff:has(.diff-item-1:focus) .diff-resizer{min-width:90cqi;max-width:90cqi}}.tab{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-align:center;webkit-user-select:none;-webkit-user-select:none;user-select:none;flex-wrap:wrap;justify-content:center;align-items:center;display:inline-flex;position:relative}@media (hover:hover){.tab:hover{color:var(--color-base-content)}}.tab{--tab-p:1rem;--tab-bg:var(--color-base-100);--tab-border-color:var(--color-base-300);--tab-radius-ss:0;--tab-radius-se:0;--tab-radius-es:0;--tab-radius-ee:0;--tab-order:0;--tab-radius-min:calc(.75rem - var(--border));order:var(--tab-order);height:var(--tab-height);border-color:#0000;padding-inline-start:var(--tab-p);padding-inline-end:var(--tab-p);font-size:.875rem}.tab:is(input[type=radio]){min-width:fit-content}.tab:is(input[type=radio]):after{content:attr(aria-label)}.tab:is(label){position:relative}.tab:is(label) input{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0;position:absolute;top:0;right:0;bottom:0;left:0}:is(.tab:checked,.tab:is(label:has(:checked)),.tab:is(.tab-active,[aria-selected=true]))+.tab-content{height:calc(100% - var(--tab-height) + var(--border));display:block}.tab:not(:checked,label:has(:checked),:hover,.tab-active,[aria-selected=true]){color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.tab:not(:checked,label:has(:checked),:hover,.tab-active,[aria-selected=true]){color:color-mix(in oklab,var(--color-base-content)50%,transparent)}}.tab:not(input):empty{cursor:default;flex-grow:1}.tab:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.tab:focus{outline-offset:2px;outline:2px solid #0000}}.tab:focus-visible,.tab:is(label:has(:checked:focus-visible)){outline-offset:-5px;outline:2px solid}.tab[disabled]{pointer-events:none;opacity:.4}.loading{pointer-events:none;aspect-ratio:1;vertical-align:middle;width:calc(var(--size-selector,.25rem)*6);background-color:currentColor;display:inline-block;-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:100%;mask-size:100%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.pointer-events-none{pointer-events:none}.collapse:not(td,tr,colgroup){visibility:visible}.collapse{border-radius:var(--radius-box,1rem);isolation:isolate;grid-template-rows:max-content 0fr;width:100%;transition:grid-template-rows .2s;display:grid;position:relative;overflow:hidden}.collapse>input:is([type=checkbox],[type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0;z-index:1;grid-row-start:1;grid-column-start:1;width:100%;min-height:1lh;padding:1rem;padding-inline-end:3rem;transition:background-color .2s ease-out}.collapse:is([open],:focus:not(.collapse-close)),.collapse:not(.collapse-close):has(>input:is([type=checkbox],[type=radio]):checked){grid-template-rows:max-content 1fr}.collapse:is([open],:focus:not(.collapse-close))>.collapse-content,.collapse:not(.collapse-close)>:where(input:is([type=checkbox],[type=radio]):checked~.collapse-content){visibility:visible;min-height:fit-content}.collapse:focus-visible,.collapse:has(>input:is([type=checkbox],[type=radio]):focus-visible){outline-color:var(--color-base-content);outline-offset:2px;outline-width:2px;outline-style:solid}.collapse:not(.collapse-close)>input[type=checkbox],.collapse:not(.collapse-close)>input[type=radio]:not(:checked),.collapse:not(.collapse-close)>.collapse-title{cursor:pointer}.collapse:focus:not(.collapse-close,.collapse[open])>.collapse-title{cursor:unset}.collapse:is([open],:focus:not(.collapse-close))>:where(.collapse-content),.collapse:not(.collapse-close)>:where(input:is([type=checkbox],[type=radio]):checked~.collapse-content){padding-bottom:1rem;transition:padding .2s ease-out,background-color .2s ease-out}.collapse[open].collapse-arrow>.collapse-title:after,.collapse.collapse-open.collapse-arrow>.collapse-title:after{transform:translateY(-50%)rotate(225deg)}.collapse.collapse-open.collapse-plus>.collapse-title:after{content:"−"}.collapse.collapse-arrow:focus:not(.collapse-close)>.collapse-title:after,.collapse.collapse-arrow:not(.collapse-close)>input:is([type=checkbox],[type=radio]):checked~.collapse-title:after{transform:translateY(-50%)rotate(225deg)}.collapse[open].collapse-plus>.collapse-title:after,.collapse.collapse-plus:focus:not(.collapse-close)>.collapse-title:after,.collapse.collapse-plus:not(.collapse-close)>input:is([type=checkbox],[type=radio]):checked~.collapse-title:after{content:"−"}.collapse:is(details){width:100%}.collapse:is(details) summary{display:block;position:relative}.collapse:is(details) summary::-webkit-details-marker{display:none}.collapse:is(details) summary{outline:none}.collapse{visibility:collapse}.visible{visibility:visible}.toggle{border:var(--border)solid currentColor;color:var(--input-color);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;vertical-align:middle;webkit-user-select:none;-webkit-user-select:none;user-select:none;--radius-selector-max:calc(var(--radius-selector) + var(--radius-selector) + var(--radius-selector));border-radius:calc(var(--radius-selector) + min(var(--toggle-p),var(--radius-selector-max)) + min(var(--border),var(--radius-selector-max)));padding:var(--toggle-p);flex-shrink:0;grid-template-columns:0fr 1fr 1fr;place-content:center;display:inline-grid;position:relative;box-shadow:inset 0 1px}@supports (color:color-mix(in lab,red,red)){.toggle{box-shadow:0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000) inset}}.toggle{--input-color:var(--color-base-content);transition:color .3s,grid-template-columns .2s}@supports (color:color-mix(in lab,red,red)){.toggle{--input-color:color-mix(in oklab,var(--color-base-content)50%,#0000)}}.toggle{--toggle-p:calc(var(--size)*.125);--size:calc(var(--size-selector,.25rem)*6);width:calc((var(--size)*2) - (var(--border) + var(--toggle-p))*2);height:var(--size)}.toggle>*{z-index:1;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#0000;border:none;grid-column:2/span 1;grid-row-start:1;height:100%;padding:.125rem;transition:opacity .2s,rotate .4s}.toggle>:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.toggle>:focus{outline-offset:2px;outline:2px solid #0000}}.toggle>:nth-child(2){color:var(--color-base-100);rotate:none}.toggle>:nth-child(3){color:var(--color-base-100);opacity:0;rotate:-15deg}.toggle:has(:checked)>:nth-child(2){opacity:0;rotate:15deg}.toggle:has(:checked)>:nth-child(3){opacity:1;rotate:none}.toggle:before{aspect-ratio:1;border-radius:var(--radius-selector);--tw-content:"";content:var(--tw-content);height:100%;box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px currentColor;background-color:currentColor;grid-row-start:1;grid-column-start:2;transition:background-color .1s,translate .2s,inset-inline-start .2s;position:relative;inset-inline-start:0;translate:0}@supports (color:color-mix(in lab,red,red)){.toggle:before{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px color-mix(in oklab,currentColor calc(var(--depth)*10%),#0000)}}.toggle:before{background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise)}@media (forced-colors:active){.toggle:before{outline-style:var(--tw-outline-style);outline-offset:-1px;outline-width:1px}}@media print{.toggle:before{outline-offset:-1rem;outline:.25rem solid}}.toggle:focus-visible,.toggle:has(:focus-visible){outline-offset:2px;outline:2px solid}.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked){background-color:var(--color-base-100);--input-color:var(--color-base-content);grid-template-columns:1fr 1fr 0fr}:is(.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked)):before{background-color:currentColor}@starting-style{:is(.toggle:checked,.toggle[aria-checked=true],.toggle:has(>input:checked)):before{opacity:0}}.toggle:indeterminate{grid-template-columns:.5fr 1fr .5fr}.toggle:disabled{cursor:not-allowed;opacity:.3}.toggle:disabled:before{border:var(--border)solid currentColor;background-color:#0000}.input{cursor:text;border:var(--border)solid #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--color-base-100);vertical-align:middle;white-space:nowrap;width:clamp(3rem,20rem,100%);height:var(--size);touch-action:manipulation;border-color:var(--input-color);box-shadow:0 1px var(--input-color) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset;border-start-start-radius:var(--join-ss,var(--radius-field));border-start-end-radius:var(--join-se,var(--radius-field));border-end-end-radius:var(--join-ee,var(--radius-field));border-end-start-radius:var(--join-es,var(--radius-field));flex-shrink:1;align-items:center;gap:.5rem;padding-inline:.75rem;font-size:.875rem;display:inline-flex;position:relative}@supports (color:color-mix(in lab,red,red)){.input{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset}}.input{--size:calc(var(--size-field,.25rem)*10);--input-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.input{--input-color:color-mix(in oklab,var(--color-base-content)20%,#0000)}}.input:where(input){display:inline-flex}.input :where(input){-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#0000;border:none;width:100%;height:100%;display:inline-flex}.input :where(input):focus,.input :where(input):focus-within{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.input :where(input):focus,.input :where(input):focus-within{outline-offset:2px;outline:2px solid #0000}}.input :where(input[type=url]),.input :where(input[type=email]){direction:ltr}.input :where(input[type=date]){display:inline-block}.input:focus,.input:focus-within{--input-color:var(--color-base-content);box-shadow:0 1px var(--input-color)}@supports (color:color-mix(in lab,red,red)){.input:focus,.input:focus-within{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000)}}.input:focus,.input:focus-within{outline:2px solid var(--input-color);outline-offset:2px;isolation:isolate;z-index:1}.input:has(>input[disabled]),.input:is(:disabled,[disabled]){cursor:not-allowed;border-color:var(--color-base-200);background-color:var(--color-base-200);color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.input:has(>input[disabled]),.input:is(:disabled,[disabled]){color:color-mix(in oklab,var(--color-base-content)40%,transparent)}}:is(.input:has(>input[disabled]),.input:is(:disabled,[disabled]))::placeholder{color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){:is(.input:has(>input[disabled]),.input:is(:disabled,[disabled]))::placeholder{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.input:has(>input[disabled]),.input:is(:disabled,[disabled]){box-shadow:none}.input:has(>input[disabled])>input[disabled]{cursor:not-allowed}.input::-webkit-date-and-time-value{text-align:inherit}.input[type=number]::-webkit-inner-spin-button{margin-block:-.75rem;margin-inline-end:-.75rem}.input::-webkit-calendar-picker-indicator{position:absolute;inset-inline-end:.75em}.table{border-radius:var(--radius-box);text-align:left;width:100%;font-size:.875rem;position:relative}.table:where(:dir(rtl),[dir=rtl],[dir=rtl] *){text-align:right}@media (hover:hover){:is(.table tr.row-hover,.table tr.row-hover:nth-child(2n)):hover{background-color:var(--color-base-200)}}.table :where(th,td){vertical-align:middle;padding-block:.75rem;padding-inline:1rem}.table :where(thead,tfoot){white-space:nowrap;color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(thead,tfoot){color:color-mix(in oklab,var(--color-base-content)60%,transparent)}}.table :where(thead,tfoot){font-size:.875rem;font-weight:600}.table :where(tfoot){border-top:var(--border)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(tfoot){border-top:var(--border)solid color-mix(in oklch,var(--color-base-content)5%,#0000)}}.table :where(.table-pin-rows thead tr){z-index:1;background-color:var(--color-base-100);position:sticky;top:0}.table :where(.table-pin-rows tfoot tr){z-index:1;background-color:var(--color-base-100);position:sticky;bottom:0}.table :where(.table-pin-cols tr th){background-color:var(--color-base-100);position:sticky;left:0;right:0}.table :where(thead tr,tbody tr:not(:last-child)){border-bottom:var(--border)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.table :where(thead tr,tbody tr:not(:last-child)){border-bottom:var(--border)solid color-mix(in oklch,var(--color-base-content)5%,#0000)}}.tabs-border .tab{--tab-border-color:#0000 #0000 var(--tab-border-color)#0000;border-radius:var(--radius-field);position:relative}.tabs-border .tab:before{--tw-content:"";content:var(--tw-content);background-color:var(--tab-border-color);border-radius:var(--radius-field);width:80%;height:3px;transition:background-color .2s;position:absolute;bottom:0;left:10%}:is(.tabs-border .tab:is(.tab-active,[aria-selected=true]):not(.tab-disabled,[disabled]),.tabs-border .tab:is(input:checked),.tabs-border .tab:is(label:has(:checked))):before{--tab-border-color:currentColor;border-top:3px solid}.select{border:var(--border)solid #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--color-base-100);vertical-align:middle;width:clamp(3rem,20rem,100%);height:var(--size);touch-action:manipulation;text-overflow:ellipsis;box-shadow:0 1px var(--input-color) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:calc(100% - 20px) calc(1px + 50%),calc(100% - 16.1px) calc(1px + 50%);background-repeat:no-repeat;background-size:4px 4px,4px 4px;border-start-start-radius:var(--join-ss,var(--radius-field));border-start-end-radius:var(--join-se,var(--radius-field));border-end-end-radius:var(--join-ee,var(--radius-field));border-end-start-radius:var(--join-es,var(--radius-field));flex-shrink:1;align-items:center;gap:.375rem;padding-inline:1rem 1.75rem;font-size:.875rem;display:inline-flex;position:relative}@supports (color:color-mix(in lab,red,red)){.select{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000) inset,0 -1px oklch(100% 0 0/calc(var(--depth)*.1)) inset}}.select{border-color:var(--input-color);--input-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.select{--input-color:color-mix(in oklab,var(--color-base-content)20%,#0000)}}.select{--size:calc(var(--size-field,.25rem)*10)}[dir=rtl] .select{background-position:12px calc(1px + 50%),16px calc(1px + 50%)}.select select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:inherit;border-radius:inherit;border-style:none;width:calc(100% + 2.75rem);height:calc(100% - 2px);margin-inline:-1rem -1.75rem;padding-inline:1rem 1.75rem}.select select:focus,.select select:focus-within{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.select select:focus,.select select:focus-within{outline-offset:2px;outline:2px solid #0000}}.select select:not(:last-child){background-image:none;margin-inline-end:-1.375rem}.select:focus,.select:focus-within{--input-color:var(--color-base-content);box-shadow:0 1px var(--input-color)}@supports (color:color-mix(in lab,red,red)){.select:focus,.select:focus-within{box-shadow:0 1px color-mix(in oklab,var(--input-color)calc(var(--depth)*10%),#0000)}}.select:focus,.select:focus-within{outline:2px solid var(--input-color);outline-offset:2px;isolation:isolate;z-index:1}.select:has(>select[disabled]),.select:is(:disabled,[disabled]){cursor:not-allowed;border-color:var(--color-base-200);background-color:var(--color-base-200);color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.select:has(>select[disabled]),.select:is(:disabled,[disabled]){color:color-mix(in oklab,var(--color-base-content)40%,transparent)}}:is(.select:has(>select[disabled]),.select:is(:disabled,[disabled]))::placeholder{color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){:is(.select:has(>select[disabled]),.select:is(:disabled,[disabled]))::placeholder{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.select:has(>select[disabled])>select[disabled]{cursor:not-allowed}.checkbox{border:var(--border)solid var(--input-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.checkbox{border:var(--border)solid var(--input-color,color-mix(in oklab,var(--color-base-content)20%,#0000))}}.checkbox{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--radius-selector);vertical-align:middle;color:var(--color-base-content);box-shadow:0 1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 0 #0000 inset,0 0 #0000;--size:calc(var(--size-selector,.25rem)*6);width:var(--size);height:var(--size);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);flex-shrink:0;padding:.25rem;transition:background-color .2s,box-shadow .2s;display:inline-block;position:relative}.checkbox:before{--tw-content:"";content:var(--tw-content);opacity:0;clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 80%,70% 80%,70% 100%);width:100%;height:100%;box-shadow:0 3px oklch(100% 0 0/calc(var(--depth)*.1)) inset;background-color:currentColor;font-size:1rem;line-height:.75;transition:clip-path .3s .1s,opacity .1s .1s,rotate .3s .1s,translate .3s .1s;display:block;rotate:45deg}.checkbox:focus-visible{outline:2px solid var(--input-color,currentColor);outline-offset:2px}.checkbox:checked,.checkbox[aria-checked=true]{background-color:var(--input-color,#0000);box-shadow:0 0 #0000 inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px oklch(0% 0 0/calc(var(--depth)*.1))}:is(.checkbox:checked,.checkbox[aria-checked=true]):before{clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 0%,70% 0%,70% 100%);opacity:1}@media (forced-colors:active){:is(.checkbox:checked,.checkbox[aria-checked=true]):before{--tw-content:"✔︎";clip-path:none;background-color:#0000;rotate:none}}@media print{:is(.checkbox:checked,.checkbox[aria-checked=true]):before{--tw-content:"✔︎";clip-path:none;background-color:#0000;rotate:none}}.checkbox:indeterminate:before{opacity:1;clip-path:polygon(20% 100%,20% 80%,50% 80%,50% 80%,80% 80%,80% 100%);translate:0 -35%;rotate:none}.checkbox:disabled{cursor:not-allowed;opacity:.2}.radio{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;vertical-align:middle;border:var(--border)solid var(--input-color,currentColor);border-radius:3.40282e38px;flex-shrink:0;padding:.25rem;display:inline-block;position:relative}@supports (color:color-mix(in lab,red,red)){.radio{border:var(--border)solid var(--input-color,color-mix(in srgb,currentColor 20%,#0000))}}.radio{box-shadow:0 1px oklch(0% 0 0/calc(var(--depth)*.1)) inset;--size:calc(var(--size-selector,.25rem)*6);width:var(--size);height:var(--size);color:var(--input-color,currentColor)}.radio:before{--tw-content:"";content:var(--tw-content);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);border-radius:3.40282e38px;width:100%;height:100%;display:block}.radio:focus-visible{outline:2px solid}.radio:checked,.radio[aria-checked=true]{background-color:var(--color-base-100);border-color:currentColor;animation:.2s ease-out radio}:is(.radio:checked,.radio[aria-checked=true]):before{box-shadow:0 -1px oklch(0% 0 0/calc(var(--depth)*.1)) inset,0 8px 0 -4px oklch(100% 0 0/calc(var(--depth)*.1)) inset,0 1px oklch(0% 0 0/calc(var(--depth)*.1));background-color:currentColor}@media (forced-colors:active){:is(.radio:checked,.radio[aria-checked=true]):before{outline-style:var(--tw-outline-style);outline-offset:-1px;outline-width:1px}}@media print{:is(.radio:checked,.radio[aria-checked=true]):before{outline-offset:-1rem;outline:.25rem solid}}.radio:disabled{cursor:not-allowed;opacity:.2}.stats{border-radius:var(--radius-box);grid-auto-flow:column;display:inline-grid;position:relative;overflow-x:auto}.absolute{position:absolute}.relative{position:relative}.static{position:static}.sticky{position:sticky}.top-0{top:calc(var(--spacing)*0)}.top-1\/2{top:50%}.top-12{top:calc(var(--spacing)*12)}.right-2{right:calc(var(--spacing)*2)}.left-0{left:calc(var(--spacing)*0)}.z-10{z-index:10}.z-20{z-index:20}.tab-content{order:var(--tabcontent-order);--tabcontent-radius-ss:0;--tabcontent-radius-se:0;--tabcontent-radius-es:0;--tabcontent-radius-ee:0;--tabcontent-order:1;width:100%;margin:var(--tabcontent-margin);border-color:#0000;border-width:var(--border);border-start-start-radius:var(--tabcontent-radius-ss);border-start-end-radius:var(--tabcontent-radius-se);border-end-end-radius:var(--tabcontent-radius-ee);border-end-start-radius:var(--tabcontent-radius-es);display:none}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.filter{flex-wrap:wrap;display:flex}.filter input[type=radio]{width:auto}.filter input{opacity:1;transition:margin .1s,opacity .3s,padding .3s,border-width .1s;overflow:hidden;scale:1}.filter input:not(:last-child){margin-inline-end:.25rem}.filter input.filter-reset{aspect-ratio:1}.filter input.filter-reset:after{content:"×"}.filter:not(:has(input:checked:not(.filter-reset))) .filter-reset,.filter:not(:has(input:checked:not(.filter-reset))) input[type=reset],.filter:has(input:checked:not(.filter-reset)) input:not(:checked,.filter-reset,input[type=reset]){opacity:0;border-width:0;width:0;margin-inline:0;padding-inline:0;scale:0}.mx-auto{margin-inline:auto}.input-sm{--size:calc(var(--size-field,.25rem)*8);font-size:.75rem}.input-sm[type=number]::-webkit-inner-spin-button{margin-block:-.5rem;margin-inline-end:-.75rem}.my-4{margin-block:calc(var(--spacing)*4)}.label{white-space:nowrap;color:currentColor;align-items:center;gap:.375rem;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.label{color:color-mix(in oklab,currentColor 60%,transparent)}}.label:has(input){cursor:pointer}.label:is(.input>*,.select>*){white-space:nowrap;height:calc(100% - .5rem);font-size:inherit;align-items:center;padding-inline:.75rem;display:flex}.label:is(.input>*,.select>*):first-child{border-inline-end:var(--border)solid currentColor;margin-inline:-.75rem .75rem}@supports (color:color-mix(in lab,red,red)){.label:is(.input>*,.select>*):first-child{border-inline-end:var(--border)solid color-mix(in oklab,currentColor 10%,#0000)}}.label:is(.input>*,.select>*):last-child{border-inline-start:var(--border)solid currentColor;margin-inline:.75rem -.75rem}@supports (color:color-mix(in lab,red,red)){.label:is(.input>*,.select>*):last-child{border-inline-start:var(--border)solid color-mix(in oklab,currentColor 10%,#0000)}}.mt-8{margin-top:calc(var(--spacing)*8)}.mr-2{margin-right:calc(var(--spacing)*2)}.fieldset-legend{color:var(--color-base-content);justify-content:space-between;align-items:center;gap:.5rem;margin-bottom:-.25rem;padding-block:.5rem;font-weight:600;display:flex}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-2{margin-left:calc(var(--spacing)*2)}.tabs{--tabs-height:auto;--tabs-direction:row;--tab-height:calc(var(--size-field,.25rem)*10);height:var(--tabs-height);flex-wrap:wrap;flex-direction:var(--tabs-direction);display:flex}.fieldset{grid-template-columns:1fr;grid-auto-rows:max-content;gap:.375rem;padding-block:.25rem;font-size:.75rem;display:grid}.card-title{font-size:var(--cardtitle-fs,1.125rem);align-items:center;gap:.5rem;font-weight:600;display:flex}.join{--join-ss:0;--join-se:0;--join-es:0;--join-ee:0;align-items:stretch;display:inline-flex}.join :where(.join-item){border-start-start-radius:var(--join-ss,0);border-start-end-radius:var(--join-se,0);border-end-end-radius:var(--join-ee,0);border-end-start-radius:var(--join-es,0)}.join :where(.join-item) *{--join-ss:var(--radius-field);--join-se:var(--radius-field);--join-es:var(--radius-field);--join-ee:var(--radius-field)}.join>.join-item:where(:first-child),.join :first-child:not(:last-child) :where(.join-item){--join-ss:var(--radius-field);--join-se:0;--join-es:var(--radius-field);--join-ee:0}.join>.join-item:where(:last-child),.join :last-child:not(:first-child) :where(.join-item){--join-ss:0;--join-se:var(--radius-field);--join-es:0;--join-ee:var(--radius-field)}.join>.join-item:where(:only-child),.join :only-child :where(.join-item){--join-ss:var(--radius-field);--join-se:var(--radius-field);--join-es:var(--radius-field);--join-ee:var(--radius-field)}.flex{display:flex}.grid{display:grid}.table{display:table}.h-4{height:calc(var(--spacing)*4)}.h-64{height:calc(var(--spacing)*64)}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-\[80vh\]{max-height:80vh}.min-h-screen{min-height:100vh}.loading-lg{width:calc(var(--size-selector,.25rem)*7)}.w-4{width:calc(var(--spacing)*4)}.w-11\/12{width:91.6667%}.w-48{width:calc(var(--spacing)*48)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-full{max-width:100%}.min-w-\[220px\]{min-width:220px}.min-w-max{min-width:max-content}.flex-1{flex:1}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*8)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*8)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-700{border-color:var(--color-gray-700)}.border-b-gray-700{border-bottom-color:var(--color-gray-700)}.bg-base-100{background-color:var(--color-base-100)}.bg-base-200{background-color:var(--color-base-200)}.loading-spinner{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E")}.radio-sm{padding:.1875rem}.radio-sm[type=radio]{--size:calc(var(--size-selector,.25rem)*5)}.p-4{padding:calc(var(--spacing)*4)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.py-1{padding-block:calc(var(--spacing)*1)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-6{padding-left:calc(var(--spacing)*6)}.pl-10{padding-left:calc(var(--spacing)*10)}.text-center{text-align:center}.text-left{text-align:left}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-gray-400{color:var(--color-gray-400)}.text-primary{color:var(--color-primary)}.text-red-500{color:var(--color-red-500)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{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,)}@media (hover:hover){.hover\:bg-base-100:hover{background-color:var(--color-base-100)}.hover\:bg-base-200:hover{background-color:var(--color-base-200)}.hover\:bg-base-300:hover{background-color:var(--color-base-300)}}@media (min-width:48rem){.md\:w-1\/2{width:50%}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-x-4{column-gap:calc(var(--spacing)*4)}}@media (min-width:64rem){.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}}@keyframes radio{0%{padding:5px}50%{padding:3px}}@keyframes skeleton{0%{background-position:150%}to{background-position:-50%}}@keyframes progress{50%{background-position-x:-115%}}@keyframes toast{0%{opacity:0;scale:.9}to{opacity:1;scale:1}}@keyframes dropdown{0%{opacity:0}}@keyframes rating{0%,40%{filter:brightness(1.05)contrast(1.05);scale:1.1}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
|
|
|
|
frontend/dist/assets/{index-RC6rN_Gk.js → index-D2ksG3qQ.js}
RENAMED
The diff for this file is too large to render.
See raw diff
|
|
frontend/dist/index.html
CHANGED
@@ -5,8 +5,8 @@
|
|
5 |
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
<title>🥇 Omni Seal Bench Watermarking Leaderboard</title>
|
8 |
-
<script type="module" crossorigin src="/assets/index-
|
9 |
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
10 |
</head>
|
11 |
<body>
|
12 |
<div id="root"></div>
|
|
|
5 |
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
<title>🥇 Omni Seal Bench Watermarking Leaderboard</title>
|
8 |
+
<script type="module" crossorigin src="/assets/index-D2ksG3qQ.js"></script>
|
9 |
+
<link rel="stylesheet" crossorigin href="/assets/index-BWZpYvtq.css">
|
10 |
</head>
|
11 |
<body>
|
12 |
<div id="root"></div>
|
frontend/src/components/DatasetSelector.tsx
CHANGED
@@ -12,8 +12,8 @@ const DatasetSelector: React.FC<DatasetSelectorProps> = ({
|
|
12 |
onDatasetNameChange,
|
13 |
}) => {
|
14 |
return (
|
15 |
-
<div className="
|
16 |
-
<fieldset className="fieldset w-full p-4 rounded border border-gray-700">
|
17 |
<legend className="fieldset-legend font-semibold">Dataset</legend>
|
18 |
<div className="flex flex-wrap gap-2">
|
19 |
{datasetNames.map((datasetName) => (
|
|
|
12 |
onDatasetNameChange,
|
13 |
}) => {
|
14 |
return (
|
15 |
+
<div className="">
|
16 |
+
<fieldset className="fieldset w-full p-4 rounded border border-gray-700 bg-base-200">
|
17 |
<legend className="fieldset-legend font-semibold">Dataset</legend>
|
18 |
<div className="flex flex-wrap gap-2">
|
19 |
{datasetNames.map((datasetName) => (
|
frontend/src/components/IndependentMetricsTable.tsx
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react'
|
2 |
+
|
3 |
+
interface Row {
|
4 |
+
metric: string
|
5 |
+
[key: string]: string | number
|
6 |
+
}
|
7 |
+
|
8 |
+
interface IndependentMetricsTableProps {
|
9 |
+
independentMetrics: string[]
|
10 |
+
tableHeader: string[]
|
11 |
+
selectedModels: Set<string>
|
12 |
+
tableRows: Row[]
|
13 |
+
}
|
14 |
+
|
15 |
+
const IndependentMetricsTable: React.FC<IndependentMetricsTableProps> = ({
|
16 |
+
independentMetrics,
|
17 |
+
tableHeader,
|
18 |
+
selectedModels,
|
19 |
+
tableRows,
|
20 |
+
}) => {
|
21 |
+
if (independentMetrics.length === 0) return null
|
22 |
+
return (
|
23 |
+
<div className="overflow-x-auto max-h-[80vh] overflow-y-auto">
|
24 |
+
<table className="table w-full min-w-max border-gray-700 border">
|
25 |
+
<thead>
|
26 |
+
<tr>
|
27 |
+
<th className="sticky left-0 top-0 bg-base-100 z-20 border-gray-700 border">Metric</th>
|
28 |
+
{tableHeader
|
29 |
+
.filter((model) => selectedModels.has(model))
|
30 |
+
.map((model) => (
|
31 |
+
<th
|
32 |
+
key={`independent-${model}`}
|
33 |
+
className="sticky top-0 bg-base-100 z-10 text-center text-xs border-gray-700 border"
|
34 |
+
>
|
35 |
+
{model}
|
36 |
+
</th>
|
37 |
+
))}
|
38 |
+
</tr>
|
39 |
+
</thead>
|
40 |
+
<tbody>
|
41 |
+
{independentMetrics.sort().map((metric) => {
|
42 |
+
const row = tableRows.find((r) => r.metric === metric)
|
43 |
+
if (!row) return null
|
44 |
+
return (
|
45 |
+
<tr key={`independent-${metric}`} className="hover:bg-base-100">
|
46 |
+
<td className="sticky left-0 bg-base-100 z-10 border-gray-700 border">{metric}</td>
|
47 |
+
{tableHeader
|
48 |
+
.filter((model) => selectedModels.has(model))
|
49 |
+
.map((col) => {
|
50 |
+
const cell = row[col]
|
51 |
+
return (
|
52 |
+
<td
|
53 |
+
key={`independent-${metric}-${col}`}
|
54 |
+
className="text-center border-gray-700 border"
|
55 |
+
>
|
56 |
+
{!isNaN(Number(cell)) ? Number(Number(cell).toFixed(3)) : cell}
|
57 |
+
</td>
|
58 |
+
)
|
59 |
+
})}
|
60 |
+
</tr>
|
61 |
+
)
|
62 |
+
})}
|
63 |
+
</tbody>
|
64 |
+
</table>
|
65 |
+
</div>
|
66 |
+
)
|
67 |
+
}
|
68 |
+
|
69 |
+
export default IndependentMetricsTable
|
frontend/src/components/LeaderboardFilter.tsx
CHANGED
@@ -20,6 +20,7 @@ const LeaderboardFilter: React.FC<FilterProps> = ({
|
|
20 |
{}
|
21 |
)
|
22 |
const [searchTerm, setSearchTerm] = useState('')
|
|
|
23 |
|
24 |
const toggleGroup = (group: string) => {
|
25 |
setOpenGroups((prev) => ({ ...prev, [group]: !prev[group] }))
|
@@ -164,166 +165,199 @@ const LeaderboardFilter: React.FC<FilterProps> = ({
|
|
164 |
setOpenSubGroups(openSubGroups)
|
165 |
}
|
166 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
167 |
return (
|
168 |
<div className="w-full mb-4">
|
169 |
-
<
|
170 |
-
<
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
onChange={(e) => {
|
179 |
-
const value = e.target.value
|
180 |
-
setSearchTerm(value)
|
181 |
-
const openGroups: { [key: string]: boolean } = {}
|
182 |
-
const openSubGroups: { [key: string]: { [key: string]: boolean } } = {}
|
183 |
-
Object.entries(groups).forEach(([group, subGroups]) => {
|
184 |
-
let groupHasMatch = false
|
185 |
-
openSubGroups[group] = {}
|
186 |
-
Object.entries(subGroups).forEach(([subGroup, metrics]) => {
|
187 |
-
const hasMatch = metrics.some((metric) =>
|
188 |
-
metric.toLowerCase().includes(value.toLowerCase())
|
189 |
-
)
|
190 |
-
openSubGroups[group][subGroup] = hasMatch || value === ''
|
191 |
-
if (hasMatch) groupHasMatch = true
|
192 |
-
})
|
193 |
-
openGroups[group] = groupHasMatch || value === ''
|
194 |
-
})
|
195 |
-
setOpenGroups(openGroups)
|
196 |
-
setOpenSubGroups(openSubGroups)
|
197 |
-
}}
|
198 |
-
/>
|
199 |
-
<span className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none">
|
200 |
-
<svg
|
201 |
-
xmlns="http://www.w3.org/2000/svg"
|
202 |
-
className="h-4 w-4"
|
203 |
-
fill="none"
|
204 |
-
viewBox="0 0 24 24"
|
205 |
-
stroke="currentColor"
|
206 |
-
>
|
207 |
-
<path
|
208 |
-
strokeLinecap="round"
|
209 |
-
strokeLinejoin="round"
|
210 |
-
strokeWidth={2}
|
211 |
-
d="M21 21l-4-4m0 0A7 7 0 104 4a7 7 0 0013 13z"
|
212 |
-
/>
|
213 |
-
</svg>
|
214 |
-
</span>
|
215 |
-
</div>
|
216 |
-
<button
|
217 |
-
type="button"
|
218 |
-
className="text-xs px-3 py-1 border rounded font-semibold bg-base-200 cursor-pointer"
|
219 |
-
onClick={selectAllGlobal}
|
220 |
-
>
|
221 |
-
All
|
222 |
-
</button>
|
223 |
-
<button
|
224 |
-
type="button"
|
225 |
-
className="text-xs px-3 py-1 border rounded font-semibold bg-base-200 cursor-pointer"
|
226 |
-
onClick={deselectAllGlobal}
|
227 |
-
>
|
228 |
-
None
|
229 |
-
</button>
|
230 |
</div>
|
231 |
-
<div className="
|
232 |
-
|
233 |
-
<div
|
234 |
-
<div className="
|
235 |
-
<
|
236 |
-
type="
|
237 |
-
|
238 |
-
className="
|
239 |
-
|
240 |
-
{
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
className="text-xs px-2 py-1 border rounded cursor-pointer"
|
252 |
-
onClick={() => deselectAllInGroup(group)}
|
253 |
-
>
|
254 |
-
None
|
255 |
-
</button>
|
256 |
-
</div>
|
257 |
-
{openGroups[group] && (
|
258 |
-
<div className="ml-2">
|
259 |
-
{Object.entries(subGroups).map(([subGroup, metrics]) => {
|
260 |
-
const filteredMetrics = searchTerm
|
261 |
-
? metrics.filter((metric) =>
|
262 |
-
metric.toLowerCase().includes(searchTerm.toLowerCase())
|
263 |
)
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
</div>
|
317 |
-
)
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
</div>
|
322 |
-
)}
|
323 |
</div>
|
324 |
-
|
325 |
</div>
|
326 |
-
</
|
327 |
</div>
|
328 |
)
|
329 |
}
|
|
|
20 |
{}
|
21 |
)
|
22 |
const [searchTerm, setSearchTerm] = useState('')
|
23 |
+
const [filterOpen, setFilterOpen] = useState(false)
|
24 |
|
25 |
const toggleGroup = (group: string) => {
|
26 |
setOpenGroups((prev) => ({ ...prev, [group]: !prev[group] }))
|
|
|
165 |
setOpenSubGroups(openSubGroups)
|
166 |
}
|
167 |
|
168 |
+
// Open all groups and subgroups if all metrics are selected (initial load)
|
169 |
+
useEffect(() => {
|
170 |
+
// Only run on initial mount
|
171 |
+
const allMetrics = Object.values(groups).flatMap((subGroups) => Object.values(subGroups).flat())
|
172 |
+
const allSelected = allMetrics.every((metric) => selectedMetrics.has(metric))
|
173 |
+
if (allSelected && Object.keys(groups).length > 0) {
|
174 |
+
const openGroups: { [key: string]: boolean } = {}
|
175 |
+
const openSubGroups: { [key: string]: { [key: string]: boolean } } = {}
|
176 |
+
Object.entries(groups).forEach(([group, subGroups]) => {
|
177 |
+
openGroups[group] = true
|
178 |
+
openSubGroups[group] = {}
|
179 |
+
Object.keys(subGroups).forEach((subGroup) => {
|
180 |
+
openSubGroups[group][subGroup] = true
|
181 |
+
})
|
182 |
+
})
|
183 |
+
setOpenGroups(openGroups)
|
184 |
+
setOpenSubGroups(openSubGroups)
|
185 |
+
}
|
186 |
+
// eslint-disable-next-line
|
187 |
+
}, [groups, selectedMetrics])
|
188 |
+
|
189 |
return (
|
190 |
<div className="w-full mb-4">
|
191 |
+
<div className="collapse collapse-arrow bg-base-200 border border-gray-700">
|
192 |
+
<input
|
193 |
+
type="checkbox"
|
194 |
+
className="peer"
|
195 |
+
checked={filterOpen}
|
196 |
+
onChange={() => setFilterOpen((open) => !open)}
|
197 |
+
/>
|
198 |
+
<div className="collapse-title select-none ">
|
199 |
+
<span className="text-sm">Filter Individual Metrics</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
</div>
|
201 |
+
<div className="collapse-content">
|
202 |
+
<fieldset className="fieldset w-full">
|
203 |
+
<div className="flex gap-2 mb-3">
|
204 |
+
<div className="relative mr-2">
|
205 |
+
<input
|
206 |
+
type="text"
|
207 |
+
placeholder="Search metrics..."
|
208 |
+
className="input input-bordered border-gray-700 input-sm w-48 pr-8"
|
209 |
+
value={searchTerm}
|
210 |
+
onChange={(e) => {
|
211 |
+
const value = e.target.value
|
212 |
+
setSearchTerm(value)
|
213 |
+
const openGroups: { [key: string]: boolean } = {}
|
214 |
+
const openSubGroups: { [key: string]: { [key: string]: boolean } } = {}
|
215 |
+
Object.entries(groups).forEach(([group, subGroups]) => {
|
216 |
+
let groupHasMatch = false
|
217 |
+
openSubGroups[group] = {}
|
218 |
+
Object.entries(subGroups).forEach(([subGroup, metrics]) => {
|
219 |
+
const hasMatch = metrics.some((metric) =>
|
220 |
+
metric.toLowerCase().includes(value.toLowerCase())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
)
|
222 |
+
openSubGroups[group][subGroup] = hasMatch || value === ''
|
223 |
+
if (hasMatch) groupHasMatch = true
|
224 |
+
})
|
225 |
+
openGroups[group] = groupHasMatch || value === ''
|
226 |
+
})
|
227 |
+
setOpenGroups(openGroups)
|
228 |
+
setOpenSubGroups(openSubGroups)
|
229 |
+
}}
|
230 |
+
/>
|
231 |
+
<span className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none">
|
232 |
+
<svg
|
233 |
+
xmlns="http://www.w3.org/2000/svg"
|
234 |
+
className="h-4 w-4"
|
235 |
+
fill="none"
|
236 |
+
viewBox="0 0 24 24"
|
237 |
+
stroke="currentColor"
|
238 |
+
>
|
239 |
+
<path
|
240 |
+
strokeLinecap="round"
|
241 |
+
strokeLinejoin="round"
|
242 |
+
strokeWidth={2}
|
243 |
+
d="M21 21l-4-4m0 0A7 7 0 104 4a7 7 0 0013 13z"
|
244 |
+
/>
|
245 |
+
</svg>
|
246 |
+
</span>
|
247 |
+
</div>
|
248 |
+
<button
|
249 |
+
type="button"
|
250 |
+
className="text-xs px-3 py-1 border border-gray-700 rounded font-semibold bg-base-200 cursor-pointer"
|
251 |
+
onClick={selectAllGlobal}
|
252 |
+
>
|
253 |
+
All
|
254 |
+
</button>
|
255 |
+
<button
|
256 |
+
type="button"
|
257 |
+
className="text-xs px-3 py-1 border border-gray-700 rounded font-semibold bg-base-200 cursor-pointer"
|
258 |
+
onClick={deselectAllGlobal}
|
259 |
+
>
|
260 |
+
None
|
261 |
+
</button>
|
262 |
+
</div>
|
263 |
+
<div className="flex flex-row flex-wrap gap-4 w-full items-start">
|
264 |
+
{Object.entries(groups).map(([group, subGroups]) => (
|
265 |
+
<div key={group} className="flex-1 min-w-[220px] max-w-full">
|
266 |
+
<div className="flex items-center gap-2 mb-1">
|
267 |
+
<button
|
268 |
+
type="button"
|
269 |
+
onClick={() => toggleGroup(group)}
|
270 |
+
className="flex-1 text-left font-medium py-1 px-2 rounded border border-gray-700 cursor-pointer"
|
271 |
+
>
|
272 |
+
{group} {openGroups[group] ? '▼' : '▶'}
|
273 |
+
</button>
|
274 |
+
<button
|
275 |
+
type="button"
|
276 |
+
className="text-xs px-2 py-1 border border-gray-700 rounded cursor-pointer"
|
277 |
+
onClick={() => selectAllInGroup(group)}
|
278 |
+
>
|
279 |
+
All
|
280 |
+
</button>
|
281 |
+
<button
|
282 |
+
type="button"
|
283 |
+
className="text-xs px-2 py-1 border border-gray-700 rounded cursor-pointer"
|
284 |
+
onClick={() => deselectAllInGroup(group)}
|
285 |
+
>
|
286 |
+
None
|
287 |
+
</button>
|
288 |
+
</div>
|
289 |
+
{openGroups[group] && (
|
290 |
+
<div className="ml-2">
|
291 |
+
{Object.entries(subGroups).map(([subGroup, metrics]) => {
|
292 |
+
const filteredMetrics = searchTerm
|
293 |
+
? metrics.filter((metric) =>
|
294 |
+
metric.toLowerCase().includes(searchTerm.toLowerCase())
|
295 |
+
)
|
296 |
+
: metrics
|
297 |
+
if (filteredMetrics.length === 0) return null
|
298 |
+
return (
|
299 |
+
<div key={subGroup} className="mb-2">
|
300 |
+
<div className="flex items-center gap-2 mb-1">
|
301 |
+
<button
|
302 |
+
type="button"
|
303 |
+
onClick={() => toggleSubGroup(group, subGroup)}
|
304 |
+
className="flex-1 text-left py-1 px-2 rounded border border-gray-700 cursor-pointer"
|
305 |
+
>
|
306 |
+
{subGroup} {openSubGroups[group]?.[subGroup] ? '▼' : '▶'}
|
307 |
+
</button>
|
308 |
+
<button
|
309 |
+
type="button"
|
310 |
+
className="text-xs px-2 py-1 border border-gray-700 rounded cursor-pointer"
|
311 |
+
onClick={() => selectAllInSubGroup(group, subGroup)}
|
312 |
+
>
|
313 |
+
All
|
314 |
+
</button>
|
315 |
+
<button
|
316 |
+
type="button"
|
317 |
+
className="text-xs px-2 py-1 border border-gray-700 rounded cursor-pointer"
|
318 |
+
onClick={() => deselectAllInSubGroup(group, subGroup)}
|
319 |
+
>
|
320 |
+
None
|
321 |
+
</button>
|
322 |
+
</div>
|
323 |
+
{openSubGroups[group]?.[subGroup] && (
|
324 |
+
<div className="grid grid-cols-1 gap-1 ml-2 max-h-48 overflow-y-auto pr-2">
|
325 |
+
{filteredMetrics.map((metric) => (
|
326 |
+
<label key={metric} className="flex items-center gap-2 text-sm">
|
327 |
+
<input
|
328 |
+
type="checkbox"
|
329 |
+
checked={selectedMetrics.has(metric)}
|
330 |
+
onChange={(event) => {
|
331 |
+
const newSet = new Set(selectedMetrics)
|
332 |
+
if (event.target.checked) {
|
333 |
+
newSet.add(metric)
|
334 |
+
} else {
|
335 |
+
newSet.delete(metric)
|
336 |
+
}
|
337 |
+
setSelectedMetrics(newSet)
|
338 |
+
}}
|
339 |
+
className="form-checkbox h-4 w-4"
|
340 |
+
/>
|
341 |
+
<span className="truncate" title={metric}>
|
342 |
+
{metric.includes('_')
|
343 |
+
? metric.split('_').slice(1).join('_')
|
344 |
+
: metric}
|
345 |
+
</span>
|
346 |
+
</label>
|
347 |
+
))}
|
348 |
+
</div>
|
349 |
+
)}
|
350 |
</div>
|
351 |
+
)
|
352 |
+
})}
|
353 |
+
</div>
|
354 |
+
)}
|
355 |
</div>
|
356 |
+
))}
|
357 |
</div>
|
358 |
+
</fieldset>
|
359 |
</div>
|
360 |
+
</div>
|
361 |
</div>
|
362 |
)
|
363 |
}
|
frontend/src/components/LeaderboardTable.tsx
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
import React, { useEffect, useState } from 'react'
|
2 |
import LeaderboardFilter from './LeaderboardFilter'
|
3 |
import LoadingSpinner from './LoadingSpinner'
|
|
|
4 |
|
5 |
interface LeaderboardTableProps {
|
6 |
benchmarkData: any
|
@@ -16,6 +17,12 @@ interface Groups {
|
|
16 |
[group: string]: { [subgroup: string]: string[] }
|
17 |
}
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
const OverallMetricFilter: React.FC<{
|
20 |
overallMetrics: string[]
|
21 |
selectedOverallMetrics: Set<string>
|
@@ -31,8 +38,8 @@ const OverallMetricFilter: React.FC<{
|
|
31 |
setSelectedOverallMetrics(newSelected)
|
32 |
}
|
33 |
return (
|
34 |
-
<div className="w-full
|
35 |
-
<fieldset className="fieldset w-full p-4 rounded border border-gray-700">
|
36 |
<legend className="fieldset-legend font-semibold">
|
37 |
Metrics ({selectedOverallMetrics.size}/{overallMetrics.length})
|
38 |
</legend>
|
@@ -60,14 +67,20 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
60 |
const [tableRows, setTableRows] = useState<Row[]>([])
|
61 |
const [tableHeader, setTableHeader] = useState<string[]>([])
|
62 |
const [error, setError] = useState<string | null>(null)
|
63 |
-
const [
|
64 |
-
const [
|
65 |
-
const [
|
66 |
-
{}
|
67 |
-
)
|
68 |
const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
|
69 |
const [overallMetrics, setOverallMetrics] = useState<string[]>([])
|
70 |
const [selectedOverallMetrics, setSelectedOverallMetrics] = useState<Set<string>>(new Set())
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
useEffect(() => {
|
73 |
if (!benchmarkData) {
|
@@ -128,9 +141,9 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
128 |
setSelectedMetrics(new Set(allMetrics))
|
129 |
setTableHeader(headers)
|
130 |
setTableRows(rows)
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
setError(null)
|
135 |
} catch (err: any) {
|
136 |
setError('Failed to parse benchmark data, please try again: ' + err.message)
|
@@ -138,11 +151,11 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
138 |
}, [benchmarkData])
|
139 |
|
140 |
const toggleGroup = (group: string) => {
|
141 |
-
|
142 |
}
|
143 |
|
144 |
const toggleSubGroup = (group: string, subGroup: string) => {
|
145 |
-
|
146 |
...prev,
|
147 |
[group]: {
|
148 |
...(prev[group] || {}),
|
@@ -151,6 +164,138 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
151 |
}))
|
152 |
}
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
// Find all metrics matching a particular extracted metric name (like "log10_p_value")
|
155 |
const findAllMetricsForName = (metricName: string): string[] => {
|
156 |
return tableRows
|
@@ -218,12 +363,12 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
218 |
if (!group) return metricNames
|
219 |
|
220 |
// Get all metrics for the specified group
|
221 |
-
const groupMetrics = Object.values(
|
222 |
|
223 |
// If subgroup is specified, further filter to that subgroup
|
224 |
-
if (subgroup &&
|
225 |
return metricNames.filter(
|
226 |
-
(metric) =>
|
227 |
)
|
228 |
}
|
229 |
|
@@ -233,8 +378,101 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
233 |
)
|
234 |
}
|
235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
return (
|
237 |
-
<div className="rounded
|
238 |
{error && <div className="text-red-500">{error}</div>}
|
239 |
{!error && (
|
240 |
<div className="flex flex-col gap-8">
|
@@ -244,11 +482,11 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
244 |
selectedOverallMetrics={selectedOverallMetrics}
|
245 |
setSelectedOverallMetrics={setSelectedOverallMetrics}
|
246 |
/>
|
247 |
-
|
248 |
-
groups={
|
249 |
selectedMetrics={selectedMetrics}
|
250 |
setSelectedMetrics={setSelectedMetrics}
|
251 |
-
/>
|
252 |
</div>
|
253 |
|
254 |
{selectedModels.size === 0 || selectedMetrics.size === 0 ? (
|
@@ -258,61 +496,12 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
258 |
) : (
|
259 |
<>
|
260 |
{/* Standalone metrics table */}
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
<thead>
|
268 |
-
<tr>
|
269 |
-
<th className="sticky left-0 top-0 bg-base-100 z-20 border-gray-700 border">
|
270 |
-
Metric
|
271 |
-
</th>
|
272 |
-
{tableHeader
|
273 |
-
.filter((model) => selectedModels.has(model))
|
274 |
-
.map((model) => (
|
275 |
-
<th
|
276 |
-
key={`standalone-${model}`}
|
277 |
-
className="sticky top-0 bg-base-100 z-10 text-center text-xs border-gray-700 border"
|
278 |
-
>
|
279 |
-
{model}
|
280 |
-
</th>
|
281 |
-
))}
|
282 |
-
</tr>
|
283 |
-
</thead>
|
284 |
-
<tbody>
|
285 |
-
{standaloneMetrics.sort().map((metric) => {
|
286 |
-
const row = tableRows.find((r) => r.metric === metric)
|
287 |
-
if (!row) return null
|
288 |
-
return (
|
289 |
-
<tr key={`standalone-${metric}`} className="hover:bg-base-100">
|
290 |
-
<td className="sticky left-0 bg-base-100 z-10 border-gray-700 border">
|
291 |
-
{metric}
|
292 |
-
</td>
|
293 |
-
{tableHeader
|
294 |
-
.filter((model) => selectedModels.has(model))
|
295 |
-
.map((col) => {
|
296 |
-
const cell = row[col]
|
297 |
-
return (
|
298 |
-
<td
|
299 |
-
key={`standalone-${metric}-${col}`}
|
300 |
-
className="text-center border-gray-700 border"
|
301 |
-
>
|
302 |
-
{!isNaN(Number(cell))
|
303 |
-
? Number(Number(cell).toFixed(3))
|
304 |
-
: cell}
|
305 |
-
</td>
|
306 |
-
)
|
307 |
-
})}
|
308 |
-
</tr>
|
309 |
-
)
|
310 |
-
})}
|
311 |
-
</tbody>
|
312 |
-
</table>
|
313 |
-
</div>
|
314 |
-
)
|
315 |
-
})()}
|
316 |
|
317 |
{/* Main metrics table */}
|
318 |
<div className="overflow-x-auto max-h-[80vh] overflow-y-auto">
|
@@ -326,11 +515,9 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
326 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
327 |
.map((metric) => (
|
328 |
<th
|
329 |
-
key={metric}
|
330 |
-
|
331 |
-
|
332 |
-
}
|
333 |
-
className="sticky top-0 bg-base-100 z-10 text-center border-x border-gray-300 border border-gray-700 border"
|
334 |
>
|
335 |
{metric}
|
336 |
</th>
|
@@ -342,27 +529,33 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
342 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
343 |
.map((metric) => (
|
344 |
<React.Fragment key={`header-models-${metric}`}>
|
345 |
-
{
|
346 |
-
|
347 |
-
|
|
|
348 |
<th
|
349 |
key={`${metric}-${model}`}
|
350 |
-
className="sticky top-12 bg-base-100 z-10 text-center text-xs border-gray-700 border border-bottom-solid border-b-gray-700 border-b-
|
|
|
351 |
>
|
352 |
{model}
|
|
|
|
|
|
|
353 |
</th>
|
354 |
-
)
|
|
|
355 |
</React.Fragment>
|
356 |
))}
|
357 |
</tr>
|
358 |
</thead>
|
359 |
<tbody>
|
360 |
-
{/* First render each group */}
|
361 |
-
{
|
362 |
// Skip the "Overall" group completely
|
363 |
if (group === 'Overall') return null
|
364 |
|
365 |
-
// Get all metrics for this group
|
366 |
const allGroupMetrics = Object.values(subGroups).flat()
|
367 |
// Filter to only include selected metrics
|
368 |
const visibleGroupMetrics = filterMetricsByGroupAndSubgroup(
|
@@ -370,9 +563,35 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
370 |
group
|
371 |
)
|
372 |
|
373 |
-
// Skip this group if no metrics are selected
|
374 |
if (visibleGroupMetrics.length === 0) return null
|
375 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
376 |
return (
|
377 |
<React.Fragment key={group}>
|
378 |
{/* Group row with average stats for the entire group */}
|
@@ -380,27 +599,45 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
380 |
className="bg-base-200 cursor-pointer hover:bg-base-300"
|
381 |
onClick={() => toggleGroup(group)}
|
382 |
>
|
383 |
-
<td className="sticky left-0 bg-base-200 z-10 font-medium border-gray-700 border">
|
384 |
-
{
|
385 |
-
{group}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
386 |
</td>
|
387 |
{/* For each metric column */}
|
388 |
{overallMetrics
|
389 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
390 |
-
.map((metric) =>
|
391 |
-
|
392 |
-
|
393 |
-
{
|
394 |
-
.
|
395 |
-
.map((col) => {
|
396 |
-
// Find all metrics in this group that match the current metric name
|
397 |
const allMetricsWithName = findAllMetricsForName(metric)
|
398 |
const metricsInGroupForThisMetric =
|
399 |
visibleGroupMetrics.filter((m) =>
|
400 |
allMetricsWithName.includes(m)
|
401 |
)
|
402 |
const stats = calculateStats(metricsInGroupForThisMetric, col)
|
403 |
-
|
404 |
return (
|
405 |
<td
|
406 |
key={`${group}-${metric}-${col}`}
|
@@ -412,21 +649,22 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
412 |
</td>
|
413 |
)
|
414 |
})}
|
415 |
-
|
416 |
-
|
|
|
417 |
</tr>
|
418 |
|
419 |
-
{/* Only render subgroups if group is open */}
|
420 |
-
{
|
421 |
-
|
422 |
-
// Filter to only include selected metrics in this subgroup
|
423 |
const visibleSubgroupMetrics = filterMetricsByGroupAndSubgroup(
|
424 |
metrics,
|
425 |
group,
|
426 |
subGroup
|
427 |
)
|
428 |
|
429 |
-
// Skip this subgroup if no metrics are selected
|
430 |
if (visibleSubgroupMetrics.length === 0) return null
|
431 |
|
432 |
return (
|
@@ -436,147 +674,208 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
436 |
className="bg-base-100 cursor-pointer hover:bg-base-200"
|
437 |
onClick={() => toggleSubGroup(group, subGroup)}
|
438 |
>
|
439 |
-
<td className="sticky left-0 bg-base-100 z-10 pl-6 font-medium border-gray-700 border">
|
440 |
-
|
441 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
442 |
</td>
|
443 |
{/* For each metric column */}
|
444 |
{overallMetrics
|
445 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
446 |
-
.map((metric) =>
|
447 |
-
|
448 |
-
|
449 |
-
{
|
450 |
-
.
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
|
|
|
|
|
|
458 |
)
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
})}
|
475 |
-
</React.Fragment>
|
476 |
-
))}
|
477 |
</tr>
|
478 |
|
479 |
{/* Individual metric rows */}
|
480 |
-
{
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
495 |
}
|
|
|
496 |
}
|
497 |
-
return ''
|
498 |
-
}
|
499 |
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
|
|
|
|
|
|
|
|
|
|
513 |
}
|
514 |
-
return metric
|
515 |
-
}
|
516 |
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
|
|
|
|
529 |
}
|
530 |
-
return metric
|
531 |
-
}
|
532 |
|
533 |
-
|
534 |
-
|
535 |
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
|
|
|
|
566 |
}
|
567 |
-
return value
|
568 |
-
}
|
569 |
|
570 |
-
|
571 |
-
|
572 |
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
|
|
580 |
const row = tableRows.find((r) => r.metric === metric)
|
581 |
if (!row) return null
|
582 |
|
@@ -587,41 +886,56 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
587 |
|
588 |
return (
|
589 |
<tr key={metric} className="hover:bg-base-100">
|
590 |
-
<td className="sticky left-0 bg-base-100 z-10 pl-10 border-gray-700 border">
|
591 |
-
{metric}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
592 |
</td>
|
593 |
-
{/* For each metric column */}
|
594 |
{overallMetrics
|
595 |
.filter((oMetric) =>
|
596 |
selectedOverallMetrics.has(oMetric)
|
597 |
)
|
598 |
.map((oMetric) => {
|
599 |
-
// Only show values for the matching metric
|
600 |
const isMatchingMetric =
|
601 |
findAllMetricsForName(oMetric).includes(metric)
|
602 |
-
|
603 |
if (!isMatchingMetric) {
|
604 |
-
// Fill empty cells for non-matching metrics
|
605 |
return (
|
606 |
<React.Fragment key={`${metric}-${oMetric}`}>
|
607 |
-
{
|
608 |
-
|
609 |
-
selectedModels.has(model)
|
610 |
-
)
|
611 |
-
.map((col) => (
|
612 |
<td
|
613 |
key={`${metric}-${oMetric}-${col}`}
|
614 |
className="text-center border-gray-700 border"
|
615 |
></td>
|
616 |
-
)
|
|
|
617 |
</React.Fragment>
|
618 |
)
|
619 |
}
|
620 |
return (
|
621 |
<React.Fragment key={`${metric}-${oMetric}`}>
|
622 |
-
{
|
623 |
-
|
624 |
-
.map((col) => {
|
625 |
const cell = row[col]
|
626 |
return (
|
627 |
<td
|
@@ -633,13 +947,15 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
633 |
: cell}
|
634 |
</td>
|
635 |
)
|
636 |
-
}
|
|
|
637 |
</React.Fragment>
|
638 |
)
|
639 |
})}
|
640 |
</tr>
|
641 |
)
|
642 |
-
})
|
|
|
643 |
</React.Fragment>
|
644 |
)
|
645 |
})}
|
|
|
1 |
import React, { useEffect, useState } from 'react'
|
2 |
import LeaderboardFilter from './LeaderboardFilter'
|
3 |
import LoadingSpinner from './LoadingSpinner'
|
4 |
+
import IndependentMetricsTable from './IndependentMetricsTable'
|
5 |
|
6 |
interface LeaderboardTableProps {
|
7 |
benchmarkData: any
|
|
|
17 |
[group: string]: { [subgroup: string]: string[] }
|
18 |
}
|
19 |
|
20 |
+
interface SortState {
|
21 |
+
[overallMetric: string]: {
|
22 |
+
[model: string]: { direction: 'asc' | 'desc' }
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
const OverallMetricFilter: React.FC<{
|
27 |
overallMetrics: string[]
|
28 |
selectedOverallMetrics: Set<string>
|
|
|
38 |
setSelectedOverallMetrics(newSelected)
|
39 |
}
|
40 |
return (
|
41 |
+
<div className="w-full">
|
42 |
+
<fieldset className="fieldset w-full p-4 rounded border border-gray-700 bg-base-200">
|
43 |
<legend className="fieldset-legend font-semibold">
|
44 |
Metrics ({selectedOverallMetrics.size}/{overallMetrics.length})
|
45 |
</legend>
|
|
|
67 |
const [tableRows, setTableRows] = useState<Row[]>([])
|
68 |
const [tableHeader, setTableHeader] = useState<string[]>([])
|
69 |
const [error, setError] = useState<string | null>(null)
|
70 |
+
const [groupRows, setGroupRows] = useState<Groups>({})
|
71 |
+
const [openGroupRows, setOpenGroupRows] = useState<{ [key: string]: boolean }>({})
|
72 |
+
const [openSubGroupRows, setOpenSubGroupRows] = useState<{
|
73 |
+
[key: string]: { [key: string]: boolean }
|
74 |
+
}>({})
|
75 |
const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
|
76 |
const [overallMetrics, setOverallMetrics] = useState<string[]>([])
|
77 |
const [selectedOverallMetrics, setSelectedOverallMetrics] = useState<Set<string>>(new Set())
|
78 |
+
const [sortState, setSortState] = useState<SortState>({})
|
79 |
+
const [columnSortState, setColumnSortState] = useState<SortState>({})
|
80 |
+
// Add state for row-based column sorting
|
81 |
+
const [selectedRowForSort, setSelectedRowForSort] = useState<{
|
82 |
+
[rowKey: string]: { direction: 'asc' | 'desc' }
|
83 |
+
}>({})
|
84 |
|
85 |
useEffect(() => {
|
86 |
if (!benchmarkData) {
|
|
|
141 |
setSelectedMetrics(new Set(allMetrics))
|
142 |
setTableHeader(headers)
|
143 |
setTableRows(rows)
|
144 |
+
setGroupRows(groupsData)
|
145 |
+
setOpenGroupRows(initialOpenGroups)
|
146 |
+
setOpenSubGroupRows(initialOpenSubGroups)
|
147 |
setError(null)
|
148 |
} catch (err: any) {
|
149 |
setError('Failed to parse benchmark data, please try again: ' + err.message)
|
|
|
151 |
}, [benchmarkData])
|
152 |
|
153 |
const toggleGroup = (group: string) => {
|
154 |
+
setOpenGroupRows((prev) => ({ ...prev, [group]: !prev[group] }))
|
155 |
}
|
156 |
|
157 |
const toggleSubGroup = (group: string, subGroup: string) => {
|
158 |
+
setOpenSubGroupRows((prev) => ({
|
159 |
...prev,
|
160 |
[group]: {
|
161 |
...(prev[group] || {}),
|
|
|
164 |
}))
|
165 |
}
|
166 |
|
167 |
+
const handleSort = (overallMetric: string, model: string) => {
|
168 |
+
setSortState((prev) => {
|
169 |
+
const prevDir = prev[overallMetric]?.[model]?.direction
|
170 |
+
let newSortState: SortState = {}
|
171 |
+
if (!prevDir) {
|
172 |
+
// No sort yet, set to 'asc'
|
173 |
+
newSortState[overallMetric] = { [model]: { direction: 'asc' } }
|
174 |
+
} else if (prevDir === 'asc') {
|
175 |
+
// Was 'asc', set to 'desc'
|
176 |
+
newSortState[overallMetric] = { [model]: { direction: 'desc' } }
|
177 |
+
}
|
178 |
+
// Else revert back to unsorted state
|
179 |
+
return newSortState
|
180 |
+
})
|
181 |
+
}
|
182 |
+
|
183 |
+
// Helper to generate a stable composite key for row-based column sorting
|
184 |
+
function getRowSortKey(group: string | null, subGroup: string | null, metric: string | null) {
|
185 |
+
return `${group ?? ''}||${subGroup ?? ''}||${metric ?? ''}`
|
186 |
+
}
|
187 |
+
|
188 |
+
// Update handleColumnSort to use setSelectedRowForSort
|
189 |
+
const handleColumnSort = (
|
190 |
+
group: string | null,
|
191 |
+
subGroup: string | null,
|
192 |
+
metric: string | null
|
193 |
+
) => {
|
194 |
+
const rowKey = getRowSortKey(group, subGroup, metric)
|
195 |
+
setSelectedRowForSort((prev) => {
|
196 |
+
const prevDir = prev[rowKey]?.direction
|
197 |
+
const newSortState: { [rowKey: string]: { direction: 'asc' | 'desc' } } = {}
|
198 |
+
if (!prevDir) {
|
199 |
+
newSortState[rowKey] = { direction: 'asc' }
|
200 |
+
} else if (prevDir === 'asc') {
|
201 |
+
newSortState[rowKey] = { direction: 'desc' }
|
202 |
+
} else if (prevDir === 'desc') {
|
203 |
+
delete newSortState[rowKey]
|
204 |
+
}
|
205 |
+
return newSortState
|
206 |
+
})
|
207 |
+
}
|
208 |
+
|
209 |
+
// Helper to get current row sort config for a row
|
210 |
+
function getRowColumnSort(group: string | null, subGroup: string | null, metric: string | null) {
|
211 |
+
return selectedRowForSort[getRowSortKey(group, subGroup, metric)] || null
|
212 |
+
}
|
213 |
+
|
214 |
+
const getSortConfig = () => {
|
215 |
+
// Find the first sorted column (overallMetric, model)
|
216 |
+
console.log({ sortState })
|
217 |
+
for (const overallMetric of overallMetrics) {
|
218 |
+
if (!selectedOverallMetrics.has(overallMetric)) continue
|
219 |
+
const models = tableHeader.filter((model) => selectedModels.has(model))
|
220 |
+
for (const model of models) {
|
221 |
+
if (sortState[overallMetric]?.[model]) {
|
222 |
+
return { overallMetric, model, direction: sortState[overallMetric][model].direction }
|
223 |
+
}
|
224 |
+
}
|
225 |
+
}
|
226 |
+
return null
|
227 |
+
}
|
228 |
+
|
229 |
+
// Move getRowSortConfig above sortModelColumns so it is defined before use
|
230 |
+
const getRowSortConfig = () => {
|
231 |
+
for (const overallMetric of overallMetrics) {
|
232 |
+
if (!selectedOverallMetrics.has(overallMetric)) continue
|
233 |
+
const models = tableHeader.filter((model) => selectedModels.has(model))
|
234 |
+
for (const model of models) {
|
235 |
+
if (sortState[overallMetric]?.[model]) {
|
236 |
+
return { overallMetric, model, direction: sortState[overallMetric][model].direction }
|
237 |
+
}
|
238 |
+
}
|
239 |
+
}
|
240 |
+
return null
|
241 |
+
}
|
242 |
+
|
243 |
+
const getColumnSortConfig = () => {
|
244 |
+
for (const overallMetric of overallMetrics) {
|
245 |
+
if (!selectedOverallMetrics.has(overallMetric)) continue
|
246 |
+
if (columnSortState[overallMetric]?.['__col__']) {
|
247 |
+
return { overallMetric, direction: columnSortState[overallMetric]['__col__'].direction }
|
248 |
+
}
|
249 |
+
}
|
250 |
+
return null
|
251 |
+
}
|
252 |
+
|
253 |
+
const sortModelColumns = (models: string[], overallMetric: string): string[] => {
|
254 |
+
// Column sort takes precedence; if no column sort, return models in default order
|
255 |
+
const columnSortConfig = getColumnSortConfig()
|
256 |
+
console.log({ columnSortConfig, overallMetric })
|
257 |
+
if (columnSortConfig && columnSortConfig.overallMetric === overallMetric) {
|
258 |
+
// Sort by average value for each model in this overallMetric
|
259 |
+
return [...models].sort((a, b) => {
|
260 |
+
const valsA = tableRows
|
261 |
+
.filter((row) => findAllMetricsForName(overallMetric).includes(row.metric as string))
|
262 |
+
.map((row) => Number(row[a]))
|
263 |
+
.filter((v) => !isNaN(v))
|
264 |
+
const valsB = tableRows
|
265 |
+
.filter((row) => findAllMetricsForName(overallMetric).includes(row.metric as string))
|
266 |
+
.map((row) => Number(row[b]))
|
267 |
+
.filter((v) => !isNaN(v))
|
268 |
+
const avgA = valsA.length ? valsA.reduce((s, v) => s + v, 0) / valsA.length : NaN
|
269 |
+
const avgB = valsB.length ? valsB.reduce((s, v) => s + v, 0) / valsB.length : NaN
|
270 |
+
if (isNaN(avgA) && isNaN(avgB)) return 0
|
271 |
+
if (isNaN(avgA)) return 1
|
272 |
+
if (isNaN(avgB)) return -1
|
273 |
+
return columnSortConfig.direction === 'asc' ? avgA - avgB : avgB - avgA
|
274 |
+
})
|
275 |
+
}
|
276 |
+
// No column sort: return models in default order
|
277 |
+
return models
|
278 |
+
}
|
279 |
+
|
280 |
+
const sortRowsBySubcolumn = (
|
281 |
+
rows: string[],
|
282 |
+
overallMetric: string,
|
283 |
+
model: string,
|
284 |
+
direction: 'asc' | 'desc'
|
285 |
+
) => {
|
286 |
+
return [...rows].sort((a, b) => {
|
287 |
+
const rowA = tableRows.find((r) => r.metric === a)
|
288 |
+
const rowB = tableRows.find((r) => r.metric === b)
|
289 |
+
if (!rowA || !rowB) return 0
|
290 |
+
const valA = Number(rowA[model])
|
291 |
+
const valB = Number(rowB[model])
|
292 |
+
if (isNaN(valA) && isNaN(valB)) return 0
|
293 |
+
if (isNaN(valA)) return 1
|
294 |
+
if (isNaN(valB)) return -1
|
295 |
+
return direction === 'asc' ? valA - valB : valB - valA
|
296 |
+
})
|
297 |
+
}
|
298 |
+
|
299 |
// Find all metrics matching a particular extracted metric name (like "log10_p_value")
|
300 |
const findAllMetricsForName = (metricName: string): string[] => {
|
301 |
return tableRows
|
|
|
363 |
if (!group) return metricNames
|
364 |
|
365 |
// Get all metrics for the specified group
|
366 |
+
const groupMetrics = Object.values(groupRows[group] || {}).flat() as string[]
|
367 |
|
368 |
// If subgroup is specified, further filter to that subgroup
|
369 |
+
if (subgroup && groupRows[group]?.[subgroup]) {
|
370 |
return metricNames.filter(
|
371 |
+
(metric) => groupRows[group][subgroup].includes(metric) && selectedMetrics.has(metric)
|
372 |
)
|
373 |
}
|
374 |
|
|
|
378 |
)
|
379 |
}
|
380 |
|
381 |
+
// Before rendering group rows:
|
382 |
+
const groupSortConfig = getSortConfig()
|
383 |
+
let groupEntries = Object.entries(groupRows).filter(([group]) => group !== 'Overall')
|
384 |
+
if (groupSortConfig) {
|
385 |
+
groupEntries = groupEntries.sort(([groupA, subGroupsA], [groupB, subGroupsB]) => {
|
386 |
+
// For each group, get all metrics in the group for the selected overallMetric
|
387 |
+
const allMetricsWithName = findAllMetricsForName(groupSortConfig.overallMetric)
|
388 |
+
const getGroupAvg = (subGroups: { [key: string]: string[] }) => {
|
389 |
+
const allGroupMetrics = Object.values(subGroups).flat()
|
390 |
+
const metricsInGroupForThisMetric = allGroupMetrics.filter((m) =>
|
391 |
+
allMetricsWithName.includes(m)
|
392 |
+
)
|
393 |
+
const stats = calculateStats(metricsInGroupForThisMetric, groupSortConfig.model)
|
394 |
+
return stats.avg
|
395 |
+
}
|
396 |
+
const avgA = getGroupAvg(subGroupsA)
|
397 |
+
const avgB = getGroupAvg(subGroupsB)
|
398 |
+
if (isNaN(avgA) && isNaN(avgB)) return 0
|
399 |
+
if (isNaN(avgA)) return 1
|
400 |
+
if (isNaN(avgB)) return -1
|
401 |
+
return groupSortConfig.direction === 'asc' ? avgA - avgB : avgB - avgA
|
402 |
+
})
|
403 |
+
}
|
404 |
+
|
405 |
+
// Compute model order for each overall metric before rendering
|
406 |
+
const modelOrderByOverallMetric: { [metric: string]: string[] } = {}
|
407 |
+
overallMetrics
|
408 |
+
.filter((metric) => selectedOverallMetrics.has(metric))
|
409 |
+
.forEach((metric) => {
|
410 |
+
// Check if there is an active row-based column sort for this metric
|
411 |
+
let sortedModels: string[] | null = null
|
412 |
+
// Find the active rowKey for this metric in rowColumnSort
|
413 |
+
const activeRowKey = Object.keys(selectedRowForSort).find((rowKey) => {
|
414 |
+
// rowKey format: group||subGroup||metric
|
415 |
+
const [group, subGroup, rowMetric] = rowKey.split('||')
|
416 |
+
// If rowMetric is empty, it's a group or subgroup row
|
417 |
+
if (rowMetric === '' && metric === metric) return true
|
418 |
+
// If rowMetric matches this metric, it's an individual metric row
|
419 |
+
if (rowMetric && findAllMetricsForName(metric).includes(rowMetric)) return true
|
420 |
+
return false
|
421 |
+
})
|
422 |
+
if (activeRowKey && selectedRowForSort[activeRowKey]) {
|
423 |
+
const direction = selectedRowForSort[activeRowKey].direction
|
424 |
+
const [group, subGroup, rowMetric] = activeRowKey.split('||')
|
425 |
+
const models = tableHeader.filter((model) => selectedModels.has(model))
|
426 |
+
if (!rowMetric) {
|
427 |
+
// Group or subgroup row: sort by average for this group/subgroup and metric
|
428 |
+
// Find all metrics in this group/subgroup for this overall metric
|
429 |
+
let relevantMetrics: string[] = []
|
430 |
+
if (group && !subGroup) {
|
431 |
+
// Group row
|
432 |
+
const groupMetrics = Object.values(groupRows[group] || {}).flat() as string[]
|
433 |
+
relevantMetrics = groupMetrics.filter((m: string) =>
|
434 |
+
findAllMetricsForName(metric).includes(m)
|
435 |
+
)
|
436 |
+
} else if (group && subGroup) {
|
437 |
+
// Subgroup row
|
438 |
+
relevantMetrics = (groupRows[group]?.[subGroup] || []).filter((m: string) =>
|
439 |
+
findAllMetricsForName(metric).includes(m)
|
440 |
+
)
|
441 |
+
}
|
442 |
+
sortedModels = [...models].sort((a, b) => {
|
443 |
+
const statsA = calculateStats(relevantMetrics, a)
|
444 |
+
const statsB = calculateStats(relevantMetrics, b)
|
445 |
+
if (isNaN(statsA.avg) && isNaN(statsB.avg)) return 0
|
446 |
+
if (isNaN(statsA.avg)) return 1
|
447 |
+
if (isNaN(statsB.avg)) return -1
|
448 |
+
return direction === 'asc' ? statsA.avg - statsB.avg : statsB.avg - statsA.avg
|
449 |
+
})
|
450 |
+
} else {
|
451 |
+
// Individual metric row: sort by value for that metric
|
452 |
+
sortedModels = [...models].sort((a, b) => {
|
453 |
+
const rowA = tableRows.find((r) => r.metric === rowMetric)
|
454 |
+
const rowB = rowA // same row
|
455 |
+
const valA = rowA ? Number(rowA[a]) : NaN
|
456 |
+
const valB = rowB ? Number(rowB[b]) : NaN
|
457 |
+
if (isNaN(valA) && isNaN(valB)) return 0
|
458 |
+
if (isNaN(valA)) return 1
|
459 |
+
if (isNaN(valB)) return -1
|
460 |
+
return direction === 'asc' ? valA - valB : valB - valA
|
461 |
+
})
|
462 |
+
}
|
463 |
+
}
|
464 |
+
modelOrderByOverallMetric[metric] =
|
465 |
+
sortedModels ||
|
466 |
+
sortModelColumns(
|
467 |
+
tableHeader.filter((model) => selectedModels.has(model)),
|
468 |
+
metric
|
469 |
+
)
|
470 |
+
})
|
471 |
+
|
472 |
+
console.log({ modelOrderByOverallMetric })
|
473 |
+
|
474 |
return (
|
475 |
+
<div className="rounded">
|
476 |
{error && <div className="text-red-500">{error}</div>}
|
477 |
{!error && (
|
478 |
<div className="flex flex-col gap-8">
|
|
|
482 |
selectedOverallMetrics={selectedOverallMetrics}
|
483 |
setSelectedOverallMetrics={setSelectedOverallMetrics}
|
484 |
/>
|
485 |
+
<LeaderboardFilter
|
486 |
+
groups={groupRows}
|
487 |
selectedMetrics={selectedMetrics}
|
488 |
setSelectedMetrics={setSelectedMetrics}
|
489 |
+
/>
|
490 |
</div>
|
491 |
|
492 |
{selectedModels.size === 0 || selectedMetrics.size === 0 ? (
|
|
|
496 |
) : (
|
497 |
<>
|
498 |
{/* Standalone metrics table */}
|
499 |
+
<IndependentMetricsTable
|
500 |
+
independentMetrics={findStandaloneMetrics()}
|
501 |
+
tableHeader={tableHeader}
|
502 |
+
selectedModels={selectedModels}
|
503 |
+
tableRows={tableRows}
|
504 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
|
506 |
{/* Main metrics table */}
|
507 |
<div className="overflow-x-auto max-h-[80vh] overflow-y-auto">
|
|
|
515 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
516 |
.map((metric) => (
|
517 |
<th
|
518 |
+
key={`header-metric-${metric}`}
|
519 |
+
className="bg-base-100 z-10 text-center text-xs border-gray-700 border"
|
520 |
+
colSpan={modelOrderByOverallMetric[metric].length}
|
|
|
|
|
521 |
>
|
522 |
{metric}
|
523 |
</th>
|
|
|
529 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
530 |
.map((metric) => (
|
531 |
<React.Fragment key={`header-models-${metric}`}>
|
532 |
+
{modelOrderByOverallMetric[metric].map((model) => {
|
533 |
+
const isSorted = sortState[metric]?.[model]?.direction !== undefined
|
534 |
+
const direction = sortState[metric]?.[model]?.direction || 'desc'
|
535 |
+
return (
|
536 |
<th
|
537 |
key={`${metric}-${model}`}
|
538 |
+
className="sticky top-12 bg-base-100 z-10 text-center text-xs border-gray-700 border border-bottom-solid border-b-gray-700 border-b-3 cursor-pointer select-none"
|
539 |
+
onClick={() => handleSort(metric, model)}
|
540 |
>
|
541 |
{model}
|
542 |
+
<span className="ml-1">
|
543 |
+
{isSorted ? (direction === 'asc' ? '↑' : '↓') : '⇅'}
|
544 |
+
</span>
|
545 |
</th>
|
546 |
+
)
|
547 |
+
})}
|
548 |
</React.Fragment>
|
549 |
))}
|
550 |
</tr>
|
551 |
</thead>
|
552 |
<tbody>
|
553 |
+
{/* First render each group row */}
|
554 |
+
{groupEntries.map(([group, subGroups]) => {
|
555 |
// Skip the "Overall" group completely
|
556 |
if (group === 'Overall') return null
|
557 |
|
558 |
+
// Get all metrics for this group row
|
559 |
const allGroupMetrics = Object.values(subGroups).flat()
|
560 |
// Filter to only include selected metrics
|
561 |
const visibleGroupMetrics = filterMetricsByGroupAndSubgroup(
|
|
|
563 |
group
|
564 |
)
|
565 |
|
566 |
+
// Skip this group row if no metrics are selected
|
567 |
if (visibleGroupMetrics.length === 0) return null
|
568 |
|
569 |
+
// Sort subgroups by average if sort config is active
|
570 |
+
let subGroupEntries = Object.entries(subGroups)
|
571 |
+
if (groupSortConfig) {
|
572 |
+
const allMetricsWithName = findAllMetricsForName(
|
573 |
+
groupSortConfig.overallMetric
|
574 |
+
)
|
575 |
+
const getSubGroupAvg = (metrics: string[]) => {
|
576 |
+
const metricsInSubGroupForThisMetric = metrics.filter((m) =>
|
577 |
+
allMetricsWithName.includes(m)
|
578 |
+
)
|
579 |
+
const stats = calculateStats(
|
580 |
+
metricsInSubGroupForThisMetric,
|
581 |
+
groupSortConfig.model
|
582 |
+
)
|
583 |
+
return stats.avg
|
584 |
+
}
|
585 |
+
subGroupEntries = subGroupEntries.sort(([, metricsA], [, metricsB]) => {
|
586 |
+
const avgA = getSubGroupAvg(metricsA)
|
587 |
+
const avgB = getSubGroupAvg(metricsB)
|
588 |
+
if (isNaN(avgA) && isNaN(avgB)) return 0
|
589 |
+
if (isNaN(avgA)) return 1
|
590 |
+
if (isNaN(avgB)) return -1
|
591 |
+
return groupSortConfig.direction === 'asc' ? avgA - avgB : avgB - avgA
|
592 |
+
})
|
593 |
+
}
|
594 |
+
|
595 |
return (
|
596 |
<React.Fragment key={group}>
|
597 |
{/* Group row with average stats for the entire group */}
|
|
|
599 |
className="bg-base-200 cursor-pointer hover:bg-base-300"
|
600 |
onClick={() => toggleGroup(group)}
|
601 |
>
|
602 |
+
<td className="sticky left-0 bg-base-200 z-10 font-medium border-gray-700 border cursor-pointer select-none flex items-center gap-1">
|
603 |
+
<span>{openGroupRows[group] ? '▼ ' : '▶ '}</span>
|
604 |
+
<span className="flex-1">{group}</span>
|
605 |
+
{/* Sort icon: only this triggers sort, and shows default if unsorted */}
|
606 |
+
<span
|
607 |
+
className="ml-1 cursor-pointer"
|
608 |
+
onClick={(e) => {
|
609 |
+
e.stopPropagation()
|
610 |
+
handleColumnSort(group, null, null)
|
611 |
+
}}
|
612 |
+
title={
|
613 |
+
getRowColumnSort(group, null, null)
|
614 |
+
? getRowColumnSort(group, null, null)?.direction === 'asc'
|
615 |
+
? 'Sort descending'
|
616 |
+
: 'Clear sort'
|
617 |
+
: 'Sort by this row'
|
618 |
+
}
|
619 |
+
>
|
620 |
+
{getRowColumnSort(group, null, null)
|
621 |
+
? getRowColumnSort(group, null, null)?.direction === 'asc'
|
622 |
+
? '↑'
|
623 |
+
: '↓'
|
624 |
+
: '⇅'}
|
625 |
+
</span>
|
626 |
</td>
|
627 |
{/* For each metric column */}
|
628 |
{overallMetrics
|
629 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
630 |
+
.map((metric) => {
|
631 |
+
const rowKey = getRowSortKey(group, null, null)
|
632 |
+
return (
|
633 |
+
<React.Fragment key={`${group}-${metric}`}>
|
634 |
+
{modelOrderByOverallMetric[metric].map((col: string) => {
|
|
|
|
|
635 |
const allMetricsWithName = findAllMetricsForName(metric)
|
636 |
const metricsInGroupForThisMetric =
|
637 |
visibleGroupMetrics.filter((m) =>
|
638 |
allMetricsWithName.includes(m)
|
639 |
)
|
640 |
const stats = calculateStats(metricsInGroupForThisMetric, col)
|
|
|
641 |
return (
|
642 |
<td
|
643 |
key={`${group}-${metric}-${col}`}
|
|
|
649 |
</td>
|
650 |
)
|
651 |
})}
|
652 |
+
</React.Fragment>
|
653 |
+
)
|
654 |
+
})}
|
655 |
</tr>
|
656 |
|
657 |
+
{/* Only render subgroups if group row is open */}
|
658 |
+
{openGroupRows[group] &&
|
659 |
+
subGroupEntries.map(([subGroup, metrics]) => {
|
660 |
+
// Filter to only include selected metrics in this subgroup row
|
661 |
const visibleSubgroupMetrics = filterMetricsByGroupAndSubgroup(
|
662 |
metrics,
|
663 |
group,
|
664 |
subGroup
|
665 |
)
|
666 |
|
667 |
+
// Skip this subgroup row if no metrics are selected
|
668 |
if (visibleSubgroupMetrics.length === 0) return null
|
669 |
|
670 |
return (
|
|
|
674 |
className="bg-base-100 cursor-pointer hover:bg-base-200"
|
675 |
onClick={() => toggleSubGroup(group, subGroup)}
|
676 |
>
|
677 |
+
<td className="sticky left-0 bg-base-100 z-10 pl-6 font-medium border-gray-700 border cursor-pointer select-none flex items-center gap-1">
|
678 |
+
<span>
|
679 |
+
{openSubGroupRows[group]?.[subGroup] ? '▼ ' : '▶ '}
|
680 |
+
</span>
|
681 |
+
<span className="flex-1">{subGroup}</span>
|
682 |
+
<span
|
683 |
+
className="ml-1 cursor-pointer"
|
684 |
+
onClick={(e) => {
|
685 |
+
e.stopPropagation()
|
686 |
+
handleColumnSort(group, subGroup, null)
|
687 |
+
}}
|
688 |
+
title={
|
689 |
+
getRowColumnSort(group, subGroup, null)
|
690 |
+
? getRowColumnSort(group, subGroup, null)?.direction ===
|
691 |
+
'asc'
|
692 |
+
? 'Sort descending'
|
693 |
+
: 'Clear sort'
|
694 |
+
: 'Sort by this row'
|
695 |
+
}
|
696 |
+
>
|
697 |
+
{getRowColumnSort(group, subGroup, null)
|
698 |
+
? getRowColumnSort(group, subGroup, null)?.direction ===
|
699 |
+
'asc'
|
700 |
+
? '↑'
|
701 |
+
: '↓'
|
702 |
+
: '⇅'}
|
703 |
+
</span>
|
704 |
</td>
|
705 |
{/* For each metric column */}
|
706 |
{overallMetrics
|
707 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
708 |
+
.map((metric) => {
|
709 |
+
const rowKey = getRowSortKey(group, subGroup, null)
|
710 |
+
return (
|
711 |
+
<React.Fragment key={`${group}-${subGroup}-${metric}`}>
|
712 |
+
{modelOrderByOverallMetric[metric].map(
|
713 |
+
(col: string) => {
|
714 |
+
const allMetricsWithName =
|
715 |
+
findAllMetricsForName(metric)
|
716 |
+
const metricsInSubgroupForThisMetric =
|
717 |
+
visibleSubgroupMetrics.filter((m) =>
|
718 |
+
allMetricsWithName.includes(m)
|
719 |
+
)
|
720 |
+
const stats = calculateStats(
|
721 |
+
metricsInSubgroupForThisMetric,
|
722 |
+
col
|
723 |
)
|
724 |
+
return (
|
725 |
+
<td
|
726 |
+
key={`${group}-${subGroup}-${metric}-${col}`}
|
727 |
+
className="font-medium text-center border-gray-700 border"
|
728 |
+
>
|
729 |
+
{!isNaN(stats.avg)
|
730 |
+
? `${stats.avg.toFixed(3)} ± ${stats.stdDev.toFixed(3)}`
|
731 |
+
: 'N/A'}
|
732 |
+
</td>
|
733 |
+
)
|
734 |
+
}
|
735 |
+
)}
|
736 |
+
</React.Fragment>
|
737 |
+
)
|
738 |
+
})}
|
|
|
|
|
|
|
739 |
</tr>
|
740 |
|
741 |
{/* Individual metric rows */}
|
742 |
+
{openSubGroupRows[group]?.[subGroup] &&
|
743 |
+
(() => {
|
744 |
+
// Sorting logic for individual metric rows
|
745 |
+
const sortConfig = getSortConfig()
|
746 |
+
let sortedMetrics = [...visibleSubgroupMetrics]
|
747 |
+
console.log(
|
748 |
+
'Sorting metrics for subgroup:',
|
749 |
+
group,
|
750 |
+
subGroup,
|
751 |
+
'with config:',
|
752 |
+
sortConfig
|
753 |
+
)
|
754 |
+
if (sortConfig) {
|
755 |
+
// Only sort metrics that match the selected overallMetric and model
|
756 |
+
const allMetricsWithName = findAllMetricsForName(
|
757 |
+
sortConfig.overallMetric
|
758 |
+
)
|
759 |
+
const metricsInSubgroupForThisMetric = sortedMetrics.filter(
|
760 |
+
(m) => allMetricsWithName.includes(m)
|
761 |
+
)
|
762 |
+
const metricsNotInSubgroupForThisMetric =
|
763 |
+
sortedMetrics.filter(
|
764 |
+
(m) => !allMetricsWithName.includes(m)
|
765 |
+
)
|
766 |
+
// Only apply subcolumn sort to matching metrics, leave others in original order
|
767 |
+
sortedMetrics = [
|
768 |
+
...sortRowsBySubcolumn(
|
769 |
+
metricsInSubgroupForThisMetric,
|
770 |
+
sortConfig.overallMetric,
|
771 |
+
sortConfig.model,
|
772 |
+
sortConfig.direction
|
773 |
+
),
|
774 |
+
...metricsNotInSubgroupForThisMetric,
|
775 |
+
]
|
776 |
+
} else {
|
777 |
+
// Fallback sort logic (category, overall, strength)
|
778 |
+
sortedMetrics = sortedMetrics.sort((a, b) => {
|
779 |
+
// For metrics with format {category}_{strength}_{overall_metric_name},
|
780 |
+
// First sort by category, then by overall_metric_name, then by strength
|
781 |
+
|
782 |
+
// First extract the overall metric group
|
783 |
+
const getOverallMetricGroup = (metric: string) => {
|
784 |
+
for (const overall of overallMetrics) {
|
785 |
+
if (
|
786 |
+
metric.endsWith(`_${overall}`) ||
|
787 |
+
metric === overall
|
788 |
+
) {
|
789 |
+
return overall
|
790 |
+
}
|
791 |
}
|
792 |
+
return ''
|
793 |
}
|
|
|
|
|
794 |
|
795 |
+
const overallA = getOverallMetricGroup(a)
|
796 |
+
const overallB = getOverallMetricGroup(b)
|
797 |
+
|
798 |
+
// Extract the strength (last part before the overall metric)
|
799 |
+
const stripOverall = (
|
800 |
+
metric: string,
|
801 |
+
overall: string
|
802 |
+
) => {
|
803 |
+
if (metric.endsWith(`_${overall}`)) {
|
804 |
+
// Remove the overall metric group and any preceding underscore
|
805 |
+
const stripped = metric.slice(
|
806 |
+
0,
|
807 |
+
metric.length - overall.length - 1
|
808 |
+
)
|
809 |
+
const parts = stripped.split('_')
|
810 |
+
return parts.length > 0 ? parts[parts.length - 1] : ''
|
811 |
+
}
|
812 |
+
return metric
|
813 |
}
|
|
|
|
|
814 |
|
815 |
+
// Extract the category (what remains after removing strength and overall_metric_name)
|
816 |
+
const getCategory = (metric: string, overall: string) => {
|
817 |
+
if (metric.endsWith(`_${overall}`)) {
|
818 |
+
const stripped = metric.slice(
|
819 |
+
0,
|
820 |
+
metric.length - overall.length - 1
|
821 |
+
)
|
822 |
+
const parts = stripped.split('_')
|
823 |
+
// Remove the last part (strength) and join the rest (category)
|
824 |
+
return parts.length > 1
|
825 |
+
? parts.slice(0, parts.length - 1).join('_')
|
826 |
+
: ''
|
827 |
+
}
|
828 |
+
return metric
|
829 |
}
|
|
|
|
|
830 |
|
831 |
+
const categoryA = getCategory(a, overallA)
|
832 |
+
const categoryB = getCategory(b, overallB)
|
833 |
|
834 |
+
// First sort by category
|
835 |
+
if (categoryA !== categoryB) {
|
836 |
+
return categoryA.localeCompare(categoryB)
|
837 |
+
}
|
838 |
|
839 |
+
// Then sort by overall metric name
|
840 |
+
if (overallA !== overallB) {
|
841 |
+
return overallA.localeCompare(overallB)
|
842 |
+
}
|
843 |
|
844 |
+
// Finally sort by strength
|
845 |
+
const subA = stripOverall(a, overallA)
|
846 |
+
const subB = stripOverall(b, overallB)
|
847 |
+
|
848 |
+
// Try to parse subA and subB as numbers, handling k/m/b suffixes
|
849 |
+
const parseNumber = (str: string) => {
|
850 |
+
const match = str.match(/^\d+(?:\.\d+)?([kKmMbB]?)$/)
|
851 |
+
if (!match) return NaN
|
852 |
+
let [_, suffix] = match
|
853 |
+
let value = parseFloat(str)
|
854 |
+
switch (suffix?.toLowerCase()) {
|
855 |
+
case 'k':
|
856 |
+
value *= 1e3
|
857 |
+
break
|
858 |
+
case 'm':
|
859 |
+
value *= 1e6
|
860 |
+
break
|
861 |
+
case 'b':
|
862 |
+
value *= 1e9
|
863 |
+
break
|
864 |
+
}
|
865 |
+
return value
|
866 |
}
|
|
|
|
|
867 |
|
868 |
+
const numA = parseNumber(subA)
|
869 |
+
const numB = parseNumber(subB)
|
870 |
|
871 |
+
if (!isNaN(numA) && !isNaN(numB)) {
|
872 |
+
return numA - numB
|
873 |
+
}
|
874 |
+
// Fallback to string comparison if not both numbers
|
875 |
+
return subA.localeCompare(subB)
|
876 |
+
})
|
877 |
+
}
|
878 |
+
return sortedMetrics.map((metric) => {
|
879 |
const row = tableRows.find((r) => r.metric === metric)
|
880 |
if (!row) return null
|
881 |
|
|
|
886 |
|
887 |
return (
|
888 |
<tr key={metric} className="hover:bg-base-100">
|
889 |
+
<td className="sticky left-0 bg-base-100 z-10 pl-10 border-gray-700 border cursor-pointer select-none flex items-center gap-1">
|
890 |
+
<span className="flex-1">{metric}</span>
|
891 |
+
<span
|
892 |
+
className="ml-1 cursor-pointer"
|
893 |
+
onClick={(e) => {
|
894 |
+
e.stopPropagation()
|
895 |
+
handleColumnSort(group, subGroup, metric)
|
896 |
+
}}
|
897 |
+
title={
|
898 |
+
getRowColumnSort(group, subGroup, metric)
|
899 |
+
? getRowColumnSort(group, subGroup, metric)
|
900 |
+
?.direction === 'asc'
|
901 |
+
? 'Sort descending'
|
902 |
+
: 'Clear sort'
|
903 |
+
: 'Sort by this row'
|
904 |
+
}
|
905 |
+
>
|
906 |
+
{getRowColumnSort(group, subGroup, metric)
|
907 |
+
? getRowColumnSort(group, subGroup, metric)
|
908 |
+
?.direction === 'asc'
|
909 |
+
? '▲'
|
910 |
+
: '▼'
|
911 |
+
: '⇅'}
|
912 |
+
</span>
|
913 |
</td>
|
|
|
914 |
{overallMetrics
|
915 |
.filter((oMetric) =>
|
916 |
selectedOverallMetrics.has(oMetric)
|
917 |
)
|
918 |
.map((oMetric) => {
|
|
|
919 |
const isMatchingMetric =
|
920 |
findAllMetricsForName(oMetric).includes(metric)
|
|
|
921 |
if (!isMatchingMetric) {
|
|
|
922 |
return (
|
923 |
<React.Fragment key={`${metric}-${oMetric}`}>
|
924 |
+
{modelOrderByOverallMetric[oMetric].map(
|
925 |
+
(col) => (
|
|
|
|
|
|
|
926 |
<td
|
927 |
key={`${metric}-${oMetric}-${col}`}
|
928 |
className="text-center border-gray-700 border"
|
929 |
></td>
|
930 |
+
)
|
931 |
+
)}
|
932 |
</React.Fragment>
|
933 |
)
|
934 |
}
|
935 |
return (
|
936 |
<React.Fragment key={`${metric}-${oMetric}`}>
|
937 |
+
{modelOrderByOverallMetric[oMetric].map(
|
938 |
+
(col) => {
|
|
|
939 |
const cell = row[col]
|
940 |
return (
|
941 |
<td
|
|
|
947 |
: cell}
|
948 |
</td>
|
949 |
)
|
950 |
+
}
|
951 |
+
)}
|
952 |
</React.Fragment>
|
953 |
)
|
954 |
})}
|
955 |
</tr>
|
956 |
)
|
957 |
+
})
|
958 |
+
})()}
|
959 |
</React.Fragment>
|
960 |
)
|
961 |
})}
|
frontend/src/components/ModelFilter.tsx
CHANGED
@@ -18,8 +18,8 @@ const ModelFilter: React.FC<ModelFilterProps> = ({ models, selectedModels, setSe
|
|
18 |
}
|
19 |
|
20 |
return (
|
21 |
-
<div className="w-full
|
22 |
-
<fieldset className="fieldset w-full p-4 rounded border border-gray-700">
|
23 |
<legend className="fieldset-legend font-semibold">
|
24 |
Models ({selectedModels.size}/{models.length})
|
25 |
</legend>
|
|
|
18 |
}
|
19 |
|
20 |
return (
|
21 |
+
<div className="w-full">
|
22 |
+
<fieldset className="fieldset w-full p-4 rounded border border-gray-700 bg-base-200">
|
23 |
<legend className="fieldset-legend font-semibold">
|
24 |
Models ({selectedModels.size}/{models.length})
|
25 |
</legend>
|