fino-rails 1.1.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc922e5e8645f1fd8b48f530b824188aa08f50ac927b90716599d118c8923aff
4
- data.tar.gz: 342c1c31ff5ef73d1b5b09d2253849b255ec0c17b8d2fb22d7073d6e7be2697f
3
+ metadata.gz: c0e79cf4e9a9dae9feb40b351881d3c631618145478cd7d373d94d99ff1a2789
4
+ data.tar.gz: aa693f31d4dce8069a1f3f75708beda588c45730ab57cb34a2c00acbba2a76c2
5
5
  SHA512:
6
- metadata.gz: 231fc9879274405b66cd869779e3ccdba2e2bd864cc248c39cd31cd436e84237eb3b6d4fa02cdcafdbada00812c68966665c7087849977745aa49ff6b4e23fe9
7
- data.tar.gz: 82d7a385e4dbadb72676dd64def317ae19c83e3a21d808c3e7515ab0725c55c848362e760eee73d68fd47da00830bcc3536b53c8ea42f4cbc8b05d98e2f497aa
6
+ metadata.gz: 41fb7577a2fea80f484b04a2c888ebfc5e61fbfbf484bc343d0cab6c32a2e3b6462f4f53a2ead5fbd856cf2f07b8b421a21f075380c7a2dcf7b906a9d3a9ff4f
7
+ data.tar.gz: 7a7603c0b64e0bd70a6f8b463cbebd94b40cf76585a000c5b5f0baf4ed1a9fdb831fefb9d7105a9a331d164127d9aaed45278449da02a0ce8b7cdcd6828e1da4
@@ -12,15 +12,24 @@ class Fino::Rails::SettingsController < Fino::Rails::ApplicationController
12
12
  end
13
13
 
14
14
  def update
15
- Fino.set(setting_name => params[:value], at: section_name)
16
-
17
- redirect_to (session.delete(:return_to) || root_path), notice: "Setting updated successfully"
18
- rescue Fino::Registry::UnknownSetting
19
- redirect_to root_path, alert: "Setting not found"
15
+ Fino.set(
16
+ setting_name => params[:value],
17
+ at: section_name,
18
+ overrides: overrides,
19
+ variants: variants
20
+ )
21
+
22
+ redirect_to return_path, notice: "Setting updated successfully"
23
+ rescue StandardError => e
24
+ redirect_to return_path, alert: "Failed to update setting: #{e.message}"
20
25
  end
21
26
 
22
27
  private
23
28
 
29
+ def return_path
30
+ session.delete(:return_to) || root_path
31
+ end
32
+
24
33
  def setting_name
25
34
  params[:setting]
26
35
  end
@@ -32,6 +41,21 @@ class Fino::Rails::SettingsController < Fino::Rails::ApplicationController
32
41
  end
33
42
  end
34
43
 
44
+ def overrides
45
+ params[:overrides].values.each_with_object({}) do |raw_override, memo|
46
+ memo[raw_override[:scope]] = raw_override[:value] if raw_override[:scope]
47
+ end
48
+ end
49
+
50
+ def variants
51
+ params[:variants].values.each_with_object({}).with_index do |(raw_variant, memo), index|
52
+ next if index.zero?
53
+ next unless raw_variant[:percentage].to_f > 0.0
54
+
55
+ memo[raw_variant[:percentage].to_f] = raw_variant[:value]
56
+ end
57
+ end
58
+
35
59
  def store_return_location
36
60
  session[:return_to] = request.referer
37
61
  end
@@ -15,4 +15,42 @@ module Fino::Rails::SettingsHelper
15
15
  setting.type.to_s.titleize
16
16
  end
17
17
  end
18
+
19
+ def boolean_setting_status(setting)
20
+ global_value = setting.value
21
+ overrides = setting.scope_overrides
22
+
23
+ if overrides.empty?
24
+ return {
25
+ text: global_value ? "Enabled" : "Disabled",
26
+ color: global_value ? "green" : "red"
27
+ }
28
+ end
29
+
30
+ if global_value
31
+ disabled_scopes = overrides.reject { |_, value| value }.keys
32
+
33
+ if disabled_scopes.any?
34
+ {
35
+ short_text: "Conditionally enabled",
36
+ text: "Enabled except for #{disabled_scopes.to_sentence}",
37
+ color: "yellow"
38
+ }
39
+ else
40
+ { text: "Enabled", color: "green" }
41
+ end
42
+ else
43
+ enabled_scopes = overrides.select { |_, value| value }.keys
44
+
45
+ if enabled_scopes.any?
46
+ {
47
+ short_text: "Conditionally enabled",
48
+ text: "Enabled for #{enabled_scopes.to_sentence}",
49
+ color: "yellow"
50
+ }
51
+ else
52
+ { text: "Disabled", color: "red" }
53
+ end
54
+ end
55
+ end
18
56
  end
@@ -1,6 +1,10 @@
1
1
  <% content_for(:title, "Dashboard") %>
2
2
 
3
- <div class="m-3">
3
+ <% content_for(:topbar) do %>
4
+ <%= render "fino/rails/common/topbar" %>
5
+ <% end %>
6
+
7
+ <div class="p-3">
4
8
  <div class="flex flex-col gap-y-3">
5
9
  <%= render "fino/rails/common/flash" %>
6
10
 
@@ -27,11 +31,13 @@
27
31
  <% case setting %>
28
32
  <% when Fino::Settings::Boolean %>
29
33
  <div class="flex items-center gap-x-2">
30
- <div class="flex-none rounded-full p-1 <%= setting.value ? 'text-green-500 bg-green-100' : 'text-red-500 bg-red-100' %>">
34
+ <% status = boolean_setting_status(setting) %>
35
+
36
+ <div class="flex-none rounded-full p-1 <%= "text-#{status[:color]}-500 bg-#{status[:color]}-100" %>">
31
37
  <div class="size-2 rounded-full bg-current"></div>
32
38
  </div>
33
39
 
34
- <span class="text-lg font-medium text-gray-800"><%= setting.value ? 'Enabled' : 'Disabled' %></span>
40
+ <span class="text-lg font-medium text-gray-800"><%= status[:short_text] || status[:text] %></span>
35
41
  </div>
36
42
  <% when Fino::Settings::String %>
37
43
  <div class="truncate text-xl font-semibold text-gray-800">
@@ -1,6 +1,10 @@
1
1
  <% content_for(:title, "#{current_section.label}") %>
2
2
 
3
- <div class="m-3">
3
+ <% content_for(:topbar) do %>
4
+ <%= render "fino/rails/common/topbar" %>
5
+ <% end %>
6
+
7
+ <div class="p-3">
4
8
  <div class="flex flex-col gap-y-3">
5
9
  <%= render "fino/rails/common/flash" %>
6
10
 
@@ -24,12 +24,13 @@
24
24
  <div>
25
25
  <% case setting %>
26
26
  <% when Fino::Settings::Boolean %>
27
+ <% status = boolean_setting_status(setting) %>
27
28
  <div class="flex items-center gap-x-2">
28
- <div class="flex-none rounded-full p-1 <%= setting.value ? 'text-green-500 bg-green-100' : 'text-red-500 bg-red-100' %>">
29
+ <div class="flex-none rounded-full p-1 text-<%= status[:color] %>-500 bg-<%= status[:color] %>-100">
29
30
  <div class="size-2 rounded-full bg-current"></div>
30
31
  </div>
31
32
 
32
- <span class="text-lg font-medium text-gray-800"><%= setting.value ? 'Enabled' : 'Disabled' %></span>
33
+ <span class="text-lg font-medium text-gray-800"><%= status[:text] %></span>
33
34
  </div>
34
35
  <% when Fino::Settings::String %>
35
36
  <div class="truncate text-xl font-semibold text-gray-800">
@@ -0,0 +1,31 @@
1
+ <% if setting.type == :boolean %>
2
+ <div class="flex gap-3">
3
+ <div class="flex h-6 shrink-0 items-center pt-3">
4
+ <%= render "fino/rails/settings/types/#{setting.type}",
5
+ form: form,
6
+ setting: setting,
7
+ field_name: field_name,
8
+ field_id: field_id,
9
+ field_name_attr: field_name_attr,
10
+ field_value: field_value %>
11
+ </div>
12
+ <div class="text-sm/6">
13
+ <label for="<%= field_id %>" class="font-medium text-gray-900"><%= setting.name %></label>
14
+ <p class="text-gray-500"><%= setting.description %></p>
15
+ </div>
16
+ </div>
17
+ <% else %>
18
+ <div>
19
+ <label for="<%= field_id %>" class="block text-sm/6 font-medium text-gray-900"><%= setting.name %></label>
20
+ <div class="mt-2">
21
+ <%= render "fino/rails/settings/types/#{setting.type}",
22
+ form: form,
23
+ setting: setting,
24
+ field_name: field_name,
25
+ field_id: field_id,
26
+ field_name_attr: field_name_attr,
27
+ field_value: field_value %>
28
+ </div>
29
+ </div>
30
+ <p class="mt-3 text-sm/6 text-gray-600"><%= setting.description %></p>
31
+ <% end %>
@@ -1,117 +1,548 @@
1
1
  <% content_for(:title, @setting.key) %>
