fino-rails 1.1.2 → 1.2.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: 0aa41cdc086dfb56b3d8901c501ed492c63de366140e1ea65260ff3fe47112e1
4
- data.tar.gz: 6d875fca0b93090caf9817c8c451400ea0a104a58523ca2aae4a68bafd3528ac
3
+ metadata.gz: ec074a93e3d93a7455a30b499f2639e2efb00836dcb29ebe1c7d97b326240722
4
+ data.tar.gz: 231e189e187fcf8c67552f4b166a8aa532d53086577ce86994d78211f0032528
5
5
  SHA512:
6
- metadata.gz: ee85940787ee390866a115f2c56fb8299483821ab55e9b2b1c12198b9915fae2b6593a7cbc7ca1f3c473387b3d67bb1b57ebb23a718fe66b2e32e6d19f70c29d
7
- data.tar.gz: be48e1a3dbd54e02a49bb6069b0e71cd8ad6cad38bdfb6cc1840d6dc94097af1f8b14acc63d0dc4b817c69de2c8482254dcc1de763b20b164e518a3eeaeaa2a6
6
+ metadata.gz: b5f73c57ece4d76260728dc55138e63bb7f7919720ab862854e896f0b92b4eb91dd833f8b1239cab43b93c5d2484e624c4992fe57720fbb2d96133e15ede040d
7
+ data.tar.gz: 74747303ceda55ae28fb9ff7e479fb0e98e38098740b6829bd0aa874d38fe6ade5233258ddb485bdab169fab3eeb353b54533af4fe3e40071a9f64a565f0b3e0
data/README.md CHANGED
@@ -75,11 +75,3 @@ end
75
75
  ```
76
76
 
77
77
  <img width="1229" height="641" alt="Screenshot 2025-09-04 at 16 01 51" src="https://github.com/user-attachments/assets/646df84c-c25b-4890-9637-c481e18c9bd4" />
78
-
79
- ## TODO
80
-
81
- - Preloading settings to be able to fetch all of them in one adapter call
82
- - Request scoped memoization when integrating with Rails
83
- - Nicer UI
84
- - Basic validations (presence, range, numericality)
85
- - Enum setting type
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Fino::Rails::SettingsController < Fino::Rails::ApplicationController
4
+ before_action :store_return_location, only: [:edit]
5
+
4
6
  def index
5
7
  @settings = Fino.settings
6
8
  end
@@ -12,13 +14,19 @@ class Fino::Rails::SettingsController < Fino::Rails::ApplicationController
12
14
  def update
13
15
  Fino.set(setting_name => params[:value], at: section_name)
14
16
 
15
- redirect_to root_path, notice: "Setting updated successfully"
16
- rescue Fino::Registry::UnknownSetting
17
- redirect_to root_path, alert: "Setting not found"
17
+ process_scope_overrides(params[:overrides]) if params[:overrides].present?
18
+
19
+ redirect_to return_path, notice: "Setting updated successfully"
20
+ rescue StandardError => e
21
+ redirect_to return_path, alert: "Failed to update setting: #{e.message}"
18
22
  end
19
23
 
20
24
  private
21
25
 
26
+ def return_path
27
+ session.delete(:return_to) || root_path
28
+ end
29
+
22
30
  def setting_name
23
31
  params[:setting]
24
32
  end
@@ -29,4 +37,20 @@ class Fino::Rails::SettingsController < Fino::Rails::ApplicationController
29
37
  else params[:section]
30
38
  end
31
39
  end
40
+
41
+ def process_scope_overrides(overrides_params)
42
+ overrides_params.each_value do |override_data|
43
+ scope = override_data[:scope]
44
+ value = override_data[:value]
45
+
46
+ next if scope.blank?
47
+ next if value.nil? || (value.is_a?(String) && value.empty?)
48
+
49
+ Fino.set(setting_name => value, scope: scope.to_sym, at: section_name)
50
+ end
51
+ end
52
+
53
+ def store_return_location
54
+ session[:return_to] = request.referer
55
+ end
32
56
  end
@@ -1,8 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fino::Rails::ApplicationHelper
4
+ FLASH_TYPE_TO_COLOR_MAPPING = {
5
+ notice: "green",
6
+ alert: "red"
7
+ }.freeze
8
+
4
9
  def fino_asset_path(file, version: true)
5
10
  path = "#{Rails.application.config.relative_url_root}/fino-assets/#{file}".gsub("//", "/")
6
11
  version ? "#{path}?v=#{Fino::VERSION}" : path
7
12
  end
13
+
14
+ def color_for_flash_type(flash_type)
15
+ FLASH_TYPE_TO_COLOR_MAPPING.fetch(flash_type.to_sym, "blue")
16
+ end
8
17
  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
@@ -0,0 +1,58 @@
1
+ <% flash.each do |type, message| %>
2
+ <% color = color_for_flash_type(type.to_sym) %>
3
+
4
+ <div id="flash-<%= type %>" class="rounded-md bg-<%= color%>-50 p-4 transition-opacity duration-500 ease-out opacity-100">
5
+ <div class="flex">
6
+ <div class="shrink-0">
7
+ <% case type.to_sym %>
8
+ <% when :notice %>
9
+ <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="size-5 text-<%= color%>-400">
10
+ <path d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" fill-rule="evenodd" />
11
+ </svg>
12
+ <% when :alert %>
13
+ <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="size-5 text-red-400">
14
+ <path d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd" fill-rule="evenodd" />
15
+ </svg>
16
+ <% end %>
17
+ </div>
18
+ <div class="ml-3">
19
+ <p class="text-sm font-medium text-<%= color%>-800"><%= message %></p>
20
+ </div>
21
+ <div class="ml-auto pl-3">
22
+ <div class="-mx-1.5 -my-1.5">
23
+ <button type="button" class="flash-dismiss inline-flex rounded-md bg-<%= color%>-50 p-1.5 text-<%= color%>-500 hover:bg-<%= color%>-100 focus-visible:ring-2 focus-visible:ring-<%= color%>-600 focus-visible:ring-offset-2 focus-visible:ring-offset-<%= color%>-50 focus-visible:outline-hidden">
24
+ <span class="sr-only">Dismiss</span>
25
+ <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="size-5">
26
+ <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
27
+ </svg>
28
+ </button>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ <% end %>
34
+
35
+ <script>
36
+ document.addEventListener('DOMContentLoaded', function() {
37
+ const flashElements = document.querySelectorAll('[id^="flash-"]');
38
+
39
+ flashElements.forEach(function(flashElement) {
40
+ const dismissButton = flashElement.querySelector('.flash-dismiss');
41
+
42
+ function dismissFlash() {
43
+ flashElement.classList.remove('opacity-100');
44
+ flashElement.classList.add('opacity-0');
45
+
46
+ setTimeout(function() {
47
+ flashElement.remove();
48
+ }, 500);
49
+ }
50
+
51
+ if (dismissButton) {
52
+ dismissButton.addEventListener('click', dismissFlash);
53
+ }
54
+
55
+ setTimeout(dismissFlash, 3000);
56
+ });
57
+ });
58
+ </script>
@@ -1,9 +1,68 @@
1
- <div class="m-3">
2
- <ul role="list" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
3
- <% @settings.each do |setting| %>
4
- <li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white border-1 border-gray-200">
5
- <%= render "fino/rails/settings/setting", locals: { setting: setting } %>
6
- </li>
1
+ <% content_for(:title, "Dashboard") %>
2
+
3
+ <% content_for(:topbar) do %>
4
+ <%= render "fino/rails/common/topbar" %>
5
+ <% end %>
6
+
7
+ <div class="p-3">
8
+ <div class="flex flex-col gap-y-3">
9
+ <%= render "fino/rails/common/flash" %>
10
+
11
+ <% @settings.group_by { |setting| setting.definition.section_definition&.label || "General" }.each do |section_label, settings| %>
12
+ <div class="mb-5">
13
+ <h3 class="text-base font-semibold text-gray-900"><%= section_label %></h3>
14
+
15
+ <ul role="list" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5 mt-2">
16
+ <% settings.each do |setting| %>
17
+ <li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white border-1 border-gray-200">
18
+ <%= link_to edit_setting_path(section: setting.section_name || :general, setting: setting.name) do %>
19
+ <div class="flex h-full justify-between p-4 hover:bg-gray-50 transition-colors rounded-lg">
20
+ <div class="flex flex-col space-y-3 justify-between truncate">
21
+ <div class="flex flex-col gap-1">
22
+ <div class="flex flex-col-reverse items-start gap-y-1 xl:flex-row xl:items-center xl:gap-x-2">
23
+ <h2 class="min-w-0 text-sm/6 font-semibold text-gray-900">
24
+ <span class="whitespace-nowrap"><%= setting.name %></span>
25
+ </h2>
26
+
27
+ <%= setting_type_label(setting) %>
28
+ </div>
29
+
30
+ <div>
31
+ <% case setting %>
32
+ <% when Fino::Settings::Boolean %>
33
+ <div class="flex items-center gap-x-2">
34
+ <% status = boolean_setting_status(setting) %>
35
+
36
+ <div class="flex-none rounded-full p-1 <%= "text-#{status[:color]}-500 bg-#{status[:color]}-100" %>">
37
+ <div class="size-2 rounded-full bg-current"></div>
38
+ </div>
39
+
40
+ <span class="text-lg font-medium text-gray-800"><%= status[:short_text] || status[:text] %></span>
41
+ </div>
42
+ <% when Fino::Settings::String %>
43
+ <div class="truncate text-xl font-semibold text-gray-800">
44
+ "<%= setting.value %>"
45
+ </div>
46
+ <% else %>
47
+ <div class="truncate text-xl font-semibold text-gray-800">
48
+ <%= setting.value %>
49
+ </div>
50
+ <% end %>
51
+ </div>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="flex items-center">
56
+ <svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="size-5 flex-none text-gray-400">
57
+ <path d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
58
+ </svg>
59
+ </div>
60
+ </div>
61
+ <% end %>
62
+ </li>
63
+ <% end %>
64
+ </ul>
65
+ </div>
7
66
  <% end %>
8
- </ul>
67
+ </div>
9
68
  </div>
@@ -1,11 +1,19 @@
1
1
  <% content_for(:title, "#{current_section.label}") %>
2
2
 
3
- <div class="m-3">
4
- <ul role="list" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
5
- <% @settings.each do |setting| %>
6
- <li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white border-1 border-gray-200">
7
- <%= render "fino/rails/settings/setting", locals: { setting: setting } %>
8
- </li>
9
- <% end %>
10
- </ul>
3
+ <% content_for(:topbar) do %>
4
+ <%= render "fino/rails/common/topbar" %>
5
+ <% end %>
6
+
7
+ <div class="p-3">
8
+ <div class="flex flex-col gap-y-3">
9
+ <%= render "fino/rails/common/flash" %>
10
+
11
+ <ul role="list" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
12
+ <% @settings.each do |setting| %>
13
+ <li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white border-1 border-gray-200">
14
+ <%= render "fino/rails/settings/setting", locals: { setting: setting } %>
15
+ </li>
16
+ <% end %>
17
+ </ul>
18
+ </div>
11
19
  </div>
@@ -1,12 +1,12 @@
1
1
  <% setting = locals.fetch(:setting) %>
2
2
 
3
3
  <%= link_to edit_setting_path(section: setting.section_name || :general, setting: setting.name) do %>
4
- <div class="flex w-full h-full justify-between p-6 hover:bg-gray-50 transition-colors rounded-lg">
5
- <div class="flex flex-col space-y-3 justify-between">
4
+ <div class="flex h-full justify-between p-6 hover:bg-gray-50 transition-colors rounded-lg">
5
+ <div class="flex flex-col space-y-3 justify-between truncate">
6
6
  <div class="flex flex-col gap-1">
7
- <div class="flex items-center gap-x-3">
7
+ <div class="flex flex-col-reverse items-start gap-y-1 xl:flex-row xl:items-center xl:gap-x-2">
8
8
  <h2 class="min-w-0 text-sm/6 font-semibold text-gray-900">
9
- <div class="flex gap-x-2">
9
+ <div class="flex gap-x-2 truncate">
10
10
  <span class="truncate"><%= setting.definition.section_definition&.label || "General" %></span>
11
11
  <span class="text-gray-500">/</span>
12
12
  <span class="whitespace-nowrap"><%= setting.name %></span>
@@ -21,15 +21,16 @@
21
21
  <% end %>
22
22
  </div>
23
23
 
24
- <div class="">
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,116 +1,195 @@
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="bg-white shadow-xs outline outline-gray-900/5 sm:rounded-xl md:col-span-2">
6
- <%= form_with url: update_setting_path(section: @setting.section_name || :general, setting: @setting.name), method: :put, local: true do |f| %>
7
- <div class="border-b border-gray-100 p-3 md:p-5 flex justify-between">
8
- <div class="flex self-center">
9
- <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>
10
- <span class="mx-2 text-gray-400">/</span>
11
- <h3 class="text-base font-semibold text-gray-900"><%= @setting.name %></h3>
12
- </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>
12
+
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>
13
18
 
14
- <div class="flex gap-3 lg:mt-0 lg:ml-4">
15
- <span>
16
- <%= 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" %>
17
- </span>
19
+ <div class="flex flex-col gap-2 pt-3">
20
+ <%= render "fino/rails/common/flash" %>
18
21
 
19
- <span>
20
- <%= 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" %>
21
- </span>
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>
22
26
  </div>
23
- </div>
24
27
 
25
- <div class="px-4 py-6 sm:p-6">
26
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
27
- <% case @setting %>
28
- <% when Fino::Settings::Boolean %>
29
- <div class="col-span-full">
30
- <div class="flex gap-3">
31
- <div class="flex h-6 shrink-0 items-center">
32
- <div class="group grid size-4 grid-cols-1">
33
- <%= f.check_box :value,
34
- {
35
- id: "value",
36
- class: "col-start-1 row-start-1 appearance-none rounded-sm border border-gray-300 bg-white checked:border-indigo-600 checked:bg-indigo-600 indeterminate:border-indigo-600 indeterminate:bg-indigo-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:border-gray-300 disabled:bg-gray-100 disabled:checked:bg-gray-100 forced-colors:appearance-auto",
37
- checked: @setting.value
38
- },
39
- '1',
40
- '0' %>
41
- <svg viewBox="0 0 14 14" fill="none" class="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-disabled:stroke-gray-950/25">
42
- <path d="M3 8L6 11L11 3.5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-0 group-has-checked:opacity-100" />
43
- <path d="M3 7H11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-0 group-has-indeterminate:opacity-100" />
44
- </svg>
45
- </div>
46
- </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>
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">
31
+ <div class="col-span-full">
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 %>
51
39
  </div>
52
40
  </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" %>
62
- </div>
63
- </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>
64
48
  </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 %>
77
- </div>
78
- </div>
79
- </div>
80
- <p class="mt-3 text-sm/6 text-gray-600"><%= @setting.description %></p>
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>
81
52
  </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 %>
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">Scope 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>
92
98
  </div>
93
99
  </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>
94
106
  </div>
95
- <p class="mt-3 text-sm/6 text-gray-600"><%= @setting.description %></p>
96
- </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" %>
97
127
  <% end %>
98
128
  </div>
99
129
  </div>
100
- <% end %>
130
+ </div>
131
+ <% end %>
132
+ </div>
133
+ </div>
134
+
135
+ <script>
136
+ document.addEventListener('DOMContentLoaded', function() {
137
+ const addButton = document.getElementById('add-override');
138
+ const overridesContainer = document.getElementById('scope-overrides');
139
+ const templateContainer = document.getElementById('override-templates');
140
+ let overrideIndex = <%= @setting.scope_overrides.length %>;
101
141
 
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>
142
+ addButton.addEventListener('click', function() {
143
+ // Get the template HTML and replace placeholders with actual index
144
+ let valueInputTemplate = templateContainer.innerHTML
145
+ .replace(/TEMPLATE_INDEX/g, overrideIndex)
146
+ .replace(/value_\d+/g, `value_${overrideIndex}`)
147
+ .trim();
148
+
149
+ const template = `
150
+ <div class="scope-override-item mb-6" data-index="${overrideIndex}">
151
+ <div class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
152
+ <div class="sm:col-span-2">
153
+ <label for="overrides_${overrideIndex}_scope" class="block text-sm/6 font-medium text-gray-900">Scope</label>
154
+ <div class="mt-2">
155
+ <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" />
156
+ </div>
157
+ </div>
158
+
159
+ <div class="sm:col-span-3">
160
+ <label for="overrides_${overrideIndex}_value" class="block text-sm/6 font-medium text-gray-900">Value</label>
161
+ <div class="mt-2">
162
+ ${valueInputTemplate}
163
+ </div>
107
164
  </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>
