Mark Duppenthaler commited on
Commit
44072a9
Β·
1 Parent(s): 9bf569f

Add description tooltips

Browse files
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
- "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,11 +88,11 @@ MODEL_DESCRIPTIONS = {
88
  "paper_link": "https://arxiv.org/abs/2401.17264",
89
  "github_link": "https://github.com/facebookresearch/audioseal",
90
  },
91
- "wavmark": {
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/abs/2308.12770",
95
- "github_link": "https://github.com/swesterfeld/audiowmark",
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 is a GAN-based watermarking method.",
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
- # "github_link": "https://github.com/ando-khachatryan/HiDDeN",
132
  },
133
- "dct_dwt": {
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": "",
138
- },
139
- # Fill this in, these are autogenned
140
- "cine": {
141
- "full_name": "CINE-Watermarking",
142
- "description": "A network inversion-based watermarking method for high-resolution images, offering strong robustness against various image transformations while maintaining visual quality.",
143
- "paper_link": "https://arxiv.org/abs/2402.19414",
144
- "github_link": "",
145
- },
146
- "mbrs": {
147
- "full_name": "Model-Based Robust Steganography (MBRS)",
148
- "description": "A deep learning approach for robust image steganography that maintains high image quality while being resilient to common image distortions.",
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/2405.20977",
156
- "github_link": "https://github.com/facebookresearch/audioseal",
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/2102.05551",
162
- "github_link": "https://github.com/eyalnakar/RivaGAN",
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
- p_value = float(data_none["p_value"])
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
- "p_value": round(p_value, 3),
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
- p_value = float(data_attack["p_value"])
85
  word_acc = data_attack["word_acc"]
86
  bit_acc = data_attack["bit_acc"]
87
 
88
  return {
89
  "detected": det,
90
- "p_value": round(p_value, 3),
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-cPMuOGs4.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-KQYUM4NH.css">
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 = ['p_value', 'bit_acc', 'word_acc']
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
- {k}
 
 
 
40
  </th>
41
  ))}
42
  </tr>
@@ -65,7 +69,7 @@ const ExampleVariantMetricsTables: React.FC<ExampleVariantMetricsTablesProps> =
65
 