2
2
 
3
- <div class="m-3">
4
- <div class="container mx-auto md:w-xl px-0 pt-10">
5
- <div class="flex flex-col gap-3">
6
- <%= render "fino/rails/common/flash" %>
7
-
8
- <div class="bg-white shadow-xs outline outline-gray-900/5 sm:rounded-xl md:col-span-2">
9
- <%= form_with url: update_setting_path(section: @setting.section_name || :general, setting: @setting.name), method: :put, local: true do |f| %>
10
- <div class="border-b border-gray-100 p-3 md:p-5 flex justify-between">
11
- <div class="flex self-center">
12
- <h3 class="text-base font-semibold text-gray-900"><%= link_to @setting.section_definition&.label || "General", settings_section_path(section: @setting.section_name || :general) %></h3>
13
- <span class="mx-2 text-gray-400">/</span>
14
- <h3 class="text-base font-semibold text-gray-900"><%= @setting.name %></h3>
15
- </div>
3
+ <div class="p-3">
4
+ <div class="container mx-auto">
5
+ <%= form_with url: update_setting_path(section: @setting.section_name || :general, setting: @setting.name), method: :put, local: true do |f| %>
6
+ <div class="border-b border-gray-200 pb-3 sm:flex sm:items-center sm:justify-between">
7
+ <h3 class="text-base font-semibold text-gray-900">
8
+ <%= link_to @setting.section_definition&.label || "General", settings_section_path(section: @setting.section_name || :general), class: "hover:text-gray-700" %>
9
+ <span class="mx-2 text-gray-400">/</span>
10
+ <%= @setting.name %>
11
+ </h3>
16
12
 
17
- <div class="flex gap-3 lg:mt-0 lg:ml-4">
18
- <span>
19
- <%= link_to "Cancel", :back, class: "inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-xs inset-ring inset-ring-gray-300 hover:bg-gray-50" %>
20
- </span>
13
+ <div class="mt-3 flex gap-2 sm:mt-0 sm:ml-4">
14
+ <%= link_to "Cancel", :back, class: "inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-xs inset-ring inset-ring-gray-300 hover:bg-gray-50" %>
15
+ <%= f.submit "Save", class: "rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" %>
16
+ </div>
17
+ </div>
21
18
 
22
- <span>
23
- <%= f.submit "Save", class: "inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" %>
24
- </span>
25
- </div>
19
+ <div class="flex flex-col gap-2 pt-3">
20
+ <%= render "fino/rails/common/flash" %>
21
+
22
+ <div class="grid grid-cols-1 gap-x-8 gap-y-8 md:grid-cols-3">
23
+ <div class="px-4 sm:px-0">
24
+ <h3 class="text-base/7 font-semibold text-gray-900">Global</h3>
25
+ <p class="mt-1 text-sm/6 text-gray-600">Default value that applies to all scopes unless overridden</p>
26
26
  </div>
27
27
 
28
- <div class="px-4 py-6 sm:p-6">
29
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
30
- <% case @setting %>
31
- <% when Fino::Settings::Boolean %>
28
+ <div class="bg-white shadow-xs outline outline-gray-900/5 sm:rounded-xl md:col-span-2">
29
+ <div class="px-4 py-6 sm:p-6">
30
+ <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
32
31
  <div class="col-span-full">
33
- <div class="flex gap-3">
34
- <div class="flex h-6 shrink-0 items-center pt-3">
35
- <div class="group relative inline-flex w-11 shrink-0 rounded-full bg-gray-200 p-0.5 inset-ring inset-ring-gray-900/5 outline-offset-2 outline-indigo-600 transition-colors duration-200 ease-in-out has-checked:bg-indigo-600 has-focus-visible:outline-2">
36
- <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-5"></span>
37
- <%= f.check_box :value,
38
- {
39
- id: "value",
40
- class: "absolute inset-0 appearance-none focus:outline-hidden",
41
- checked: @setting.value
42
- },
43
- '1',
44
- '0' %>
32
+ <%= render "fino/rails/settings/setting_input",
33
+ form: f,
34
+ setting: @setting,
35
+ field_name: :value,
36
+ field_id: "value",
37
+ field_name_attr: nil,
38
+ field_value: @setting.value %>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <div class="border-t border-gray-100">
44
+ <dl class="divide-y divide-gray-100">
45
+ <div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
46
+ <dt class="text-sm font-medium text-gray-900">Type</dt>
47
+ <dd class="mt-1 text-sm/6 text-gray-700 sm:col-span-1 sm:mt-0 flex"><%= setting_type_label(@setting) %></dd>
48
+ </div>
49
+ <div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
50
+ <dt class="text-sm font-medium text-gray-900">Default</dt>
51
+ <dd class="mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0"><%= @setting.definition.default.inspect %></dd>
52
+ </div>
53
+ </dl>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="px-4 sm:px-0">
58
+ <h3 class="text-base/7 font-semibold text-gray-900">Overrides</h3>
59
+ <p class="mt-1 text-sm/6 text-gray-600">Override the setting value for specific scopes</p>
60
+ </div>
61
+
62
+ <div class="bg-white shadow-xs outline outline-gray-900/5 sm:rounded-xl md:col-span-2">
63
+ <div class="px-4 py-6 sm:p-6">
64
+ <div id="scope-overrides">
65
+ <%= f.fields_for :overrides do |override_form| %>
66
+ <% @setting.scope_overrides.each_with_index do |(scope, value), index| %>
67
+ <div class="scope-override-item mb-6 last:mb-0" data-index="<%= index %>">
68
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
69
+ <div class="sm:col-span-2">
70
+ <%= override_form.label "scope_#{index}", "Scope", class: "block text-sm/6 font-medium text-gray-900" %>
71
+ <div class="mt-2">
72
+ <%= override_form.text_field "scope_#{index}",
73
+ value: scope,
74
+ name: "overrides[#{index}][scope]",
75
+ class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6",
76
+ placeholder: "e.g., qa, admin" %>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="sm:col-span-3">
81
+ <%= override_form.label "value_#{index}", "Value", class: "block text-sm/6 font-medium text-gray-900" %>
82
+ <div class="mt-2">
83
+ <%= render "fino/rails/settings/types/#{@setting.type}",
84
+ form: override_form,
85
+ setting: @setting,
86
+ field_name: "value_#{index}",
87
+ field_id: "overrides_#{index}_value",
88
+ field_name_attr: "overrides[#{index}][value]",
89
+ field_value: value,
90
+ wrapper_class: "",
91
+ input_class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" %>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="sm:col-span-1 flex items-end">
96
+ <%= button_tag "Remove", type: "button", class: "remove-override rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600" %>
97
+ </div>
45
98
  </div>
46
99
  </div>
47
- <div class="text-sm/6">
48
- <label for="value" class="font-medium text-gray-900"><%= @setting.name %></label>
49
- <p id="comments-description" class="text-gray-500"><%= @setting.description %></p>
50
- </div>
100
+ <% end %>
101
+ <% end %>
102
+
103
+ <% if @setting.scope_overrides.empty? %>
104
+ <div class="text-center py-6">
105
+ <p class="text-sm text-gray-500">No scope overrides configured</p>
51
106
  </div>