165
+
166
+ <div class="sm:col-span-1 flex items-end">
167
+ <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>
111
168
  </div>
112
- </dl>
169
+ </div>
113
170
  </div>
114
- </div>
115
- </div>
116
- </div>
171
+ `;
172
+
173
+ // Remove "no overrides" message if it exists
174
+ const noOverridesMsg = overridesContainer.querySelector('.text-center');
175
+ if (noOverridesMsg) {
176
+ noOverridesMsg.remove();
177
+ }
178
+
179
+ overridesContainer.insertAdjacentHTML('beforeend', template);
180
+ overrideIndex++;
181
+ });
182
+
183
+ // Handle remove buttons
184
+ overridesContainer.addEventListener('click', function(e) {
185
+ if (e.target.classList.contains('remove-override')) {
186
+ e.target.closest('.scope-override-item').remove();
187
+
188
+ // Show "no overrides" message if all removed
189
+ if (!overridesContainer.querySelector('.scope-override-item')) {
190
+ overridesContainer.innerHTML = '<div class="text-center py-6"><p class="text-sm text-gray-500">No scope overrides configured.</p></div>';
191
+ }
192
+ }
193
+ });
194
+ });
195
+ </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}}}@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-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-700:oklch(55.4% .135 66.442);--color-green-100:oklch(96.2% .044 156.743);--color-green-500:oklch(72.3% .219 149.579);--color-blue-50:oklch(97% .014 254.604);--color-blue-700:oklch(48.8% .243 264.376);--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;--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}.sticky{position:sticky}.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\.5{margin:calc(var(--spacing)*-2.5)}.m-3{margin:calc(var(--spacing)*3)}.-mx-2{margin-inline:calc(var(--spacing)*-2)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-auto{margin-inline:auto}.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-5{margin-top:calc(var(--spacing)*5)}.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}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.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\.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-32{min-height:calc(var(--spacing)*32)}.w-9{width:calc(var(--spacing)*9)}.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}.items-center{align-items:center}.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-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-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-current{background-color:currentColor}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-200{background-color:var(--color-gray-200)}.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-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)}.stroke-white{stroke:var(--color-white)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-2\.5{padding:calc(var(--spacing)*2.5)}.p-3{padding:calc(var(--spacing)*3)}.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\.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-10{padding-top:calc(var(--spacing)*10)}.pr-3{padding-right:calc(var(--spacing)*3)}.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-700{color:var(--color-blue-700)}.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-500{color:var(--color-green-500)}.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-500{color:var(--color-red-500)}.text-white{color:var(--color-white)}.text-yellow-700{color:var(--color-yellow-700)}.opacity-0{opacity:0}.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)}.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-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-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)}}.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))}@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\: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-indigo-500:hover{background-color:var(--color-indigo-500)}.hover\:text-indigo-600:hover{color:var(--color-indigo-600)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.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)}@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\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.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\: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\: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}
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-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)}.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)}.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}.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-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)}}.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)}.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-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)}.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-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\: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\:mt-0{margin-top:calc(var(--spacing)*0)}.sm\:ml-4{margin-left:calc(var(--spacing)*4)}.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\: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-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.2"
4
+ VERSION = "1.2.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.2
4
+ version: 1.2.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.2
18
+ version: 1.2.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.2
25
+ version: 1.2.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rails
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -54,12 +54,18 @@ files:
54
54
  - lib/fino/rails/app/controllers/fino/rails/settings_controller.rb
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
- - lib/fino/rails/app/views/fino/rails/common/_navbar.html.erb
57
+ - lib/fino/rails/app/views/fino/rails/common/_flash.html.erb
58
58
  - lib/fino/rails/app/views/fino/rails/common/_sidebar.html.erb
59
+ - lib/fino/rails/app/views/fino/rails/common/_topbar.html.erb
59
60
  - lib/fino/rails/app/views/fino/rails/dashboard/index.html.erb
60
61
  - lib/fino/rails/app/views/fino/rails/sections/show.html.erb
61
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
62
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
63
69
  - lib/fino/rails/app/views/layouts/fino/rails/application.html.erb
64
70
  - lib/fino/rails/config/routes.rb
65
71
  - lib/fino/rails/engine.rb