Spaces:
Running
Running
Mark Duppenthaler
commited on
Commit
Β·
44072a9
1
Parent(s):
9bf569f
Add description tooltips
Browse files- backend/descriptions.py +28 -29
- backend/examples.py +4 -4
- frontend/dist/assets/{index-cPMuOGs4.js β index-DC3IGjBs.js} +0 -0
- frontend/dist/assets/index-KQYUM4NH.css +0 -1
- frontend/dist/assets/index-stFRue7K.css +1 -0
- frontend/dist/index.html +2 -2
- frontend/package-lock.json +80 -0
- frontend/package.json +3 -1
- frontend/src/components/AudioGallery.tsx +15 -0
- frontend/src/components/ExampleVariantMetricsTable.tsx +7 -3
- frontend/src/components/ExampleVariantSelector.tsx +5 -1
- frontend/src/components/Examples.tsx +37 -16
- frontend/src/components/ImageGallery.tsx +15 -1
- frontend/src/components/LeaderboardTable.tsx +711 -532
- frontend/src/components/LeaderboardTabs.tsx +0 -0
- frontend/src/components/MetricInfoIcon.tsx +69 -0
- frontend/src/components/ModelFilter.tsx +35 -15
- frontend/src/components/ModelInfoIcon.tsx +88 -0
- frontend/src/components/QualityMetricsTable.tsx +12 -8
- frontend/src/components/icons/GitHubIcon.tsx +20 -0
- frontend/src/components/icons/github.json +4 -0
- frontend/src/main.tsx +1 -0
backend/descriptions.py
CHANGED
@@ -52,24 +52,24 @@ DESCRIPTIONS = {
|
|
52 |
"bit_acc": {
|
53 |
"full_name": "Bit Accuracy",
|
54 |
"description": "The percentage of bits correctly decoded from a watermark. Values range from 0 to 1, with 1 indicating perfect extraction of the watermark message.",
|
55 |
-
"link": "",
|
56 |
},
|
57 |
"word_acc": {
|
58 |
"full_name": "Word Accuracy",
|
59 |
"description": "A binary metric indicating whether the entire watermark message was correctly decoded (True) or not (False).",
|
60 |
-
"link": "",
|
61 |
},
|
62 |
"log10_p_value": {
|
63 |
"full_name": "Log10 P-Value",
|
64 |
"description": "The logarithm (base 10) of the probability that a decoded watermark could have occurred by chance. More negative values indicate stronger confidence that a real watermark was detected. This metric provides a better comparison that bit accuracy because it fairly compares different message sizes.",
|
65 |
-
"link": "",
|
66 |
},
|
67 |
-
"
|
68 |
"full_name": "True Positive Rate",
|
69 |
"description": "The proportion of watermarked media correctly identified as containing a watermark. Also known as sensitivity or recall. Values range from 0 to 1, with higher values indicating better detection performance.",
|
70 |
"link": "https://en.wikipedia.org/wiki/Sensitivity_and_specificity",
|
71 |
},
|
72 |
-
"
|
73 |
"full_name": "False Positive Rate",
|
74 |
"description": "The proportion of unwatermarked media incorrectly identified as containing a watermark. Values range from 0 to 1, with lower values indicating better detection performance.",
|
75 |
"link": "https://en.wikipedia.org/wiki/False_positive_rate",
|
@@ -88,11 +88,11 @@ MODEL_DESCRIPTIONS = {
|
|
88 |
"paper_link": "https://arxiv.org/abs/2401.17264",
|
89 |
"github_link": "https://github.com/facebookresearch/audioseal",
|
90 |
},
|
91 |
-
"
|
92 |
"full_name": "WavMark",
|
93 |
"description": "WavMark uses invertible networks to hide 32 bits in 1-second audio segments. Detection is performed by sliding along the audio in 0.05-second steps and decoding the message for each window. If the first 10 decoded bits match a synchronization pattern, the rest of the payload is saved (22 bits), and the window can directly slide 1 second (instead of 0.05 seconds).",
|
94 |
-
"paper_link": "https://arxiv.org/
|
95 |
-
"github_link": "https://github.com/
|
96 |
},
|
97 |
"timbre": {
|
98 |
"full_name": "Timbre",
|
@@ -107,8 +107,8 @@ MODEL_DESCRIPTIONS = {
|
|
107 |
"github_link": "https://github.com/facebookresearch/watermark-anything",
|
108 |
},
|
109 |
"trustmark": {
|
110 |
-
"full_name": "TrustMark",
|
111 |
-
"description": "TrustMark
|
112 |
"paper_link": "https://arxiv.org/abs/2311.18297",
|
113 |
"github_link": "https://github.com/adobe/trustmark",
|
114 |
},
|
@@ -128,37 +128,36 @@ MODEL_DESCRIPTIONS = {
|
|
128 |
"full_name": "Hiding Data With Deep Networks",
|
129 |
"description": "First deep watermarking approach from 2018. We use the model trained and open-sourced here, which uses the same architecture and a similar training procedure. Note that this implementation uses a Just Noticeable Difference heatmap to modulate the watermark distortion for less visibility instead of using a perceptual loss during training like in the original paper.",
|
130 |
"paper_link": "https://arxiv.org/abs/1807.09937",
|
131 |
-
|
132 |
},
|
133 |
-
"
|
134 |
"full_name": "Combined DCT-DWT",
|
135 |
"description": "The algorithm watermarks a given image using a combination of the Discrete Wavelet Transform (DWT) and the Discrete Cosine Transform (DCT). Performance evaluation results show that combining the two transforms improved the performance of the watermarking algorithms that are based solely on the DWT transform.",
|
136 |
"paper_link": "https://pdfs.semanticscholar.org/1c47/f281c00cffad4e30deff48a922553cb04d17.pdf",
|
137 |
-
|
138 |
-
},
|
139 |
-
|
140 |
-
|
141 |
-
"
|
142 |
-
"
|
143 |
-
"
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
"
|
148 |
-
"
|
149 |
-
"paper_link": "https://arxiv.org/abs/2204.12677",
|
150 |
"github_link": "https://github.com/jzyustc/mbrs",
|
151 |
},
|
152 |
"videoseal": {
|
153 |
"full_name": "VideoSeal",
|
154 |
"description": "A neural video watermarking system designed to embed imperceptible watermarks that are robust against common video manipulations and processing operations.",
|
155 |
-
"paper_link": "https://arxiv.org/abs/
|
156 |
-
"github_link": "https://github.com/facebookresearch/
|
157 |
},
|
158 |
"rivagan": {
|
159 |
"full_name": "RivaGAN",
|
160 |
"description": "A GAN-based approach for robust invisible video watermarking that maintains high visual quality while providing resistance against common video attacks and transformations.",
|
161 |
-
"paper_link": "https://arxiv.org/abs/
|
162 |
-
"github_link": "https://github.com/
|
163 |
},
|
164 |
}
|
|
|
52 |
"bit_acc": {
|
53 |
"full_name": "Bit Accuracy",
|
54 |
"description": "The percentage of bits correctly decoded from a watermark. Values range from 0 to 1, with 1 indicating perfect extraction of the watermark message.",
|
55 |
+
"link": "https://en.wikipedia.org/wiki/Bit_error_rate",
|
56 |
},
|
57 |
"word_acc": {
|
58 |
"full_name": "Word Accuracy",
|
59 |
"description": "A binary metric indicating whether the entire watermark message was correctly decoded (True) or not (False).",
|
60 |
+
"link": "https://en.wikipedia.org/wiki/Word_error_rate",
|
61 |
},
|
62 |
"log10_p_value": {
|
63 |
"full_name": "Log10 P-Value",
|
64 |
"description": "The logarithm (base 10) of the probability that a decoded watermark could have occurred by chance. More negative values indicate stronger confidence that a real watermark was detected. This metric provides a better comparison that bit accuracy because it fairly compares different message sizes.",
|
65 |
+
"link": "https://en.wikipedia.org/wiki/P-value",
|
66 |
},
|
67 |
+
"TPR": {
|
68 |
"full_name": "True Positive Rate",
|
69 |
"description": "The proportion of watermarked media correctly identified as containing a watermark. Also known as sensitivity or recall. Values range from 0 to 1, with higher values indicating better detection performance.",
|
70 |
"link": "https://en.wikipedia.org/wiki/Sensitivity_and_specificity",
|
71 |
},
|
72 |
+
"FPR": {
|
73 |
"full_name": "False Positive Rate",
|
74 |
"description": "The proportion of unwatermarked media incorrectly identified as containing a watermark. Values range from 0 to 1, with lower values indicating better detection performance.",
|
75 |
"link": "https://en.wikipedia.org/wiki/False_positive_rate",
|
|
|
88 |
"paper_link": "https://arxiv.org/abs/2401.17264",
|
89 |
"github_link": "https://github.com/facebookresearch/audioseal",
|
90 |
},
|
91 |
+
"wavmark_fast": {
|
92 |
"full_name": "WavMark",
|
93 |
"description": "WavMark uses invertible networks to hide 32 bits in 1-second audio segments. Detection is performed by sliding along the audio in 0.05-second steps and decoding the message for each window. If the first 10 decoded bits match a synchronization pattern, the rest of the payload is saved (22 bits), and the window can directly slide 1 second (instead of 0.05 seconds).",
|
94 |
+
"paper_link": "https://arxiv.org/pdf/2308.12770",
|
95 |
+
"github_link": "https://github.com/wavmark/wavmark",
|
96 |
},
|
97 |
"timbre": {
|
98 |
"full_name": "Timbre",
|
|
|
107 |
"github_link": "https://github.com/facebookresearch/watermark-anything",
|
108 |
},
|
109 |
"trustmark": {
|
110 |
+
"full_name": "TrustMark - Universal Watermarking for Arbitrary Resolution Images",
|
111 |
+
"description": "TrustMark - a GAN-based watermarking method with novel design in architecture and spatio-spectra losses to balance the trade-off between watermarked image quality with the watermark recovery accuracy.",
|
112 |
"paper_link": "https://arxiv.org/abs/2311.18297",
|
113 |
"github_link": "https://github.com/adobe/trustmark",
|
114 |
},
|
|
|
128 |
"full_name": "Hiding Data With Deep Networks",
|
129 |
"description": "First deep watermarking approach from 2018. We use the model trained and open-sourced here, which uses the same architecture and a similar training procedure. Note that this implementation uses a Just Noticeable Difference heatmap to modulate the watermark distortion for less visibility instead of using a perceptual loss during training like in the original paper.",
|
130 |
"paper_link": "https://arxiv.org/abs/1807.09937",
|
131 |
+
"github_link": "https://github.com/ando-khachatryan/HiDDeN",
|
132 |
},
|
133 |
+
"dctdwt": {
|
134 |
"full_name": "Combined DCT-DWT",
|
135 |
"description": "The algorithm watermarks a given image using a combination of the Discrete Wavelet Transform (DWT) and the Discrete Cosine Transform (DCT). Performance evaluation results show that combining the two transforms improved the performance of the watermarking algorithms that are based solely on the DWT transform.",
|
136 |
"paper_link": "https://pdfs.semanticscholar.org/1c47/f281c00cffad4e30deff48a922553cb04d17.pdf",
|
137 |
+
"github_link": "https://github.com/ShieldMnt/invisible-watermark",
|
138 |
+
},
|
139 |
+
"cine_jit": {
|
140 |
+
"full_name": "CINE: Towards Blind Watermarking: Combining Invertible and Non-invertible Mechanisms",
|
141 |
+
"description": "It remains a challenge to design a watermarking model with high imperceptibility and robustness against strong noise attacks. To resolve this issue, we present a framework Combining the Invertible and Non-invertible (CIN) mechanisms. The CIN is composed of the invertible part to achieve high imperceptibility and the non-invertible part to strengthen the robustness against strong noise attacks.",
|
142 |
+
"paper_link": "https://arxiv.org/abs/2212.12678",
|
143 |
+
"github_link": "https://github.com/rmpku/CIN",
|
144 |
+
},
|
145 |
+
"mbrs_jit": {
|
146 |
+
"full_name": "MBRS: Mini-Batch of Real and Simulated JPEG Compression",
|
147 |
+
"description": "An end-to-end auto-encoder watermarking framework that, during training, randomly applies one of three noise layers per mini-batch: a real JPEG compressor (with variable quality factors), a differentiable simulated JPEG layer, or a noise-free identity layer. To boost performance it incorporates Squeeze-and-Excitation blocks for richer feature learning, a message processor to expand the payload more effectively, and an additive diffusion block to guard against crop attacks. Under JPEG compression at Q=50, MBRS achieves a bit error rate <0.01% and PSNR >36 dB, while also demonstrating strong robustness to Gaussian filtering, cropping, crop-out, and dropout distortions.",
|
148 |
+
"paper_link": "https://arxiv.org/pdf/2108.08211",
|
|
|
149 |
"github_link": "https://github.com/jzyustc/mbrs",
|
150 |
},
|
151 |
"videoseal": {
|
152 |
"full_name": "VideoSeal",
|
153 |
"description": "A neural video watermarking system designed to embed imperceptible watermarks that are robust against common video manipulations and processing operations.",
|
154 |
+
"paper_link": "https://arxiv.org/abs/2412.09492",
|
155 |
+
"github_link": "https://github.com/facebookresearch/videoseal",
|
156 |
},
|
157 |
"rivagan": {
|
158 |
"full_name": "RivaGAN",
|
159 |
"description": "A GAN-based approach for robust invisible video watermarking that maintains high visual quality while providing resistance against common video attacks and transformations.",
|
160 |
+
"paper_link": "https://arxiv.org/abs/1909.01285",
|
161 |
+
"github_link": "https://github.com/DAI-Lab/RivaGAN",
|
162 |
},
|
163 |
}
|
backend/examples.py
CHANGED
@@ -55,7 +55,7 @@ def build_description(
|
|
55 |
elif i == 1:
|
56 |
# Fixed metrics
|
57 |
det = data_none["watermark_det"]
|
58 |
-
|
59 |
word_acc = data_attack["word_acc"]
|
60 |
bit_acc = data_none["bit_acc"]
|
61 |
|
@@ -69,7 +69,7 @@ def build_description(
|
|
69 |
metrics_output.update(
|
70 |
{
|
71 |
"detected": det,
|
72 |
-
"
|
73 |
"bit_acc": round(bit_acc, 3),
|
74 |
"word_acc": word_acc,
|
75 |
}
|
@@ -81,13 +81,13 @@ def build_description(
|
|
81 |
return {"detected": fake_det}
|
82 |
elif i == 3: # REVISIT THIS, it used to be == 3
|
83 |
det = data_attack["watermark_det"]
|
84 |
-
|
85 |
word_acc = data_attack["word_acc"]
|
86 |
bit_acc = data_attack["bit_acc"]
|
87 |
|
88 |
return {
|
89 |
"detected": det,
|
90 |
-
"
|
91 |
"bit_acc": round(bit_acc, 3),
|
92 |
"word_acc": word_acc,
|
93 |
}
|
|
|
55 |
elif i == 1:
|
56 |
# Fixed metrics
|
57 |
det = data_none["watermark_det"]
|
58 |
+
log10_p_value = float(data_none["log10_p_value"])
|
59 |
word_acc = data_attack["word_acc"]
|
60 |
bit_acc = data_none["bit_acc"]
|
61 |
|
|
|
69 |
metrics_output.update(
|
70 |
{
|
71 |
"detected": det,
|
72 |
+
"log10_p_value": round(log10_p_value, 3),
|
73 |
"bit_acc": round(bit_acc, 3),
|
74 |
"word_acc": word_acc,
|
75 |
}
|
|
|
81 |
return {"detected": fake_det}
|
82 |
elif i == 3: # REVISIT THIS, it used to be == 3
|
83 |
det = data_attack["watermark_det"]
|
84 |
+
log10_p_value = float(data_attack["log10_p_value"])
|
85 |
word_acc = data_attack["word_acc"]
|
86 |
bit_acc = data_attack["bit_acc"]
|
87 |
|
88 |
return {
|
89 |
"detected": det,
|
90 |
+
"log10_p_value": round(log10_p_value, 3),
|
91 |
"bit_acc": round(bit_acc, 3),
|
92 |
"word_acc": word_acc,
|
93 |
}
|
frontend/dist/assets/{index-cPMuOGs4.js β index-DC3IGjBs.js}
RENAMED
The diff for this file is too large to render.
See raw diff
|
|
frontend/dist/assets/index-KQYUM4NH.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-border-spacing-x:0;--tw-border-spacing-y:0;--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-leading:initial;--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-outline-style:solid;--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-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-700:oklch(37.3% .034 259.733);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--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}.menu{--menu-active-fg:var(--color-neutral-content);--menu-active-bg:var(--color-neutral);flex-flow:column wrap;width:fit-content;padding:.5rem;font-size:.875rem;display:flex}.menu :where(li ul){white-space:nowrap;margin-inline-start:1rem;padding-inline-start:.5rem;position:relative}.menu :where(li ul):before{background-color:var(--color-base-content);opacity:.1;width:var(--border);content:"";inset-inline-start:0;position:absolute;top:.75rem;bottom:.75rem}.menu :where(li>.menu-dropdown:not(.menu-dropdown-show)){display:none}.menu :where(li:not(.menu-title)>:not(ul,details,.menu-title,.btn)),.menu :where(li:not(.menu-title)>details>summary:not(.menu-title)){border-radius:var(--radius-field);text-align:start;text-wrap:balance;-webkit-user-select:none;user-select:none;grid-auto-columns:minmax(auto,max-content) auto max-content;grid-auto-flow:column;align-content:flex-start;align-items:center;gap:.5rem;padding-block:.375rem;padding-inline:.75rem;transition-property:color,background-color,box-shadow;transition-duration:.2s;transition-timing-function:cubic-bezier(0,0,.2,1);display:grid}.menu :where(li>details>summary){--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li>details>summary){outline-offset:2px;outline:2px solid #0000}}.menu :where(li>details>summary)::-webkit-details-marker{display:none}:is(.menu :where(li>details>summary),.menu :where(li>.menu-dropdown-toggle)):after{content:"";transform-origin:50%;pointer-events:none;justify-self:flex-end;width:.375rem;height:.375rem;transition-property:rotate,translate;transition-duration:.2s;display:block;translate:0 -1px;rotate:-135deg;box-shadow:inset 2px 2px}.menu :where(li>details[open]>summary):after,.menu :where(li>.menu-dropdown-toggle.menu-dropdown-show):after{translate:0 1px;rotate:45deg}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{cursor:pointer;background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{color:var(--color-base-content);--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{outline-offset:2px;outline:2px solid #0000}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){cursor:pointer;background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){outline-offset:2px;outline:2px solid #0000}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){box-shadow:inset 0 1px #00000003,inset 0 -1px #ffffff03}.menu :where(li:empty){background-color:var(--color-base-content);opacity:.1;height:1px;margin:.5rem 1rem}.menu :where(li){flex-flow:column wrap;flex-shrink:0;align-items:stretch;display:flex;position:relative}.menu :where(li) .badge{justify-self:flex-end}.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{outline-offset:2px;outline:2px solid #0000}}.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{color:var(--menu-active-fg);background-color:var(--menu-active-bg);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise)}:is(.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active):not(:is(.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active):active){box-shadow:0 2px calc(var(--depth)*3px) -2px var(--menu-active-bg)}.menu :where(li).menu-disabled{pointer-events:none;color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li).menu-disabled{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.menu .dropdown:focus-within .menu-dropdown-toggle:after{translate:0 1px;rotate:45deg}.menu .dropdown-content{margin-top:.5rem;padding:.5rem}.menu .dropdown-content:before{display:none}.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}:where(.btn){width:unset}.btn{cursor:pointer;text-align:center;vertical-align:middle;outline-offset:2px;webkit-user-select:none;-webkit-user-select:none;user-select:none;padding-inline:var(--btn-p);color:var(--btn-fg);--tw-prose-links:var(--btn-fg);height:var(--size);font-size:var(--fontsize,.875rem);outline-color:var(--btn-color,var(--color-base-content));background-color:var(--btn-bg);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--btn-noise);border-width:var(--border);border-style:solid;border-color:var(--btn-border);text-shadow:0 .5px oklch(100% 0 0/calc(var(--depth)*.15));touch-action:manipulation;box-shadow:0 .5px 0 .5px oklch(100% 0 0/calc(var(--depth)*6%)) inset,var(--btn-shadow);--size:calc(var(--size-field,.25rem)*10);--btn-bg:var(--btn-color,var(--color-base-200));--btn-fg:var(--color-base-content);--btn-p:1rem;--btn-border:var(--btn-bg);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-wrap:nowrap;flex-shrink:0;justify-content:center;align-items:center;gap:.375rem;font-weight:600;transition-property:color,background-color,border-color,box-shadow;transition-duration:.2s;transition-timing-function:cubic-bezier(0,0,.2,1);display:inline-flex}@supports (color:color-mix(in lab,red,red)){.btn{--btn-border:color-mix(in oklab,var(--btn-bg),#000 calc(var(--depth)*5%))}}.btn{--btn-shadow:0 3px 2px -2px var(--btn-bg),0 4px 3px -2px var(--btn-bg)}@supports (color:color-mix(in lab,red,red)){.btn{--btn-shadow:0 3px 2px -2px color-mix(in oklab,var(--btn-bg)calc(var(--depth)*30%),#0000),0 4px 3px -2px color-mix(in oklab,var(--btn-bg)calc(var(--depth)*30%),#0000)}}.btn{--btn-noise:var(--fx-noise)}.prose .btn{text-decoration-line:none}@media (hover:hover){.btn:hover{--btn-bg:var(--btn-color,var(--color-base-200))}@supports (color:color-mix(in lab,red,red)){.btn:hover{--btn-bg:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 7%)}}}.btn:focus-visible{isolation:isolate;outline-width:2px;outline-style:solid}.btn:active:not(.btn-active){--btn-bg:var(--btn-color,var(--color-base-200));translate:0 .5px}@supports (color:color-mix(in lab,red,red)){.btn:active:not(.btn-active){--btn-bg:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 5%)}}.btn:active:not(.btn-active){--btn-border:var(--btn-color,var(--color-base-200))}@supports (color:color-mix(in lab,red,red)){.btn:active:not(.btn-active){--btn-border:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 7%)}}.btn:active:not(.btn-active){--btn-shadow:0 0 0 0 oklch(0% 0 0/0),0 0 0 0 oklch(0% 0 0/0)}.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){box-shadow:none}.btn:is(:disabled,[disabled],.btn-disabled){pointer-events:none;--btn-border:#0000;--btn-noise:none;--btn-fg:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled){--btn-fg:color-mix(in oklch,var(--color-base-content)20%,#0000)}}@media (hover:hover){.btn:is(:disabled,[disabled],.btn-disabled):hover{pointer-events:none;background-color:var(--color-neutral)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):hover{background-color:color-mix(in oklab,var(--color-neutral)20%,transparent)}}.btn:is(:disabled,[disabled],.btn-disabled):hover{--btn-border:#0000;--btn-fg:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):hover{--btn-fg:color-mix(in oklch,var(--color-base-content)20%,#0000)}}}.btn:is(input[type=checkbox],input[type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none}.btn:is(input[type=checkbox],input[type=radio]):after{content:attr(aria-label)}.btn:where(input:checked:not(.filter .btn)){--btn-color:var(--color-primary);--btn-fg:var(--color-primary-content);isolation:isolate}.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}.list{flex-direction:column;font-size:.875rem;display:flex}.list :where(.list-row){--list-grid-cols:minmax(0,auto)1fr;border-radius:var(--radius-box);word-break:break-word;grid-auto-flow:column;grid-template-columns:var(--list-grid-cols);gap:1rem;padding:1rem;display:grid;position:relative}.list :where(.list-row):has(.list-col-grow:first-child){--list-grid-cols:1fr}.list :where(.list-row):has(.list-col-grow:nth-child(2)){--list-grid-cols:minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(3)){--list-grid-cols:minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(4)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(5)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(6)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row) :not(.list-col-wrap){grid-row-start:1}:is(.list>:not(:last-child).list-row,.list>:not(:last-child) .list-row):after{content:"";border-bottom:var(--border)solid;inset-inline:var(--radius-box);border-color:var(--color-base-content);position:absolute;bottom:0}@supports (color:color-mix(in lab,red,red)){:is(.list>:not(:last-child).list-row,.list>:not(:last-child) .list-row):after{border-color:color-mix(in oklab,var(--color-base-content)5%,transparent)}}.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}.indicator{width:max-content;display:inline-flex;position:relative}.indicator :where(.indicator-item){z-index:1;white-space:nowrap;top:var(--indicator-t,0);bottom:var(--indicator-b,auto);left:var(--indicator-s,auto);right:var(--indicator-e,0);translate:var(--indicator-x,50%)var(--indicator-y,-50%);position:absolute}.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}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.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-0{right:calc(var(--spacing)*0)}.right-2{right:calc(var(--spacing)*2)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.left-1\/2{left:50%}.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}.z-30{z-index:30}.z-40{z-index:40}.float-right{float:right}.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-2{margin-block:calc(var(--spacing)*2)}.my-3{margin-block:calc(var(--spacing)*3)}.my-4{margin-block:calc(var(--spacing)*4)}.my-6{margin-block:calc(var(--spacing)*6)}.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-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-5{margin-top:calc(var(--spacing)*5)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-12{margin-top:calc(var(--spacing)*12)}.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-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-4{margin-left:calc(var(--spacing)*4)}.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)}}.kbd{border-radius:var(--radius-field);background-color:var(--color-base-200);vertical-align:middle;border:var(--border)solid var(--color-base-content);justify-content:center;align-items:center;padding-left:.5em;padding-right:.5em;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.kbd{border:var(--border)solid color-mix(in srgb,var(--color-base-content)20%,#0000)}}.kbd{border-bottom:calc(var(--border) + 1px)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.kbd{border-bottom:calc(var(--border) + 1px)solid color-mix(in srgb,var(--color-base-content)20%,#0000)}}.kbd{--size:calc(var(--size-selector,.25rem)*6);height:var(--size);min-width:var(--size);font-size:.875rem}.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}.footer{grid-auto-flow:row;place-items:start;gap:2.5rem 1rem;width:100%;font-size:.875rem;line-height:1.25rem;display:grid}.footer>*{place-items:start;gap:.5rem;display:grid}.footer.footer-center{text-align:center;grid-auto-flow:column dense;place-items:center}.footer.footer-center>*{place-items:center}.alert{border-radius:var(--radius-box);color:var(--color-base-content);background-color:var(--alert-color,var(--color-base-200));text-align:start;border:var(--border)solid var(--color-base-200);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);box-shadow:0 3px 0 -2px oklch(100% 0 0/calc(var(--depth)*.08)) inset,0 1px #000,0 4px 3px -2px oklch(0% 0 0/calc(var(--depth)*.08));grid-template-columns:auto;grid-auto-flow:column;justify-content:start;place-items:center start;gap:1rem;padding-block:.75rem;padding-inline:1rem;font-size:.875rem;line-height:1.25rem;display:grid}@supports (color:color-mix(in lab,red,red)){.alert{box-shadow:0 3px 0 -2px oklch(100% 0 0/calc(var(--depth)*.08)) inset,0 1px color-mix(in oklab,color-mix(in oklab,#000 20%,var(--alert-color,var(--color-base-200)))calc(var(--depth)*20%),#0000),0 4px 3px -2px oklch(0% 0 0/calc(var(--depth)*.08))}}.alert:has(:nth-child(2)){grid-template-columns:auto minmax(auto,1fr)}.alert.alert-outline{color:var(--alert-color);box-shadow:none;background-color:#0000;background-image:none}.alert.alert-dash{color:var(--alert-color);box-shadow:none;background-color:#0000;background-image:none;border-style:dashed}.alert.alert-soft{color:var(--alert-color,var(--color-base-content));background:var(--alert-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.alert.alert-soft{background:color-mix(in oklab,var(--alert-color,var(--color-base-content))8%,var(--color-base-100))}}.alert.alert-soft{border-color:var(--alert-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.alert.alert-soft{border-color:color-mix(in oklab,var(--alert-color,var(--color-base-content))10%,var(--color-base-100))}}.alert.alert-soft{box-shadow:none;background-image:none}.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}.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}.btn-circle{width:var(--size);height:var(--size);border-radius:3.40282e38px;padding-inline:0}.h-4{height:calc(var(--spacing)*4)}.h-6{height:calc(var(--spacing)*6)}.h-64{height:calc(var(--spacing)*64)}.h-auto{height:auto}.h-full{height:100%}.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-1{width:calc(var(--spacing)*1)}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-11\/12{width:91.6667%}.w-20{width:calc(var(--spacing)*20)}.w-48{width:calc(var(--spacing)*48)}.w-full{width:100%}.max-w-full{max-width:100%}.min-w-\[220px\]{min-width:220px}.min-w-max{min-width:max-content}.flex-1{flex:1}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:calc(var(--spacing)*0);--tw-border-spacing-y:calc(var(--spacing)*0);border-spacing:var(--tw-border-spacing-x)var(--tw-border-spacing-y)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-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}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.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-6{gap:calc(var(--spacing)*6)}: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}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.alert-error{border-color:var(--color-error);color:var(--color-error-content);--alert-color:var(--color-error)}.border-base-300{border-color:var(--color-base-300)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-700{border-color:var(--color-gray-700)}.border-primary{border-color:var(--color-primary)}.table-zebra tbody tr:where(:nth-child(2n)),.table-zebra tbody tr:where(:nth-child(2n)) :where(.table-pin-cols tr th){background-color:var(--color-base-200)}@media (hover:hover){:is(.table-zebra tbody tr.row-hover,.table-zebra tbody tr.row-hover:where(:nth-child(2n))):hover{background-color:var(--color-base-300)}}.bg-base-100{background-color:var(--color-base-100)}.bg-base-200{background-color:var(--color-base-200)}.bg-base-300{background-color:var(--color-base-300)}.bg-black{background-color:var(--color-black)}.bg-white{background-color:var(--color-white)}.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-1\.5{padding:calc(var(--spacing)*1.5)}.p-4{padding:calc(var(--spacing)*4)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-4{padding-right:calc(var(--spacing)*4)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-6{padding-left:calc(var(--spacing)*6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.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-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.select-xs{--size:calc(var(--size-field,.25rem)*6);font-size:.6875rem}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.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)}.link-primary{color:var(--color-primary)}@media (hover:hover){.link-primary:hover{color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.link-primary:hover{color:color-mix(in oklab,var(--color-primary)80%,#000)}}}.text-accent{color:var(--color-accent)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-primary{color:var(--color-primary)}.text-red-500{color:var(--color-red-500)}.text-secondary{color:var(--color-secondary)}.italic{font-style:italic}.link-hover{text-decoration-line:none}@media (hover:hover){.link-hover:hover{text-decoration-line:underline}}.underline{text-decoration-line:underline}.opacity-0{opacity:0}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.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)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px 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)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.btn-ghost:not(.btn-active,:hover,:active:focus,:focus-visible){--btn-shadow:"";--btn-bg:#0000;--btn-border:#0000;--btn-noise:none}.btn-ghost:not(.btn-active,:hover,:active:focus,:focus-visible):not(:disabled,[disabled],.btn-disabled){--btn-fg:currentColor;outline-color:currentColor}@media (hover:none){.btn-ghost:hover:not(.btn-active,:active,:focus-visible,:disabled,[disabled],.btn-disabled){--btn-shadow:"";--btn-bg:#0000;--btn-border:#0000;--btn-noise:none;--btn-fg:currentColor}}.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)}.btn-outline:not(.btn-active,:hover,:active:focus,:focus-visible,:disabled,[disabled],.btn-disabled,:checked){--btn-shadow:"";--btn-bg:#0000;--btn-fg:var(--btn-color);--btn-border:var(--btn-color);--btn-noise:none}@media (hover:none){.btn-outline:hover:not(.btn-active,:active,:focus-visible,:disabled,[disabled],.btn-disabled,:checked){--btn-shadow:"";--btn-bg:#0000;--btn-fg:var(--btn-color);--btn-border:var(--btn-color);--btn-noise:none}}.btn-xs{--fontsize:.6875rem;--btn-p:.5rem;--size:calc(var(--size-field,.25rem)*6)}.btn-primary{--btn-color:var(--color-primary);--btn-fg:var(--color-primary-content)}.select-none{-webkit-user-select:none;user-select:none}.range-xs{--range-thumb-size:calc(var(--size-selector,.25rem)*4)}@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-border-spacing-x{syntax:"<length>";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"<length>";inherits:false;initial-value:0}@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-leading{syntax:"*";inherits:false}@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-outline-style{syntax:"*";inherits:false;initial-value:solid}@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-stFRue7K.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
:root{--rt-color-white:#fff;--rt-color-dark:#222;--rt-color-success:#8dc572;--rt-color-error:#be6464;--rt-color-warning:#f0ad4e;--rt-color-info:#337ab7;--rt-opacity:.9;--rt-transition-show-delay:.15s;--rt-transition-closing-delay:.15s;--rt-arrow-size:8px}.core-styles-module_tooltip__3vRRp{left:0;opacity:0;pointer-events:none;position:absolute;top:0;will-change:opacity}.core-styles-module_fixed__pcSol{position:fixed}.core-styles-module_arrow__cvMwQ{background:inherit;position:absolute;z-index:-1}.core-styles-module_noArrow__xock6{display:none}.core-styles-module_clickable__ZuTTB{pointer-events:auto}.core-styles-module_show__Nt9eE{opacity:var(--rt-opacity);transition:opacity var(--rt-transition-show-delay) ease-out}.core-styles-module_closing__sGnxF{opacity:0;transition:opacity var(--rt-transition-closing-delay) ease-in}.styles-module_tooltip__mnnfp{border-radius:3px;font-size:90%;padding:8px 16px;width:max-content}.styles-module_arrow__K0L3T{height:var(--rt-arrow-size);width:var(--rt-arrow-size)}[class*=react-tooltip__place-top]>.styles-module_arrow__K0L3T{transform:rotate(45deg)}[class*=react-tooltip__place-right]>.styles-module_arrow__K0L3T{transform:rotate(135deg)}[class*=react-tooltip__place-bottom]>.styles-module_arrow__K0L3T{transform:rotate(225deg)}[class*=react-tooltip__place-left]>.styles-module_arrow__K0L3T{transform:rotate(315deg)}.styles-module_dark__xNqje{background:var(--rt-color-dark);color:var(--rt-color-white)}.styles-module_light__Z6W-X{background-color:var(--rt-color-white);color:var(--rt-color-dark)}.styles-module_success__A2AKt{background-color:var(--rt-color-success);color:var(--rt-color-white)}.styles-module_warning__SCK0X{background-color:var(--rt-color-warning);color:var(--rt-color-white)}.styles-module_error__JvumD{background-color:var(--rt-color-error);color:var(--rt-color-white)}.styles-module_info__BWdHW{background-color:var(--rt-color-info);color:var(--rt-color-white)}/*! 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-border-spacing-x:0;--tw-border-spacing-y:0;--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-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--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-outline-style:solid;--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-blue-300:oklch(80.9% .105 251.813);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-700:oklch(37.3% .034 259.733);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--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}}.tooltip{--tt-bg:var(--color-neutral);--tt-off: calc(100% + .5rem) ;--tt-tail: calc(100% + 1px + .25rem) ;display:inline-block;position:relative}.tooltip>:where(.tooltip-content),.tooltip:where([data-tip]):before{border-radius:var(--radius-field);text-align:center;white-space:normal;max-width:20rem;color:var(--color-neutral-content);opacity:0;background-color:var(--tt-bg);pointer-events:none;z-index:2;--tw-content:attr(data-tip);content:var(--tw-content);width:max-content;padding-block:.25rem;padding-inline:.5rem;font-size:.875rem;line-height:1.25;transition:opacity .2s cubic-bezier(.4,0,.2,1) 75ms,transform .2s cubic-bezier(.4,0,.2,1) 75ms;position:absolute}.tooltip:after{opacity:0;background-color:var(--tt-bg);content:"";pointer-events:none;--mask-tooltip:url("data:image/svg+xml,%3Csvg width='10' height='4' viewBox='0 0 8 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.500009 1C3.5 1 3.00001 4 5.00001 4C7 4 6.5 1 9.5 1C10 1 10 0.499897 10 0H0C-1.99338e-08 0.5 0 1 0.500009 1Z' fill='black'/%3E%3C/svg%3E%0A");width:.625rem;height:.25rem;-webkit-mask-position:-1px 0;mask-position:-1px 0;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-image:var(--mask-tooltip);mask-image:var(--mask-tooltip);transition:opacity .2s cubic-bezier(.4,0,.2,1) 75ms,transform .2s cubic-bezier(.4,0,.2,1) 75ms;display:block;position:absolute}:is(.tooltip.tooltip-open,.tooltip[data-tip]:not([data-tip=""]):hover,.tooltip:not(:has(.tooltip-content:empty)):has(.tooltip-content):hover,.tooltip:has(:focus-visible))>.tooltip-content,:is(.tooltip.tooltip-open,.tooltip[data-tip]:not([data-tip=""]):hover,.tooltip:not(:has(.tooltip-content:empty)):has(.tooltip-content):hover,.tooltip:has(:focus-visible))[data-tip]:before,:is(.tooltip.tooltip-open,.tooltip[data-tip]:not([data-tip=""]):hover,.tooltip:not(:has(.tooltip-content:empty)):has(.tooltip-content):hover,.tooltip:has(:focus-visible)):after{opacity:1;--tt-pos:0rem;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}.tooltip>.tooltip-content,.tooltip[data-tip]:before{transform:translate(-50%)translateY(var(--tt-pos,.25rem));inset:auto auto var(--tt-off)50%}.tooltip:after{transform:translate(-50%)translateY(var(--tt-pos,.25rem));inset:auto auto var(--tt-tail)50%}.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}.menu{--menu-active-fg:var(--color-neutral-content);--menu-active-bg:var(--color-neutral);flex-flow:column wrap;width:fit-content;padding:.5rem;font-size:.875rem;display:flex}.menu :where(li ul){white-space:nowrap;margin-inline-start:1rem;padding-inline-start:.5rem;position:relative}.menu :where(li ul):before{background-color:var(--color-base-content);opacity:.1;width:var(--border);content:"";inset-inline-start:0;position:absolute;top:.75rem;bottom:.75rem}.menu :where(li>.menu-dropdown:not(.menu-dropdown-show)){display:none}.menu :where(li:not(.menu-title)>:not(ul,details,.menu-title,.btn)),.menu :where(li:not(.menu-title)>details>summary:not(.menu-title)){border-radius:var(--radius-field);text-align:start;text-wrap:balance;-webkit-user-select:none;user-select:none;grid-auto-columns:minmax(auto,max-content) auto max-content;grid-auto-flow:column;align-content:flex-start;align-items:center;gap:.5rem;padding-block:.375rem;padding-inline:.75rem;transition-property:color,background-color,box-shadow;transition-duration:.2s;transition-timing-function:cubic-bezier(0,0,.2,1);display:grid}.menu :where(li>details>summary){--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li>details>summary){outline-offset:2px;outline:2px solid #0000}}.menu :where(li>details>summary)::-webkit-details-marker{display:none}:is(.menu :where(li>details>summary),.menu :where(li>.menu-dropdown-toggle)):after{content:"";transform-origin:50%;pointer-events:none;justify-self:flex-end;width:.375rem;height:.375rem;transition-property:rotate,translate;transition-duration:.2s;display:block;translate:0 -1px;rotate:-135deg;box-shadow:inset 2px 2px}.menu :where(li>details[open]>summary):after,.menu :where(li>.menu-dropdown-toggle.menu-dropdown-show):after{translate:0 1px;rotate:45deg}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{cursor:pointer;background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{color:var(--color-base-content);--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn).menu-focus,.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title),li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(.menu-active,:active,.btn):focus-visible{outline-offset:2px;outline:2px solid #0000}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){cursor:pointer;background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){outline-offset:2px;outline:2px solid #0000}}.menu :where(li:not(.menu-title,.disabled)>:not(ul,details,.menu-title):not(.menu-active,:active,.btn):hover,li:not(.menu-title,.disabled)>details>summary:not(.menu-title):not(.menu-active,:active,.btn):hover){box-shadow:inset 0 1px #00000003,inset 0 -1px #ffffff03}.menu :where(li:empty){background-color:var(--color-base-content);opacity:.1;height:1px;margin:.5rem 1rem}.menu :where(li){flex-flow:column wrap;flex-shrink:0;align-items:stretch;display:flex;position:relative}.menu :where(li) .badge{justify-self:flex-end}.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{outline-offset:2px;outline:2px solid #0000}}.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active{color:var(--menu-active-fg);background-color:var(--menu-active-bg);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise)}:is(.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active):not(:is(.menu :where(li)>:not(ul,.menu-title,details,.btn):active,.menu :where(li)>:not(ul,.menu-title,details,.btn).menu-active,.menu :where(li)>details>summary:active):active){box-shadow:0 2px calc(var(--depth)*3px) -2px var(--menu-active-bg)}.menu :where(li).menu-disabled{pointer-events:none;color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.menu :where(li).menu-disabled{color:color-mix(in oklab,var(--color-base-content)20%,transparent)}}.menu .dropdown:focus-within .menu-dropdown-toggle:after{translate:0 1px;rotate:45deg}.menu .dropdown-content{margin-top:.5rem;padding:.5rem}.menu .dropdown-content:before{display:none}.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}:where(.btn){width:unset}.btn{cursor:pointer;text-align:center;vertical-align:middle;outline-offset:2px;webkit-user-select:none;-webkit-user-select:none;user-select:none;padding-inline:var(--btn-p);color:var(--btn-fg);--tw-prose-links:var(--btn-fg);height:var(--size);font-size:var(--fontsize,.875rem);outline-color:var(--btn-color,var(--color-base-content));background-color:var(--btn-bg);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--btn-noise);border-width:var(--border);border-style:solid;border-color:var(--btn-border);text-shadow:0 .5px oklch(100% 0 0/calc(var(--depth)*.15));touch-action:manipulation;box-shadow:0 .5px 0 .5px oklch(100% 0 0/calc(var(--depth)*6%)) inset,var(--btn-shadow);--size:calc(var(--size-field,.25rem)*10);--btn-bg:var(--btn-color,var(--color-base-200));--btn-fg:var(--color-base-content);--btn-p:1rem;--btn-border:var(--btn-bg);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-wrap:nowrap;flex-shrink:0;justify-content:center;align-items:center;gap:.375rem;font-weight:600;transition-property:color,background-color,border-color,box-shadow;transition-duration:.2s;transition-timing-function:cubic-bezier(0,0,.2,1);display:inline-flex}@supports (color:color-mix(in lab,red,red)){.btn{--btn-border:color-mix(in oklab,var(--btn-bg),#000 calc(var(--depth)*5%))}}.btn{--btn-shadow:0 3px 2px -2px var(--btn-bg),0 4px 3px -2px var(--btn-bg)}@supports (color:color-mix(in lab,red,red)){.btn{--btn-shadow:0 3px 2px -2px color-mix(in oklab,var(--btn-bg)calc(var(--depth)*30%),#0000),0 4px 3px -2px color-mix(in oklab,var(--btn-bg)calc(var(--depth)*30%),#0000)}}.btn{--btn-noise:var(--fx-noise)}.prose .btn{text-decoration-line:none}@media (hover:hover){.btn:hover{--btn-bg:var(--btn-color,var(--color-base-200))}@supports (color:color-mix(in lab,red,red)){.btn:hover{--btn-bg:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 7%)}}}.btn:focus-visible{isolation:isolate;outline-width:2px;outline-style:solid}.btn:active:not(.btn-active){--btn-bg:var(--btn-color,var(--color-base-200));translate:0 .5px}@supports (color:color-mix(in lab,red,red)){.btn:active:not(.btn-active){--btn-bg:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 5%)}}.btn:active:not(.btn-active){--btn-border:var(--btn-color,var(--color-base-200))}@supports (color:color-mix(in lab,red,red)){.btn:active:not(.btn-active){--btn-border:color-mix(in oklab,var(--btn-color,var(--color-base-200)),#000 7%)}}.btn:active:not(.btn-active){--btn-shadow:0 0 0 0 oklch(0% 0 0/0),0 0 0 0 oklch(0% 0 0/0)}.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){background-color:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){background-color:color-mix(in oklab,var(--color-base-content)10%,transparent)}}.btn:is(:disabled,[disabled],.btn-disabled):not(.btn-link,.btn-ghost){box-shadow:none}.btn:is(:disabled,[disabled],.btn-disabled){pointer-events:none;--btn-border:#0000;--btn-noise:none;--btn-fg:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled){--btn-fg:color-mix(in oklch,var(--color-base-content)20%,#0000)}}@media (hover:hover){.btn:is(:disabled,[disabled],.btn-disabled):hover{pointer-events:none;background-color:var(--color-neutral)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):hover{background-color:color-mix(in oklab,var(--color-neutral)20%,transparent)}}.btn:is(:disabled,[disabled],.btn-disabled):hover{--btn-border:#0000;--btn-fg:var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.btn:is(:disabled,[disabled],.btn-disabled):hover{--btn-fg:color-mix(in oklch,var(--color-base-content)20%,#0000)}}}.btn:is(input[type=checkbox],input[type=radio]){-webkit-appearance:none;-moz-appearance:none;appearance:none}.btn:is(input[type=checkbox],input[type=radio]):after{content:attr(aria-label)}.btn:where(input:checked:not(.filter .btn)){--btn-color:var(--color-primary);--btn-fg:var(--color-primary-content);isolation:isolate}.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}.list{flex-direction:column;font-size:.875rem;display:flex}.list :where(.list-row){--list-grid-cols:minmax(0,auto)1fr;border-radius:var(--radius-box);word-break:break-word;grid-auto-flow:column;grid-template-columns:var(--list-grid-cols);gap:1rem;padding:1rem;display:grid;position:relative}.list :where(.list-row):has(.list-col-grow:first-child){--list-grid-cols:1fr}.list :where(.list-row):has(.list-col-grow:nth-child(2)){--list-grid-cols:minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(3)){--list-grid-cols:minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(4)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(5)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row):has(.list-col-grow:nth-child(6)){--list-grid-cols:minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)minmax(0,auto)1fr}.list :where(.list-row) :not(.list-col-wrap){grid-row-start:1}:is(.list>:not(:last-child).list-row,.list>:not(:last-child) .list-row):after{content:"";border-bottom:var(--border)solid;inset-inline:var(--radius-box);border-color:var(--color-base-content);position:absolute;bottom:0}@supports (color:color-mix(in lab,red,red)){:is(.list>:not(:last-child).list-row,.list>:not(:last-child) .list-row):after{border-color:color-mix(in oklab,var(--color-base-content)5%,transparent)}}.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}.indicator{width:max-content;display:inline-flex;position:relative}.indicator :where(.indicator-item){z-index:1;white-space:nowrap;top:var(--indicator-t,0);bottom:var(--indicator-b,auto);left:var(--indicator-s,auto);right:var(--indicator-e,0);translate:var(--indicator-x,50%)var(--indicator-y,-50%);position:absolute}.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}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.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-0{right:calc(var(--spacing)*0)}.right-2{right:calc(var(--spacing)*2)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.left-1\/2{left:50%}.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}.z-30{z-index:30}.z-40{z-index:40}.z-\[10000\]{z-index:10000}.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}.filter\!{flex-wrap:wrap!important;display:flex!important}.filter\! input[type=radio]{width:auto!important}.filter\! input{opacity:1!important;transition:margin .1s,opacity .3s,padding .3s,border-width .1s!important;overflow:hidden!important;scale:1!important}.filter\! input:not(:last-child){margin-inline-end:.25rem!important}.filter\! input.filter-reset{aspect-ratio:1!important}.filter\! input.filter-reset:after{content:"Γ"!important}.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!important;border-width:0!important;width:0!important;margin-inline:0!important;padding-inline:0!important;scale:0!important}.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-2{margin-block:calc(var(--spacing)*2)}.my-3{margin-block:calc(var(--spacing)*3)}.my-4{margin-block:calc(var(--spacing)*4)}.my-6{margin-block:calc(var(--spacing)*6)}.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-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-5{margin-top:calc(var(--spacing)*5)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-12{margin-top:calc(var(--spacing)*12)}.mr-1{margin-right:calc(var(--spacing)*1)}.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-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-auto{margin-left:auto}.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)}}.kbd{border-radius:var(--radius-field);background-color:var(--color-base-200);vertical-align:middle;border:var(--border)solid var(--color-base-content);justify-content:center;align-items:center;padding-left:.5em;padding-right:.5em;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.kbd{border:var(--border)solid color-mix(in srgb,var(--color-base-content)20%,#0000)}}.kbd{border-bottom:calc(var(--border) + 1px)solid var(--color-base-content)}@supports (color:color-mix(in lab,red,red)){.kbd{border-bottom:calc(var(--border) + 1px)solid color-mix(in srgb,var(--color-base-content)20%,#0000)}}.kbd{--size:calc(var(--size-selector,.25rem)*6);height:var(--size);min-width:var(--size);font-size:.875rem}.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}.footer{grid-auto-flow:row;place-items:start;gap:2.5rem 1rem;width:100%;font-size:.875rem;line-height:1.25rem;display:grid}.footer>*{place-items:start;gap:.5rem;display:grid}.footer.footer-center{text-align:center;grid-auto-flow:column dense;place-items:center}.footer.footer-center>*{place-items:center}.alert{border-radius:var(--radius-box);color:var(--color-base-content);background-color:var(--alert-color,var(--color-base-200));text-align:start;border:var(--border)solid var(--color-base-200);background-size:auto,calc(var(--noise)*100%);background-image:none,var(--fx-noise);box-shadow:0 3px 0 -2px oklch(100% 0 0/calc(var(--depth)*.08)) inset,0 1px #000,0 4px 3px -2px oklch(0% 0 0/calc(var(--depth)*.08));grid-template-columns:auto;grid-auto-flow:column;justify-content:start;place-items:center start;gap:1rem;padding-block:.75rem;padding-inline:1rem;font-size:.875rem;line-height:1.25rem;display:grid}@supports (color:color-mix(in lab,red,red)){.alert{box-shadow:0 3px 0 -2px oklch(100% 0 0/calc(var(--depth)*.08)) inset,0 1px color-mix(in oklab,color-mix(in oklab,#000 20%,var(--alert-color,var(--color-base-200)))calc(var(--depth)*20%),#0000),0 4px 3px -2px oklch(0% 0 0/calc(var(--depth)*.08))}}.alert:has(:nth-child(2)){grid-template-columns:auto minmax(auto,1fr)}.alert.alert-outline{color:var(--alert-color);box-shadow:none;background-color:#0000;background-image:none}.alert.alert-dash{color:var(--alert-color);box-shadow:none;background-color:#0000;background-image:none;border-style:dashed}.alert.alert-soft{color:var(--alert-color,var(--color-base-content));background:var(--alert-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.alert.alert-soft{background:color-mix(in oklab,var(--alert-color,var(--color-base-content))8%,var(--color-base-100))}}.alert.alert-soft{border-color:var(--alert-color,var(--color-base-content))}@supports (color:color-mix(in lab,red,red)){.alert.alert-soft{border-color:color-mix(in oklab,var(--alert-color,var(--color-base-content))10%,var(--color-base-100))}}.alert.alert-soft{box-shadow:none;background-image:none}.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}.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}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.btn-circle{width:var(--size);height:var(--size);border-radius:3.40282e38px;padding-inline:0}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-6{height:calc(var(--spacing)*6)}.h-64{height:calc(var(--spacing)*64)}.h-auto{height:auto}.h-full{height:100%}.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-1{width:calc(var(--spacing)*1)}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-11\/12{width:91.6667%}.w-20{width:calc(var(--spacing)*20)}.w-48{width:calc(var(--spacing)*48)}.w-full{width:100%}.max-w-full{max-width:100%}.max-w-xs{max-width:var(--container-xs)}.min-w-\[220px\]{min-width:220px}.min-w-max{min-width:max-content}.flex-1{flex:1}.flex-grow{flex-grow:1}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:calc(var(--spacing)*0);--tw-border-spacing-y:calc(var(--spacing)*0);border-spacing:var(--tw-border-spacing-x)var(--tw-border-spacing-y)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-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}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.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-6{gap:calc(var(--spacing)*6)}: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)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-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}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.alert-error{border-color:var(--color-error);color:var(--color-error-content);--alert-color:var(--color-error)}.border-base-300{border-color:var(--color-base-300)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-700{border-color:var(--color-gray-700)}.border-primary{border-color:var(--color-primary)}.table-zebra tbody tr:where(:nth-child(2n)),.table-zebra tbody tr:where(:nth-child(2n)) :where(.table-pin-cols tr th){background-color:var(--color-base-200)}@media (hover:hover){:is(.table-zebra tbody tr.row-hover,.table-zebra tbody tr.row-hover:where(:nth-child(2n))):hover{background-color:var(--color-base-300)}}.bg-base-100{background-color:var(--color-base-100)}.bg-base-200{background-color:var(--color-base-200)}.bg-base-300{background-color:var(--color-base-300)}.bg-black{background-color:var(--color-black)}.bg-white{background-color:var(--color-white)}.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-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-4{padding:calc(var(--spacing)*4)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-4{padding-right:calc(var(--spacing)*4)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-6{padding-left:calc(var(--spacing)*6)}.pl-12{padding-left:calc(var(--spacing)*12)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.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-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.select-xs{--size:calc(var(--size-field,.25rem)*6);font-size:.6875rem}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.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)}.whitespace-pre-line{white-space:pre-line}.link-primary{color:var(--color-primary)}@media (hover:hover){.link-primary:hover{color:var(--color-primary)}@supports (color:color-mix(in lab,red,red)){.link-primary:hover{color:color-mix(in oklab,var(--color-primary)80%,#000)}}}.text-accent{color:var(--color-accent)}.text-base-content{color:var(--color-base-content)}.text-blue-400{color:var(--color-blue-400)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-primary{color:var(--color-primary)}.text-red-500{color:var(--color-red-500)}.text-secondary{color:var(--color-secondary)}.italic{font-style:italic}.link-hover{text-decoration-line:none}@media (hover:hover){.link-hover:hover{text-decoration-line:underline}}.underline{text-decoration-line:underline}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.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)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px 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)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.btn-ghost:not(.btn-active,:hover,:active:focus,:focus-visible){--btn-shadow:"";--btn-bg:#0000;--btn-border:#0000;--btn-noise:none}.btn-ghost:not(.btn-active,:hover,:active:focus,:focus-visible):not(:disabled,[disabled],.btn-disabled){--btn-fg:currentColor;outline-color:currentColor}@media (hover:none){.btn-ghost:hover:not(.btn-active,:active,:focus-visible,:disabled,[disabled],.btn-disabled){--btn-shadow:"";--btn-bg:#0000;--btn-border:#0000;--btn-noise:none;--btn-fg:currentColor}}.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,)}.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,)!important}.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)}.btn-outline:not(.btn-active,:hover,:active:focus,:focus-visible,:disabled,[disabled],.btn-disabled,:checked){--btn-shadow:"";--btn-bg:#0000;--btn-fg:var(--btn-color);--btn-border:var(--btn-color);--btn-noise:none}@media (hover:none){.btn-outline:hover:not(.btn-active,:active,:focus-visible,:disabled,[disabled],.btn-disabled,:checked){--btn-shadow:"";--btn-bg:#0000;--btn-fg:var(--btn-color);--btn-border:var(--btn-color);--btn-noise:none}}.btn-xs{--fontsize:.6875rem;--btn-p:.5rem;--size:calc(var(--size-field,.25rem)*6)}.btn-primary{--btn-color:var(--color-primary);--btn-fg:var(--color-primary-content)}.select-none{-webkit-user-select:none;user-select:none}.range-xs{--range-thumb-size:calc(var(--size-selector,.25rem)*4)}@media (hover:hover){.hover\:z-30:hover{z-index:30}.hover\:z-40:hover{z-index:40}.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)}.hover\:text-blue-300:hover{color:var(--color-blue-300)}.hover\:text-blue-600:hover{color:var(--color-blue-600)}}@media (min-width:48rem){.md\:w-1\/2{width:50%}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.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-4{grid-template-columns:repeat(4,minmax(0,1fr))}.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-border-spacing-x{syntax:"<length>";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"<length>";inherits:false;initial-value:0}@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-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@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-outline-style{syntax:"*";inherits:false;initial-value:solid}@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/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-DC3IGjBs.js"></script>
|
9 |
+
<link rel="stylesheet" crossorigin href="/assets/index-stFRue7K.css">
|
10 |
</head>
|
11 |
<body>
|
12 |
<div id="root"></div>
|
frontend/package-lock.json
CHANGED
@@ -10,11 +10,13 @@
|
|
10 |
"dependencies": {
|
11 |
"@heroicons/react": "^2.2.0",
|
12 |
"@tailwindcss/vite": "^4.0.0",
|
|
|
13 |
"@types/wavesurfer.js": "^6.0.12",
|
14 |
"react": "^18.3.1",
|
15 |
"react-dom": "^18.3.1",
|
16 |
"react-markdown": "^10.1.0",
|
17 |
"react-router-dom": "^7.6.2",
|
|
|
18 |
"recharts": "^2.9.0",
|
19 |
"rehype-raw": "^7.0.0",
|
20 |
"rehype-sanitize": "^6.0.0",
|
@@ -840,6 +842,31 @@
|
|
840 |
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
841 |
}
|
842 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
843 |
"node_modules/@heroicons/react": {
|
844 |
"version": "2.2.0",
|
845 |
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
@@ -1566,6 +1593,39 @@
|
|
1566 |
"vite": "^5.2.0 || ^6"
|
1567 |
}
|
1568 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1569 |
"node_modules/@types/babel__core": {
|
1570 |
"version": "7.20.5",
|
1571 |
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
@@ -2298,6 +2358,12 @@
|
|
2298 |
"node": ">=18"
|
2299 |
}
|
2300 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
2301 |
"node_modules/clsx": {
|
2302 |
"version": "2.1.1",
|
2303 |
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
@@ -5416,6 +5482,20 @@
|
|
5416 |
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
5417 |
}
|
5418 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5419 |
"node_modules/react-transition-group": {
|
5420 |
"version": "4.4.5",
|
5421 |
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
|
|
10 |
"dependencies": {
|
11 |
"@heroicons/react": "^2.2.0",
|
12 |
"@tailwindcss/vite": "^4.0.0",
|
13 |
+
"@tanstack/react-table": "^8.21.3",
|
14 |
"@types/wavesurfer.js": "^6.0.12",
|
15 |
"react": "^18.3.1",
|
16 |
"react-dom": "^18.3.1",
|
17 |
"react-markdown": "^10.1.0",
|
18 |
"react-router-dom": "^7.6.2",
|
19 |
+
"react-tooltip": "^5.29.1",
|
20 |
"recharts": "^2.9.0",
|
21 |
"rehype-raw": "^7.0.0",
|
22 |
"rehype-sanitize": "^6.0.0",
|
|
|
842 |
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
843 |
}
|
844 |
},
|
845 |
+
"node_modules/@floating-ui/core": {
|
846 |
+
"version": "1.7.1",
|
847 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz",
|
848 |
+
"integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==",
|
849 |
+
"license": "MIT",
|
850 |
+
"dependencies": {
|
851 |
+
"@floating-ui/utils": "^0.2.9"
|
852 |
+
}
|
853 |
+
},
|
854 |
+
"node_modules/@floating-ui/dom": {
|
855 |
+
"version": "1.7.1",
|
856 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz",
|
857 |
+
"integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==",
|
858 |
+
"license": "MIT",
|
859 |
+
"dependencies": {
|
860 |
+
"@floating-ui/core": "^1.7.1",
|
861 |
+
"@floating-ui/utils": "^0.2.9"
|
862 |
+
}
|
863 |
+
},
|
864 |
+
"node_modules/@floating-ui/utils": {
|
865 |
+
"version": "0.2.9",
|
866 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
|
867 |
+
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
868 |
+
"license": "MIT"
|
869 |
+
},
|
870 |
"node_modules/@heroicons/react": {
|
871 |
"version": "2.2.0",
|
872 |
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
|
|
1593 |
"vite": "^5.2.0 || ^6"
|
1594 |
}
|
1595 |
},
|
1596 |
+
"node_modules/@tanstack/react-table": {
|
1597 |
+
"version": "8.21.3",
|
1598 |
+
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz",
|
1599 |
+
"integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==",
|
1600 |
+
"license": "MIT",
|
1601 |
+
"dependencies": {
|
1602 |
+
"@tanstack/table-core": "8.21.3"
|
1603 |
+
},
|
1604 |
+
"engines": {
|
1605 |
+
"node": ">=12"
|
1606 |
+
},
|
1607 |
+
"funding": {
|
1608 |
+
"type": "github",
|
1609 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1610 |
+
},
|
1611 |
+
"peerDependencies": {
|
1612 |
+
"react": ">=16.8",
|
1613 |
+
"react-dom": ">=16.8"
|
1614 |
+
}
|
1615 |
+
},
|
1616 |
+
"node_modules/@tanstack/table-core": {
|
1617 |
+
"version": "8.21.3",
|
1618 |
+
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz",
|
1619 |
+
"integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==",
|
1620 |
+
"license": "MIT",
|
1621 |
+
"engines": {
|
1622 |
+
"node": ">=12"
|
1623 |
+
},
|
1624 |
+
"funding": {
|
1625 |
+
"type": "github",
|
1626 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1627 |
+
}
|
1628 |
+
},
|
1629 |
"node_modules/@types/babel__core": {
|
1630 |
"version": "7.20.5",
|
1631 |
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
|
|
2358 |
"node": ">=18"
|
2359 |
}
|
2360 |
},
|
2361 |
+
"node_modules/classnames": {
|
2362 |
+
"version": "2.5.1",
|
2363 |
+
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
2364 |
+
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
2365 |
+
"license": "MIT"
|
2366 |
+
},
|
2367 |
"node_modules/clsx": {
|
2368 |
"version": "2.1.1",
|
2369 |
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
|
|
5482 |
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
5483 |
}
|
5484 |
},
|
5485 |
+
"node_modules/react-tooltip": {
|
5486 |
+
"version": "5.29.1",
|
5487 |
+
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.29.1.tgz",
|
5488 |
+
"integrity": "sha512-rmJmEb/p99xWhwmVT7F7riLG08wwKykjHiMGbDPloNJk3tdI73oHsVOwzZ4SRjqMdd5/xwb/4nmz0RcoMfY7Bw==",
|
5489 |
+
"license": "MIT",
|
5490 |
+
"dependencies": {
|
5491 |
+
"@floating-ui/dom": "^1.6.1",
|
5492 |
+
"classnames": "^2.3.0"
|
5493 |
+
},
|
5494 |
+
"peerDependencies": {
|
5495 |
+
"react": ">=16.14.0",
|
5496 |
+
"react-dom": ">=16.14.0"
|
5497 |
+
}
|
5498 |
+
},
|
5499 |
"node_modules/react-transition-group": {
|
5500 |
"version": "4.4.5",
|
5501 |
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
frontend/package.json
CHANGED
@@ -13,11 +13,13 @@
|
|
13 |
"dependencies": {
|
14 |
"@heroicons/react": "^2.2.0",
|
15 |
"@tailwindcss/vite": "^4.0.0",
|
|
|
16 |
"@types/wavesurfer.js": "^6.0.12",
|
17 |
"react": "^18.3.1",
|
18 |
"react-dom": "^18.3.1",
|
19 |
"react-markdown": "^10.1.0",
|
20 |
"react-router-dom": "^7.6.2",
|
|
|
21 |
"recharts": "^2.9.0",
|
22 |
"rehype-raw": "^7.0.0",
|
23 |
"rehype-sanitize": "^6.0.0",
|
@@ -39,4 +41,4 @@
|
|
39 |
"typescript": "^5.4.5",
|
40 |
"vite": "^5.2.10"
|
41 |
}
|
42 |
-
}
|
|
|
13 |
"dependencies": {
|
14 |
"@heroicons/react": "^2.2.0",
|
15 |
"@tailwindcss/vite": "^4.0.0",
|
16 |
+
"@tanstack/react-table": "^8.21.3",
|
17 |
"@types/wavesurfer.js": "^6.0.12",
|
18 |
"react": "^18.3.1",
|
19 |
"react-dom": "^18.3.1",
|
20 |
"react-markdown": "^10.1.0",
|
21 |
"react-router-dom": "^7.6.2",
|
22 |
+
"react-tooltip": "^5.29.1",
|
23 |
"recharts": "^2.9.0",
|
24 |
"rehype-raw": "^7.0.0",
|
25 |
"rehype-sanitize": "^6.0.0",
|
|
|
41 |
"typescript": "^5.4.5",
|
42 |
"vite": "^5.2.10"
|
43 |
}
|
44 |
+
}
|
frontend/src/components/AudioGallery.tsx
CHANGED
@@ -8,6 +8,9 @@ import ExampleVariantMetricsTables from './ExampleVariantMetricsTable'
|
|
8 |
import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle'
|
9 |
import LoadingSpinner from './LoadingSpinner'
|
10 |
import API from '../API'
|
|
|
|
|
|
|
11 |
|
12 |
interface GalleryProps {
|
13 |
selectedModel: string
|
@@ -143,6 +146,18 @@ const AudioGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, e
|
|
143 |
selectedVariant={selectedVariant}
|
144 |
setSelectedVariant={setSelectedVariant}
|
145 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
<ExampleVariantToggle
|
147 |
toggleMode={toggleMode}
|
148 |
setToggleMode={setToggleMode}
|
|
|
8 |
import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle'
|
9 |
import LoadingSpinner from './LoadingSpinner'
|
10 |
import API from '../API'
|
11 |
+
import { InformationCircleIcon } from '@heroicons/react/24/outline'
|
12 |
+
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
13 |
+
import 'react-tooltip/dist/react-tooltip.css'
|
14 |
|
15 |
interface GalleryProps {
|
16 |
selectedModel: string
|
|
|
146 |
selectedVariant={selectedVariant}
|
147 |
setSelectedVariant={setSelectedVariant}
|
148 |
/>
|
149 |
+
<ReactTooltip
|
150 |
+
id="variant-selector-tooltip"
|
151 |
+
place="top"
|
152 |
+
className="z-[10000] max-w-xs !opacity-100 bg-base-100 text-base-content"
|
153 |
+
style={{ boxShadow: '0 0 10px rgba(0,0,0,0.2)', zIndex: 10000 }}
|
154 |
+
positionStrategy="fixed"
|
155 |
+
>
|
156 |
+
<div className="p-2 text-xs text-left relative z-[10000]">
|
157 |
+
You can also change the variant using keys <b>1</b>, <b>2</b>, <b>3</b>, <b>4</b>{' '}
|
158 |
+
on your keyboard.
|
159 |
+
</div>
|
160 |
+
</ReactTooltip>
|
161 |
<ExampleVariantToggle
|
162 |
toggleMode={toggleMode}
|
163 |
setToggleMode={setToggleMode}
|
frontend/src/components/ExampleVariantMetricsTable.tsx
CHANGED
@@ -1,11 +1,12 @@
|
|
1 |
import React from 'react'
|
2 |
import { VARIANT_NAME_MAP } from './galleryUtils'
|
|
|
3 |
|
4 |
interface ExampleVariantMetricsTablesProps {
|
5 |
variantMetadatas: Record<string, Record<string, string | number | boolean>>
|
6 |
}
|
7 |
|
8 |
-
const ACCURACY_METRICS = ['
|
9 |
|
10 |
const ExampleVariantMetricsTables: React.FC<ExampleVariantMetricsTablesProps> = ({
|
11 |
variantMetadatas,
|
@@ -36,7 +37,10 @@ const ExampleVariantMetricsTables: React.FC<ExampleVariantMetricsTablesProps> =
|
|
36 |
<th className="bg-base-100 border-gray-700 border">Variant</th>
|
37 |
{keys.map((k) => (
|
38 |
<th key={k} className="bg-base-100 border-gray-700 border text-center">
|
39 |
-
|
|
|
|
|
|
|
40 |
</th>
|
41 |
))}
|
42 |
</tr>
|
@@ -65,7 +69,7 @@ const ExampleVariantMetricsTables: React.FC<ExampleVariantMetricsTablesProps> =
|
|
65 |
|
66 |
return (
|
67 |
<>
|
68 |
-
{renderTable(accuracyKeys, 'Accuracy Metrics', ['
|
69 |
{renderTable(qualityKeys, 'Quality Metrics', ['wmd'])}
|
70 |
</>
|
71 |
)
|
|
|
1 |
import React from 'react'
|
2 |
import { VARIANT_NAME_MAP } from './galleryUtils'
|
3 |
+
import MetricInfoIcon from './MetricInfoIcon'
|
4 |
|
5 |
interface ExampleVariantMetricsTablesProps {
|
6 |
variantMetadatas: Record<string, Record<string, string | number | boolean>>
|
7 |
}
|
8 |
|
9 |
+
const ACCURACY_METRICS = ['bit_acc', 'word_acc', 'log10_p_value']
|
10 |
|
11 |
const ExampleVariantMetricsTables: React.FC<ExampleVariantMetricsTablesProps> = ({
|
12 |
variantMetadatas,
|
|
|
37 |
<th className="bg-base-100 border-gray-700 border">Variant</th>
|
38 |
{keys.map((k) => (
|
39 |
<th key={k} className="bg-base-100 border-gray-700 border text-center">
|
40 |
+
<span className="inline-flex items-center gap-1">
|
41 |
+
{k}
|
42 |
+
{k !== 'detected' && <MetricInfoIcon metricName={k} />}
|
43 |
+
</span>
|
44 |
</th>
|
45 |
))}
|
46 |
</tr>
|
|
|
69 |
|
70 |
return (
|
71 |
<>
|
72 |
+
{renderTable(accuracyKeys, 'Accuracy Metrics', ['wmd', 'attacked_wmd'])}
|
73 |
{renderTable(qualityKeys, 'Quality Metrics', ['wmd'])}
|
74 |
</>
|
75 |
)
|
frontend/src/components/ExampleVariantSelector.tsx
CHANGED
@@ -31,7 +31,11 @@ const ExampleVariantSelector: React.FC<ExampleVariantSelectorProps> = ({
|
|
31 |
<legend className="fieldset-legend font-semibold">Variants</legend>
|
32 |
<div className="mb-2 flex gap-4 flex-wrap">
|
33 |
{variantKeys.map((variant, idx) => (
|
34 |
-
<label
|
|
|
|
|
|
|
|
|
35 |
<input
|
36 |
type="radio"
|
37 |
name={`variant-selector`}
|
|
|
31 |
<legend className="fieldset-legend font-semibold">Variants</legend>
|
32 |
<div className="mb-2 flex gap-4 flex-wrap">
|
33 |
{variantKeys.map((variant, idx) => (
|
34 |
+
<label
|
35 |
+
key={variant}
|
36 |
+
className="flex items-center gap-1 cursor-pointer"
|
37 |
+
data-tooltip-id="variant-selector-tooltip"
|
38 |
+
>
|
39 |
<input
|
40 |
type="radio"
|
41 |
name={`variant-selector`}
|
frontend/src/components/Examples.tsx
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
-
import React, { useState, useEffect } from 'react'
|
2 |
import { useLocation, useNavigate } from 'react-router-dom'
|
3 |
import API from '../API'
|
4 |
import LoadingSpinner from './LoadingSpinner'
|
5 |
import ImageGallery from './ImageGallery'
|
6 |
import AudioGallery from './AudioGallery'
|
7 |
import VideoGallery from './VideoGallery'
|
|
|
|
|
8 |
|
9 |
interface ExamplesProps {
|
10 |
fileType: 'image' | 'audio' | 'video'
|
@@ -29,6 +31,12 @@ const Examples = ({ fileType }: ExamplesProps) => {
|
|
29 |
const [error, setError] = useState<string | null>(null)
|
30 |
const [selectedModel, setSelectedModel] = useState<string | null>(null)
|
31 |
const [selectedAttack, setSelectedAttack] = useState<string | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
const location = useLocation()
|
34 |
// Parse query params for model and attack
|
@@ -97,27 +105,40 @@ const Examples = ({ fileType }: ExamplesProps) => {
|
|
97 |
|
98 |
return (
|
99 |
<div className="examples-container">
|
100 |
-
<div className="selectors-container flex flex-col
|
101 |
-
<fieldset className="fieldset">
|
102 |
-
<legend className="fieldset-legend">Model</legend>
|
103 |
-
<
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
</fieldset>
|
115 |
|
116 |
{selectedModel && (
|
117 |
<fieldset className="fieldset">
|
118 |
<legend className="fieldset-legend">Attack</legend>
|
119 |
<select
|
120 |
-
className="select select-bordered
|
121 |
value={selectedAttack || ''}
|
122 |
onChange={(e) => setSelectedAttack(e.target.value || null)}
|
123 |
>
|
|
|
1 |
+
import React, { useState, useEffect, useRef } from 'react'
|
2 |
import { useLocation, useNavigate } from 'react-router-dom'
|
3 |
import API from '../API'
|
4 |
import LoadingSpinner from './LoadingSpinner'
|
5 |
import ImageGallery from './ImageGallery'
|
6 |
import AudioGallery from './AudioGallery'
|
7 |
import VideoGallery from './VideoGallery'
|
8 |
+
import ModelInfoIcon from './ModelInfoIcon'
|
9 |
+
import Descriptions from '../Descriptions'
|
10 |
|
11 |
interface ExamplesProps {
|
12 |
fileType: 'image' | 'audio' | 'video'
|
|
|
31 |
const [error, setError] = useState<string | null>(null)
|
32 |
const [selectedModel, setSelectedModel] = useState<string | null>(null)
|
33 |
const [selectedAttack, setSelectedAttack] = useState<string | null>(null)
|
34 |
+
const [descriptionsLoaded, setDescriptionsLoaded] = useState(false)
|
35 |
+
const descriptions = useRef(Descriptions.getInstance())
|
36 |
+
|
37 |
+
useEffect(() => {
|
38 |
+
descriptions.current.load().then(() => setDescriptionsLoaded(true))
|
39 |
+
}, [])
|
40 |
|
41 |
const location = useLocation()
|
42 |
// Parse query params for model and attack
|
|
|
105 |
|
106 |
return (
|
107 |
<div className="examples-container">
|
108 |
+
<div className="selectors-container flex flex-col gap-4">
|
109 |
+
<fieldset className="fieldset w-full p-4 rounded border border-gray-700 bg-base-200">
|
110 |
+
<legend className="fieldset-legend font-semibold">Model</legend>
|
111 |
+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-1 max-h-48 overflow-y-auto pr-2">
|
112 |
+
{Object.keys(examples).map((model) => {
|
113 |
+
const fullName = descriptions.current.getModelFullName(model) || model
|
114 |
+
return (
|
115 |
+
<div key={model} className="flex items-center gap-2 text-sm relative group">
|
116 |
+
<label className="flex items-center gap-2 flex-grow">
|
117 |
+
<input
|
118 |
+
type="radio"
|
119 |
+
className="radio radio-sm"
|
120 |
+
checked={selectedModel === model}
|
121 |
+
onChange={() => setSelectedModel(model)}
|
122 |
+
name="model-selection"
|
123 |
+
/>
|
124 |
+
<div className="flex items-center">
|
125 |
+
<span className="truncate" title={fullName}>
|
126 |
+
{model}
|
127 |
+
</span>
|
128 |
+
<ModelInfoIcon modelName={model} />
|
129 |
+
</div>
|
130 |
+
</label>
|
131 |
+
</div>
|
132 |
+
)
|
133 |
+
})}
|
134 |
+
</div>
|
135 |
</fieldset>
|
136 |
|
137 |
{selectedModel && (
|
138 |
<fieldset className="fieldset">
|
139 |
<legend className="fieldset-legend">Attack</legend>
|
140 |
<select
|
141 |
+
className="select select-bordered"
|
142 |
value={selectedAttack || ''}
|
143 |
onChange={(e) => setSelectedAttack(e.target.value || null)}
|
144 |
>
|
frontend/src/components/ImageGallery.tsx
CHANGED
@@ -6,6 +6,8 @@ import ExampleDetailsSection from './ExampleDetailsSection'
|
|
6 |
import ExampleVariantSelector from './ExampleVariantSelector'
|
7 |
import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle'
|
8 |
import API from '../API'
|
|
|
|
|
9 |
|
10 |
interface GalleryProps {
|
11 |
selectedModel: string
|
@@ -78,7 +80,7 @@ const ImageGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, e
|
|
78 |
<label className="font-semibold text-xs mb-1">Zoom Level: {zoomLevel}x</label>
|
79 |
<input
|
80 |
type="range"
|
81 |
-
min={
|
82 |
max={6}
|
83 |
step={0.1}
|
84 |
value={zoomLevel}
|
@@ -138,6 +140,18 @@ const ImageGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, e
|
|
138 |
selectedVariant={selectedVariant}
|
139 |
setSelectedVariant={setSelectedVariant}
|
140 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
<ExampleVariantToggle
|
142 |
toggleMode={toggleMode}
|
143 |
setToggleMode={setToggleMode}
|
|
|
6 |
import ExampleVariantSelector from './ExampleVariantSelector'
|
7 |
import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle'
|
8 |
import API from '../API'
|
9 |
+
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
10 |
+
import 'react-tooltip/dist/react-tooltip.css'
|
11 |
|
12 |
interface GalleryProps {
|
13 |
selectedModel: string
|
|
|
80 |
<label className="font-semibold text-xs mb-1">Zoom Level: {zoomLevel}x</label>
|
81 |
<input
|
82 |
type="range"
|
83 |
+
min={1}
|
84 |
max={6}
|
85 |
step={0.1}
|
86 |
value={zoomLevel}
|
|
|
140 |
selectedVariant={selectedVariant}
|
141 |
setSelectedVariant={setSelectedVariant}
|
142 |
/>
|
143 |
+
<ReactTooltip
|
144 |
+
id="variant-selector-tooltip"
|
145 |
+
place="top"
|
146 |
+
className="z-[10000] max-w-xs !opacity-100 bg-base-100 text-base-content"
|
147 |
+
style={{ boxShadow: '0 0 10px rgba(0,0,0,0.2)', zIndex: 10000 }}
|
148 |
+
positionStrategy="fixed"
|
149 |
+
>
|
150 |
+
<div className="p-2 text-xs text-left relative z-[10000]">
|
151 |
+
You can also change the variant using keys <b>1</b>, <b>2</b>, <b>3</b>, <b>4</b>{' '}
|
152 |
+
on your keyboard.
|
153 |
+
</div>
|
154 |
+
</ReactTooltip>
|
155 |
<ExampleVariantToggle
|
156 |
toggleMode={toggleMode}
|
157 |
setToggleMode={setToggleMode}
|
frontend/src/components/LeaderboardTable.tsx
CHANGED
@@ -1,25 +1,73 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import { ArrowDownTrayIcon } from '@heroicons/react/24/solid'
|
3 |
import QualityMetricsTable from './QualityMetricsTable'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
interface LeaderboardTableProps {
|
6 |
benchmarkData: any
|
7 |
selectedModels: Set<string>
|
8 |
}
|
9 |
|
10 |
-
|
|
|
11 |
metric: string
|
12 |
[key: string]: string | number
|
13 |
}
|
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
interface Groups {
|
16 |
[group: string]: { [subgroup: string]: string[] }
|
17 |
}
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
}
|
24 |
|
25 |
const OVERALL_ROW = 'Overall'
|
@@ -54,9 +102,12 @@ const OverallMetricFilter: React.FC<{
|
|
54 |
checked={selectedOverallMetrics.has(metric)}
|
55 |
onChange={() => toggleMetric(metric)}
|
56 |
/>
|
57 |
-
<
|
58 |
-
{metric}
|
59 |
-
|
|
|
|
|
|
|
60 |
</label>
|
61 |
))}
|
62 |
</div>
|
@@ -66,33 +117,35 @@ const OverallMetricFilter: React.FC<{
|
|
66 |
}
|
67 |
|
68 |
const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, selectedModels }) => {
|
69 |
-
const [
|
70 |
const [tableHeader, setTableHeader] = useState<string[]>([])
|
71 |
const [error, setError] = useState<string | null>(null)
|
72 |
const [groupRows, setGroupRows] = useState<Groups>({})
|
73 |
const [openGroupRows, setOpenGroupRows] = useState<{ [key: string]: boolean }>({})
|
74 |
-
|
75 |
-
[key: string]: { [key: string]: boolean }
|
76 |
-
}>({})
|
77 |
const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
|
78 |
const [overallMetrics, setOverallMetrics] = useState<string[]>([])
|
79 |
-
const [selectedOverallMetrics, setSelectedOverallMetrics] =
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
const [
|
84 |
-
[
|
85 |
}>({})
|
86 |
|
87 |
-
|
|
|
|
|
|
|
88 |
|
|
|
89 |
useEffect(() => {
|
90 |
if (!benchmarkData) {
|
91 |
return
|
92 |
}
|
93 |
try {
|
94 |
const data = benchmarkData
|
95 |
-
const rows:
|
96 |
const allGroups = data['groups'] as { [key: string]: string[] }
|
97 |
const { Overall: overallGroup, ...groups } = allGroups
|
98 |
const uniqueMetrics = new Set<string>()
|
@@ -134,24 +187,31 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
134 |
const allKeys: string[] = Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
|
135 |
const headers = allKeys.filter((key) => key !== 'metric')
|
136 |
const initialOpenGroups: { [key: string]: boolean } = {}
|
137 |
-
const initialOpenSubGroups: { [key: string]: { [key: string]: boolean } } = {}
|
138 |
Object.keys(groupsData).forEach((group) => {
|
139 |
initialOpenGroups[group] = false
|
140 |
-
initialOpenSubGroups[group] = {}
|
141 |
-
Object.keys(groupsData[group]).forEach((subGroup) => {
|
142 |
-
initialOpenSubGroups[group][subGroup] = false
|
143 |
-
})
|
144 |
})
|
145 |
const allMetrics = Object.values(allGroups).flat()
|
146 |
setSelectedMetrics(new Set(allMetrics))
|
147 |
setTableHeader(headers)
|
148 |
-
|
149 |
setGroupRows(groupsData)
|
150 |
setOpenGroupRows(initialOpenGroups)
|
151 |
-
|
152 |
-
|
153 |
-
|
|
|
|
|
154 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
setError(null)
|
156 |
} catch (err: any) {
|
157 |
setError('Failed to parse benchmark data, please try again: ' + err.message)
|
@@ -159,19 +219,18 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
159 |
}, [benchmarkData])
|
160 |
|
161 |
const handleRowSort = (overallMetric: string, model: string) => {
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
})
|
175 |
}
|
176 |
|
177 |
// Helper to generate a stable composite key for row-based column sorting
|
@@ -179,219 +238,613 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
179 |
group: string | null,
|
180 |
subGroup: string | null,
|
181 |
metric: string | null
|
182 |
-
) {
|
183 |
return `${group ?? ''}||${subGroup ?? ''}||${metric ?? ''}`
|
184 |
}
|
185 |
|
186 |
-
// Update
|
187 |
const handleColumnSort = (
|
188 |
group: string | null,
|
189 |
subGroup: string | null,
|
190 |
metric: string | null
|
191 |
) => {
|
192 |
const rowKey = getColumnSortRowKey(group, subGroup, metric)
|
193 |
-
|
194 |
-
const prevDir = prev[rowKey]?.direction
|
195 |
-
const newSortState: { [rowKey: string]: { direction: 'asc' | 'desc' } } = {}
|
196 |
-
if (!prevDir) {
|
197 |
-
newSortState[rowKey] = { direction: 'asc' }
|
198 |
-
} else if (prevDir === 'asc') {
|
199 |
-
newSortState[rowKey] = { direction: 'desc' }
|
200 |
-
} else if (prevDir === 'desc') {
|
201 |
-
delete newSortState[rowKey]
|
202 |
-
}
|
203 |
-
return newSortState
|
204 |
-
})
|
205 |
-
}
|
206 |
|
207 |
-
|
208 |
-
|
209 |
-
return selectedRowForSort[getColumnSortRowKey(group, subGroup, metric)] || null
|
210 |
-
}
|
211 |
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
}
|
222 |
-
return null
|
223 |
-
}
|
224 |
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
}
|
234 |
-
return false
|
235 |
})
|
236 |
-
|
237 |
}
|
238 |
|
239 |
-
//
|
240 |
-
const
|
241 |
-
|
242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
|
244 |
-
|
245 |
-
|
246 |
-
|
|
|
247 |
for (const overall of overallMetrics) {
|
248 |
if (metric.endsWith(`_${overall}`) || metric === overall) {
|
249 |
-
return false
|
250 |
}
|
251 |
}
|
252 |
return true
|
253 |
})
|
254 |
-
}
|
255 |
|
256 |
// Calculate average and standard deviation for a set of metrics for a specific column
|
257 |
-
const calculateStats = (
|
258 |
-
metricNames: string[],
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
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 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
|
|
|
|
|
|
|
|
322 |
}
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
})
|
330 |
-
}
|
331 |
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
return false
|
348 |
})
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 |
})
|
388 |
-
}
|
389 |
-
|
390 |
-
|
391 |
-
sortedModels || tableHeader.filter((model) => selectedModels.has(model))
|
392 |
})
|
393 |
|
394 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
395 |
|
396 |
return (
|
397 |
<div className="rounded">
|
@@ -424,7 +877,7 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
424 |
qualityMetrics={findQualityMetrics()}
|
425 |
tableHeader={tableHeader}
|
426 |
selectedModels={selectedModels}
|
427 |
-
tableRows={
|
428 |
/>
|
429 |
|
430 |
{/* Main metrics table */}
|
@@ -432,104 +885,7 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
432 |
<button
|
433 |
className="absolute top-0 right-0 btn btn-ghost btn-circle"
|
434 |
title="Export CSV"
|
435 |
-
onClick={
|
436 |
-
// Export the main metrics table as displayed
|
437 |
-
// Build header row
|
438 |
-
|
439 |
-
const header = [
|
440 |
-
'Attack Categories',
|
441 |
-
...visibleMetrics.flatMap((metric) => modelOrderByOverallMetric[metric]),
|
442 |
-
]
|
443 |
-
// Build data rows
|
444 |
-
const rows: (string | number)[][] = []
|
445 |
-
groupEntries.forEach(([group, subGroups]) => {
|
446 |
-
// Group row
|
447 |
-
const allGroupMetrics = Object.values(subGroups).flat()
|
448 |
-
const visibleGroupMetrics = filterMetricsByGroupAndSubgroup(
|
449 |
-
allGroupMetrics,
|
450 |
-
group
|
451 |
-
)
|
452 |
-
if (visibleGroupMetrics.length === 0) return
|
453 |
-
// Group row label
|
454 |
-
const groupRow: (string | number)[] = [group]
|
455 |
-
visibleMetrics.forEach((metric) => {
|
456 |
-
modelOrderByOverallMetric[metric].forEach((col) => {
|
457 |
-
const allMetricsWithName = findAllMetricsForName(metric)
|
458 |
-
const metricsInGroupForThisMetric = visibleGroupMetrics.filter((m) =>
|
459 |
-
allMetricsWithName.includes(m)
|
460 |
-
)
|
461 |
-
const stats = calculateStats(metricsInGroupForThisMetric, col)
|
462 |
-
groupRow.push(
|
463 |
-
!isNaN(stats.avg)
|
464 |
-
? `${stats.avg.toFixed(3)} Β± ${stats.stdDev.toFixed(3)}`
|
465 |
-
: 'N/A'
|
466 |
-
)
|
467 |
-
})
|
468 |
-
})
|
469 |
-
rows.push(groupRow)
|
470 |
-
// Subgroup rows
|
471 |
-
let subGroupEntries = Object.entries(subGroups)
|
472 |
-
subGroupEntries.forEach(([subGroup, metrics]) => {
|
473 |
-
const visibleSubgroupMetrics = filterMetricsByGroupAndSubgroup(
|
474 |
-
metrics,
|
475 |
-
group,
|
476 |
-
subGroup
|
477 |
-
)
|
478 |
-
if (visibleSubgroupMetrics.length === 0) return
|
479 |
-
const subGroupRow: (string | number)[] = [' ' + subGroup] // Indent subgroup
|
480 |
-
visibleMetrics.forEach((metric) => {
|
481 |
-
modelOrderByOverallMetric[metric].forEach((col) => {
|
482 |
-
const allMetricsWithName = findAllMetricsForName(metric)
|
483 |
-
const metricsInSubgroupForThisMetric = visibleSubgroupMetrics.filter(
|
484 |
-
(m) => allMetricsWithName.includes(m)
|
485 |
-
)
|
486 |
-
const stats = calculateStats(metricsInSubgroupForThisMetric, col)
|
487 |
-
subGroupRow.push(
|
488 |
-
!isNaN(stats.avg)
|
489 |
-
? `${stats.avg.toFixed(3)} Β± ${stats.stdDev.toFixed(3)}`
|
490 |
-
: 'N/A'
|
491 |
-
)
|
492 |
-
})
|
493 |
-
})
|
494 |
-
rows.push(subGroupRow)
|
495 |
-
// Individual metric rows
|
496 |
-
visibleSubgroupMetrics.forEach((metric) => {
|
497 |
-
const row = tableRows.find((r) => r.metric === metric)
|
498 |
-
if (!row) return
|
499 |
-
const metricRow: (string | number)[] = [' ' + metric] // Indent metric
|
500 |
-
visibleMetrics.forEach((oMetric) => {
|
501 |
-
if (!findAllMetricsForName(oMetric).includes(metric)) {
|
502 |
-
modelOrderByOverallMetric[oMetric].forEach(() => metricRow.push(''))
|
503 |
-
} else {
|
504 |
-
modelOrderByOverallMetric[oMetric].forEach((col) => {
|
505 |
-
const cell = row[col]
|
506 |
-
metricRow.push(
|
507 |
-
!isNaN(Number(cell)) ? Number(Number(cell).toFixed(3)) : cell
|
508 |
-
)
|
509 |
-
})
|
510 |
-
}
|
511 |
-
})
|
512 |
-
rows.push(metricRow)
|
513 |
-
})
|
514 |
-
})
|
515 |
-
})
|
516 |
-
// CSV encode
|
517 |
-
const csv = [header, ...rows]
|
518 |
-
.map((row) =>
|
519 |
-
row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(',')
|
520 |
-
)
|
521 |
-
.join('\n')
|
522 |
-
// Download
|
523 |
-
const blob = new Blob([csv], { type: 'text/csv' })
|
524 |
-
const url = URL.createObjectURL(blob)
|
525 |
-
const a = document.createElement('a')
|
526 |
-
a.href = url
|
527 |
-
a.download = 'leaderboard_metrics.csv'
|
528 |
-
document.body.appendChild(a)
|
529 |
-
a.click()
|
530 |
-
document.body.removeChild(a)
|
531 |
-
URL.revokeObjectURL(url)
|
532 |
-
}}
|
533 |
>
|
534 |
<ArrowDownTrayIcon className="h-6 w-6" />
|
535 |
</button>
|
@@ -541,241 +897,64 @@ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, sele
|
|
541 |
<th className="sticky left-0 top-0 bg-base-100 z-20 border border-gray-700">
|
542 |
Attack Categories
|
543 |
</th>
|
|
|
544 |
{overallMetrics
|
545 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
546 |
.map((metric) => (
|
547 |
<th
|
548 |
key={`header-metric-${metric}`}
|
549 |
className="sticky top-0 bg-base-100 z-10 text-center text-xs border border-gray-700 select-none"
|
550 |
-
colSpan={modelOrderByOverallMetric[metric].length}
|
551 |
>
|
552 |
-
|
|
|
|
|
|
|
553 |
</th>
|
554 |
))}
|
555 |
</tr>
|
|
|
556 |
<tr>
|
557 |
<th className="sticky left-0 top-12 bg-base-100 z-30 border border-gray-700"></th>
|
558 |
-
{
|
559 |
-
.
|
560 |
-
.
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
>
|
571 |
-
{model}
|
572 |
-
<span className="ml-1">
|
573 |
-
{isSorted ? (direction === 'asc' ? 'β' : 'β') : 'β
'}
|
574 |
-
</span>
|
575 |
-
</th>
|
576 |
-
)
|
577 |
-
})}
|
578 |
-
</React.Fragment>
|
579 |
))}
|
580 |
</tr>
|
581 |
</thead>
|
582 |
<tbody>
|
583 |
-
{
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
let subGroupEntries = Object.entries(subGroups)
|
601 |
-
if (groupSortConfig) {
|
602 |
-
const allMetricsWithName = findAllMetricsForName(
|
603 |
-
groupSortConfig.overallMetric
|
604 |
-
)
|
605 |
-
const getSubGroupAvg = (metrics: string[]) => {
|
606 |
-
const metricsInSubGroupForThisMetric = metrics.filter((m) =>
|
607 |
-
allMetricsWithName.includes(m)
|
608 |
-
)
|
609 |
-
const stats = calculateStats(
|
610 |
-
metricsInSubGroupForThisMetric,
|
611 |
-
groupSortConfig.model
|
612 |
-
)
|
613 |
-
return stats.avg
|
614 |
-
}
|
615 |
-
subGroupEntries = subGroupEntries.sort(([, metricsA], [, metricsB]) => {
|
616 |
-
const avgA = getSubGroupAvg(metricsA)
|
617 |
-
const avgB = getSubGroupAvg(metricsB)
|
618 |
-
if (isNaN(avgA) && isNaN(avgB)) return 0
|
619 |
-
if (isNaN(avgA)) return 1
|
620 |
-
if (isNaN(avgB)) return -1
|
621 |
-
return groupSortConfig.direction === 'asc' ? avgA - avgB : avgB - avgA
|
622 |
-
})
|
623 |
-
}
|
624 |
-
|
625 |
-
return (
|
626 |
-
<React.Fragment key={group}>
|
627 |
-
{/* Group row with average stats for the entire group */}
|
628 |
-
<tr
|
629 |
-
className="bg-base-200 cursor-pointer hover:bg-base-300"
|
630 |
-
onClick={() =>
|
631 |
-
setOpenGroupRows((prev) => ({ ...prev, [group]: !prev[group] }))
|
632 |
-
}
|
633 |
>
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
className="ml-1 cursor-pointer"
|
640 |
-
onClick={(e) => {
|
641 |
-
e.stopPropagation()
|
642 |
-
handleColumnSort(group, null, null)
|
643 |
-
}}
|
644 |
-
title={
|
645 |
-
getColumnSort(group, null, null)
|
646 |
-
? getColumnSort(group, null, null)?.direction === 'asc'
|
647 |
-
? 'Sort descending'
|
648 |
-
: 'Clear sort'
|
649 |
-
: 'Sort by this row'
|
650 |
-
}
|
651 |
-
>
|
652 |
-
{getColumnSort(group, null, null)
|
653 |
-
? getColumnSort(group, null, null)?.direction === 'asc'
|
654 |
-
? 'β'
|
655 |
-
: 'β'
|
656 |
-
: 'β'}
|
657 |
-
</span>
|
658 |
-
</td>
|
659 |
-
{/* For each metric column */}
|
660 |
-
{overallMetrics
|
661 |
-
.filter((metric) => selectedOverallMetrics.has(metric))
|
662 |
-
.map((metric) => {
|
663 |
-
const rowKey = getColumnSortRowKey(group, null, null)
|
664 |
-
return (
|
665 |
-
<React.Fragment key={`${group}-${metric}`}>
|
666 |
-
{modelOrderByOverallMetric[metric].map((col: string) => {
|
667 |
-
const allMetricsWithName = findAllMetricsForName(metric)
|
668 |
-
const metricsInGroupForThisMetric =
|
669 |
-
visibleGroupMetrics.filter((m) =>
|
670 |
-
allMetricsWithName.includes(m)
|
671 |
-
)
|
672 |
-
const stats = calculateStats(metricsInGroupForThisMetric, col)
|
673 |
-
return (
|
674 |
-
<td
|
675 |
-
key={`${group}-${metric}-${col}`}
|
676 |
-
className="font-medium text-center border-gray-700 border"
|
677 |
-
>
|
678 |
-
{!isNaN(stats.avg)
|
679 |
-
? `${stats.avg.toFixed(3)} Β± ${stats.stdDev.toFixed(3)}`
|
680 |
-
: 'N/A'}
|
681 |
-
</td>
|
682 |
-
)
|
683 |
-
})}
|
684 |
-
</React.Fragment>
|
685 |
-
)
|
686 |
-
})}
|
687 |
-
</tr>
|
688 |
-
|
689 |
-
{/* Only render subgroups if group row is open */}
|
690 |
-
{openGroupRows[group] &&
|
691 |
-
subGroupEntries.map(([subGroup, metrics]) => {
|
692 |
-
// Filter to only include selected metrics in this subgroup row
|
693 |
-
const visibleSubgroupMetrics = filterMetricsByGroupAndSubgroup(
|
694 |
-
metrics,
|
695 |
-
group,
|
696 |
-
subGroup
|
697 |
-
)
|
698 |
-
|
699 |
-
// Skip this subgroup row if no metrics are selected
|
700 |
-
if (visibleSubgroupMetrics.length === 0) return null
|
701 |
-
|
702 |
-
return (
|
703 |
-
<React.Fragment key={`${group}-${subGroup}`}>
|
704 |
-
{/* Subgroup row with average stats for the subgroup */}
|
705 |
-
<tr
|
706 |
-
className="bg-base-100 hover:bg-base-200"
|
707 |
-
// onClick={() => toggleSubGroup(group, subGroup)}
|
708 |
-
>
|
709 |
-
<td className="sticky left-0 bg-base-100 z-10 pl-6 font-medium flex items-center gap-1">
|
710 |
-
{/* <span>
|
711 |
-
{openSubGroupRows[group]?.[subGroup] ? 'βΌ ' : 'βΆ '}
|
712 |
-
</span> */}
|
713 |
-
<span className="flex-1">{subGroup}</span>
|
714 |
-
<span
|
715 |
-
className="ml-1 cursor-pointer"
|
716 |
-
onClick={(e) => {
|
717 |
-
e.stopPropagation()
|
718 |
-
handleColumnSort(group, subGroup, null)
|
719 |
-
}}
|
720 |
-
title={
|
721 |
-
getColumnSort(group, subGroup, null)
|
722 |
-
? getColumnSort(group, subGroup, null)?.direction ===
|
723 |
-
'asc'
|
724 |
-
? 'Sort descending'
|
725 |
-
: 'Clear sort'
|
726 |
-
: 'Sort by this row'
|
727 |
-
}
|
728 |
-
>
|
729 |
-
{getColumnSort(group, subGroup, null)
|
730 |
-
? getColumnSort(group, subGroup, null)?.direction ===
|
731 |
-
'asc'
|
732 |
-
? 'β'
|
733 |
-
: 'β'
|
734 |
-
: 'β'}
|
735 |
-
</span>
|
736 |
-
</td>
|
737 |
-
{/* For each metric column */}
|
738 |
-
{overallMetrics
|
739 |
-
.filter((metric) => selectedOverallMetrics.has(metric))
|
740 |
-
.map((metric) => {
|
741 |
-
return (
|
742 |
-
<React.Fragment key={`${group}-${subGroup}-${metric}`}>
|
743 |
-
{modelOrderByOverallMetric[metric].map(
|
744 |
-
(col: string) => {
|
745 |
-
const allMetricsWithName =
|
746 |
-
findAllMetricsForName(metric)
|
747 |
-
const metricsInSubgroupForThisMetric =
|
748 |
-
visibleSubgroupMetrics.filter((m) =>
|
749 |
-
allMetricsWithName.includes(m)
|
750 |
-
)
|
751 |
-
const stats = calculateStats(
|
752 |
-
metricsInSubgroupForThisMetric,
|
753 |
-
col
|
754 |
-
)
|
755 |
-
return (
|
756 |
-
<td
|
757 |
-
key={`${group}-${subGroup}-${metric}-${col}`}
|
758 |
-
className="font-medium text-center border-gray-700 border"
|
759 |
-
>
|
760 |
-
{!isNaN(stats.avg)
|
761 |
-
? `${stats.avg.toFixed(3)} Β± ${stats.stdDev.toFixed(3)}`
|
762 |
-
: 'N/A'}
|
763 |
-
</td>
|
764 |
-
)
|
765 |
-
}
|
766 |
-
)}
|
767 |
-
</React.Fragment>
|
768 |
-
)
|
769 |
-
})}
|
770 |
-
</tr>
|
771 |
-
|
772 |
-
{/* Individual metric rows, currently removed in favor of aggregate */}
|
773 |
-
</React.Fragment>
|
774 |
-
)
|
775 |
-
})}
|
776 |
-
</React.Fragment>
|
777 |
-
)
|
778 |
-
})}
|
779 |
</tbody>
|
780 |
</table>
|
781 |
</div>
|
|
|
1 |
+
/**
|
2 |
+
* LeaderboardTable.tsx
|
3 |
+
*
|
4 |
+
* This component displays a structured table with hierarchical data (groups, subgroups, metrics)
|
5 |
+
* and provides two independent sorting mechanisms:
|
6 |
+
*
|
7 |
+
* 1. Row Sorting: Clicking on a column header (model name) sorts the rows
|
8 |
+
* - Implemented using TanStack Table's built-in sorting
|
9 |
+
* - Controls which rows appear first in the table
|
10 |
+
* - Groups sort against other groups based on their values
|
11 |
+
* - Subgroups stay with their parent group but sort within the group
|
12 |
+
*
|
13 |
+
* 2. Column Sorting: Clicking on a row header sorts the columns (models)
|
14 |
+
* - Custom implementation using modelOrderByOverallMetric
|
15 |
+
* - Controls the order of models (columns) for each metric
|
16 |
+
* - Completely independent of row sorting
|
17 |
+
*
|
18 |
+
* Both sorting mechanisms operate independently and can be used simultaneously.
|
19 |
+
*/
|
20 |
+
import React, { useEffect, useState, useMemo, useCallback } from 'react'
|
21 |
import { ArrowDownTrayIcon } from '@heroicons/react/24/solid'
|
22 |
import QualityMetricsTable from './QualityMetricsTable'
|
23 |
+
import MetricInfoIcon from './MetricInfoIcon'
|
24 |
+
import {
|
25 |
+
createColumnHelper,
|
26 |
+
flexRender,
|
27 |
+
getCoreRowModel,
|
28 |
+
useReactTable,
|
29 |
+
ColumnDef,
|
30 |
+
} from '@tanstack/react-table'
|
31 |
|
32 |
interface LeaderboardTableProps {
|
33 |
benchmarkData: any
|
34 |
selectedModels: Set<string>
|
35 |
}
|
36 |
|
37 |
+
// Original Row interface - used for the raw data
|
38 |
+
interface OriginalRow {
|
39 |
metric: string
|
40 |
[key: string]: string | number
|
41 |
}
|
42 |
|
43 |
+
// New TableRow interface for the structured hierarchical data
|
44 |
+
interface TableRow {
|
45 |
+
id: string
|
46 |
+
type: 'group' | 'subgroup' | 'metric'
|
47 |
+
groupId?: string
|
48 |
+
subgroupId?: string
|
49 |
+
metricName?: string
|
50 |
+
name: string
|
51 |
+
visible: boolean
|
52 |
+
depth: number
|
53 |
+
isExpanded?: boolean
|
54 |
+
[key: string]: any
|
55 |
+
}
|
56 |
+
|
57 |
interface Groups {
|
58 |
[group: string]: { [subgroup: string]: string[] }
|
59 |
}
|
60 |
|
61 |
+
// For sorting rows (used when clicking column headers)
|
62 |
+
interface RowSortState {
|
63 |
+
columnId: string
|
64 |
+
direction: 'asc' | 'desc'
|
65 |
+
}
|
66 |
+
|
67 |
+
// For sorting columns (used when clicking row headers)
|
68 |
+
interface ColumnSortState {
|
69 |
+
rowKey: string
|
70 |
+
direction: 'asc' | 'desc'
|
71 |
}
|
72 |
|
73 |
const OVERALL_ROW = 'Overall'
|
|
|
102 |
checked={selectedOverallMetrics.has(metric)}
|
103 |
onChange={() => toggleMetric(metric)}
|
104 |
/>
|
105 |
+
<div className="flex items-center truncate">
|
106 |
+
<span className="truncate" title={metric}>
|
107 |
+
{metric}
|
108 |
+
</span>
|
109 |
+
<MetricInfoIcon metricName={metric} />
|
110 |
+
</div>
|
111 |
</label>
|
112 |
))}
|
113 |
</div>
|
|
|
117 |
}
|
118 |
|
119 |
const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ benchmarkData, selectedModels }) => {
|
120 |
+
const [rawRows, setRawRows] = useState<OriginalRow[]>([])
|
121 |
const [tableHeader, setTableHeader] = useState<string[]>([])
|
122 |
const [error, setError] = useState<string | null>(null)
|
123 |
const [groupRows, setGroupRows] = useState<Groups>({})
|
124 |
const [openGroupRows, setOpenGroupRows] = useState<{ [key: string]: boolean }>({})
|
125 |
+
|
|
|
|
|
126 |
const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
|
127 |
const [overallMetrics, setOverallMetrics] = useState<string[]>([])
|
128 |
+
const [selectedOverallMetrics, setSelectedOverallMetrics] =
|
129 |
+
useState<Set<string>>(DEFAULT_SELECTED_METRICS)
|
130 |
+
const [rowSortState, setRowSortState] = useState<RowSortState | null>(null)
|
131 |
+
const [columnSortState, setColumnSortState] = useState<ColumnSortState | null>(null)
|
132 |
+
const [modelOrderByOverallMetric, setModelOrderByOverallMetric] = useState<{
|
133 |
+
[key: string]: string[]
|
134 |
}>({})
|
135 |
|
136 |
+
// Get filtered models based on selectedModels
|
137 |
+
const models = useMemo(() => {
|
138 |
+
return tableHeader.filter((model) => selectedModels.has(model))
|
139 |
+
}, [tableHeader, selectedModels])
|
140 |
|
141 |
+
// Parse benchmark data when it changes
|
142 |
useEffect(() => {
|
143 |
if (!benchmarkData) {
|
144 |
return
|
145 |
}
|
146 |
try {
|
147 |
const data = benchmarkData
|
148 |
+
const rows: OriginalRow[] = data['rows']
|
149 |
const allGroups = data['groups'] as { [key: string]: string[] }
|
150 |
const { Overall: overallGroup, ...groups } = allGroups
|
151 |
const uniqueMetrics = new Set<string>()
|
|
|
187 |
const allKeys: string[] = Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
|
188 |
const headers = allKeys.filter((key) => key !== 'metric')
|
189 |
const initialOpenGroups: { [key: string]: boolean } = {}
|
|
|
190 |
Object.keys(groupsData).forEach((group) => {
|
191 |
initialOpenGroups[group] = false
|
|
|
|
|
|
|
|
|
192 |
})
|
193 |
const allMetrics = Object.values(allGroups).flat()
|
194 |
setSelectedMetrics(new Set(allMetrics))
|
195 |
setTableHeader(headers)
|
196 |
+
setRawRows(rows)
|
197 |
setGroupRows(groupsData)
|
198 |
setOpenGroupRows(initialOpenGroups)
|
199 |
+
|
200 |
+
// Initialize row sort state for Overall group
|
201 |
+
setColumnSortState({
|
202 |
+
rowKey: getColumnSortRowKey(OVERALL_ROW, null, null),
|
203 |
+
direction: 'asc',
|
204 |
})
|
205 |
+
|
206 |
+
// Initialize model order by overall metric
|
207 |
+
const metricOrders: { [key: string]: string[] } = {}
|
208 |
+
Array.from(uniqueMetrics).forEach((metric) => {
|
209 |
+
metricOrders[metric] = [...headers]
|
210 |
+
})
|
211 |
+
|
212 |
+
// Store the original model order for resetting when sort is cleared
|
213 |
+
setModelOrderByOverallMetric(metricOrders)
|
214 |
+
|
215 |
setError(null)
|
216 |
} catch (err: any) {
|
217 |
setError('Failed to parse benchmark data, please try again: ' + err.message)
|
|
|
219 |
}, [benchmarkData])
|
220 |
|
221 |
const handleRowSort = (overallMetric: string, model: string) => {
|
222 |
+
// Create the column ID for this metric-model combination
|
223 |
+
const columnId = `${overallMetric}-${model}`
|
224 |
+
let nextDirection: 'asc' | 'desc' | null = null
|
225 |
+
if (!rowSortState || rowSortState.columnId !== columnId) {
|
226 |
+
nextDirection = 'asc'
|
227 |
+
} else if (rowSortState.direction === 'asc') {
|
228 |
+
nextDirection = 'desc'
|
229 |
+
} else {
|
230 |
+
nextDirection = null
|
231 |
+
}
|
232 |
+
|
233 |
+
setRowSortState(nextDirection ? { columnId, direction: nextDirection } : null)
|
|
|
234 |
}
|
235 |
|
236 |
// Helper to generate a stable composite key for row-based column sorting
|
|
|
238 |
group: string | null,
|
239 |
subGroup: string | null,
|
240 |
metric: string | null
|
241 |
+
): string {
|
242 |
return `${group ?? ''}||${subGroup ?? ''}||${metric ?? ''}`
|
243 |
}
|
244 |
|
245 |
+
// Update the column order when a row's sort icon is clicked
|
246 |
const handleColumnSort = (
|
247 |
group: string | null,
|
248 |
subGroup: string | null,
|
249 |
metric: string | null
|
250 |
) => {
|
251 |
const rowKey = getColumnSortRowKey(group, subGroup, metric)
|
252 |
+
console.log('Column sort clicked:', { group, subGroup, metric, rowKey })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
+
// First determine the new sort direction
|
255 |
+
let newDirection: 'asc' | 'desc' | null = null
|
|
|
|
|
256 |
|
257 |
+
if (!columnSortState || columnSortState.rowKey !== rowKey) {
|
258 |
+
// New sort, start with ascending
|
259 |
+
newDirection = 'asc'
|
260 |
+
} else if (columnSortState.direction === 'asc') {
|
261 |
+
// Toggle from ascending to descending
|
262 |
+
newDirection = 'desc'
|
263 |
+
} else {
|
264 |
+
// Toggle from descending to null (clear sort)
|
265 |
+
newDirection = null
|
266 |
}
|
|
|
|
|
267 |
|
268 |
+
setColumnSortState(newDirection ? { rowKey, direction: newDirection } : null)
|
269 |
+
|
270 |
+
// If clearing the sort, reset to default column order for this metric only
|
271 |
+
if (!newDirection && metric) {
|
272 |
+
setModelOrderByOverallMetric((prev) => {
|
273 |
+
const newOrder = { ...prev }
|
274 |
+
newOrder[metric] = [...tableHeader.filter((model) => selectedModels.has(model))]
|
275 |
+
return newOrder
|
|
|
|
|
276 |
})
|
277 |
+
}
|
278 |
}
|
279 |
|
280 |
+
// Find all metrics matching a particular extracted metric name (like "log10_p_value")
|
281 |
+
const findAllMetricsForName = useCallback(
|
282 |
+
(metricName: string): string[] => {
|
283 |
+
return rawRows
|
284 |
+
.filter((row) => {
|
285 |
+
const metric = row.metric as string
|
286 |
+
if (metric.includes('_')) {
|
287 |
+
const extractedName = metric.split('_').slice(1).join('_')
|
288 |
+
return extractedName.endsWith(metricName)
|
289 |
+
}
|
290 |
+
return false
|
291 |
+
})
|
292 |
+
.map((row) => row.metric as string)
|
293 |
+
},
|
294 |
+
[rawRows]
|
295 |
+
)
|
296 |
|
297 |
+
// Identify metrics that don't belong to any overall metric group
|
298 |
+
const findQualityMetrics = useCallback((): string[] => {
|
299 |
+
const allMetrics = rawRows.map((row) => row.metric as string)
|
300 |
+
return allMetrics.filter((metric: string) => {
|
301 |
for (const overall of overallMetrics) {
|
302 |
if (metric.endsWith(`_${overall}`) || metric === overall) {
|
303 |
+
return false
|
304 |
}
|
305 |
}
|
306 |
return true
|
307 |
})
|
308 |
+
}, [rawRows, overallMetrics])
|
309 |
|
310 |
// Calculate average and standard deviation for a set of metrics for a specific column
|
311 |
+
const calculateStats = useCallback(
|
312 |
+
(metricNames: string[], columnKey: string): { avg: number; stdDev: number } => {
|
313 |
+
const values = metricNames
|
314 |
+
.map((metricName) => {
|
315 |
+
const row = rawRows.find((row) => row.metric === metricName)
|
316 |
+
return row ? Number(row[columnKey]) : NaN
|
317 |
+
})
|
318 |
+
.filter((value) => !isNaN(value))
|
319 |
+
if (values.length === 0) return { avg: NaN, stdDev: NaN }
|
320 |
+
const avg = values.reduce((sum, val) => sum + val, 0) / values.length
|
321 |
+
const squareDiffs = values.map((value) => {
|
322 |
+
const diff = value - avg
|
323 |
+
return diff * diff
|
324 |
})
|
325 |
+
const variance = squareDiffs.reduce((sum, sqrDiff) => sum + sqrDiff, 0) / values.length
|
326 |
+
const stdDev = Math.sqrt(variance)
|
327 |
+
return { avg, stdDev }
|
328 |
+
},
|
329 |
+
[rawRows]
|
330 |
+
)
|
331 |
|
332 |
+
// Filter metrics by group and/or subgroup
|
333 |
+
const filterMetricsByGroupAndSubgroup = useCallback(
|
334 |
+
(
|
335 |
+
metricNames: string[],
|
336 |
+
group: string | null = null,
|
337 |
+
subgroup: string | null = null
|
338 |
+
): string[] => {
|
339 |
+
if (!group) return metricNames
|
340 |
+
const groupMetrics = Object.values(groupRows[group] || {}).flat() as string[]
|
341 |
+
if (subgroup && groupRows[group]?.[subgroup]) {
|
342 |
+
return metricNames.filter(
|
343 |
+
(metric) => groupRows[group][subgroup].includes(metric) && selectedMetrics.has(metric)
|
344 |
+
)
|
345 |
+
}
|
346 |
+
return metricNames.filter(
|
347 |
+
(metric) => groupMetrics.includes(metric) && selectedMetrics.has(metric)
|
348 |
+
)
|
349 |
+
},
|
350 |
+
[groupRows, selectedMetrics]
|
351 |
+
)
|
352 |
|
353 |
+
// Compute visible metrics for rendering
|
354 |
+
const visibleMetrics = overallMetrics.filter((metric) => selectedOverallMetrics.has(metric))
|
355 |
|
356 |
+
// Generate data for the table
|
357 |
+
const tableData = useMemo(() => {
|
358 |
+
const rows: TableRow[] = []
|
359 |
+
let groupEntries = Object.entries(groupRows)
|
360 |
+
// --- Manual row sorting using rowSortState ---
|
361 |
+
if (rowSortState) {
|
362 |
+
const { columnId, direction } = rowSortState
|
363 |
+
const [metric, model] = columnId.split('-')
|
364 |
+
groupEntries = [...groupEntries].sort(([groupA, subGroupsA], [groupB, subGroupsB]) => {
|
365 |
+
const allGroupMetricsA = Object.values(subGroupsA).flat()
|
366 |
+
const allGroupMetricsB = Object.values(subGroupsB).flat()
|
367 |
+
const allMetricsWithNameA = findAllMetricsForName(metric)
|
368 |
+
const allMetricsWithNameB = allMetricsWithNameA
|
369 |
+
const metricsInGroupA = allGroupMetricsA.filter((m) => allMetricsWithNameA.includes(m))
|
370 |
+
const metricsInGroupB = allGroupMetricsB.filter((m) => allMetricsWithNameB.includes(m))
|
371 |
+
const statsA = calculateStats(metricsInGroupA, model)
|
372 |
+
const statsB = calculateStats(metricsInGroupB, model)
|
373 |
+
const valueA = !isNaN(statsA.avg) ? statsA.avg : -Infinity
|
374 |
+
const valueB = !isNaN(statsB.avg) ? statsB.avg : -Infinity
|
375 |
+
return direction === 'asc' ? valueA - valueB : valueB - valueA
|
376 |
+
})
|
377 |
+
}
|
378 |
+
groupEntries.forEach(([group, subGroups]) => {
|
379 |
+
const allGroupMetrics = Object.values(subGroups).flat()
|
380 |
+
const visibleGroupMetrics = filterMetricsByGroupAndSubgroup(allGroupMetrics, group)
|
381 |
+
if (visibleGroupMetrics.length === 0) return
|
382 |
+
const groupRow: TableRow = {
|
383 |
+
id: `group-${group}`,
|
384 |
+
type: 'group',
|
385 |
+
name: group,
|
386 |
+
visible: true,
|
387 |
+
depth: 0,
|
388 |
+
isExpanded: openGroupRows[group],
|
389 |
+
}
|
390 |
+
selectedOverallMetrics.forEach((metric) => {
|
391 |
+
if (overallMetrics.includes(metric)) {
|
392 |
+
models.forEach((model) => {
|
393 |
+
const allMetricsWithName = findAllMetricsForName(metric)
|
394 |
+
const metricsInGroupForThisMetric = visibleGroupMetrics.filter((m) =>
|
395 |
+
allMetricsWithName.includes(m)
|
396 |
+
)
|
397 |
+
const stats = calculateStats(metricsInGroupForThisMetric, model)
|
398 |
+
groupRow[`${metric}-${model}`] = !isNaN(stats.avg)
|
399 |
+
? { avg: stats.avg, stdDev: stats.stdDev }
|
400 |
+
: null
|
401 |
+
})
|
402 |
+
}
|
403 |
+
})
|
404 |
+
rows.push(groupRow)
|
405 |
+
if (openGroupRows[group]) {
|
406 |
+
let subGroupEntries = Object.entries(subGroups).sort(([a], [b]) => a.localeCompare(b))
|
407 |
+
if (rowSortState) {
|
408 |
+
const { columnId, direction } = rowSortState
|
409 |
+
const [metric, model] = columnId.split('-')
|
410 |
+
subGroupEntries = [...subGroupEntries].sort(([subA, metricsA], [subB, metricsB]) => {
|
411 |
+
const allMetricsWithName = findAllMetricsForName(metric)
|
412 |
+
const metricsInSubgroupA = metricsA.filter((m) => allMetricsWithName.includes(m))
|
413 |
+
const metricsInSubgroupB = metricsB.filter((m) => allMetricsWithName.includes(m))
|
414 |
+
const statsA = calculateStats(metricsInSubgroupA, model)
|
415 |
+
const statsB = calculateStats(metricsInSubgroupB, model)
|
416 |
+
const valueA = !isNaN(statsA.avg) ? statsA.avg : -Infinity
|
417 |
+
const valueB = !isNaN(statsB.avg) ? statsB.avg : -Infinity
|
418 |
+
return direction === 'asc' ? valueA - valueB : valueB - valueA
|
419 |
+
})
|
420 |
+
}
|
421 |
+
subGroupEntries.forEach(([subGroup, metrics]) => {
|
422 |
+
const visibleSubgroupMetrics = filterMetricsByGroupAndSubgroup(metrics, group, subGroup)
|
423 |
+
if (visibleSubgroupMetrics.length === 0) return
|
424 |
+
const subgroupRow: TableRow = {
|
425 |
+
id: `group-${group}-subgroup-${subGroup}`,
|
426 |
+
type: 'subgroup',
|
427 |
+
groupId: group,
|
428 |
+
name: subGroup,
|
429 |
+
visible: true,
|
430 |
+
depth: 1,
|
431 |
+
isExpanded: false,
|
432 |
+
}
|
433 |
+
selectedOverallMetrics.forEach((metric) => {
|
434 |
+
if (overallMetrics.includes(metric)) {
|
435 |
+
models.forEach((model) => {
|
436 |
+
const allMetricsWithName = findAllMetricsForName(metric)
|
437 |
+
const metricsInSubgroupForThisMetric = visibleSubgroupMetrics.filter((m) =>
|
438 |
+
allMetricsWithName.includes(m)
|
439 |
+
)
|
440 |
+
const stats = calculateStats(metricsInSubgroupForThisMetric, model)
|
441 |
+
subgroupRow[`${metric}-${model}`] = !isNaN(stats.avg)
|
442 |
+
? { avg: stats.avg, stdDev: stats.stdDev }
|
443 |
+
: null
|
444 |
+
})
|
445 |
+
}
|
446 |
+
})
|
447 |
+
rows.push(subgroupRow)
|
448 |
+
})
|
449 |
+
}
|
450 |
})
|
451 |
+
return rows
|
452 |
+
}, [
|
453 |
+
rawRows,
|
454 |
+
groupRows,
|
455 |
+
openGroupRows,
|
456 |
+
selectedOverallMetrics,
|
457 |
+
selectedMetrics,
|
458 |
+
models,
|
459 |
+
columnSortState,
|
460 |
+
modelOrderByOverallMetric,
|
461 |
+
rowSortState,
|
462 |
+
])
|
463 |
+
|
464 |
+
// Effect: update model order when columnSortState or dependencies change
|
465 |
+
useEffect(() => {
|
466 |
+
console.log(columnSortState)
|
467 |
+
if (!columnSortState) return
|
468 |
+
// Parse out group, subGroup, metric from rowKey
|
469 |
+
const [group, subGroup, metric] = columnSortState.rowKey.split('||').map((v) => v || null)
|
470 |
+
const newDirection = columnSortState.direction
|
471 |
+
console.log(newDirection, group, subGroup, metric)
|
472 |
+
if (!newDirection) return // Only run if a sort direction is present
|
473 |
+
|
474 |
+
// Update model order for all visible metrics
|
475 |
+
const metricsToUpdate = Array.from(selectedOverallMetrics)
|
476 |
+
|
477 |
+
// Find the row in tableData that was clicked for sorting
|
478 |
+
let rowToSort: TableRow | undefined
|
479 |
+
|
480 |
+
if (group && subGroup && !metric) {
|
481 |
+
// Subgroup row
|
482 |
+
rowToSort = tableData.find(
|
483 |
+
(row) => row.type === 'subgroup' && row.groupId === group && row.name === subGroup
|
484 |
)
|
485 |
+
} else if (group && !subGroup && !metric) {
|
486 |
+
// Group row
|
487 |
+
rowToSort = tableData.find((row) => row.type === 'group' && row.name === group)
|
488 |
+
} else if (metric) {
|
489 |
+
// Metric row - not currently in tableData, handled differently
|
490 |
+
rowToSort = undefined
|
491 |
}
|
492 |
|
493 |
+
if (!rowToSort && !metric) {
|
494 |
+
console.log('Row to sort not found', {
|
495 |
+
group,
|
496 |
+
subGroup,
|
497 |
+
metric,
|
498 |
+
rowKey: columnSortState.rowKey,
|
499 |
+
})
|
500 |
|
501 |
+
// Try to proceed anyway with group/subgroup sorting
|
502 |
+
if (group) {
|
503 |
+
metricsToUpdate.forEach((metricName) => {
|
504 |
+
// Get existing model order
|
505 |
+
const currentOrder = modelOrderByOverallMetric[metricName] || [...models]
|
506 |
+
|
507 |
+
// For group/subgroup with no row found, keep current model order but reverse it if changing direction
|
508 |
+
if (newDirection === 'asc') {
|
509 |
+
setModelOrderByOverallMetric((prev) => ({
|
510 |
+
...prev,
|
511 |
+
[metricName]: [...currentOrder],
|
512 |
+
}))
|
513 |
+
} else {
|
514 |
+
setModelOrderByOverallMetric((prev) => ({
|
515 |
+
...prev,
|
516 |
+
[metricName]: [...currentOrder].reverse(),
|
517 |
+
}))
|
518 |
+
}
|
519 |
+
})
|
520 |
}
|
521 |
+
return
|
522 |
+
}
|
523 |
+
|
524 |
+
// Check if rowToSort has all the expected metrics
|
525 |
+
for (const metricName of metricsToUpdate) {
|
526 |
+
if (
|
527 |
+
!rowToSort ||
|
528 |
+
!models.some((model) => rowToSort[`${metricName}-${model}`] !== undefined)
|
529 |
+
) {
|
530 |
+
console.log(`Row does not have metric values for ${metricName}`, rowToSort)
|
531 |
+
}
|
532 |
+
}
|
533 |
+
|
534 |
+
// Sort the models for each metric
|
535 |
+
const newOrders: { [key: string]: string[] } = {}
|
536 |
+
|
537 |
+
metricsToUpdate.forEach((metricName) => {
|
538 |
+
// Sort models based on the values in the clicked row
|
539 |
+
const modelScores: { model: string; score: number }[] = models.map((model: string) => {
|
540 |
+
let score = -Infinity
|
541 |
+
|
542 |
+
if (rowToSort) {
|
543 |
+
// For group/subgroup rows, use the aggregated values in the row for each metric
|
544 |
+
const value: { avg: number; stdDev: number } | null =
|
545 |
+
rowToSort[`${metricName}-${model}`] ?? null
|
546 |
+
score = value && !isNaN(value.avg) ? value.avg : -Infinity
|
547 |
+
} else if (metric) {
|
548 |
+
// For metric rows (which aren't in tableData), we need a different approach
|
549 |
+
// Find metrics for this group that have this metric name
|
550 |
+
const allMetricsWithName = findAllMetricsForName(metric)
|
551 |
+
if (allMetricsWithName.length > 0) {
|
552 |
+
const values = allMetricsWithName
|
553 |
+
.map((metricId) => {
|
554 |
+
const row = rawRows.find((r) => r.metric === metricId)
|
555 |
+
return row ? Number(row[model]) : NaN
|
556 |
+
})
|
557 |
+
.filter((val) => !isNaN(val))
|
558 |
+
|
559 |
+
if (values.length > 0) {
|
560 |
+
const avg = values.reduce((sum, val) => sum + val, 0) / values.length
|
561 |
+
score = !isNaN(avg) ? avg : -Infinity
|
562 |
+
}
|
563 |
+
}
|
564 |
+
}
|
565 |
+
|
566 |
+
return { model, score }
|
567 |
+
})
|
568 |
+
|
569 |
+
modelScores.sort((a, b) => (newDirection === 'asc' ? a.score - b.score : b.score - a.score))
|
570 |
+
newOrders[metricName] = modelScores
|
571 |
+
.map((item) => item.model)
|
572 |
+
.filter((m) => selectedModels.has(m))
|
573 |
})
|
|
|
574 |
|
575 |
+
// Only update if any order actually changed
|
576 |
+
setModelOrderByOverallMetric((prev) => {
|
577 |
+
let changed = false
|
578 |
+
const next = { ...prev }
|
579 |
+
|
580 |
+
metricsToUpdate.forEach((metricName) => {
|
581 |
+
const currentOrder = prev[metricName] || []
|
582 |
+
const newOrder = newOrders[metricName] || []
|
583 |
+
const arraysEqual = (a: string[], b: string[]) =>
|
584 |
+
a.length === b.length && a.every((v, i) => v === b[i])
|
585 |
+
|
586 |
+
if (!arraysEqual(currentOrder, newOrder)) {
|
587 |
+
next[metricName] = [...newOrder]
|
588 |
+
changed = true
|
589 |
+
}
|
|
|
590 |
})
|
591 |
+
|
592 |
+
return changed ? next : prev
|
593 |
+
})
|
594 |
+
}, [
|
595 |
+
columnSortState,
|
596 |
+
models,
|
597 |
+
selectedModels,
|
598 |
+
modelOrderByOverallMetric,
|
599 |
+
tableData,
|
600 |
+
rawRows,
|
601 |
+
selectedOverallMetrics,
|
602 |
+
])
|
603 |
+
|
604 |
+
console.log(modelOrderByOverallMetric)
|
605 |
+
|
606 |
+
// CSV export function
|
607 |
+
const exportToCsv = () => {
|
608 |
+
// Build header row
|
609 |
+
const header = [
|
610 |
+
'Attack Categories',
|
611 |
+
...overallMetrics
|
612 |
+
.filter((metric) => selectedOverallMetrics.has(metric))
|
613 |
+
.flatMap((metric) => {
|
614 |
+
const metricModels = modelOrderByOverallMetric[metric] || models
|
615 |
+
return metricModels.map((model) => `${metric} - ${model}`)
|
616 |
+
}),
|
617 |
+
]
|
618 |
+
|
619 |
+
// Build data rows
|
620 |
+
const rows: (string | number)[][] = []
|
621 |
+
tableData.forEach((row) => {
|
622 |
+
const csvRow: (string | number)[] = [row.name]
|
623 |
+
|
624 |
+
overallMetrics
|
625 |
+
.filter((metric) => selectedOverallMetrics.has(metric))
|
626 |
+
.forEach((metric) => {
|
627 |
+
const metricModels = modelOrderByOverallMetric[metric] || models
|
628 |
+
metricModels.forEach((model: string) => {
|
629 |
+
const value = row[`${metric}-${model}`] as { avg: number; stdDev: number } | null
|
630 |
+
|
631 |
+
if (!value) {
|
632 |
+
csvRow.push('N/A')
|
633 |
+
} else {
|
634 |
+
csvRow.push(`${value.avg.toFixed(3)} Β± ${value.stdDev.toFixed(3)}`)
|
635 |
+
}
|
636 |
})
|
637 |
+
})
|
638 |
+
|
639 |
+
rows.push(csvRow)
|
|
|
640 |
})
|
641 |
|
642 |
+
// Generate CSV
|
643 |
+
const csv = [header, ...rows]
|
644 |
+
.map((row) => row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(','))
|
645 |
+
.join('\n')
|
646 |
+
|
647 |
+
// Download
|
648 |
+
const blob = new Blob([csv], { type: 'text/csv' })
|
649 |
+
const url = URL.createObjectURL(blob)
|
650 |
+
const a = document.createElement('a')
|
651 |
+
a.href = url
|
652 |
+
a.download = 'leaderboard_metrics.csv'
|
653 |
+
document.body.appendChild(a)
|
654 |
+
a.click()
|
655 |
+
document.body.removeChild(a)
|
656 |
+
URL.revokeObjectURL(url)
|
657 |
+
}
|
658 |
+
|
659 |
+
// Toggle group expansion
|
660 |
+
const toggleGroup = (group: string) => {
|
661 |
+
setOpenGroupRows((prev) => ({
|
662 |
+
...prev,
|
663 |
+
[group]: !prev[group],
|
664 |
+
}))
|
665 |
+
}
|
666 |
+
|
667 |
+
// Helper to get current column sort config for a row
|
668 |
+
function getColumnSort(group: string | null, subGroup: string | null, metric: string | null) {
|
669 |
+
const rowKey = getColumnSortRowKey(group, subGroup, metric)
|
670 |
+
return columnSortState && columnSortState.rowKey === rowKey ? columnSortState : null
|
671 |
+
}
|
672 |
+
|
673 |
+
// Prepare columns for TanStack Table
|
674 |
+
const columns = useMemo<any[]>(() => {
|
675 |
+
const columnHelper = createColumnHelper<TableRow>()
|
676 |
+
const cols: any[] = []
|
677 |
+
cols.push(
|
678 |
+
columnHelper.accessor((row) => row.name, {
|
679 |
+
id: 'category',
|
680 |
+
header: () => 'Attack Categories',
|
681 |
+
cell: (info) => {
|
682 |
+
const row = info.row.original as TableRow
|
683 |
+
const depth = row.depth || 0
|
684 |
+
if (row.type === 'group') {
|
685 |
+
return (
|
686 |
+
<div
|
687 |
+
className="sticky left-0 font-medium cursor-pointer select-none flex items-center"
|
688 |
+
onClick={() => toggleGroup(row.name)}
|
689 |
+
>
|
690 |
+
<span>{row.isExpanded ? 'βΌ ' : 'βΆ '}</span>
|
691 |
+
<span className="flex-1">{row.name}</span>{' '}
|
692 |
+
<span
|
693 |
+
className="ml-1 cursor-pointer font-bold"
|
694 |
+
onClick={(e) => {
|
695 |
+
e.stopPropagation()
|
696 |
+
handleColumnSort(row.name, null, null)
|
697 |
+
}}
|
698 |
+
title={
|
699 |
+
getColumnSort(row.name, null, null)
|
700 |
+
? getColumnSort(row.name, null, null)?.direction === 'asc'
|
701 |
+
? 'Currently sorting models by this row in ascending order (low to high). Click for descending order.'
|
702 |
+
: 'Currently sorting models by this row in descending order (high to low). Click to clear sort.'
|
703 |
+
: 'Click to sort models by values in this row (independent of row sorting)'
|
704 |
+
}
|
705 |
+
>
|
706 |
+
{getColumnSort(row.name, null, null)
|
707 |
+
? getColumnSort(row.name, null, null)?.direction === 'asc'
|
708 |
+
? 'β'
|
709 |
+
: 'β'
|
710 |
+
: 'β'}
|
711 |
+
</span>
|
712 |
+
</div>
|
713 |
+
)
|
714 |
+
} else if (row.type === 'subgroup') {
|
715 |
+
return (
|
716 |
+
<div className="sticky left-0 pl-6 font-medium flex items-center gap-1">
|
717 |
+
<span className="flex-1">{row.name}</span>
|
718 |
+
<span
|
719 |
+
className="ml-1 cursor-pointer font-bold"
|
720 |
+
onClick={(e) => {
|
721 |
+
e.stopPropagation()
|
722 |
+
handleColumnSort(row.groupId!, row.name, null)
|
723 |
+
}}
|
724 |
+
title={
|
725 |
+
getColumnSort(row.groupId!, row.name, null)
|
726 |
+
? getColumnSort(row.groupId!, row.name, null)?.direction === 'asc'
|
727 |
+
? 'Currently sorting models by this subgroup in ascending order (low to high). Click for descending order.'
|
728 |
+
: 'Currently sorting models by this subgroup in descending order (high to low). Click to clear sort.'
|
729 |
+
: 'Click to sort models by values in this subgroup (independent of row sorting)'
|
730 |
+
}
|
731 |
+
>
|
732 |
+
{getColumnSort(row.groupId!, row.name, null)
|
733 |
+
? getColumnSort(row.groupId!, row.name, null)?.direction === 'asc'
|
734 |
+
? 'β'
|
735 |
+
: 'β'
|
736 |
+
: 'β'}
|
737 |
+
</span>
|
738 |
+
</div>
|
739 |
+
)
|
740 |
+
} else {
|
741 |
+
// Metric row (add column sorting for model order)
|
742 |
+
return (
|
743 |
+
<div className="sticky left-0 pl-12 font-medium flex items-center gap-1">
|
744 |
+
<span className="flex-1">{row.name}</span>
|
745 |
+
<span
|
746 |
+
className="ml-1 cursor-pointer font-bold"
|
747 |
+
onClick={(e) => {
|
748 |
+
e.stopPropagation()
|
749 |
+
handleColumnSort(
|
750 |
+
row.groupId ?? null,
|
751 |
+
row.subgroupId ?? null,
|
752 |
+
row.metricName ?? row.name
|
753 |
+
)
|
754 |
+
}}
|
755 |
+
title={
|
756 |
+
getColumnSort(
|
757 |
+
row.groupId ?? null,
|
758 |
+
row.subgroupId ?? null,
|
759 |
+
row.metricName ?? row.name
|
760 |
+
)
|
761 |
+
? getColumnSort(
|
762 |
+
row.groupId ?? null,
|
763 |
+
row.subgroupId ?? null,
|
764 |
+
row.metricName ?? row.name
|
765 |
+
)?.direction === 'asc'
|
766 |
+
? 'Currently sorting models by this metric in ascending order (low to high). Click for descending order.'
|
767 |
+
: 'Currently sorting models by this metric in descending order (high to low). Click to clear sort.'
|
768 |
+
: 'Click to sort models by values in this metric (independent of row sorting)'
|
769 |
+
}
|
770 |
+
>
|
771 |
+
{getColumnSort(
|
772 |
+
row.groupId ?? null,
|
773 |
+
row.subgroupId ?? null,
|
774 |
+
row.metricName ?? row.name
|
775 |
+
)
|
776 |
+
? getColumnSort(
|
777 |
+
row.groupId ?? null,
|
778 |
+
row.subgroupId ?? null,
|
779 |
+
row.metricName ?? row.name
|
780 |
+
)?.direction === 'asc'
|
781 |
+
? 'β'
|
782 |
+
: 'β'
|
783 |
+
: 'β'}
|
784 |
+
</span>
|
785 |
+
</div>
|
786 |
+
)
|
787 |
+
}
|
788 |
+
},
|
789 |
+
})
|
790 |
+
)
|
791 |
+
overallMetrics
|
792 |
+
.filter((metric) => selectedOverallMetrics.has(metric))
|
793 |
+
.forEach((metric) => {
|
794 |
+
const metricModels = modelOrderByOverallMetric[metric] || models
|
795 |
+
metricModels.forEach((model: string) => {
|
796 |
+
cols.push(
|
797 |
+
columnHelper.accessor((row) => row[`${metric}-${model}`], {
|
798 |
+
id: `${metric}-${model}`,
|
799 |
+
header: () => {
|
800 |
+
const isSorted = rowSortState && rowSortState.columnId === `${metric}-${model}`
|
801 |
+
const direction = rowSortState ? rowSortState.direction : 'desc'
|
802 |
+
return (
|
803 |
+
<div
|
804 |
+
className="cursor-pointer select-none"
|
805 |
+
onClick={() => handleRowSort(metric, model)}
|
806 |
+
>
|
807 |
+
{model}
|
808 |
+
<span
|
809 |
+
className="ml-1 font-bold"
|
810 |
+
title={
|
811 |
+
isSorted
|
812 |
+
? direction === 'asc'
|
813 |
+
? 'Currently sorting rows by this column in ascending order (low to high). Click for descending order.'
|
814 |
+
: 'Currently sorting rows by this column in descending order (high to low). Click to clear sort.'
|
815 |
+
: 'Click to sort rows by values in this column (subgroups always stay with their parent group)'
|
816 |
+
}
|
817 |
+
>
|
818 |
+
{isSorted ? (direction === 'asc' ? 'β' : 'β') : 'β
'}
|
819 |
+
</span>
|
820 |
+
</div>
|
821 |
+
)
|
822 |
+
},
|
823 |
+
cell: (info) => {
|
824 |
+
const value = info.getValue() as { avg: number; stdDev: number } | null
|
825 |
+
if (!value) return 'N/A'
|
826 |
+
return `${value.avg.toFixed(3)} Β± ${value.stdDev.toFixed(3)}`
|
827 |
+
},
|
828 |
+
})
|
829 |
+
)
|
830 |
+
})
|
831 |
+
})
|
832 |
+
return cols
|
833 |
+
}, [
|
834 |
+
selectedOverallMetrics,
|
835 |
+
overallMetrics,
|
836 |
+
modelOrderByOverallMetric,
|
837 |
+
rowSortState,
|
838 |
+
columnSortState,
|
839 |
+
models,
|
840 |
+
])
|
841 |
+
|
842 |
+
// Create the table instance
|
843 |
+
const table = useReactTable({
|
844 |
+
data: tableData,
|
845 |
+
columns,
|
846 |
+
getCoreRowModel: getCoreRowModel(),
|
847 |
+
})
|
848 |
|
849 |
return (
|
850 |
<div className="rounded">
|
|
|
877 |
qualityMetrics={findQualityMetrics()}
|
878 |
tableHeader={tableHeader}
|
879 |
selectedModels={selectedModels}
|
880 |
+
tableRows={rawRows}
|
881 |
/>
|
882 |
|
883 |
{/* Main metrics table */}
|
|
|
885 |
<button
|
886 |
className="absolute top-0 right-0 btn btn-ghost btn-circle"
|
887 |
title="Export CSV"
|
888 |
+
onClick={exportToCsv}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
889 |
>
|
890 |
<ArrowDownTrayIcon className="h-6 w-6" />
|
891 |
</button>
|
|
|
897 |
<th className="sticky left-0 top-0 bg-base-100 z-20 border border-gray-700">
|
898 |
Attack Categories
|
899 |
</th>
|
900 |
+
{/* Add metric group headers */}
|
901 |
{overallMetrics
|
902 |
.filter((metric) => selectedOverallMetrics.has(metric))
|
903 |
.map((metric) => (
|
904 |
<th
|
905 |
key={`header-metric-${metric}`}
|
906 |
className="sticky top-0 bg-base-100 z-10 text-center text-xs border border-gray-700 select-none"
|
907 |
+
colSpan={(modelOrderByOverallMetric[metric] || models).length}
|
908 |
>
|
909 |
+
<div className="flex items-center justify-center">
|
910 |
+
<span>{metric}</span>
|
911 |
+
<MetricInfoIcon metricName={metric} />
|
912 |
+
</div>
|
913 |
</th>
|
914 |
))}
|
915 |
</tr>
|
916 |
+
{/* Add model headers */}
|
917 |
<tr>
|
918 |
<th className="sticky left-0 top-12 bg-base-100 z-30 border border-gray-700"></th>
|
919 |
+
{table
|
920 |
+
.getHeaderGroups()[0]
|
921 |
+
.headers.slice(1)
|
922 |
+
.map((header) => (
|
923 |
+
<th
|
924 |
+
key={header.id}
|
925 |
+
className="sticky top-12 bg-base-100 z-10 text-center text-xs border border-gray-700"
|
926 |
+
>
|
927 |
+
{header.isPlaceholder
|
928 |
+
? null
|
929 |
+
: flexRender(header.column.columnDef.header, header.getContext())}
|
930 |
+
</th>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
931 |
))}
|
932 |
</tr>
|
933 |
</thead>
|
934 |
<tbody>
|
935 |
+
{table.getRowModel().rows.map((row) => (
|
936 |
+
<tr
|
937 |
+
key={row.id}
|
938 |
+
className={`${
|
939 |
+
row.original.type === 'group'
|
940 |
+
? 'bg-base-200 hover:bg-base-300'
|
941 |
+
: 'bg-base-100 hover:bg-base-200'
|
942 |
+
}`}
|
943 |
+
>
|
944 |
+
{row.getVisibleCells().map((cell) => (
|
945 |
+
<td
|
946 |
+
key={cell.id}
|
947 |
+
className={`${
|
948 |
+
cell.column.id === 'category'
|
949 |
+
? `sticky left-0 ${row.original.type === 'group' ? 'bg-base-200' : 'bg-base-100'} z-10`
|
950 |
+
: 'font-medium text-center'
|
951 |
+
} border-gray-700 border`}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
952 |
>
|
953 |
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
954 |
+
</td>
|
955 |
+
))}
|
956 |
+
</tr>
|
957 |
+
))}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
958 |
</tbody>
|
959 |
</table>
|
960 |
</div>
|
frontend/src/components/LeaderboardTabs.tsx
DELETED
File without changes
|
frontend/src/components/MetricInfoIcon.tsx
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useRef, useEffect, useState } from 'react'
|
2 |
+
import { InformationCircleIcon, DocumentTextIcon } from '@heroicons/react/24/outline'
|
3 |
+
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
4 |
+
import 'react-tooltip/dist/react-tooltip.css'
|
5 |
+
import Descriptions from '../Descriptions'
|
6 |
+
|
7 |
+
interface MetricInfoIconProps {
|
8 |
+
metricName: string
|
9 |
+
}
|
10 |
+
|
11 |
+
const MetricInfoIcon: React.FC<MetricInfoIconProps> = ({ metricName }) => {
|
12 |
+
const [descriptionsLoaded, setDescriptionsLoaded] = useState(false)
|
13 |
+
const descriptions = useRef(Descriptions.getInstance())
|
14 |
+
|
15 |
+
useEffect(() => {
|
16 |
+
descriptions.current.load().then(() => setDescriptionsLoaded(true))
|
17 |
+
}, [])
|
18 |
+
|
19 |
+
const fullName = descriptions.current.getFullName(metricName) || metricName
|
20 |
+
const description = descriptions.current.getDescription(metricName)
|
21 |
+
const paperUrl = descriptions.current.getUrl(metricName)
|
22 |
+
|
23 |
+
if (!description) return null
|
24 |
+
|
25 |
+
return (
|
26 |
+
<>
|
27 |
+
<span
|
28 |
+
className="ml-1 cursor-pointer"
|
29 |
+
data-tooltip-id={`tooltip-metric-${metricName}`}
|
30 |
+
tabIndex={0}
|
31 |
+
aria-label={`Show info for ${metricName}`}
|
32 |
+
role="button"
|
33 |
+
>
|
34 |
+
<InformationCircleIcon className="h-4 w-4 text-blue-400 hover:text-blue-600" />
|
35 |
+
</span>
|
36 |
+
<ReactTooltip
|
37 |
+
id={`tooltip-metric-${metricName}`}
|
38 |
+
place="top"
|
39 |
+
className="z-[10000] max-w-xs !opacity-100 bg-base-100 text-base-content"
|
40 |
+
style={{
|
41 |
+
boxShadow: '0 0 10px rgba(0,0,0,0.2)',
|
42 |
+
zIndex: 10000, // Ensure tooltips appear above sticky elements
|
43 |
+
}}
|
44 |
+
positionStrategy="fixed"
|
45 |
+
clickable={true}
|
46 |
+
>
|
47 |
+
<div className="p-2 text-xs text-left relative z-[10000]">
|
48 |
+
<div className="font-semibold mb-1">{fullName}</div>
|
49 |
+
<div className="whitespace-pre-line mb-2">{description}</div>
|
50 |
+
{paperUrl && (
|
51 |
+
<div>
|
52 |
+
<a
|
53 |
+
href={paperUrl}
|
54 |
+
target="_blank"
|
55 |
+
rel="noopener noreferrer"
|
56 |
+
className="text-blue-400 hover:text-blue-300 underline flex items-center"
|
57 |
+
>
|
58 |
+
<DocumentTextIcon className="h-3 w-3 mr-1" />
|
59 |
+
Link
|
60 |
+
</a>
|
61 |
+
</div>
|
62 |
+
)}
|
63 |
+
</div>
|
64 |
+
</ReactTooltip>
|
65 |
+
</>
|
66 |
+
)
|
67 |
+
}
|
68 |
+
|
69 |
+
export default MetricInfoIcon
|
frontend/src/components/ModelFilter.tsx
CHANGED
@@ -1,4 +1,6 @@
|
|
1 |
-
import React from 'react'
|
|
|
|
|
2 |
|
3 |
interface ModelFilterProps {
|
4 |
models: string[]
|
@@ -7,6 +9,13 @@ interface ModelFilterProps {
|
|
7 |
}
|
8 |
|
9 |
const ModelFilter: React.FC<ModelFilterProps> = ({ models, selectedModels, setSelectedModels }) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
const toggleModel = (model: string) => {
|
11 |
const newSelected = new Set(selectedModels)
|
12 |
if (newSelected.has(model)) {
|
@@ -23,20 +32,31 @@ const ModelFilter: React.FC<ModelFilterProps> = ({ models, selectedModels, setSe
|
|
23 |
<legend className="fieldset-legend font-semibold">
|
24 |
Models ({selectedModels.size}/{models.length})
|
25 |
</legend>
|
26 |
-
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-1 max-h-48
|
27 |
-
{models.map((model) =>
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
</div>
|
41 |
</fieldset>
|
42 |
</div>
|
|
|
1 |
+
import React, { useState, useRef, useEffect } from 'react'
|
2 |
+
import Descriptions from '../Descriptions'
|
3 |
+
import ModelInfoIcon from './ModelInfoIcon'
|
4 |
|
5 |
interface ModelFilterProps {
|
6 |
models: string[]
|
|
|
9 |
}
|
10 |
|
11 |
const ModelFilter: React.FC<ModelFilterProps> = ({ models, selectedModels, setSelectedModels }) => {
|
12 |
+
const [descriptionsLoaded, setDescriptionsLoaded] = useState(false)
|
13 |
+
const descriptions = useRef(Descriptions.getInstance())
|
14 |
+
|
15 |
+
useEffect(() => {
|
16 |
+
descriptions.current.load().then(() => setDescriptionsLoaded(true))
|
17 |
+
}, [])
|
18 |
+
|
19 |
const toggleModel = (model: string) => {
|
20 |
const newSelected = new Set(selectedModels)
|
21 |
if (newSelected.has(model)) {
|
|
|
32 |
<legend className="fieldset-legend font-semibold">
|
33 |
Models ({selectedModels.size}/{models.length})
|
34 |
</legend>
|
35 |
+
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-1 max-h-48 pr-2">
|
36 |
+
{models.map((model) => {
|
37 |
+
const fullName = descriptions.current.getModelFullName(model) || model
|
38 |
+
const description = descriptions.current.getModelDescription(model)
|
39 |
+
const paperUrl = descriptions.current.getModelPaperUrl(model)
|
40 |
+
const githubUrl = descriptions.current.getModelGithubUrl(model)
|
41 |
+
return (
|
42 |
+
<div key={model} className="flex items-center gap-2 text-sm relative group">
|
43 |
+
<label className="flex items-center gap-2 flex-grow">
|
44 |
+
<input
|
45 |
+
type="checkbox"
|
46 |
+
className="form-checkbox h-4 w-4"
|
47 |
+
checked={selectedModels.has(model)}
|
48 |
+
onChange={() => toggleModel(model)}
|
49 |
+
/>
|
50 |
+
<div className="flex items-center">
|
51 |
+
<span className="truncate" title={fullName}>
|
52 |
+
{model}
|
53 |
+
</span>
|
54 |
+
<ModelInfoIcon modelName={model} />
|
55 |
+
</div>
|
56 |
+
</label>
|
57 |
+
</div>
|
58 |
+
)
|
59 |
+
})}
|
60 |
</div>
|
61 |
</fieldset>
|
62 |
</div>
|
frontend/src/components/ModelInfoIcon.tsx
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useRef, useEffect, useState } from 'react'
|
2 |
+
import { InformationCircleIcon, DocumentTextIcon } from '@heroicons/react/24/outline'
|
3 |
+
import GitHubIcon from './icons/GitHubIcon'
|
4 |
+
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
5 |
+
import 'react-tooltip/dist/react-tooltip.css'
|
6 |
+
import Descriptions from '../Descriptions'
|
7 |
+
|
8 |
+
interface ModelInfoIconProps {
|
9 |
+
modelName: string
|
10 |
+
}
|
11 |
+
|
12 |
+
const ModelInfoIcon: React.FC<ModelInfoIconProps> = ({ modelName }) => {
|
13 |
+
const [descriptionsLoaded, setDescriptionsLoaded] = useState(false)
|
14 |
+
const descriptions = useRef(Descriptions.getInstance())
|
15 |
+
|
16 |
+
useEffect(() => {
|
17 |
+
descriptions.current.load().then(() => setDescriptionsLoaded(true))
|
18 |
+
}, [])
|
19 |
+
|
20 |
+
const fullName = descriptions.current.getModelFullName(modelName) || modelName
|
21 |
+
const description = descriptions.current.getModelDescription(modelName)
|
22 |
+
const paperUrl = descriptions.current.getModelPaperUrl(modelName)
|
23 |
+
const githubUrl = descriptions.current.getModelGithubUrl(modelName)
|
24 |
+
|
25 |
+
return (
|
26 |
+
<>
|
27 |
+
<span
|
28 |
+
className="ml-1 cursor-pointer"
|
29 |
+
data-tooltip-id={`tooltip-${modelName}`}
|
30 |
+
tabIndex={0}
|
31 |
+
aria-label={`Show info for ${modelName}`}
|
32 |
+
role="button"
|
33 |
+
>
|
34 |
+
<InformationCircleIcon className="h-4 w-4 text-blue-400 hover:text-blue-600" />
|
35 |
+
</span>
|
36 |
+
<ReactTooltip
|
37 |
+
id={`tooltip-${modelName}`}
|
38 |
+
place="top"
|
39 |
+
className="z-[10000] max-w-xs !opacity-100 bg-base-100 text-base-content"
|
40 |
+
style={{
|
41 |
+
boxShadow: '0 0 10px rgba(0,0,0,0.2)',
|
42 |
+
zIndex: 10000, // Ensure tooltips appear above sticky elements
|
43 |
+
}}
|
44 |
+
openOnClick={false}
|
45 |
+
clickable={true}
|
46 |
+
delayHide={200}
|
47 |
+
positionStrategy="fixed"
|
48 |
+
>
|
49 |
+
<div className="p-2 text-xs text-left relative z-[10000]">
|
50 |
+
<div className="font-semibold mb-1">{fullName}</div>
|
51 |
+
<div className="mb-2 whitespace-pre-line">
|
52 |
+
{description || 'No description available.'}
|
53 |
+
</div>
|
54 |
+
<div className="flex space-x-4">
|
55 |
+
{paperUrl && (
|
56 |
+
<div>
|
57 |
+
<a
|
58 |
+
href={paperUrl}
|
59 |
+
target="_blank"
|
60 |
+
rel="noopener noreferrer"
|
61 |
+
className="text-blue-400 hover:text-blue-300 underline flex items-center"
|
62 |
+
>
|
63 |
+
<DocumentTextIcon className="h-3 w-3 mr-1" />
|
64 |
+
Paper
|
65 |
+
</a>
|
66 |
+
</div>
|
67 |
+
)}
|
68 |
+
{githubUrl && (
|
69 |
+
<div>
|
70 |
+
<a
|
71 |
+
href={githubUrl}
|
72 |
+
target="_blank"
|
73 |
+
rel="noopener noreferrer"
|
74 |
+
className="text-blue-400 hover:text-blue-300 underline flex items-center"
|
75 |
+
>
|
76 |
+
<GitHubIcon className="h-3 w-3 mr-1" />
|
77 |
+
GitHub
|
78 |
+
</a>
|
79 |
+
</div>
|
80 |
+
)}
|
81 |
+
</div>
|
82 |
+
</div>
|
83 |
+
</ReactTooltip>
|
84 |
+
</>
|
85 |
+
)
|
86 |
+
}
|
87 |
+
|
88 |
+
export default ModelInfoIcon
|
frontend/src/components/QualityMetricsTable.tsx
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import React, { useState } from 'react'
|
2 |
import { ArrowDownTrayIcon } from '@heroicons/react/24/outline'
|
|
|
3 |
|
4 |
interface Row {
|
5 |
metric: string
|
@@ -113,7 +114,7 @@ const QualityMetricsTable: React.FC<QualityMetricsTableProps> = ({
|
|
113 |
|
114 |
if (qualityMetrics.length === 0) return null
|
115 |
return (
|
116 |
-
<div className="
|
117 |
<div className="flex justify-end">
|
118 |
<button className="btn btn-ghost btn-circle" title="Export CSV" onClick={exportToCSV}>
|
119 |
<ArrowDownTrayIcon className="h-6 w-6" />
|
@@ -155,9 +156,9 @@ const QualityMetricsTable: React.FC<QualityMetricsTableProps> = ({
|
|
155 |
const isSorted = rowSort && rowSort.metric === metric
|
156 |
const direction = isSorted ? rowSort.direction : undefined
|
157 |
return (
|
158 |
-
<tr key={`quality-${metric}`} className="hover:bg-base-100">
|
159 |
<td
|
160 |
-
className="sticky left-0 bg-base-100 z-10 border-gray-700 border cursor-pointer select-none pr-4"
|
161 |
onClick={() => handleRowSort(metric)}
|
162 |
title={
|
163 |
isSorted
|
@@ -167,17 +168,20 @@ const QualityMetricsTable: React.FC<QualityMetricsTableProps> = ({
|
|
167 |
: 'Sort by this row (sorts columns)'
|
168 |
}
|
169 |
>
|
170 |
-
<
|
171 |
-
|
172 |
-
{
|
173 |
-
|
|
|
|
|
|
|
174 |
</td>
|
175 |
{sortedModels.map((col) => {
|
176 |
const cell = row[col]
|
177 |
return (
|
178 |
<td
|
179 |
key={`quality-${metric}-${col}`}
|
180 |
-
className="text-center border-gray-700 border"
|
181 |
>
|
182 |
{!isNaN(Number(cell)) ? Number(Number(cell).toFixed(3)) : cell}
|
183 |
</td>
|
|
|
1 |
import React, { useState } from 'react'
|
2 |
import { ArrowDownTrayIcon } from '@heroicons/react/24/outline'
|
3 |
+
import MetricInfoIcon from './MetricInfoIcon'
|
4 |
|
5 |
interface Row {
|
6 |
metric: string
|
|
|
114 |
|
115 |
if (qualityMetrics.length === 0) return null
|
116 |
return (
|
117 |
+
<div className="max-h-[80vh]">
|
118 |
<div className="flex justify-end">
|
119 |
<button className="btn btn-ghost btn-circle" title="Export CSV" onClick={exportToCSV}>
|
120 |
<ArrowDownTrayIcon className="h-6 w-6" />
|
|
|
156 |
const isSorted = rowSort && rowSort.metric === metric
|
157 |
const direction = isSorted ? rowSort.direction : undefined
|
158 |
return (
|
159 |
+
<tr key={`quality-${metric}`} className="hover:bg-base-100 hover:z-30 relative">
|
160 |
<td
|
161 |
+
className="sticky left-0 bg-base-100 z-10 hover:z-40 border-gray-700 border cursor-pointer select-none pr-4"
|
162 |
onClick={() => handleRowSort(metric)}
|
163 |
title={
|
164 |
isSorted
|
|
|
168 |
: 'Sort by this row (sorts columns)'
|
169 |
}
|
170 |
>
|
171 |
+
<div className="flex items-center">
|
172 |
+
<span className="inline-block">{metric}</span>
|
173 |
+
<MetricInfoIcon metricName={metric} />
|
174 |
+
<span className="ml-auto">
|
175 |
+
{isSorted ? (direction === 'asc' ? 'β' : 'β') : 'β'}
|
176 |
+
</span>
|
177 |
+
</div>
|
178 |
</td>
|
179 |
{sortedModels.map((col) => {
|
180 |
const cell = row[col]
|
181 |
return (
|
182 |
<td
|
183 |
key={`quality-${metric}-${col}`}
|
184 |
+
className="text-center border-gray-700 border hover:z-40 relative"
|
185 |
>
|
186 |
{!isNaN(Number(cell)) ? Number(Number(cell).toFixed(3)) : cell}
|
187 |
</td>
|
frontend/src/components/icons/GitHubIcon.tsx
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react'
|
2 |
+
|
3 |
+
interface GitHubIconProps {
|
4 |
+
className?: string
|
5 |
+
}
|
6 |
+
|
7 |
+
export const GitHubIcon: React.FC<GitHubIconProps> = ({ className = 'h-4 w-4' }) => {
|
8 |
+
return (
|
9 |
+
<svg
|
10 |
+
xmlns="http://www.w3.org/2000/svg"
|
11 |
+
viewBox="0 0 24 24"
|
12 |
+
fill="currentColor"
|
13 |
+
className={className}
|
14 |
+
>
|
15 |
+
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
16 |
+
</svg>
|
17 |
+
)
|
18 |
+
}
|
19 |
+
|
20 |
+
export default GitHubIcon
|
frontend/src/components/icons/github.json
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "GitHub",
|
3 |
+
"svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"/></svg>"
|
4 |
+
}
|
frontend/src/main.tsx
CHANGED
@@ -2,6 +2,7 @@ import React from 'react'
|
|
2 |
import ReactDOM from 'react-dom/client'
|
3 |
import App from './App'
|
4 |
import './index.css'
|
|
|
5 |
|
6 |
ReactDOM.createRoot(document.getElementById('root')!).render(
|
7 |
<React.StrictMode>
|
|
|
2 |
import ReactDOM from 'react-dom/client'
|
3 |
import App from './App'
|
4 |
import './index.css'
|
5 |
+
import 'react-tooltip/dist/react-tooltip.css'
|
6 |
|
7 |
ReactDOM.createRoot(document.getElementById('root')!).render(
|
8 |
<React.StrictMode>
|