107
+ <% end %>
108
+ </div>
109
+
110
+ <div class="mt-6">
111
+ <%= button_tag "Add Override", type: "button", id: "add-override", class: "rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" %>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <div id="override-templates" style="display: none;">
117
+ <%= f.fields_for :template do |template_form| %>
118
+ <%= render "fino/rails/settings/types/#{@setting.type}",
119
+ form: template_form,
120
+ setting: @setting,
121
+ field_name: "value_TEMPLATE_INDEX",
122
+ field_id: "overrides_TEMPLATE_INDEX_value",
123
+ field_name_attr: "overrides[TEMPLATE_INDEX][value]",
124
+ field_value: nil,
125
+ wrapper_class: "",
126
+ input_class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" %>
127
+ <% end %>
128
+ </div>
129
+
130
+ <div class="px-4 sm:px-0">
131
+ <h3 class="text-base/7 font-semibold text-gray-900">A/B Testing</h3>
132
+ <p class="mt-1 text-sm/6 text-gray-600">Set up variants for A/B testing with percentage-based traffic distribution</p>
133
+ </div>
134
+
135
+ <div class="bg-white shadow-xs outline outline-gray-900/5 sm:rounded-xl md:col-span-2">
136
+ <div class="px-4 py-6 sm:p-6">
137
+ <% if @setting.variants.empty? %>
138
+ <div class="text-center py-6" id="ab-setup">
139
+ <p class="text-sm text-gray-500 mb-4">No A/B test variants configured</p>
140
+ <%= button_tag "Set Up", type: "button", id: "setup-ab-testing", class: "rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" %>
52
141
  </div>
53
- <% when Fino::Settings::String %>
54
- <div class="col-span-full">
55
- <div>
56
- <label for="username" class="block text-sm/6 font-medium text-gray-900"><%= @setting.name %></label>
57
- <div class="mt-2">
58
- <div class="flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600">
59
- <%= f.text_field :value,
60
- value: @setting.value,
61
- class: "block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6" %>
142
+ <% else %>
143
+ <div id="ab-testing-content">
144
+ <div id="variant-tabs">
145
+ <div class="grid grid-cols-1 sm:hidden">
146
+ <select id="variant-select" aria-label="Select a variant" class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-2 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600">
147
+ <option value="control">Control</option>
148
+ <% @setting.variants.each_with_index do |variant, index| %>
149
+ <% if index == 0 %>
150
+ <!-- Control is handled separately -->
151
+ <% else %>
152
+ <option value="variant-<%= index - 1 %>">Variant <%= index %></option>
153
+ <% end %>
154
+ <% end %>
155
+ </select>
156
+ <svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end fill-gray-500">
157
+ <path d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
158
+ </svg>
159
+ </div>
160
+ <div class="hidden sm:block">
161
+ <div class="border-b border-gray-200">
162
+ <nav aria-label="Tabs" class="-mb-px flex space-x-8">
163
+ <a href="#" data-tab="control" class="variant-tab border-b-2 border-indigo-500 px-1 py-4 text-sm font-medium whitespace-nowrap text-indigo-600" aria-current="page">Control</a>
164
+ <% @setting.variants.each_with_index do |variant, index| %>
165
+ <% if index == 0 %>
166
+ <!-- Control is handled separately -->
167
+ <% else %>
168
+ <a href="#" data-tab="variant-<%= index - 1 %>" class="variant-tab border-b-2 border-transparent px-1 py-4 text-sm font-medium whitespace-nowrap text-gray-500 hover:border-gray-300 hover:text-gray-700">Variant <%= index %></a>
169
+ <% end %>
170
+ <% end %>
171
+ <button type="button" id="add-variant" class="border-b-2 border-transparent px-1 py-4 text-sm font-medium whitespace-nowrap text-gray-500 hover:border-gray-300 hover:text-gray-700">+ Add Variant</button>
172
+ </nav>
62
173
  </div>
63
174
  </div>
64
175
  </div>
65
- <p class="mt-3 text-sm/6 text-gray-600"><%= @setting.description %></p>
66
- </div>
67
- <% when Fino::Settings::Integer %>
68
- <div class="col-span-full">
69
- <div>
70
- <label for="username" class="block text-sm/6 font-medium text-gray-900"><%= @setting.name %></label>
71
- <div class="mt-2">
72
- <div class="flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600">
73
- <%= f.number_field :value,
74
- value: @setting.value,
75
- class: "block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6",
76
- step: 1 %>
176
+
177
+ <div id="variant-content" class="mt-6">
178
+ <% @setting.variants.each_with_index do |variant, index| %>
179
+ <div id="<%= index == 0 ? 'control' : "variant-#{index - 1}" %>-content" class="variant-content <%= 'hidden' unless index == 0 %>">
180
+ <div class="flex flex-col gap-3">
181
+ <p class="mt-1 text-xs text-gray-500">Control variant falls back to the global setting value, percentage is calculated automatically</p>
182
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
183
+ <div class="sm:col-span-2">
184
+ <label for="variants_<%= index %>_percentage" class="block text-sm/6 font-medium text-gray-900">Percentage</label>
185
+ <div class="mt-2">
186
+ <input type="number" name="variants[<%= index %>][percentage]" id="variants_<%= index %>_percentage" class="<%= index == 0 ? '' : 'variant-percentage' %> block w-full rounded-md px-3 py-1.5 text-base outline-1 -outline-offset-1 outline-gray-300 sm:text-sm/6 <%= index == 0 ? 'bg-gray-100 text-gray-500' : 'bg-white text-gray-900 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600' %>" value="<%= variant.percentage %>" min="0" max="100" <%= 'readonly' if index == 0 %> />
187
+ </div>
188
+ </div>
189
+ <div class="sm:col-span-3">
190
+ <label for="variants_<%= index %>_value" class="block text-sm/6 font-medium text-gray-900">Value</label>
191
+ <div class="mt-2">
192
+ <% if index == 0 %>
193
+ <div class="block w-full rounded-md bg-gray-100 px-3 py-1.5 text-base text-gray-500 outline-1 -outline-offset-1 outline-gray-300 sm:text-sm/6">
194
+ <%= @setting.value.inspect %>
195
+ </div>
196
+ <input type="hidden" name="variants[<%= index %>][value]" value="<%= variant.value %>" />
197
+ <% else %>
198
+ <%= render "fino/rails/settings/types/#{@setting.type}",
199
+ form: f,
200
+ setting: @setting,
201
+ field_name: "variants_#{index}_value",
202
+ field_id: "variants_#{index}_value",
203
+ field_name_attr: "variants[#{index}][value]",
204
+ field_value: variant.value,
205
+ wrapper_class: "",
206
+ input_class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" %>
207
+ <% end %>
208
+ </div>
209
+ </div>
210
+ <div class="sm:col-span-1 flex items-end">
211
+ <% if index != 0 %>
212
+ <%= button_tag "Remove", type: "button", class: "remove-variant rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600", data: { variant_index: index } %>
213
+ <% end %>
214
+ </div>
215
+ </div>
77
216
  </div>
78
217
  </div>
218
+ <% end %>
219
+ </div>
220
+ </div>
221
+ <% end %>
222
+
223
+ <div id="ab-testing-content" class="hidden">
224
+ <div id="variant-tabs">
225
+ <div class="grid grid-cols-1 sm:hidden">
226
+ <select id="variant-select" aria-label="Select a variant" class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-2 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600">
227
+ <option value="control">Control</option>
228
+ </select>
229
+ <svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end fill-gray-500">
230
+ <path d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
231
+ </svg>
232
+ </div>
233
+ <div class="hidden sm:block">
234
+ <div class="border-b border-gray-200">
235
+ <nav aria-label="Tabs" class="-mb-px flex space-x-8">
236
+ <a href="#" data-tab="control" class="variant-tab border-b-2 border-indigo-500 px-1 py-4 text-sm font-medium whitespace-nowrap text-indigo-600" aria-current="page">Control</a>
237
+ <button type="button" id="add-variant" class="border-b-2 border-transparent px-1 py-4 text-sm font-medium whitespace-nowrap text-gray-500 hover:border-gray-300 hover:text-gray-700">+ Add Variant</button>
238
+ </nav>
79
239
  </div>
80
- <p class="mt-3 text-sm/6 text-gray-600"><%= @setting.description %></p>
81
240
  </div>
82
- <% when Fino::Settings::Float %>
83
- <div class="col-span-full">
84
- <div>
85
- <label for="username" class="block text-sm/6 font-medium text-gray-900"><%= @setting.name %></label>
86
- <div class="mt-2">
87
- <div class="flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600">
88
- <%= f.number_field :value,
89
- value: @setting.value,
90
- class:"block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6",
91
- step: 0.1 %>
241
+ </div>
242
+
243
+ <div id="variant-content" class="mt-6">
244
+ <div id="control-content" class="variant-content">
245
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
246
+ <div class="sm:col-span-2">
247
+ <label class="block text-sm/6 font-medium text-gray-900">Percentage</label>
248
+ <div class="mt-2">
249
+ <input type="number" id="control-percentage" class="block w-full rounded-md bg-gray-100 px-3 py-1.5 text-base text-gray-500 outline-1 -outline-offset-1 outline-gray-300 sm:text-sm/6" value="100" readonly />
250
+ </div>
251
+ </div>
252
+ <div class="sm:col-span-4">
253
+ <label class="block text-sm/6 font-medium text-gray-900">Value</label>
254
+ <div class="mt-2">
255
+ <div class="block w-full rounded-md bg-gray-100 px-3 py-1.5 text-base text-gray-500 outline-1 -outline-offset-1 outline-gray-300 sm:text-sm/6">
256
+ <%= @setting.value.inspect %>
257
+ </div>
92
258
  </div>