66
  return (
67
  <>
68
- {renderTable(accuracyKeys, 'Accuracy Metrics', ['original', 'wmd', 'attacked_wmd'])}
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 key={variant} className="flex items-center gap-1 cursor-pointer">
 
 
 
 
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 md:flex-row gap-4">
101
- <fieldset className="fieldset">
102
- <legend className="fieldset-legend">Model</legend>
103
- <select
104
- className="select select-bordered w-full"
105
- value={selectedModel || ''}
106
- onChange={(e) => setSelectedModel(e.target.value || null)}
107
- >
108
- {Object.keys(examples).map((model) => (
109
- <option key={model} value={model}>
110
- {model}
111
- </option>
112
- ))}
113
- </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  </fieldset>
115
 
116
  {selectedModel && (
117
  <fieldset className="fieldset">
118
  <legend className="fieldset-legend">Attack</legend>
119
  <select
120
- className="select select-bordered w-full"
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={2}
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
- import React, { useEffect, useState } from 'react'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- interface Row {
 
11
  metric: string
12
  [key: string]: string | number
13
  }
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  interface Groups {
16
  [group: string]: { [subgroup: string]: string[] }
17
  }
18
 
19
- interface SortState {
20
- [overallMetric: string]: {
21
- [model: string]: { direction: 'asc' | 'desc' }
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
- <span className="truncate" title={metric}>
58
- {metric}
59
- </span>
 
 
 
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 [tableRows, setTableRows] = useState<Row[]>([])
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
- const [openSubGroupRows, setOpenSubGroupRows] = useState<{
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] = useState<Set<string>>(new Set())
80
- const [sortState, setSortState] = useState<SortState>({})
81
-
82
- // Add state for row-based column sorting
83
- const [selectedRowForSort, setSelectedRowForSort] = useState<{
84
- [rowKey: string]: { direction: 'asc' | 'desc' }
85
  }>({})
86
 
87
- const models = tableHeader.filter((model) => selectedModels.has(model))
 
 
 
88
 
 
89
  useEffect(() => {
90
  if (!benchmarkData) {
91
  return
92
  }
93
  try {
94
  const data = benchmarkData
95
- const rows: Row[] = data['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
- setTableRows(rows)
149
  setGroupRows(groupsData)
150
  setOpenGroupRows(initialOpenGroups)
151
- setOpenSubGroupRows(initialOpenSubGroups)
152
- setSelectedRowForSort({
153
- [getColumnSortRowKey(OVERALL_ROW, null, null)]: { direction: 'asc' },
 
 
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
- setSortState((prev) => {
163
- const prevDir = prev[overallMetric]?.[model]?.direction
164
- let newSortState: SortState = {}
165
- if (!prevDir) {
166
- // No sort yet, set to 'asc'
167
- newSortState[overallMetric] = { [model]: { direction: 'asc' } }
168
- } else if (prevDir === 'asc') {
169
- // Was 'asc', set to 'desc'
170
- newSortState[overallMetric] = { [model]: { direction: 'desc' } }
171
- }
172
- // Else revert back to unsorted state
173
- return newSortState
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 handleColumnSort to use setSelectedRowForSort
187
  const handleColumnSort = (
188
  group: string | null,
189
  subGroup: string | null,
190
  metric: string | null
191
  ) => {
192
  const rowKey = getColumnSortRowKey(group, subGroup, metric)
193
- setSelectedRowForSort((prev) => {
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
- // Helper to get current row sort config for a row
208
- function getColumnSort(group: string | null, subGroup: string | null, metric: string | null) {
209
- return selectedRowForSort[getColumnSortRowKey(group, subGroup, metric)] || null
210
- }
211
 
212
- const getSortConfig = () => {
213
- // Find the first sorted column (overallMetric, model)
214
- for (const overallMetric of overallMetrics) {
215
- if (!selectedOverallMetrics.has(overallMetric)) continue
216
- for (const model of models) {
217
- if (sortState[overallMetric]?.[model]) {
218
- return { overallMetric, model, direction: sortState[overallMetric][model].direction }
219
- }
220
- }
221
  }
222
- return null
223
- }
224
 
225
- // Find all metrics matching a particular extracted metric name (like "log10_p_value")
226
- const findAllMetricsForName = (metricName: string): string[] => {
227
- return tableRows
228
- .filter((row) => {
229
- const metric = row.metric as string
230
- if (metric.includes('_')) {
231
- const extractedName = metric.split('_').slice(1).join('_')
232
- return extractedName.endsWith(metricName)
233
- }
234
- return false
235
  })
236
- .map((row) => row.metric as string)
237
  }
238
 
239
- // Identify metrics that don't belong to any overall metric group
240
- const findQualityMetrics = (): string[] => {
241
- // Get all metrics from the table rows
242
- const allMetrics = tableRows.map((row) => row.metric as string)
 
 
 
 
 
 
 
 
 
 
 
 
243
 
244
- // Filter to only include metrics that aren't part of any of the overall metrics
245
- return allMetrics.filter((metric) => {
246
- // Check if this metric is part of any of the overall metrics
 
247
  for (const overall of overallMetrics) {
248
  if (metric.endsWith(`_${overall}`) || metric === overall) {
249
- return false // This metric belongs to an overall group
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
- columnKey: string
260
- ): { avg: number; stdDev: number } => {
261
- const values = metricNames
262
- .map((metricName) => {
263
- const row = tableRows.find((row) => row.metric === metricName)
264
- return row ? Number(row[columnKey]) : NaN
 
 
 
 
 
265
  })
266
- .filter((value) => !isNaN(value))
 
 
 
 
 
267
 
268
- if (values.length === 0) return { avg: NaN, stdDev: NaN }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
- const avg = values.reduce((sum, val) => sum + val, 0) / values.length
 
271
 
272
- const squareDiffs = values.map((value) => {
273
- const diff = value - avg
274
- return diff * diff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  })
276
- const variance = squareDiffs.reduce((sum, sqrDiff) => sum + sqrDiff, 0) / values.length
277
- const stdDev = Math.sqrt(variance)
278
-
279
- return { avg, stdDev }
280
- }
281
-
282
- // Filter metrics by group and/or subgroup
283
- const filterMetricsByGroupAndSubgroup = (
284
- metricNames: string[],
285
- group: string | null = null,
286
- subgroup: string | null = null
287
- ): string[] => {
288
- // If no group specified, return all metrics
289
- if (!group) return metricNames
290
-
291
- // Get all metrics for the specified group
292
- const groupMetrics = Object.values(groupRows[group] || {}).flat() as string[]
293
-
294
- // If subgroup is specified, further filter to that subgroup
295
- if (subgroup && groupRows[group]?.[subgroup]) {
296
- return metricNames.filter(
297
- (metric) => groupRows[group][subgroup].includes(metric) && selectedMetrics.has(metric)
 
 
 
 
 
 
 
 
 
 
 
298
  )
 
 
 
 
 
 
299
  }
300
 
301
- // Otherwise return all metrics in the group
302
- return metricNames.filter(
303
- (metric) => groupMetrics.includes(metric) && selectedMetrics.has(metric)
304
- )
305
- }
 
 
306
 
307
- // Before rendering group rows:
308
- const groupSortConfig = getSortConfig()
309
- let groupEntries = Object.entries(groupRows)
310
- //.filter(([group]) => group !== OVERALL_ROW) // Keep overall row for now
311
- if (groupSortConfig) {
312
- groupEntries = groupEntries.sort(([groupA, subGroupsA], [groupB, subGroupsB]) => {
313
- // For each group, get all metrics in the group for the selected overallMetric
314
- const allMetricsWithName = findAllMetricsForName(groupSortConfig.overallMetric)
315
- const getGroupAvg = (subGroups: { [key: string]: string[] }) => {
316
- const allGroupMetrics = Object.values(subGroups).flat()
317
- const metricsInGroupForThisMetric = allGroupMetrics.filter((m) =>
318
- allMetricsWithName.includes(m)
319
- )
320
- const stats = calculateStats(metricsInGroupForThisMetric, groupSortConfig.model)
321
- return stats.avg
 
 
 
 
322
  }
323
- const avgA = getGroupAvg(subGroupsA)
324
- const avgB = getGroupAvg(subGroupsB)
325
- if (isNaN(avgA) && isNaN(avgB)) return 0
326
- if (isNaN(avgA)) return 1
327
- if (isNaN(avgB)) return -1
328
- return groupSortConfig.direction === 'asc' ? avgA - avgB : avgB - avgA
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  })
330
- }
331
 
332
- // Compute model order for each overall metric before rendering
333
- const modelOrderByOverallMetric: { [metric: string]: string[] } = {}
334
- overallMetrics
335
- .filter((metric) => selectedOverallMetrics.has(metric))
336
- .forEach((metric) => {
337
- // Check if there is an active row-based column sort for this metric
338
- let sortedModels: string[] | null = null
339
- // Find the active rowKey for this metric in rowColumnSort
340
- const activeRowKey = Object.keys(selectedRowForSort).find((rowKey) => {
341
- // rowKey format: group||subGroup||metric
342
- const [group, subGroup, rowMetric] = rowKey.split('||')
343
- // If rowMetric is empty, it's a group or subgroup row
344
- if (rowMetric === '' && metric === metric) return true
345
- // If rowMetric matches this metric, it's an individual metric row
346
- if (rowMetric && findAllMetricsForName(metric).includes(rowMetric)) return true
347
- return false
348
  })
349
- if (activeRowKey && selectedRowForSort[activeRowKey]) {
350
- const direction = selectedRowForSort[activeRowKey].direction
351
- const [group, subGroup, rowMetric] = activeRowKey.split('||')
352
- if (!rowMetric) {
353
- // Group or subgroup row: sort by average for this group/subgroup and metric
354
- // Find all metrics in this group/subgroup for this overall metric
355
- let relevantMetrics: string[] = []
356
- if (group && !subGroup) {
357
- // Group row
358
- const groupMetrics = Object.values(groupRows[group] || {}).flat() as string[]
359
- relevantMetrics = groupMetrics.filter((m: string) =>
360
- findAllMetricsForName(metric).includes(m)
361
- )
362
- } else if (group && subGroup) {
363
- // Subgroup row
364
- relevantMetrics = (groupRows[group]?.[subGroup] || []).filter((m: string) =>
365
- findAllMetricsForName(metric).includes(m)
366
- )
367
- }
368
- sortedModels = [...models].sort((a, b) => {
369
- const statsA = calculateStats(relevantMetrics, a)
370
- const statsB = calculateStats(relevantMetrics, b)
371
- if (isNaN(statsA.avg) && isNaN(statsB.avg)) return 0
372
- if (isNaN(statsA.avg)) return 1
373
- if (isNaN(statsB.avg)) return -1
374
- return direction === 'asc' ? statsA.avg - statsB.avg : statsB.avg - statsA.avg
375
- })
376
- } else {
377
- // Individual metric row: sort by value for that metric
378
- sortedModels = [...models].sort((a, b) => {
379
- const rowA = tableRows.find((r) => r.metric === rowMetric)
380
- const rowB = rowA // same row
381
- const valA = rowA ? Number(rowA[a]) : NaN
382
- const valB = rowB ? Number(rowB[b]) : NaN
383
- if (isNaN(valA) && isNaN(valB)) return 0
384
- if (isNaN(valA)) return 1
385
- if (isNaN(valB)) return -1
386
- return direction === 'asc' ? valA - valB : valB - valA
 
 
 
 
 
 
 
387
  })
388
- }
389
- }
390
- modelOrderByOverallMetric[metric] =
391
- sortedModels || tableHeader.filter((model) => selectedModels.has(model))
392
  })
393
 
394
- const visibleMetrics = overallMetrics.filter((metric) => selectedOverallMetrics.has(metric))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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={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
- {metric}
 
 
 
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
- {overallMetrics
559
- .filter((metric) => selectedOverallMetrics.has(metric))
560
- .map((metric) => (
561
- <React.Fragment key={`header-models-${metric}`}>
562
- {modelOrderByOverallMetric[metric].map((model) => {
563
- const isSorted = sortState[metric]?.[model]?.direction !== undefined
564
- const direction = sortState[metric]?.[model]?.direction || 'desc'
565
- return (
566
- <th
567
- key={`${metric}-${model}`}
568
- className="sticky top-12 bg-base-100 z-10 text-center text-xs border border-gray-700 cursor-pointer select-none"
569
- onClick={() => handleRowSort(metric, model)}
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
- {/* First render each group row */}
584
- {groupEntries.map(([group, subGroups]) => {
585
- // Skip the "Overall" group completely, keep for now
586
- // if (group === OVERALL_ROW) return null
587
-
588
- // Get all metrics for this group row
589
- const allGroupMetrics = Object.values(subGroups).flat()
590
- // Filter to only include selected metrics
591
- const visibleGroupMetrics = filterMetricsByGroupAndSubgroup(
592
- allGroupMetrics,
593
- group
594
- )
595
-
596
- // Skip this group row if no metrics are selected
597
- if (visibleGroupMetrics.length === 0) return null
598
-
599
- // Sort subgroups by average if sort config is active
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
- <td className="sticky left-0 bg-base-200 z-10 font-medium cursor-pointer select-none flex items-center">
635
- <span>{openGroupRows[group] ? 'β–Ό ' : 'β–Ά '}</span>
636
- <span className="flex-1">{group}</span>
637
- {/* Sort icon: only this triggers sort, and shows default if unsorted */}
638
- <span
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 overflow-y-auto pr-2">
27
- {models.map((model) => (
28
- <label key={model} className="flex items-center gap-2 text-sm">
29
- <input
30
- type="checkbox"
31
- className="form-checkbox h-4 w-4"
32
- checked={selectedModels.has(model)}
33
- onChange={() => toggleModel(model)}
34
- />
35
- <span className="truncate" title={model}>
36
- {model}
37
- </span>
38
- </label>
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="overflow-x-auto max-h-[80vh] overflow-y-auto">
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
- <span className="inline-block">{metric}</span>
171
- <span className="float-right">
172
- {isSorted ? (direction === 'asc' ? '←' : 'β†’') : '⇆'}
173
- </span>
 
 
 
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>