93
259
  </div>
94
260
  </div>
95
- <p class="mt-3 text-sm/6 text-gray-600"><%= @setting.description %></p>
96
261
  </div>
97
- <% end %>
262
+ </div>
263
+ </div>
98
264
  </div>
99
265
  </div>
100
- <% end %>
101
266
 
102
- <div class="border-t border-gray-100">
103
- <dl class="divide-y divide-gray-100">
104
- <div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
105
- <dt class="text-sm font-medium text-gray-900">Type</dt>
106
- <dd class="mt-1 text-sm/6 text-gray-700 sm:col-span-1 sm:mt-0 flex"><%= setting_type_label(@setting) %></dd>
107
- </div>
108
- <div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
109
- <dt class="text-sm font-medium text-gray-900">Default</dt>
110
- <dd class="mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0"><%= @setting.definition.default.inspect %></dd>
111
- </div>
112
- </dl>
267
+ <div id="variant-templates" style="display: none;">
268
+ <%= f.fields_for :template do |template_form| %>
269
+ <%= render "fino/rails/settings/types/#{@setting.type}",
270
+ form: template_form,
271
+ setting: @setting,
272
+ field_name: "variants_TEMPLATE_INDEX_value",
273
+ field_id: "variants_TEMPLATE_INDEX_value",
274
+ field_name_attr: "variants[TEMPLATE_INDEX][value]",
275
+ field_value: nil,
276
+ wrapper_class: "",
277
+ input_class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" %>
278
+ <% end %>
279
+ </div>
113
280
  </div>
114
281
  </div>
115
- </div>
282
+ <% end %>
116
283
  </div>
117
284
  </div>
285
+
286
+ <script>
287
+ document.addEventListener('DOMContentLoaded', function() {
288
+ const addButton = document.getElementById('add-override');
289
+ const overridesContainer = document.getElementById('scope-overrides');
290
+ const templateContainer = document.getElementById('override-templates');
291
+ let overrideIndex = <%= @setting.scope_overrides.length %>;
292
+
293
+ addButton.addEventListener('click', function() {
294
+ // Get the template HTML and replace placeholders with actual index
295
+ let valueInputTemplate = templateContainer.innerHTML
296
+ .replace(/TEMPLATE_INDEX/g, overrideIndex)
297
+ .replace(/value_\d+/g, `value_${overrideIndex}`)
298
+ .trim();
299
+
300
+ const template = `
301
+ <div class="scope-override-item mb-6" data-index="${overrideIndex}">
302
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
303
+ <div class="sm:col-span-2">
304
+ <label for="overrides_${overrideIndex}_scope" class="block text-sm/6 font-medium text-gray-900">Scope</label>
305
+ <div class="mt-2">
306
+ <input type="text" name="overrides[${overrideIndex}][scope]" id="overrides_${overrideIndex}_scope" class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" placeholder="e.g., qa, admin" />
307
+ </div>
308
+ </div>
309
+
310
+ <div class="sm:col-span-3">
311
+ <label for="overrides_${overrideIndex}_value" class="block text-sm/6 font-medium text-gray-900">Value</label>
312
+ <div class="mt-2">
313
+ ${valueInputTemplate}
314
+ </div>
315
+ </div>
316
+
317
+ <div class="sm:col-span-1 flex items-end">
318
+ <button type="button" class="remove-override rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600">Remove</button>
319
+ </div>
320
+ </div>
321
+ </div>
322
+ `;
323
+
324
+ // Remove "no overrides" message if it exists
325
+ const noOverridesMsg = overridesContainer.querySelector('.text-center');
326
+ if (noOverridesMsg) {
327
+ noOverridesMsg.remove();
328
+ }
329
+
330
+ overridesContainer.insertAdjacentHTML('beforeend', template);
331
+ overrideIndex++;
332
+ });
333
+
334
+ // Handle remove buttons
335
+ overridesContainer.addEventListener('click', function(e) {
336
+ if (e.target.classList.contains('remove-override')) {
337
+ e.target.closest('.scope-override-item').remove();
338
+
339
+ // Show "no overrides" message if all removed
340
+ if (!overridesContainer.querySelector('.scope-override-item')) {
341
+ overridesContainer.innerHTML = '<div class="text-center py-6"><p class="text-sm text-gray-500">No scope overrides configured.</p></div>';
342
+ }
343
+ }
344
+ });
345
+
346
+ // A/B Testing functionality
347
+ const setupAbButton = document.getElementById('setup-ab-testing');
348
+ const abSetup = document.getElementById('ab-setup');
349
+ const abTestingContent = document.getElementById('ab-testing-content');
350
+ const addVariantButton = document.getElementById('add-variant');
351
+ const variantTemplates = document.getElementById('variant-templates');
352
+ let variantIndex = <%= @setting.variants.length - 1 %>;
353
+
354
+ // Set up A/B testing
355
+ if (setupAbButton) {
356
+ setupAbButton.addEventListener('click', function() {
357
+ abSetup.style.display = 'none';
358
+ abTestingContent.style.display = 'block';
359
+ abTestingContent.classList.remove('hidden');
360
+ });
361
+ }
362
+
363
+ // Tab switching functionality
364
+ function switchToTab(tabName) {
365
+ // Update tab appearance
366
+ document.querySelectorAll('.variant-tab').forEach(tab => {
367
+ tab.classList.remove('border-indigo-500', 'text-indigo-600');
368
+ tab.classList.add('border-transparent', 'text-gray-500');
369
+ tab.removeAttribute('aria-current');
370
+ });
371
+
372
+ const activeTab = document.querySelector(`[data-tab="${tabName}"]`);
373
+ if (activeTab) {
374
+ activeTab.classList.remove('border-transparent', 'text-gray-500');
375
+ activeTab.classList.add('border-indigo-500', 'text-indigo-600');
376
+ activeTab.setAttribute('aria-current', 'page');
377
+ }
378
+
379
+ // Show/hide content
380
+ document.querySelectorAll('.variant-content').forEach(content => {
381
+ content.classList.add('hidden');
382
+ });
383
+
384
+ const activeContent = document.getElementById(`${tabName}-content`);
385
+ if (activeContent) {
386
+ activeContent.classList.remove('hidden');
387
+ }
388
+
389
+ // Update mobile select
390
+ const variantSelect = document.getElementById('variant-select');
391
+ if (variantSelect) {
392
+ variantSelect.value = tabName;
393
+ }
394
+ }
395
+
396
+ // Tab click handlers
397
+ document.addEventListener('click', function(e) {
398
+ if (e.target.classList.contains('variant-tab')) {
399
+ e.preventDefault();
400
+ const tabName = e.target.getAttribute('data-tab');
401
+ switchToTab(tabName);
402
+ }
403
+ });
404
+
405
+ // Mobile select handler
406
+ const variantSelect = document.getElementById('variant-select');
407
+ if (variantSelect) {
408
+ variantSelect.addEventListener('change', function() {
409
+ switchToTab(this.value);
410
+ });
411
+ }
412
+
413
+ // Add variant functionality
414
+ if (addVariantButton) {
415
+ addVariantButton.addEventListener('click', function() {
416
+ // The actual array index will be variantIndex + 1 (since control is at index 0)
417
+ const actualArrayIndex = variantIndex + 1;
418
+
419
+ // Get template HTML
420
+ let valueInputTemplate = variantTemplates.innerHTML
421
+ .replace(/TEMPLATE_INDEX/g, actualArrayIndex)
422
+ .replace(/variants_\w+_value/g, `variants_${actualArrayIndex}_value`)
423
+ .trim();
424
+
425
+ // Add new tab
426
+ const tabsNav = document.querySelector('nav[aria-label="Tabs"]');
427
+ const newTab = document.createElement('a');
428
+ newTab.href = '#';
429
+ newTab.setAttribute('data-tab', `variant-${variantIndex}`);
430
+ newTab.className = 'variant-tab border-b-2 border-transparent px-1 py-4 text-sm font-medium whitespace-nowrap text-gray-500 hover:border-gray-300 hover:text-gray-700';
431
+ newTab.textContent = `Variant ${actualArrayIndex}`;
432
+
433
+ tabsNav.insertBefore(newTab, addVariantButton);
434
+
435
+ // Add to mobile select
436
+ const option = document.createElement('option');
437
+ option.value = `variant-${variantIndex}`;
438
+ option.textContent = `Variant ${actualArrayIndex}`;
439
+ variantSelect.appendChild(option);
440
+
441
+ // Add new content
442
+ const variantContent = document.getElementById('variant-content');
443
+ const newContent = document.createElement('div');
444
+ newContent.id = `variant-${variantIndex}-content`;
445
+ newContent.className = 'variant-content hidden';
446
+ newContent.innerHTML = `
447
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
448
+ <div class="sm:col-span-2">
449
+ <label for="variants_${actualArrayIndex}_percentage" class="block text-sm/6 font-medium text-gray-900">Percentage</label>
450
+ <div class="mt-2">
451
+ <input type="number" name="variants[${actualArrayIndex}][percentage]" id="variants_${actualArrayIndex}_percentage" class="variant-percentage block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" value="20" min="0" max="100" />
452
+ </div>
453
+ </div>
454
+ <div class="sm:col-span-3">
455
+ <label for="variants_${actualArrayIndex}_value" class="block text-sm/6 font-medium text-gray-900">Value</label>
456
+ <div class="mt-2">
457
+ ${valueInputTemplate}
458
+ </div>
459
+ </div>
460
+ <div class="sm:col-span-1 flex items-end">
461
+ <button type="button" class="remove-variant rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600" data-variant-index="${actualArrayIndex}">Remove</button>
462
+ </div>
463
+ </div>
464
+ `;
465
+
466
+ variantContent.appendChild(newContent);
467
+
468
+ // Switch to new tab
469
+ switchToTab(`variant-${variantIndex}`);
470
+
471
+ // Recalculate percentages
472
+ recalculatePercentages();
473
+
474
+ variantIndex++;
475
+ });
476
+ }
477
+
478
+ // Remove variant functionality
479
+ document.addEventListener('click', function(e) {
480
+ if (e.target.classList.contains('remove-variant')) {
481
+ const variantIndex = e.target.getAttribute('data-variant-index');
482
+ const tabName = `variant-${variantIndex}`;
483
+
484
+ // Remove tab
485
+ const tab = document.querySelector(`[data-tab="${tabName}"]`);
486
+ if (tab) {
487
+ tab.remove();
488
+ }
489
+
490
+ // Remove from mobile select
491
+ const option = document.querySelector(`option[value="${tabName}"]`);
492
+ if (option) {
493
+ option.remove();
494
+ }
495
+
496
+ // Remove content
497
+ const content = document.getElementById(`${tabName}-content`);
498
+ if (content) {
499
+ content.remove();
500
+ }
501
+
502
+ // Switch to control tab
503
+ switchToTab('control');
504
+
505
+ // Recalculate percentages
506
+ recalculatePercentages();
507
+ }
508
+ });
509
+
510
+ // Percentage recalculation
511
+ function recalculatePercentages() {
512
+ const percentageInputs = document.querySelectorAll('.variant-percentage');
513
+
514
+ // Find the control percentage input (first variant, index 0)
515
+ const controlPercentage = document.getElementById('variants_0_percentage');
516
+
517
+ if (!controlPercentage) return;
518
+
519
+ let totalVariantPercentage = 0;
520
+ percentageInputs.forEach(input => {
521
+ const value = parseInt(input.value) || 0;
522
+ totalVariantPercentage += value;
523
+ });
524
+
525
+ const controlValue = Math.max(0, 100 - totalVariantPercentage);
526
+ controlPercentage.value = controlValue;
527
+
528
+ // Update control percentage color based on validity
529
+ if (totalVariantPercentage > 100) {
530
+ controlPercentage.classList.add('text-red-600');
531
+ controlPercentage.classList.remove('text-gray-500');
532
+ } else {
533
+ controlPercentage.classList.remove('text-red-600');
534
+ controlPercentage.classList.add('text-gray-500');
535
+ }
536
+ }
537
+
538
+ // Listen for percentage changes
539
+ document.addEventListener('input', function(e) {
540
+ if (e.target.classList.contains('variant-percentage')) {
541
+ recalculatePercentages();
542
+ }
543
+ });
544
+
545
+ // Initial percentage calculation
546
+ recalculatePercentages();
547
+ });
548
+ </script>
@@ -0,0 +1,11 @@
1
+ <div class="group relative inline-flex w-11 shrink-0 rounded-full bg-gray-200 p-0.5 inset-ring inset-ring-gray-900/5 outline-offset-2 outline-indigo-600 transition-colors duration-200 ease-in-out has-checked:bg-indigo-600 has-focus-visible:outline-2">
2
+ <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-5"></span>
3
+ <%= form.check_box field_name,
4
+ {
5
+ id: field_id,
6
+ class: "absolute inset-0 appearance-none focus:outline-hidden",
7
+ checked: field_value
8
+ }.merge(field_name_attr ? { name: field_name_attr } : {}),
9
+ '1',
10
+ '0' %>
11
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="<%= local_assigns[:wrapper_class] || 'flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600' %>">
2
+ <%= form.number_field field_name,
3
+ {
4
+ value: field_value,
5
+ id: field_id,
6
+ step: 0.1,
7
+ class: local_assigns[:input_class] || "block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
8
+ }.merge(field_name_attr ? { name: field_name_attr } : {}) %>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="<%= local_assigns[:wrapper_class] || 'flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600' %>">
2
+ <%= form.number_field field_name,
3
+ {
4
+ value: field_value,
5
+ id: field_id,
6
+ step: 1,
7
+ class: local_assigns[:input_class] || "block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
8
+ }.merge(field_name_attr ? { name: field_name_attr } : {}) %>
9
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="<%= local_assigns[:wrapper_class] || 'flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600' %>">
2
+ <%= form.text_field field_name,
3
+ {
4
+ value: field_value,
5
+ id: field_id,
6
+ class: local_assigns[:input_class] || "block min-w-0 grow bg-white py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
7
+ }.merge(field_name_attr ? { name: field_name_attr } : {}) %>
8
+ </div>
@@ -16,7 +16,7 @@
16
16
  <%= render "fino/rails/common/sidebar" %>
17
17
 
18
18
  <div class="xl:pl-72">
19
- <%= render "fino/rails/common/navbar" %>
19
+ <%= yield(:topbar) %>
20
20
 
21
21
  <main>
22
22
  <%= yield %>
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */
2
- @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-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-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-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@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-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-800:oklch(44.4% .177 26.899);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-800:oklch(44.8% .119 151.328);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-700:oklch(49.6% .265 301.924);--color-pink-50:oklch(97.1% .014 343.198);--color-pink-700:oklch(52.5% .223 3.958);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-gray-950:oklch(13% .028 261.692);--color-white:#fff;--spacing:.25rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--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:calc(1.5/1);--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);--font-weight-medium:500;--font-weight-semibold:600;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--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%;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;-webkit-text-decoration: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}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.end-0{inset-inline-end:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.z-40{z-index:40}.col-span-1{grid-column:span 1/span 1}.col-span-full{grid-column:1/-1}.col-start-1{grid-column-start:1}.row-start-1{grid-row-start:1}.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}}.-m-2{margin:calc(var(--spacing)*-2)}.-m-2\.5{margin:calc(var(--spacing)*-2.5)}.m-3{margin:calc(var(--spacing)*3)}.-mx-1{margin-inline:calc(var(--spacing)*-1)}.-mx-1\.5{margin-inline:calc(var(--spacing)*-1.5)}.-mx-2{margin-inline:calc(var(--spacing)*-2)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-auto{margin-inline:auto}.-my-1{margin-block:calc(var(--spacing)*-1)}.-my-1\.5{margin-block:calc(var(--spacing)*-1.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.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)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-full{width:100%;height:100%}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.h-auto{height:auto}.h-full{height:100%}.h-max{height:max-content}.h-px{height:1px}.max-h-2{max-height:calc(var(--spacing)*2)}.max-h-2\.5{max-height:calc(var(--spacing)*2.5)}.max-h-3{max-height:calc(var(--spacing)*3)}.max-h-4{max-height:calc(var(--spacing)*4)}.max-h-5{max-height:calc(var(--spacing)*5)}.max-h-6{max-height:calc(var(--spacing)*6)}.max-h-7{max-height:calc(var(--spacing)*7)}.max-h-10{max-height:calc(var(--spacing)*10)}.max-h-20{max-height:calc(var(--spacing)*20)}.max-h-full{max-height:100%}.max-h-max{max-height:max-content}.min-h-5{min-height:calc(var(--spacing)*5)}.min-h-10{min-height:calc(var(--spacing)*10)}.min-h-32{min-height:calc(var(--spacing)*32)}.w-9{width:calc(var(--spacing)*9)}.w-11{width:calc(var(--spacing)*11)}.w-auto{width:auto}.w-full{width:100%}.w-lg{width:var(--container-lg)}.w-xl{width:var(--container-xl)}.max-w-2xl{max-width:var(--container-2xl)}.max-w-lg{max-width:var(--container-lg)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-max{min-width:max-content}.flex-1{flex:1}.flex-2{flex:2}.flex-none{flex:none}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.appearance-none{appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-row{flex-direction:row}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-items-center{justify-items:center}.justify-items-center-safe{justify-items:safe center}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-10{gap:calc(var(--spacing)*10)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing)*2)}.gap-x-3{column-gap:calc(var(--spacing)*3)}.gap-x-4{column-gap:calc(var(--spacing)*4)}.gap-x-6{column-gap:calc(var(--spacing)*6)}:where(.space-x-6>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*6)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-x-reverse)))}.gap-y-1{row-gap:calc(var(--spacing)*1)}.gap-y-2{row-gap:calc(var(--spacing)*2)}.gap-y-3{row-gap:calc(var(--spacing)*3)}.gap-y-5{row-gap:calc(var(--spacing)*5)}.gap-y-7{row-gap:calc(var(--spacing)*7)}.gap-y-8{row-gap:calc(var(--spacing)*8)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}:where(.divide-gray-200>:not(:last-child)){border-color:var(--color-gray-200)}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-center{justify-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border,.border-1{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-current{background-color:currentColor}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-pink-50{background-color:var(--color-pink-50)}.bg-purple-50{background-color:var(--color-purple-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.stroke-white{stroke:var(--color-white)}.p-0{padding:calc(var(--spacing)*0)}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-2\.5{padding:calc(var(--spacing)*2.5)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.px-0{padding-inline:calc(var(--spacing)*0)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-50{padding-inline:calc(var(--spacing)*50)}.py-0{padding-block:calc(var(--spacing)*0)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-10{padding-top:calc(var(--spacing)*10)}.pr-3{padding-right:calc(var(--spacing)*3)}.pb-0{padding-bottom:calc(var(--spacing)*0)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-5{padding-bottom:calc(var(--spacing)*5)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-8{padding-left:calc(var(--spacing)*8)}.text-center{text-align:center}.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-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing)*6)}.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))}.text-xs\/5{font-size:var(--text-xs);line-height:calc(var(--spacing)*5)}.text-xs\/6{font-size:var(--text-xs);line-height:calc(var(--spacing)*6)}.text-\[0\.625rem\]{font-size:.625rem}.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)}.break-words{overflow-wrap:break-word}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.text-blue-400{color:var(--color-blue-400)}.text-blue-500{color:var(--color-blue-500)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-400{color:var(--color-green-400)}.text-green-500{color:var(--color-green-500)}.text-green-800{color:var(--color-green-800)}.text-indigo-600{color:var(--color-indigo-600)}.text-pink-700{color:var(--color-pink-700)}.text-purple-700{color:var(--color-purple-700)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.text-yellow-500{color:var(--color-yellow-500)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.inset-ring{--tw-inset-ring-shadow:inset 0 0 0 1px var(--tw-inset-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-gray-200{--tw-ring-color:var(--color-gray-200)}.ring-gray-900{--tw-ring-color:var(--color-gray-900)}.ring-gray-900\/5{--tw-ring-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.ring-gray-900\/5{--tw-ring-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.inset-ring-blue-700{--tw-inset-ring-color:var(--color-blue-700)}.inset-ring-blue-700\/10{--tw-inset-ring-color:#1447e61a}@supports (color:color-mix(in lab, red, red)){.inset-ring-blue-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-blue-700)10%,transparent)}}.inset-ring-gray-300{--tw-inset-ring-color:var(--color-gray-300)}.inset-ring-gray-700{--tw-inset-ring-color:var(--color-gray-700)}.inset-ring-gray-700\/10{--tw-inset-ring-color:#3641531a}@supports (color:color-mix(in lab, red, red)){.inset-ring-gray-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-gray-700)10%,transparent)}}.inset-ring-gray-900{--tw-inset-ring-color:var(--color-gray-900)}.inset-ring-gray-900\/5{--tw-inset-ring-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.inset-ring-gray-900\/5{--tw-inset-ring-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.inset-ring-pink-700{--tw-inset-ring-color:var(--color-pink-700)}.inset-ring-pink-700\/10{--tw-inset-ring-color:#c4005c1a}@supports (color:color-mix(in lab, red, red)){.inset-ring-pink-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-pink-700)10%,transparent)}}.inset-ring-purple-700{--tw-inset-ring-color:var(--color-purple-700)}.inset-ring-purple-700\/10{--tw-inset-ring-color:#8200da1a}@supports (color:color-mix(in lab, red, red)){.inset-ring-purple-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-purple-700)10%,transparent)}}.inset-ring-yellow-700{--tw-inset-ring-color:var(--color-yellow-700)}.inset-ring-yellow-700\/10{--tw-inset-ring-color:#a361001a}@supports (color:color-mix(in lab, red, red)){.inset-ring-yellow-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-yellow-700)10%,transparent)}}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline,.outline-1{outline-style:var(--tw-outline-style);outline-width:1px}.-outline-offset-1{outline-offset:calc(1px*-1)}.outline-offset-2{outline-offset:2px}.outline-gray-200{outline-color:var(--color-gray-200)}.outline-gray-300{outline-color:var(--color-gray-300)}.outline-gray-900{outline-color:var(--color-gray-900)}.outline-gray-900\/5{outline-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.outline-gray-900\/5{outline-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.outline-indigo-600{outline-color:var(--color-indigo-600)}.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,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-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.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)}@media (hover:hover){.group-hover\:border-indigo-600:is(:where(.group):hover *){border-color:var(--color-indigo-600)}.group-hover\:text-indigo-600:is(:where(.group):hover *){color:var(--color-indigo-600)}}.group-has-checked\:translate-x-5:is(:where(.group):has(:checked) *){--tw-translate-x:calc(var(--spacing)*5);translate:var(--tw-translate-x)var(--tw-translate-y)}.group-has-checked\:opacity-100:is(:where(.group):has(:checked) *),.group-has-indeterminate\:opacity-100:is(:where(.group):has(:indeterminate) *){opacity:1}.group-has-disabled\:stroke-gray-950\/25:is(:where(.group):has(:disabled) *){stroke:#03071240}@supports (color:color-mix(in lab, red, red)){.group-has-disabled\:stroke-gray-950\/25:is(:where(.group):has(:disabled) *){stroke:color-mix(in oklab,var(--color-gray-950)25%,transparent)}}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}.checked\:border-indigo-600:checked{border-color:var(--color-indigo-600)}.checked\:bg-indigo-600:checked{background-color:var(--color-indigo-600)}.indeterminate\:border-indigo-600:indeterminate{border-color:var(--color-indigo-600)}.indeterminate\:bg-indigo-600:indeterminate{background-color:var(--color-indigo-600)}.focus-within\:outline-2:focus-within{outline-style:var(--tw-outline-style);outline-width:2px}.focus-within\:-outline-offset-2:focus-within{outline-offset:calc(2px*-1)}.focus-within\:outline-indigo-600:focus-within{outline-color:var(--color-indigo-600)}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-green-100:hover{background-color:var(--color-green-100)}.hover\:bg-indigo-500:hover{background-color:var(--color-indigo-500)}.hover\:text-indigo-600:hover{color:var(--color-indigo-600)}}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-blue-600:focus-visible{--tw-ring-color:var(--color-blue-600)}.focus-visible\:ring-gray-600:focus-visible{--tw-ring-color:var(--color-gray-600)}.focus-visible\:ring-green-600:focus-visible{--tw-ring-color:var(--color-green-600)}.focus-visible\:ring-red-600:focus-visible{--tw-ring-color:var(--color-red-600)}.focus-visible\:ring-yellow-600:focus-visible{--tw-ring-color:var(--color-yellow-600)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus-visible\:ring-offset-blue-50:focus-visible{--tw-ring-offset-color:var(--color-blue-50)}.focus-visible\:ring-offset-gray-50:focus-visible{--tw-ring-offset-color:var(--color-gray-50)}.focus-visible\:ring-offset-green-50:focus-visible{--tw-ring-offset-color:var(--color-green-50)}.focus-visible\:ring-offset-red-50:focus-visible{--tw-ring-offset-color:var(--color-red-50)}.focus-visible\:ring-offset-yellow-50:focus-visible{--tw-ring-offset-color:var(--color-yellow-50)}.focus-visible\:outline-hidden:focus-visible{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus-visible\:outline-hidden:focus-visible{outline-offset:2px;outline:2px solid #0000}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-indigo-600:focus-visible{outline-color:var(--color-indigo-600)}.disabled\:border-gray-300:disabled{border-color:var(--color-gray-300)}.disabled\:bg-gray-100:disabled,.disabled\:checked\:bg-gray-100:disabled:checked{background-color:var(--color-gray-100)}.has-checked\:bg-indigo-600:has(:checked){background-color:var(--color-indigo-600)}.has-focus-visible\:outline-2:has(:focus-visible){outline-style:var(--tw-outline-style);outline-width:2px}@media (min-width:40rem){.sm\:col-span-1{grid-column:span 1/span 1}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:mt-0{margin-top:calc(var(--spacing)*0)}.sm\:ml-3{margin-left:calc(var(--spacing)*3)}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:gap-4{gap:calc(var(--spacing)*4)}.sm\:rounded-xl{border-radius:var(--radius-xl)}.sm\:p-5{padding:calc(var(--spacing)*5)}.sm\:p-6{padding:calc(var(--spacing)*6)}.sm\:px-6{padding-inline:calc(var(--spacing)*6)}.sm\:text-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing)*6)}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:w-xl{width:var(--container-xl)}.md\:justify-between{justify-content:space-between}.md\:p-5{padding:calc(var(--spacing)*5)}.md\:px-50{padding-inline:calc(var(--spacing)*50)}}@media (min-width:64rem){.lg\:mt-0{margin-top:calc(var(--spacing)*0)}.lg\:ml-4{margin-left:calc(var(--spacing)*4)}.lg\:flex{display:flex}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:flex-col{flex-direction:column}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:gap-x-2{column-gap:calc(var(--spacing)*2)}.lg\:gap-x-3{column-gap:calc(var(--spacing)*3)}.lg\:gap-x-6{column-gap:calc(var(--spacing)*6)}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}.lg\:px-20{padding-inline:calc(var(--spacing)*20)}.lg\:px-50{padding-inline:calc(var(--spacing)*50)}}@media (min-width:80rem){.xl\:fixed{position:fixed}.xl\:inset-y-0{inset-block:calc(var(--spacing)*0)}.xl\:z-50{z-index:50}.xl\:flex{display:flex}.xl\:hidden{display:none}.xl\:w-72{width:calc(var(--spacing)*72)}.xl\:flex-col{flex-direction:column}.xl\:flex-row{flex-direction:row}.xl\:items-center{align-items:center}.xl\:gap-x-2{column-gap:calc(var(--spacing)*2)}.xl\:px-30{padding-inline:calc(var(--spacing)*30)}.xl\:px-50{padding-inline:calc(var(--spacing)*50)}.xl\:pl-72{padding-left:calc(var(--spacing)*72)}}@media (min-width:96rem){.\32 xl\:flex-row{flex-direction:row}.\32 xl\:items-center{align-items:center}.\32 xl\:gap-x-2{column-gap:calc(var(--spacing)*2)}.\32 xl\:px-100{padding-inline:calc(var(--spacing)*100)}}@media (forced-colors:active){.forced-colors\:appearance-auto{appearance:auto}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@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}
2
+ @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-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-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-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@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-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-800:oklch(44.4% .177 26.899);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-800:oklch(44.8% .119 151.328);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-700:oklch(49.6% .265 301.924);--color-pink-50:oklch(97.1% .014 343.198);--color-pink-700:oklch(52.5% .223 3.958);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-xl:36rem;--container-2xl:42rem;--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:calc(1.5/1);--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);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--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%;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;-webkit-text-decoration: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}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.z-40{z-index:40}.col-span-1{grid-column:span 1/span 1}.col-span-full{grid-column:1/-1}.col-start-1{grid-column-start:1}.row-start-1{grid-row-start:1}.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}}.-m-2\.5{margin:calc(var(--spacing)*-2.5)}.m-3{margin:calc(var(--spacing)*3)}.-mx-1\.5{margin-inline:calc(var(--spacing)*-1.5)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-auto{margin-inline:auto}.-my-1\.5{margin-block:calc(var(--spacing)*-1.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-6{margin-top:calc(var(--spacing)*6)}.mr-2{margin-right:calc(var(--spacing)*2)}.-mb-px{margin-bottom:-1px}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-full{width:100%;height:100%}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.h-full{height:100%}.w-9{width:calc(var(--spacing)*9)}.w-11{width:calc(var(--spacing)*11)}.w-auto{width:auto}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-max{min-width:max-content}.flex-1{flex:1}.flex-none{flex:none}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.appearance-none{appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.items-center{align-items:center}.items-end{align-items:flex-end}.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-3{gap:calc(var(--spacing)*3)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing)*2)}.gap-x-3{column-gap:calc(var(--spacing)*3)}.gap-x-4{column-gap:calc(var(--spacing)*4)}.gap-x-6{column-gap:calc(var(--spacing)*6)}.gap-x-8{column-gap:calc(var(--spacing)*8)}:where(.space-x-8>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*8)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*8)*calc(1 - var(--tw-space-x-reverse)))}.gap-y-1{row-gap:calc(var(--spacing)*1)}.gap-y-3{row-gap:calc(var(--spacing)*3)}.gap-y-4{row-gap:calc(var(--spacing)*4)}.gap-y-5{row-gap:calc(var(--spacing)*5)}.gap-y-7{row-gap:calc(var(--spacing)*7)}.gap-y-8{row-gap:calc(var(--spacing)*8)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}:where(.divide-gray-200>:not(:last-child)){border-color:var(--color-gray-200)}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border,.border-1{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-900\/10{border-color:#1018281a}@supports (color:color-mix(in lab, red, red)){.border-gray-900\/10{border-color:color-mix(in oklab,var(--color-gray-900)10%,transparent)}}.border-indigo-500{border-color:var(--color-indigo-500)}.border-transparent{border-color:#0000}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-current{background-color:currentColor}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-pink-50{background-color:var(--color-pink-50)}.bg-purple-50{background-color:var(--color-purple-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.fill-gray-500{fill:var(--color-gray-500)}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-2\.5{padding:calc(var(--spacing)*2.5)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-0{padding-inline:calc(var(--spacing)*0)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.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-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-5{padding-top:calc(var(--spacing)*5)}.pt-10{padding-top:calc(var(--spacing)*10)}.pr-3{padding-right:calc(var(--spacing)*3)}.pr-8{padding-right:calc(var(--spacing)*8)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-5{padding-bottom:calc(var(--spacing)*5)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-8{padding-left:calc(var(--spacing)*8)}.text-center{text-align:center}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-base\/7{font-size:var(--text-base);line-height:calc(var(--spacing)*7)}.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-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing)*6)}.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))}.text-xs\/5{font-size:var(--text-xs);line-height:calc(var(--spacing)*5)}.text-xs\/6{font-size:var(--text-xs);line-height:calc(var(--spacing)*6)}.text-\[0\.625rem\]{font-size:.625rem}.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)}.break-words{overflow-wrap:break-word}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.text-blue-400{color:var(--color-blue-400)}.text-blue-500{color:var(--color-blue-500)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-400{color:var(--color-green-400)}.text-green-500{color:var(--color-green-500)}.text-green-800{color:var(--color-green-800)}.text-indigo-600{color:var(--color-indigo-600)}.text-pink-700{color:var(--color-pink-700)}.text-purple-700{color:var(--color-purple-700)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.text-yellow-500{color:var(--color-yellow-500)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.inset-ring{--tw-inset-ring-shadow:inset 0 0 0 1px var(--tw-inset-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-gray-200{--tw-ring-color:var(--color-gray-200)}.ring-gray-900\/5{--tw-ring-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.ring-gray-900\/5{--tw-ring-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.inset-ring-blue-700\/10{--tw-inset-ring-color:#1447e61a}@supports (color:color-mix(in lab, red, red)){.inset-ring-blue-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-blue-700)10%,transparent)}}.inset-ring-gray-300{--tw-inset-ring-color:var(--color-gray-300)}.inset-ring-gray-700\/10{--tw-inset-ring-color:#3641531a}@supports (color:color-mix(in lab, red, red)){.inset-ring-gray-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-gray-700)10%,transparent)}}.inset-ring-gray-900\/5{--tw-inset-ring-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.inset-ring-gray-900\/5{--tw-inset-ring-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.inset-ring-pink-700\/10{--tw-inset-ring-color:#c4005c1a}@supports (color:color-mix(in lab, red, red)){.inset-ring-pink-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-pink-700)10%,transparent)}}.inset-ring-purple-700\/10{--tw-inset-ring-color:#8200da1a}@supports (color:color-mix(in lab, red, red)){.inset-ring-purple-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-purple-700)10%,transparent)}}.inset-ring-yellow-700\/10{--tw-inset-ring-color:#a361001a}@supports (color:color-mix(in lab, red, red)){.inset-ring-yellow-700\/10{--tw-inset-ring-color:color-mix(in oklab,var(--color-yellow-700)10%,transparent)}}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline,.outline-1{outline-style:var(--tw-outline-style);outline-width:1px}.-outline-offset-1{outline-offset:calc(1px*-1)}.outline-offset-2{outline-offset:2px}.outline-gray-200{outline-color:var(--color-gray-200)}.outline-gray-300{outline-color:var(--color-gray-300)}.outline-gray-900\/5{outline-color:#1018280d}@supports (color:color-mix(in lab, red, red)){.outline-gray-900\/5{outline-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.outline-indigo-600{outline-color:var(--color-indigo-600)}.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-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.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)}@media (hover:hover){.group-hover\:border-indigo-600:is(:where(.group):hover *){border-color:var(--color-indigo-600)}.group-hover\:text-indigo-600:is(:where(.group):hover *){color:var(--color-indigo-600)}}.group-has-checked\:translate-x-5:is(:where(.group):has(:checked) *){--tw-translate-x:calc(var(--spacing)*5);translate:var(--tw-translate-x)var(--tw-translate-y)}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}.last\:mb-0:last-child{margin-bottom:calc(var(--spacing)*0)}.focus-within\:outline-2:focus-within{outline-style:var(--tw-outline-style);outline-width:2px}.focus-within\:-outline-offset-2:focus-within{outline-offset:calc(2px*-1)}.focus-within\:outline-indigo-600:focus-within{outline-color:var(--color-indigo-600)}@media (hover:hover){.hover\:border-gray-300:hover{border-color:var(--color-gray-300)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-indigo-500:hover{background-color:var(--color-indigo-500)}.hover\:bg-red-500:hover{background-color:var(--color-red-500)}.hover\:text-gray-700:hover{color:var(--color-gray-700)}.hover\:text-indigo-600:hover{color:var(--color-indigo-600)}}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus\:outline-2:focus{outline-style:var(--tw-outline-style);outline-width:2px}.focus\:-outline-offset-2:focus{outline-offset:calc(2px*-1)}.focus\:outline-indigo-600:focus{outline-color:var(--color-indigo-600)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-blue-600:focus-visible{--tw-ring-color:var(--color-blue-600)}.focus-visible\:ring-gray-600:focus-visible{--tw-ring-color:var(--color-gray-600)}.focus-visible\:ring-green-600:focus-visible{--tw-ring-color:var(--color-green-600)}.focus-visible\:ring-red-600:focus-visible{--tw-ring-color:var(--color-red-600)}.focus-visible\:ring-yellow-600:focus-visible{--tw-ring-color:var(--color-yellow-600)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus-visible\:ring-offset-blue-50:focus-visible{--tw-ring-offset-color:var(--color-blue-50)}.focus-visible\:ring-offset-gray-50:focus-visible{--tw-ring-offset-color:var(--color-gray-50)}.focus-visible\:ring-offset-green-50:focus-visible{--tw-ring-offset-color:var(--color-green-50)}.focus-visible\:ring-offset-red-50:focus-visible{--tw-ring-offset-color:var(--color-red-50)}.focus-visible\:ring-offset-yellow-50:focus-visible{--tw-ring-offset-color:var(--color-yellow-50)}.focus-visible\:outline-hidden:focus-visible{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus-visible\:outline-hidden:focus-visible{outline-offset:2px;outline:2px solid #0000}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-indigo-600:focus-visible{outline-color:var(--color-indigo-600)}.focus-visible\:outline-red-600:focus-visible{outline-color:var(--color-red-600)}.has-checked\:bg-indigo-600:has(:checked){background-color:var(--color-indigo-600)}.has-focus-visible\:outline-2:has(:focus-visible){outline-style:var(--tw-outline-style);outline-width:2px}@media (min-width:40rem){.sm\:col-span-1{grid-column:span 1/span 1}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:col-span-3{grid-column:span 3/span 3}.sm\:col-span-4{grid-column:span 4/span 4}.sm\:mt-0{margin-top:calc(var(--spacing)*0)}.sm\:ml-4{margin-left:calc(var(--spacing)*4)}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-4{gap:calc(var(--spacing)*4)}.sm\:rounded-xl{border-radius:var(--radius-xl)}.sm\:p-6{padding:calc(var(--spacing)*6)}.sm\:px-0{padding-inline:calc(var(--spacing)*0)}.sm\:px-6{padding-inline:calc(var(--spacing)*6)}.sm\:px-8{padding-inline:calc(var(--spacing)*8)}.sm\:text-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing)*6)}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:w-xl{width:var(--container-xl)}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:p-5{padding:calc(var(--spacing)*5)}}@media (min-width:64rem){.lg\:mt-0{margin-top:calc(var(--spacing)*0)}.lg\:ml-4{margin-left:calc(var(--spacing)*4)}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:gap-x-6{column-gap:calc(var(--spacing)*6)}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}}@media (min-width:80rem){.xl\:fixed{position:fixed}.xl\:inset-y-0{inset-block:calc(var(--spacing)*0)}.xl\:z-50{z-index:50}.xl\:flex{display:flex}.xl\:hidden{display:none}.xl\:w-72{width:calc(var(--spacing)*72)}.xl\:flex-col{flex-direction:column}.xl\:flex-row{flex-direction:row}.xl\:items-center{align-items:center}.xl\:gap-x-2{column-gap:calc(var(--spacing)*2)}.xl\:pl-72{padding-left:calc(var(--spacing)*72)}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@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}
@@ -24,13 +24,10 @@ class Fino::Rails::RequestScopedCache::Pipe
24
24
  end
25
25
  end
26
26
 
27
- def write(setting_definition, value)
28
- pipe.write(setting_definition, value)
27
+ def write(setting_definition, value, **context)
28
+ pipe.write(setting_definition, value, **context)
29
29
 
30
- cache.write(
31
- setting_definition.key,
32
- setting_definition.type_class.build(setting_definition, value)
33
- )
30
+ cache.delete(setting_definition.key)
34
31
  end
35
32
 
36
33
  private
data/lib/fino/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fino
4
- VERSION = "1.1.4"
4
+ VERSION = "1.3.0"
5
5
  REQUIRED_RUBY_VERSION = ">= 3.0.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fino-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Egor Iskrenkov
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 1.1.4
18
+ version: 1.3.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 1.1.4
25
+ version: 1.3.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rails
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -55,12 +55,17 @@ files:
55
55
  - lib/fino/rails/app/helpers/fino/rails/application_helper.rb
56
56
  - lib/fino/rails/app/helpers/fino/rails/settings_helper.rb
57
57
  - lib/fino/rails/app/views/fino/rails/common/_flash.html.erb
58
- - lib/fino/rails/app/views/fino/rails/common/_navbar.html.erb
59
58
  - lib/fino/rails/app/views/fino/rails/common/_sidebar.html.erb
59
+ - lib/fino/rails/app/views/fino/rails/common/_topbar.html.erb
60
60
  - lib/fino/rails/app/views/fino/rails/dashboard/index.html.erb
61
61
  - lib/fino/rails/app/views/fino/rails/sections/show.html.erb
62
62
  - lib/fino/rails/app/views/fino/rails/settings/_setting.html.erb
63
+ - lib/fino/rails/app/views/fino/rails/settings/_setting_input.html.erb
63
64
  - lib/fino/rails/app/views/fino/rails/settings/edit.html.erb
65
+ - lib/fino/rails/app/views/fino/rails/settings/types/_boolean.html.erb
66
+ - lib/fino/rails/app/views/fino/rails/settings/types/_float.html.erb
67
+ - lib/fino/rails/app/views/fino/rails/settings/types/_integer.html.erb
68
+ - lib/fino/rails/app/views/fino/rails/settings/types/_string.html.erb
64
69
  - lib/fino/rails/app/views/layouts/fino/rails/application.html.erb
65
70
  - lib/fino/rails/config/routes.rb
66
71
  - lib/fino/rails/engine.rb