From 8684a684712205324894723a776f9392816c9fb1 Mon Sep 17 00:00:00 2001 From: Bryce Date: Fri, 20 Oct 2023 13:56:59 -0700 Subject: [PATCH 01/34] stacked radios --- resources/public/output.css | 8 ++++++++ .../auto_ap/ssr/admin/transaction_rules.clj | 9 ++++++++- src/clj/auto_ap/ssr/components/radio.clj | 18 +++++++++++++----- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index fd7ea057..5029ff16 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1404,6 +1404,10 @@ input:checked + .toggle-bg { width: 100%; } +.w-auto { + width: auto; +} + .max-w-2xl { max-width: 42rem; } @@ -1444,6 +1448,10 @@ input:checked + .toggle-bg { flex-shrink: 1; } +.shrink-0 { + flex-shrink: 0; +} + .basis-1\/4 { flex-basis: 25%; } diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 17b95695..01fcbdca 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -546,7 +546,8 @@ :errors (fc/field-errors)} (com/radio {:options (ref->radio-options "transaction-approval-status") :value (fc/field-value) - :name (fc/field-name)}))) + :name (fc/field-name) + :orientation :horizontal}))) [:div#form-errors [:span.error-content (com/errors {:errors (:errors fc/*form-errors*)})]] @@ -554,6 +555,12 @@ "Save")])]] [:div]))) + +;; TODO Should forms have some kind of helper to render an individual field? saving +;; could generate the entire form and swap if there are errors +;; but also when you tab out it could call the same function, and just +;; pull out the single field to swap + (defn new-account [{{:keys [client-id index]} :query-params}] (let [index (or index 0) ;; TODO schema decode is not working transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] diff --git a/src/clj/auto_ap/ssr/components/radio.clj b/src/clj/auto_ap/ssr/components/radio.clj index a793a901..bd27c9bb 100644 --- a/src/clj/auto_ap/ssr/components/radio.clj +++ b/src/clj/auto_ap/ssr/components/radio.clj @@ -1,10 +1,15 @@ -(ns auto-ap.ssr.components.radio) +(ns auto-ap.ssr.components.radio + (:require [auto-ap.ssr.hiccup-helper :as hh])) -(defn radio- [{:keys [options name title size] :or {size :medium} selected-value :value}] +(defn radio- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] - [:ul {:class "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white"} + [:ul {:class (cond-> "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white" + (= orientation :horizontal) (-> (hh/add-class "flex gap-8") + (hh/remove-wildcard ["w-" "rounded-lg" "border" "bg-"])))} (for [{:keys [value content]} options] - [:li {:class "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600"} + [:li {:class (cond-> "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600" + (= orientation :horizontal) (-> (hh/remove-wildcard ["w-full" "rounded-"]) + (hh/add-class "w-auto shrink-0 block rounded-lg border border-gray-200 dark:border-gray-600 px-3")))} [:div {:class "flex items-center pl-3"} [:input (cond-> {:id (str "list-" name "-" value) :type "radio", @@ -25,4 +30,7 @@ (str " " "text-xs py-2") (= size :medium) - (str " " "text-sm py-3"))} content]]])]) + (str " " "text-sm py-3") + + (= orientation :horizontal) + (hh/remove-class "w-full"))} content]]])]) From ffcc43ba5e5894fa6ca30293100d6dcfe58138af Mon Sep 17 00:00:00 2001 From: Bryce Date: Fri, 20 Oct 2023 17:52:15 -0700 Subject: [PATCH 02/34] alpine for dropdown. --- resources/public/output.css | 85 +++++++++++++++++++ .../auto_ap/ssr/admin/transaction_rules.clj | 49 ++++++----- src/clj/auto_ap/ssr/company.clj | 19 ++--- src/clj/auto_ap/ssr/components.clj | 1 + src/clj/auto_ap/ssr/components/dialog.clj | 6 +- src/clj/auto_ap/ssr/components/inputs.clj | 70 ++++++++++++++- src/clj/auto_ap/ssr/svg.clj | 2 +- src/clj/auto_ap/ssr/ui.clj | 32 ++++--- 8 files changed, 215 insertions(+), 49 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 5029ff16..fc47979a 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1252,6 +1252,26 @@ input:checked + .toggle-bg { margin-top: 1.25rem; } +.\!mt-0 { + margin-top: 0px !important; +} + +.\!mt-3 { + margin-top: 0.75rem !important; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.\!mt-1 { + margin-top: 0.25rem !important; +} + +.ml-64 { + margin-left: 16rem; +} + .block { display: block; } @@ -1408,6 +1428,11 @@ input:checked + .toggle-bg { width: auto; } +.w-max { + width: -moz-max-content; + width: max-content; +} + .max-w-2xl { max-width: 42rem; } @@ -1452,6 +1477,10 @@ input:checked + .toggle-bg { flex-shrink: 0; } +.flex-grow { + flex-grow: 1; +} + .basis-1\/4 { flex-basis: 25%; } @@ -1622,6 +1651,10 @@ input:checked + .toggle-bg { justify-content: space-between; } +.justify-items-stretch { + justify-items: stretch; +} + .gap-1 { gap: 0.25rem; } @@ -1714,6 +1747,22 @@ input:checked + .toggle-bg { border-color: rgb(243 244 246 / var(--tw-divide-opacity)); } +.place-self-start { + place-self: start; +} + +.place-self-end { + place-self: end; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + .overflow-auto { overflow: auto; } @@ -2326,6 +2375,10 @@ input:checked + .toggle-bg { opacity: 1; } +.\!opacity-0 { + opacity: 0 !important; +} + .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -2354,6 +2407,10 @@ input:checked + .toggle-bg { outline-style: solid; } +.outline-0 { + outline-width: 0px; +} + .ring { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); @@ -2411,6 +2468,10 @@ input:checked + .toggle-bg { transition-duration: 75ms; } +.duration-200 { + transition-duration: 200ms; +} + .ease-in-out { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } @@ -2419,6 +2480,10 @@ input:checked + .toggle-bg { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } +.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { + transition-timing-function: cubic-bezier(.3,2.3,.6,1); +} + .htmx-added .fade-in { opacity: 0.0 !important; } @@ -2862,6 +2927,11 @@ input:checked + .toggle-bg { background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } +.hover\:bg-neutral-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(245 245 245 / var(--tw-bg-opacity)); +} + .hover\:text-blue-600:hover { --tw-text-opacity: 1; color: rgb(0 125 187 / var(--tw-text-opacity)); @@ -2910,6 +2980,11 @@ input:checked + .toggle-bg { border-color: rgb(121 181 46 / var(--tw-border-opacity)); } +.focus\:bg-neutral-100:focus { + --tw-bg-opacity: 1; + background-color: rgb(245 245 245 / var(--tw-bg-opacity)); +} + .focus\:text-green-700:focus { --tw-text-opacity: 1; color: rgb(73 109 28 / var(--tw-text-opacity)); @@ -3524,3 +3599,13 @@ input:checked + .toggle-bg { padding-left: 16rem; } } + +.\[\&\.active\]\:bg-red-500.active { + --tw-bg-opacity: 1; + background-color: rgb(255 3 3 / var(--tw-bg-opacity)); +} + +.\[\&\.active\]\:bg-primary-500.active { + --tw-bg-opacity: 1; + background-color: rgb(121 181 46 / var(--tw-bg-opacity)); +} diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 01fcbdca..d7b0cc0d 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -306,7 +306,7 @@ (or (get tempids (:db/id entity)) (:db/id entity)))] (html-response (row* identity updated-account {:flash? true}) - :headers {"hx-trigger" "modalClosing" + :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#transaction-rule-table tr[data-id=\"%d\"]" (:db/id updated-account))}))) @@ -330,7 +330,7 @@ (defn- account-typeahead* [{:keys [name value client-id]}] [:div.flex.flex-col - (com/typeahead {:name name + (com/typeahead-2 {:name name :placeholder "Search..." :url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id) :id name @@ -408,6 +408,7 @@ :href "#"} svg/x)))) +;; TODO dialog is no longer closeable (defn dialog* [& {:keys [ entity form-params form-errors]}] (com/modal {:modal-class "max-w-4xl"} @@ -417,7 +418,8 @@ [:form#edit-form (merge {:hx-ext "response-targets" :hx-swap "outerHTML swap:300ms" :hx-target "#modal-holder" - :hx-target-400 "#form-errors .error-content"} + :hx-target-400 "#form-errors .error-content" + #_#_:x-trap "true"} form-params) [:fieldset {:class "hx-disable" :hx-disinherit "hx-target"} @@ -433,17 +435,18 @@ {:label "Client" :errors (fc/field-errors)} [:div.w-96 - (com/typeahead {:name (fc/field-name) - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :company-search) - :id (str "form-client-search") - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) + (com/typeahead-2 {:name (fc/field-name) + :x-init "$el.focus()" + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :id (str "form-client-search") + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (fn [c] (cond->> c + (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) + true :client/name))})])) (fc/with-field :transaction-rule/bank-account @@ -510,13 +513,13 @@ (com/validated-field {:label "Assign Vendor" :errors (fc/field-errors)} [:div.w-96 - (com/typeahead {:name (fc/field-name) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :id (str "form-vendor-search") - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :id (str "form-vendor-search") + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) (fc/with-field :transaction-rule/accounts (list @@ -609,7 +612,7 @@ (html-response (dialog* :entity entity :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger" "modalOpening"}))) + :headers {"hx-trigger" "modalopen"}))) (defn transaction-rule-error [request] (let [entity (some-> request :last-form)] @@ -629,7 +632,7 @@ :form-errors {} :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger" "modalOpening"})) + :headers {"hx-trigger" "modalopen"})) (def transaction-rule-schema (mc/schema [:map diff --git a/src/clj/auto_ap/ssr/company.clj b/src/clj/auto_ap/ssr/company.clj index 3891bb3a..075bae63 100644 --- a/src/clj/auto_ap/ssr/company.clj +++ b/src/clj/auto_ap/ssr/company.clj @@ -95,7 +95,7 @@ selected-client-id) :client/bank-accounts (filter (fn [{:keys [bank-account/name]}] - (str/includes? (str/upper-case name) + (str/includes? (or (some-> name str/upper-case) "") (or (some-> query-params (get "q") str/upper-case) @@ -108,15 +108,14 @@ (defn bank-account-typeahead* [{:keys [client-id name value]}] (if client-id - (com/typeahead {:name name - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :bank-account-search - :db/id client-id) - :id (str "form-bank-account-search") - :value value - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :bank-account/name #(pull-attr (dc/db conn) :bank-account/name %))}) + (com/typeahead-2 {:name name + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :bank-account-search + :db/id client-id) + :value value + :value-fn (some-fn :db/id identity) + :content-fn (some-fn :bank-account/name #(pull-attr (dc/db conn) :bank-account/name %))}) [:span.text-xs.text-gray-500 "Please select a client before selecting a bank account." [:input {:type "hidden" :name name}]])) diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index e7f6782d..41fff258 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -31,6 +31,7 @@ (def hidden inputs/hidden-) (def select inputs/select-) (def typeahead inputs/typeahead-) +(def typeahead-2 inputs/typeahead-2-) (def field-errors inputs/field-errors-) (def field inputs/field-) (def validated-field inputs/validated-field-) diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index e6e2e99e..4087c83c 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -2,10 +2,10 @@ (:require [hiccup2.core :as hiccup])) (defn modal- [params & children] - [:div {:class (str "relative w-full max-h-full " (or (:modal-class params) " max-w-2xl "))} + [:div {:class (str "relative w-full max-h-full " (or (:modal-class params) " max-w-2xl ")) + "@click.outside" "open=false"} (into [:div#modal-content] - children)] - ) + children)]) (defn modal-card- [params header content footer] [:div#modal-card params diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 02678df7..a19199e6 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -2,7 +2,9 @@ (:require [hiccup2.core :as hiccup] [auto-ap.ssr.hiccup-helper :as hh] - [clojure.string :as str])) + [clojure.string :as str] + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.hx :as hx])) (def default-input-classes @@ -68,6 +70,72 @@ c.clearChoices(); (:url params) ))]]) +(defn typeahead-2- [params] + [:div {:x-data (hx/json {:open false + :baseUrl (if (str/includes? (:url params) "?") + (str (:url params) "&q=") + (str (:url params) "?q=")) + :value {:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))} + :search "" + :active 0 + :elements (if (:value params) + [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] + [])}) + } + [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) + (hh/add-class "cursor-pointer")) + "@click.prevent.stop" "open = !open;" + "@keydown.enter.prevent.stop" "open = !open;" + :x-init (:x-init params) + :tabindex 0} + [:input (-> params + (dissoc :class) + (dissoc :value-fn) + (dissoc :content-fn) + (dissoc :x-init) + (dissoc :placeholder) + (assoc + "x-ref" "hidden" + :type "hidden" + ":value" "value.value" + :x-init "$watch('value', v => $dispatch('change'))"))] + [:div.flex.w-full.justify-items-stretch + [:span.flex-grow.text-left {"x-text" "value.label"}] + [:div {:class "w-5 h-5 inline ml-1 justify-self-end"} + svg/drop-down]]] + + [:ul.dropdown-contents {:class "absolute bg-white rounded-lg shadow-lg py-1 w-max z-10 mt-1" + "@keydown.escape.window" "open = false" + "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" + "x-transition:enter-start" "!opacity-0 !mt-0" + "x-transition:enter-end" "!opacity-1 !mt-1" + "x-transition:leave" "ease-out duration-200" + "x-transition:leave-start" "!opacity-1 !mt-1" + "x-transition:leave-end" "!opacity-0 !mt-0" + "x-show ""open" + "x-trap" "open" + "@click.outside" "open=false"} + [:input {:type "text" :class (hh/add-class (or (:class params) "") default-input-classes) + "x-model" "search" + "placeholder" (:placeholder params) + "@keydown.down.prevent" "active ++; active = active >= elements.length - 1 ? elements.length - 1 : active" + "@keydown.up.prevent" "active --; active = active < 0 ? 0 : active" + "@keydown.enter.prevent" "open = false; value = elements.length > 0 ? $data.elements[active] : {'value': '', label: ''}; console.log('are we here')" + "x-init" "$watch('search', s => { if($el.value.length > 2) {fetch(baseUrl + s).then(data=>data.json()).then(data => {elements = data; active=-1}) }})"}] + [:div.dropdown-options + [:template {:x-for "(element, index) in elements"} + [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500" + :href "#" + ":class" "active == index ? 'active' : ''" + "@mouseover" "active = index" + "@mouseout" "active = -1" + "@click.prevent" "value = element; open=false; " + "x-html" "element.label" + }]]] + [:template {:x-if "elements.length == 0"} + [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-500 text-xs "} + "No results found"]]]]]) + (defn use-size [size] (if (= :small size) diff --git a/src/clj/auto_ap/ssr/svg.clj b/src/clj/auto_ap/ssr/svg.clj index 385bbc1b..077f0988 100644 --- a/src/clj/auto_ap/ssr/svg.clj +++ b/src/clj/auto_ap/ssr/svg.clj @@ -200,7 +200,7 @@ :stroke-linejoin "round"}]]) (def drop-down - [:svg {:class "w-4 h-4 ml-2", :aria-hidden "true", :fill "none", :stroke "currentColor", :viewbox "0 0 24 24", :xmlns "http://www.w3.org/2000/svg"} + [:svg {:aria-hidden "true", :fill "none", :stroke "currentColor", :viewbox "0 0 24 24", :xmlns "http://www.w3.org/2000/svg"} [:path {:stroke-linecap "round", :stroke-linejoin "round", :stroke-width "2", :d "M19 9l-7 7-7-7"}]]) (def download diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 41ba3fe2..2564987f 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -1,6 +1,7 @@ (ns auto-ap.ssr.ui (:require - [hiccup2.core :as hiccup])) + [hiccup2.core :as hiccup] + [auto-ap.ssr.hx :as hx])) (defn html-page [hiccup] {:status 200 @@ -42,7 +43,8 @@ [:script {:src "https://unpkg.com/dropzone@5.9.3/dist/min/dropzone.min.js"}] [:link {:rel "stylesheet" :href "https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" :type "text/css"}] - #_[:script {:defer true :src "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"}] + [:script {:defer true :src "https://cdn.jsdelivr.net/npm/@alpinejs/focus@3.x.x/dist/cdn.min.js"}] + [:script {:defer true :src "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"}] [:style " input::-webkit-outer-spin-button, @@ -58,24 +60,32 @@ input[type=number] { " ] - [:body {:hx-ext "disable-submit"} + [:body {:hx-ext "disable-submit" + "x-data" (hx/json {:modalOpen false})} contents [:script {:src "/js/flowbite.min.js"}] - [:div [:div#modal-holder - { :tabindex "-1", :class "fixed top-0 left-0 right-0 z-50 w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full flex justify-center hidden" - :aria-hidden true - "_" (hiccup/raw "on \"modalClosed\" remove my children - on \"modalOpening\" from call curModal.show() - on \"modalClosing\" from call curModal.hide()") + [:div + {"x-data" (hx/json {"open" false}) + "@modalopen.document" "open=true" + "@modalclose.document" "open=false"} + + [:div#modal-holder + { :tabindex "-1", :class "fixed top-0 left-0 right-0 z-50 w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full flex justify-center" + ":class" "open ? '' : 'hidden'" + ":aria-hidden" "!open" }] - [:script {:lang "text/javascript"} + [:div {:class " bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" + ":class" "open ? '' : 'hidden'" + ":aria-hidden" "!open" + }] + #_[:script {:lang "text/javascript"} (hiccup/raw " var modal_element = document.getElementById('modal-holder'); var modal_options = { placement: 'center', backdrop: 'dynamic', backdropClasess: 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40', - closable: true, + closable: false, onOpen: function() { htmx.trigger(document.getElementById('modal-holder'), 'modalOpened', {}); From 2fc9a7157727adbd1747e728dcc88290d22f8dd3 Mon Sep 17 00:00:00 2001 From: Bryce Date: Fri, 20 Oct 2023 22:23:47 -0700 Subject: [PATCH 03/34] vertical alignment --- resources/public/output.css | 8 ++++++++ src/clj/auto_ap/ssr/admin/transaction_rules.clj | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index fc47979a..8df77b4b 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1755,6 +1755,10 @@ input:checked + .toggle-bg { place-self: end; } +.self-start { + align-self: flex-start; +} + .justify-self-start { justify-self: start; } @@ -2208,6 +2212,10 @@ input:checked + .toggle-bg { vertical-align: baseline; } +.align-top { + vertical-align: top; +} + .text-2xl { font-size: 1.5rem; line-height: 2rem; diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index d7b0cc0d..34928a2b 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -402,11 +402,11 @@ :value (some-> (fc/field-value) (* 100 ) (long ))})))))) - (com/data-grid-cell - (com/a-icon-button - {"_" (hiccup/raw "on click halt the event then transition the closest 's opacity to 0 then remove closest ") - :href "#"} - svg/x)))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button + {"_" (hiccup/raw "on click halt the event then transition the closest 's opacity to 0 then remove closest ") + :href "#"} + svg/x)))) ;; TODO dialog is no longer closeable (defn dialog* [& {:keys [ entity form-params form-errors]}] From aa14a310ab69d540fde455b3e00ca2151b358404 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Oct 2023 07:37:05 -0700 Subject: [PATCH 04/34] big ui improvemet --- resources/public/output.css | 261 +++++++++++++--- .../auto_ap/ssr/admin/transaction_rules.clj | 281 +++++++++--------- src/clj/auto_ap/ssr/components/dialog.clj | 13 +- src/clj/auto_ap/ssr/components/inputs.clj | 38 ++- src/clj/auto_ap/ssr/ui.clj | 64 ++-- .../extract-line-items-from-invoice.repl | 31 ++ 6 files changed, 438 insertions(+), 250 deletions(-) create mode 100644 src/cljc/auto_ap/extract-line-items-from-invoice.repl diff --git a/resources/public/output.css b/resources/public/output.css index 8df77b4b..15e78cd2 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1123,6 +1123,10 @@ input:checked + .toggle-bg { z-index: 50; } +.z-\[99\] { + z-index: 99; +} + .col-span-1 { grid-column: span 1 / span 1; } @@ -1172,6 +1176,29 @@ input:checked + .toggle-bg { margin-bottom: 1rem; } +.mx-8 { + margin-left: 2rem; + margin-right: 2rem; +} + +.my-8 { + margin-top: 2rem; + margin-bottom: 2rem; +} + +.my-64 { + margin-top: 16rem; + margin-bottom: 16rem; +} + +.\!mt-0 { + margin-top: 0px !important; +} + +.\!mt-1 { + margin-top: 0.25rem !important; +} + .-mb-1 { margin-bottom: -0.25rem; } @@ -1252,24 +1279,16 @@ input:checked + .toggle-bg { margin-top: 1.25rem; } -.\!mt-0 { - margin-top: 0px !important; +.\!mt-64 { + margin-top: 16rem !important; } -.\!mt-3 { - margin-top: 0.75rem !important; +.\!mt-32 { + margin-top: 8rem !important; } -.mt-3 { - margin-top: 0.75rem; -} - -.\!mt-1 { - margin-top: 0.25rem !important; -} - -.ml-64 { - margin-left: 16rem; +.mr-5 { + margin-right: 1.25rem; } .block { @@ -1356,6 +1375,19 @@ input:checked + .toggle-bg { height: 100vh; } +.h-auto { + height: auto; +} + +.h-min { + height: -moz-min-content; + height: min-content; +} + +.h-64 { + height: 16rem; +} + .max-h-96 { max-height: 24rem; } @@ -1364,6 +1396,10 @@ input:checked + .toggle-bg { max-height: 100%; } +.max-h-screen { + max-height: 100vh; +} + .w-1\/2 { width: 50%; } @@ -1420,19 +1456,23 @@ input:checked + .toggle-bg { width: 24rem; } -.w-full { - width: 100%; -} - .w-auto { width: auto; } +.w-full { + width: 100%; +} + .w-max { width: -moz-max-content; width: max-content; } +.w-screen { + width: 100vw; +} + .max-w-2xl { max-width: 42rem; } @@ -1481,6 +1521,10 @@ input:checked + .toggle-bg { flex-grow: 1; } +.grow-0 { + flex-grow: 0; +} + .basis-1\/4 { flex-basis: 25%; } @@ -1520,6 +1564,26 @@ input:checked + .toggle-bg { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } +.\!translate-y-0 { + --tw-translate-y: 0px !important; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; +} + +.\!translate-y-32 { + --tw-translate-y: 8rem !important; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; +} + +.translate-y-0 { + --tw-translate-y: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.translate-y-4 { + --tw-translate-y: 1rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .rotate-180 { --tw-rotate: 180deg; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1611,10 +1675,18 @@ input:checked + .toggle-bg { flex-wrap: wrap; } +.place-content-center { + place-content: center; +} + .place-items-center { place-items: center; } +.content-center { + align-content: center; +} + .items-start { align-items: flex-start; } @@ -1651,6 +1723,10 @@ input:checked + .toggle-bg { justify-content: space-between; } +.justify-items-center { + justify-items: center; +} + .justify-items-stretch { justify-items: stretch; } @@ -1747,22 +1823,6 @@ input:checked + .toggle-bg { border-color: rgb(243 244 246 / var(--tw-divide-opacity)); } -.place-self-start { - place-self: start; -} - -.place-self-end { - place-self: end; -} - -.self-start { - align-self: flex-start; -} - -.justify-self-start { - justify-self: start; -} - .justify-self-end { justify-self: end; } @@ -1775,6 +1835,10 @@ input:checked + .toggle-bg { overflow: hidden; } +.overflow-scroll { + overflow: scroll; +} + .overflow-x-auto { overflow-x: auto; } @@ -2060,10 +2124,31 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + .bg-opacity-50 { --tw-bg-opacity: 0.5; } +.\!bg-opacity-0 { + --tw-bg-opacity: 0 !important; +} + +.\!bg-opacity-50 { + --tw-bg-opacity: 0.5 !important; +} + +.bg-opacity-40 { + --tw-bg-opacity: 0.4; +} + +.\!bg-opacity-100 { + --tw-bg-opacity: 1 !important; +} + .p-1 { padding: 0.25rem; } @@ -2088,6 +2173,10 @@ input:checked + .toggle-bg { padding: 1.5rem; } +.p-12 { + padding: 3rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -2148,6 +2237,16 @@ input:checked + .toggle-bg { padding-bottom: 1.25rem; } +.px-7 { + padding-left: 1.75rem; + padding-right: 1.75rem; +} + +.py-6 { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + .pb-2 { padding-bottom: 0.5rem; } @@ -2371,10 +2470,19 @@ input:checked + .toggle-bg { color: rgb(114 59 19 / var(--tw-text-opacity)); } +.text-gray-200 { + --tw-text-opacity: 1; + color: rgb(229 231 235 / var(--tw-text-opacity)); +} + .underline { text-decoration-line: underline; } +.\!opacity-0 { + opacity: 0 !important; +} + .opacity-0 { opacity: 0; } @@ -2383,8 +2491,12 @@ input:checked + .toggle-bg { opacity: 1; } -.\!opacity-0 { - opacity: 0 !important; +.\!opacity-50 { + opacity: 0.5 !important; +} + +.\!opacity-100 { + opacity: 1 !important; } .shadow { @@ -2464,6 +2576,10 @@ input:checked + .toggle-bg { transition-duration: 100ms; } +.duration-200 { + transition-duration: 200ms; +} + .duration-300 { transition-duration: 300ms; } @@ -2476,8 +2592,12 @@ input:checked + .toggle-bg { transition-duration: 75ms; } -.duration-200 { - transition-duration: 200ms; +.duration-1000 { + transition-duration: 1000ms; +} + +.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { + transition-timing-function: cubic-bezier(.3,2.3,.6,1); } .ease-in-out { @@ -2488,8 +2608,8 @@ input:checked + .toggle-bg { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } -.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { - transition-timing-function: cubic-bezier(.3,2.3,.6,1); +.ease-in { + transition-timing-function: cubic-bezier(0.4, 0, 1, 1); } .htmx-added .fade-in { @@ -2920,6 +3040,11 @@ input:checked + .toggle-bg { background-color: rgb(73 109 28 / var(--tw-bg-opacity)); } +.hover\:bg-neutral-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(245 245 245 / var(--tw-bg-opacity)); +} + .hover\:bg-primary-100:hover { --tw-bg-opacity: 1; background-color: rgb(228 240 213 / var(--tw-bg-opacity)); @@ -2935,9 +3060,9 @@ input:checked + .toggle-bg { background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.hover\:bg-neutral-100:hover { +.hover\:bg-gray-50:hover { --tw-bg-opacity: 1; - background-color: rgb(245 245 245 / var(--tw-bg-opacity)); + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); } .hover\:text-blue-600:hover { @@ -3483,6 +3608,43 @@ input:checked + .toggle-bg { display: block; } + .sm\:max-h-\[80vh\] { + max-height: 80vh; + } + + .sm\:max-w-lg { + max-width: 32rem; + } + + .sm\:max-w-xl { + max-width: 36rem; + } + + .sm\:max-w-2xl { + max-width: 42rem; + } + + .sm\:max-w-4xl { + max-width: 56rem; + } + + .sm\:translate-y-0 { + --tw-translate-y: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .sm\:scale-100 { + --tw-scale-x: 1; + --tw-scale-y: 1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .sm\:scale-95 { + --tw-scale-x: .95; + --tw-scale-y: .95; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .sm\:rounded-lg { border-radius: 0.5rem; } @@ -3608,12 +3770,17 @@ input:checked + .toggle-bg { } } -.\[\&\.active\]\:bg-red-500.active { - --tw-bg-opacity: 1; - background-color: rgb(255 3 3 / var(--tw-bg-opacity)); -} - .\[\&\.active\]\:bg-primary-500.active { --tw-bg-opacity: 1; background-color: rgb(121 181 46 / var(--tw-bg-opacity)); } + +.\[\&\.active\]\:bg-primary-300.active { + --tw-bg-opacity: 1; + background-color: rgb(175 211 130 / var(--tw-bg-opacity)); +} + +:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active { + --tw-bg-opacity: 1; + background-color: rgb(73 109 28 / var(--tw-bg-opacity)); +} diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 34928a2b..dbb4d10b 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -196,7 +196,7 @@ :action-buttons (fn [request] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-new-dialog)) - :hx-target "#modal-holder" + :hx-target "#modal-content" :hx-swap "innerHTML" :color :primary} "New Transaction Rule")]) @@ -204,7 +204,7 @@ [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-dialog :db/id (:db/id entity))) - :hx-target "#modal-holder" + :hx-target "#modal-content" :hx-swap "innerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes @@ -409,154 +409,153 @@ svg/x)))) ;; TODO dialog is no longer closeable -(defn dialog* [& {:keys [ entity form-params form-errors]}] +(defn dialog* [& {:keys [entity form-params form-errors]}] (com/modal - {:modal-class "max-w-4xl"} - (com/modal-card - {} - [:div.flex [:div.p-2 "Transaction Rule"] ] - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target "#modal-holder" - :hx-target-400 "#form-errors .error-content" - #_#_:x-trap "true"} - form-params) - [:fieldset {:class "hx-disable" :hx-disinherit "hx-target"} - - (fc/start-form entity form-errors - [:div.space-y-2 - (when-let [id (:db/id entity)] - (com/hidden {:name "db/id" - :value id})) + {:modal-class "max-w-4xl"} + (com/modal-card + {} + [:div.flex [:div.p-2 "Transaction Rule"]] + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target "#modal-holder" + :hx-target-400 "#form-errors .error-content" + :x-trap "true"} + form-params) + [:fieldset {:class "hx-disable" :hx-disinherit "hx-target"} - (fc/with-field :transaction-rule/client + (fc/start-form entity form-errors + [:div.space-y-2 + (when-let [id (:db/id entity)] + (com/hidden {:name "db/id" + :value id})) - (com/validated-field - {:label "Client" - :errors (fc/field-errors)} - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :x-init "$el.focus()" - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :company-search) - :id (str "form-client-search") - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) - + (fc/with-field :transaction-rule/client - (fc/with-field :transaction-rule/bank-account - (com/validated-field {:label "Bank Account" - :errors (fc/field-errors)} - [:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) - :hx-trigger (hx/trigger-field-change :name "transaction-rule/client" - :from "#edit-form") - :hx-swap "innerHTML" - :hx-ext "rename-params" - :hx-include "#edit-form" - :hx-vals (hx/vals {:name (fc/field-name)}) - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "name" "name"})} - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) - :name (fc/field-name) - :value (fc/field-value)})])) + (com/validated-field + {:label "Client" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :x-init "$el.focus()" + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :id (str "form-client-search") + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (fn [c] (cond->> c + (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) + true :client/name))})])) - (fc/with-field :transaction-rule/description - (com/validated-field {:label "Description" - :errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :error? (fc/error?) - :placeholder "HOME DEPOT" - :class "w-96" - :value (fc/field-value)}))) + (fc/with-field :transaction-rule/bank-account + (com/validated-field {:label "Bank Account" + :errors (fc/field-errors)} + [:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) + :hx-trigger (hx/trigger-field-change :name "transaction-rule/client" + :from "#edit-form") + :hx-swap "innerHTML" + :hx-ext "rename-params" + :hx-include "#edit-form" + :hx-vals (hx/vals {:name (fc/field-name)}) + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "name" "name"})} + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) + :name (fc/field-name) + :value (fc/field-value)})])) - (com/field {:label "Amount"} - [:div.flex.gap-2 - (fc/with-field :transaction-rule/amount-gte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})]) - (fc/with-field :transaction-rule/amount-lte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) - :placeholder "<=" - :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})])]) + (fc/with-field :transaction-rule/description + (com/validated-field {:label "Description" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :placeholder "HOME DEPOT" + :class "w-96" + :value (fc/field-value)}))) - (com/field {:label "Day of month"} - [:div.flex.gap-2 - (fc/with-field :transaction-rule/dom-gte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}))) - (fc/with-field :transaction-rule/dom-lte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)})))]) + (com/field {:label "Amount"} + [:div.flex.gap-2 + (fc/with-field :transaction-rule/amount-gte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})]) + (fc/with-field :transaction-rule/amount-lte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder "<=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})])]) - [:h2.text-lg "Outcomes"] - (fc/with-field :transaction-rule/vendor - (com/validated-field {:label "Assign Vendor" - :errors (fc/field-errors)} - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :id (str "form-vendor-search") - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + (com/field {:label "Day of month"} + [:div.flex.gap-2 + (fc/with-field :transaction-rule/dom-gte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}))) + (fc/with-field :transaction-rule/dom-lte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)})))]) - (fc/with-field :transaction-rule/accounts - (list - (com/data-grid {:headers [(com/data-grid-header {} - "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} - (when @fc/*current* - (doall (for [tra fc/*current*] - (fc/with-cursor tra - (transaction-rule-account-row* entity tra)))))) - (com/errors {:errors (fc/field-errors)}))) - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :hx-include "#edit-form" - :hx-ext "rename-params" - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#transaction-rule-account-table tbody" - :hx-swap "beforeend"} - "New account") - (fc/with-field :transaction-rule/transaction-approval-status - (com/validated-field {:label "Approval status" - :errors (fc/field-errors)} - (com/radio {:options (ref->radio-options "transaction-approval-status") - :value (fc/field-value) - :name (fc/field-name) - :orientation :horizontal}))) - - [:div#form-errors [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})]] - (com/button {:color :primary :form "edit-form" :type "submit"} - "Save")])]] - [:div]))) + [:h2.text-lg "Outcomes"] + (fc/with-field :transaction-rule/vendor + (com/validated-field {:label "Assign Vendor" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :id (str "form-vendor-search") + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + + (fc/with-field :transaction-rule/accounts + (list + (com/data-grid {:headers [(com/data-grid-header {} + "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})] + :id "transaction-rule-account-table"} + (when @fc/*current* + (doall (for [tra fc/*current*] + (fc/with-cursor tra + (transaction-rule-account-row* entity tra)))))) + (com/errors {:errors (fc/field-errors)}))) + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :hx-include "#edit-form" + :hx-ext "rename-params" + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "index" "index"}) + :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") + :hx-target "#transaction-rule-account-table tbody" + :hx-swap "beforeend"} + "New account") + (fc/with-field :transaction-rule/transaction-approval-status + (com/validated-field {:label "Approval status" + :errors (fc/field-errors)} + (com/radio {:options (ref->radio-options "transaction-approval-status") + :value (fc/field-value) + :name (fc/field-name) + :orientation :horizontal}))) + + [:div#form-errors [:span.error-content + (com/errors {:errors (:errors fc/*form-errors*)})]] + (com/button {:color :primary :form "edit-form" :type "submit" :class "w-32"} + "Save")])]] + [:div]))) ;; TODO Should forms have some kind of helper to render an individual field? saving diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index 4087c83c..937716be 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -1,16 +1,17 @@ (ns auto-ap.ssr.components.dialog - (:require [hiccup2.core :as hiccup])) + (:require [hiccup2.core :as hiccup] + [auto-ap.ssr.hx :as hx])) (defn modal- [params & children] - [:div {:class (str "relative w-full max-h-full " (or (:modal-class params) " max-w-2xl ")) - "@click.outside" "open=false"} - (into [:div#modal-content] - children)]) + [:div#modal-content {:class "flex items-center justify-between pb-2"} + children]) (defn modal-card- [params header content footer] [:div#modal-card params - [:div {:class "relative bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white fade-in-settle slide-up-settle duration-300 transition-all modal-content"} + [:div {:class "relative bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content"} [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600"} header] [:div {:class "p-6 space-y-6"} content] [:div footer]]]) + +;; fade-in-settle slide-up-settle duration-300 transition-all diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index a19199e6..6057270f 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -80,31 +80,30 @@ c.clearChoices(); :active 0 :elements (if (:value params) [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] - [])}) - } + [])})} [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) - (hh/add-class "cursor-pointer")) + (hh/add-class "cursor-pointer")) "@click.prevent.stop" "open = !open;" "@keydown.enter.prevent.stop" "open = !open;" - :x-init (:x-init params) - :tabindex 0} + :tabindex 0 + :x-init (:x-init params)} [:input (-> params (dissoc :class) (dissoc :value-fn) (dissoc :content-fn) - (dissoc :x-init) + (dissoc :placeholder) - (assoc - "x-ref" "hidden" - :type "hidden" - ":value" "value.value" - :x-init "$watch('value', v => $dispatch('change'))"))] - [:div.flex.w-full.justify-items-stretch + (assoc + "x-ref" "hidden" + :type "hidden" + ":value" "value.value" + :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] + [:div.flex.w-full.justify-items-stretch [:span.flex-grow.text-left {"x-text" "value.label"}] [:div {:class "w-5 h-5 inline ml-1 justify-self-end"} svg/drop-down]]] - - [:ul.dropdown-contents {:class "absolute bg-white rounded-lg shadow-lg py-1 w-max z-10 mt-1" + + [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-10 mt-1" "@keydown.escape.window" "open = false" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" "x-transition:enter-start" "!opacity-0 !mt-0" @@ -112,9 +111,9 @@ c.clearChoices(); "x-transition:leave" "ease-out duration-200" "x-transition:leave-start" "!opacity-1 !mt-1" "x-transition:leave-end" "!opacity-0 !mt-0" - "x-show ""open" + "x-show " "open" "x-trap" "open" - "@click.outside" "open=false"} + "@click.outside" "open=false; console.log('is this ihid')"} [:input {:type "text" :class (hh/add-class (or (:class params) "") default-input-classes) "x-model" "search" "placeholder" (:placeholder params) @@ -124,16 +123,15 @@ c.clearChoices(); "x-init" "$watch('search', s => { if($el.value.length > 2) {fetch(baseUrl + s).then(data=>data.json()).then(data => {elements = data; active=-1}) }})"}] [:div.dropdown-options [:template {:x-for "(element, index) in elements"} - [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500" + [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-300 [&.active]:dark:bg-primary-700 text-gray-800 dark:text-gray-100" :href "#" ":class" "active == index ? 'active' : ''" "@mouseover" "active = index" "@mouseout" "active = -1" "@click.prevent" "value = element; open=false; " - "x-html" "element.label" - }]]] + "x-html" "element.label"}]]] [:template {:x-if "elements.length == 0"} - [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-500 text-xs "} + [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "} "No results found"]]]]]) diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 2564987f..7527004e 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -36,7 +36,6 @@ [:script {:type "text/javascript" :src "https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.1.4/dist/js/datepicker-full.min.js"}] - [:link {:rel "stylesheet" :href "https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/styles/choices.min.css"}] [:script {:src "https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/scripts/choices.min.js"}] [:script {:src "https://unpkg.com/htmx.org/dist/ext/response-targets.js"}] @@ -55,46 +54,39 @@ input::-webkit-inner-spin-button { } input[type=number] { -moz-appearance:textfield; /* Firefox */ -} +} "] - " - - ] - [:body {:hx-ext "disable-submit" - "x-data" (hx/json {:modalOpen false})} + [:body {:hx-ext "disable-submit"} contents [:script {:src "/js/flowbite.min.js"}] - [:div - {"x-data" (hx/json {"open" false}) + [:div#modal-holder + {:tabindex "-1", :class "fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" + "x-show" "open" + ":aria-hidden" "!open" + "x-data" (hx/json {"open" false}) "@modalopen.document" "open=true" "@modalclose.document" "open=false"} - - [:div#modal-holder - { :tabindex "-1", :class "fixed top-0 left-0 right-0 z-50 w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full flex justify-center" - ":class" "open ? '' : 'hidden'" - ":aria-hidden" "!open" - }] - [:div {:class " bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" - ":class" "open ? '' : 'hidden'" + + [:div {:class "bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" + "x-show" "open" ":aria-hidden" "!open" - }] - #_[:script {:lang "text/javascript"} - (hiccup/raw " - var modal_element = document.getElementById('modal-holder'); - var modal_options = { - placement: 'center', - backdrop: 'dynamic', - backdropClasess: 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40', - closable: false, - onOpen: function() { - htmx.trigger(document.getElementById('modal-holder'), 'modalOpened', {}); + "x-transition:enter" "duration-300" + "x-transition:enter-start" "!bg-opacity-0" + "x-transition:enter-end" "!bg-opacity-50" + "x-transition:leave" "duration-300" + "x-transition:leave-start" "!bg-opacity-50" + "x-transition:leave-end" "!bg-opacity-0"} - }, - onHide: function() { - htmx.trigger(document.getElementById('modal-holder'), 'modalClosed', {}); - }, - }; - var curModal = new Modal(modal_element, modal_options); -") + [:div.flex.place-items-center.place-content-center.w-full.h-full.p-12 + [:div {:class (str "w-full sm:max-w-4xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[80vh]") + "@click.outside" "open=false" + "x-trap.inert" "open" + "x-show" "open" + "x-transition:enter" "ease-out duration-300" + "x-transition:enter-start" "!bg-opacity-0 !translate-y-32" + "x-transition:enter-end" "!bg-opacity-100 !translate-y-0" + "x-transition:leave" "duration-300" + "x-transition:leave-start" "!opacity-100 !translate-y-0" + "x-transition:leave-end" "!opacity-0 !translate-y-32"} - ]]]])) + [:div#modal-content {:class "flex items-center justify-between pb-2"}]]]]]]])) diff --git a/src/cljc/auto_ap/extract-line-items-from-invoice.repl b/src/cljc/auto_ap/extract-line-items-from-invoice.repl new file mode 100644 index 00000000..a4c2cbd7 --- /dev/null +++ b/src/cljc/auto_ap/extract-line-items-from-invoice.repl @@ -0,0 +1,31 @@ +;; This buffer is for Clojure experiments and evaluation. + +;; Press C-j to evaluate the last expression. + +;; You can also press C-u C-j to evaluate the expression and pretty-print its result. + +(user/init-repl) + +(dc/q '[:find ?nc + :in $ ?c + :where + [?je :journal-entry/client ?c] + ] + [:client/code "NGOP"]) + + + + + +(->> + (:line-items (first (:line-item-groups (first p)))) + (map (fn [li] + (->> (:line-item-expense-fields li) + (map + (fn [field] + [(:text (:label-detection field)) (:text (:value-detection field))]) + ) + (filter first) + (into {})))) + (clojure.data.json/pprint)) + From fc3634c6bd12e42c711ad5890f9e67ea2bc64585 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Oct 2023 12:43:01 -0700 Subject: [PATCH 05/34] does not change now. --- resources/public/output.css | 208 +++++------------- .../auto_ap/ssr/admin/transaction_rules.clj | 11 +- src/clj/auto_ap/ssr/components/inputs.clj | 65 +++--- src/clj/auto_ap/ssr/ui.clj | 3 +- 4 files changed, 103 insertions(+), 184 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 15e78cd2..c83024f1 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1151,6 +1151,10 @@ input:checked + .toggle-bg { margin: 1rem; } +.m-1 { + margin: 0.25rem; +} + .mx-2 { margin-left: 0.5rem; margin-right: 0.5rem; @@ -1176,29 +1180,6 @@ input:checked + .toggle-bg { margin-bottom: 1rem; } -.mx-8 { - margin-left: 2rem; - margin-right: 2rem; -} - -.my-8 { - margin-top: 2rem; - margin-bottom: 2rem; -} - -.my-64 { - margin-top: 16rem; - margin-bottom: 16rem; -} - -.\!mt-0 { - margin-top: 0px !important; -} - -.\!mt-1 { - margin-top: 0.25rem !important; -} - .-mb-1 { margin-bottom: -0.25rem; } @@ -1279,16 +1260,24 @@ input:checked + .toggle-bg { margin-top: 1.25rem; } -.\!mt-64 { - margin-top: 16rem !important; +.\!mt-0 { + margin-top: 0px !important; } -.\!mt-32 { - margin-top: 8rem !important; +.\!mt-3 { + margin-top: 0.75rem !important; } -.mr-5 { - margin-right: 1.25rem; +.mt-3 { + margin-top: 0.75rem; +} + +.\!mt-1 { + margin-top: 0.25rem !important; +} + +.ml-64 { + margin-left: 16rem; } .block { @@ -1375,19 +1364,6 @@ input:checked + .toggle-bg { height: 100vh; } -.h-auto { - height: auto; -} - -.h-min { - height: -moz-min-content; - height: min-content; -} - -.h-64 { - height: 16rem; -} - .max-h-96 { max-height: 24rem; } @@ -1396,10 +1372,6 @@ input:checked + .toggle-bg { max-height: 100%; } -.max-h-screen { - max-height: 100vh; -} - .w-1\/2 { width: 50%; } @@ -1456,14 +1428,14 @@ input:checked + .toggle-bg { width: 24rem; } -.w-auto { - width: auto; -} - .w-full { width: 100%; } +.w-auto { + width: auto; +} + .w-max { width: -moz-max-content; width: max-content; @@ -1521,10 +1493,6 @@ input:checked + .toggle-bg { flex-grow: 1; } -.grow-0 { - flex-grow: 0; -} - .basis-1\/4 { flex-basis: 25%; } @@ -1574,16 +1542,6 @@ input:checked + .toggle-bg { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; } -.translate-y-0 { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.translate-y-4 { - --tw-translate-y: 1rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - .rotate-180 { --tw-rotate: 180deg; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1683,10 +1641,6 @@ input:checked + .toggle-bg { place-items: center; } -.content-center { - align-content: center; -} - .items-start { align-items: flex-start; } @@ -1723,10 +1677,6 @@ input:checked + .toggle-bg { justify-content: space-between; } -.justify-items-center { - justify-items: center; -} - .justify-items-stretch { justify-items: stretch; } @@ -1823,6 +1773,26 @@ input:checked + .toggle-bg { border-color: rgb(243 244 246 / var(--tw-divide-opacity)); } +.place-self-start { + place-self: start; +} + +.place-self-end { + place-self: end; +} + +.self-start { + align-self: flex-start; +} + +.self-center { + align-self: center; +} + +.justify-self-start { + justify-self: start; +} + .justify-self-end { justify-self: end; } @@ -2124,11 +2094,6 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } -.bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); -} - .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -2137,18 +2102,14 @@ input:checked + .toggle-bg { --tw-bg-opacity: 0 !important; } -.\!bg-opacity-50 { - --tw-bg-opacity: 0.5 !important; -} - -.bg-opacity-40 { - --tw-bg-opacity: 0.4; -} - .\!bg-opacity-100 { --tw-bg-opacity: 1 !important; } +.\!bg-opacity-50 { + --tw-bg-opacity: 0.5 !important; +} + .p-1 { padding: 0.25rem; } @@ -2237,16 +2198,6 @@ input:checked + .toggle-bg { padding-bottom: 1.25rem; } -.px-7 { - padding-left: 1.75rem; - padding-right: 1.75rem; -} - -.py-6 { - padding-top: 1.5rem; - padding-bottom: 1.5rem; -} - .pb-2 { padding-bottom: 0.5rem; } @@ -2479,10 +2430,6 @@ input:checked + .toggle-bg { text-decoration-line: underline; } -.\!opacity-0 { - opacity: 0 !important; -} - .opacity-0 { opacity: 0; } @@ -2491,8 +2438,8 @@ input:checked + .toggle-bg { opacity: 1; } -.\!opacity-50 { - opacity: 0.5 !important; +.\!opacity-0 { + opacity: 0 !important; } .\!opacity-100 { @@ -2576,10 +2523,6 @@ input:checked + .toggle-bg { transition-duration: 100ms; } -.duration-200 { - transition-duration: 200ms; -} - .duration-300 { transition-duration: 300ms; } @@ -2592,12 +2535,8 @@ input:checked + .toggle-bg { transition-duration: 75ms; } -.duration-1000 { - transition-duration: 1000ms; -} - -.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { - transition-timing-function: cubic-bezier(.3,2.3,.6,1); +.duration-200 { + transition-duration: 200ms; } .ease-in-out { @@ -2608,8 +2547,8 @@ input:checked + .toggle-bg { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } -.ease-in { - transition-timing-function: cubic-bezier(0.4, 0, 1, 1); +.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { + transition-timing-function: cubic-bezier(.3,2.3,.6,1); } .htmx-added .fade-in { @@ -3040,11 +2979,6 @@ input:checked + .toggle-bg { background-color: rgb(73 109 28 / var(--tw-bg-opacity)); } -.hover\:bg-neutral-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(245 245 245 / var(--tw-bg-opacity)); -} - .hover\:bg-primary-100:hover { --tw-bg-opacity: 1; background-color: rgb(228 240 213 / var(--tw-bg-opacity)); @@ -3060,9 +2994,9 @@ input:checked + .toggle-bg { background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.hover\:bg-gray-50:hover { +.hover\:bg-neutral-100:hover { --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)); + background-color: rgb(245 245 245 / var(--tw-bg-opacity)); } .hover\:text-blue-600:hover { @@ -3612,39 +3546,14 @@ input:checked + .toggle-bg { max-height: 80vh; } - .sm\:max-w-lg { - max-width: 32rem; - } - - .sm\:max-w-xl { - max-width: 36rem; - } - - .sm\:max-w-2xl { - max-width: 42rem; + .sm\:max-h-\[90vh\] { + max-height: 90vh; } .sm\:max-w-4xl { max-width: 56rem; } - .sm\:translate-y-0 { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - - .sm\:scale-100 { - --tw-scale-x: 1; - --tw-scale-y: 1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - - .sm\:scale-95 { - --tw-scale-x: .95; - --tw-scale-y: .95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .sm\:rounded-lg { border-radius: 0.5rem; } @@ -3770,6 +3679,11 @@ input:checked + .toggle-bg { } } +.\[\&\.active\]\:bg-red-500.active { + --tw-bg-opacity: 1; + background-color: rgb(255 3 3 / var(--tw-bg-opacity)); +} + .\[\&\.active\]\:bg-primary-500.active { --tw-bg-opacity: 1; background-color: rgb(121 181 46 / var(--tw-bg-opacity)); diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index dbb4d10b..2e5d8353 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -424,7 +424,7 @@ [:fieldset {:class "hx-disable" :hx-disinherit "hx-target"} (fc/start-form entity form-errors - [:div.space-y-2 + [:div.space-y-1 (when-let [id (:db/id entity)] (com/hidden {:name "db/id" :value id})) @@ -551,8 +551,9 @@ :name (fc/field-name) :orientation :horizontal}))) - [:div#form-errors [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})]] + [:div#form-errors (when (:errors fc/*form-errors*) + [:span.error-content + (com/errors {:errors (:errors fc/*form-errors*)})])] (com/button {:color :primary :form "edit-form" :type "submit" :class "w-32"} "Save")])]] [:div]))) @@ -611,7 +612,7 @@ (html-response (dialog* :entity entity :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger" "modalopen"}))) + :headers {"hx-trigger-after-settle" "modalopen"}))) (defn transaction-rule-error [request] (let [entity (some-> request :last-form)] @@ -631,7 +632,7 @@ :form-errors {} :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger" "modalopen"})) + :headers {"hx-trigger-after-settle" "modalopen"})) (def transaction-rule-schema (mc/schema [:map diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 6057270f..af06787d 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -81,12 +81,14 @@ c.clearChoices(); :elements (if (:value params) [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] [])})} - [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) - (hh/add-class "cursor-pointer")) - "@click.prevent.stop" "open = !open;" + [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) + (hh/add-class "cursor-pointer")) + "@click.prevent" "open = !open;" "@keydown.enter.prevent.stop" "open = !open;" - :tabindex 0 - :x-init (:x-init params)} + "@keydown.down.prevent.stop" "open = true;" + "@keydown.backspace" "value = {value: '', label: '' }" + :tabindex 0 + :x-init (:x-init params)} [:input (-> params (dissoc :class) (dissoc :value-fn) @@ -94,42 +96,43 @@ c.clearChoices(); (dissoc :placeholder) (assoc - "x-ref" "hidden" - :type "hidden" - ":value" "value.value" - :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] + "x-ref" "hidden" + :type "hidden" + ":value" "value.value" + :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] [:div.flex.w-full.justify-items-stretch [:span.flex-grow.text-left {"x-text" "value.label"}] - [:div {:class "w-5 h-5 inline ml-1 justify-self-end"} + [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-10 mt-1" - "@keydown.escape.window" "open = false" - "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" + + [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-10 mt-1" + "@keydown.escape" "open = false; value = {value: '', label: '' }" + "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" "x-transition:enter-start" "!opacity-0 !mt-0" - "x-transition:enter-end" "!opacity-1 !mt-1" - "x-transition:leave" "ease-out duration-200" + "x-transition:enter-end" "!opacity-1 !mt-1" + "x-transition:leave" "ease-out duration-200" "x-transition:leave-start" "!opacity-1 !mt-1" - "x-transition:leave-end" "!opacity-0 !mt-0" - "x-show " "open" - "x-trap" "open" - "@click.outside" "open=false; console.log('is this ihid')"} - [:input {:type "text" :class (hh/add-class (or (:class params) "") default-input-classes) - "x-model" "search" - "placeholder" (:placeholder params) - "@keydown.down.prevent" "active ++; active = active >= elements.length - 1 ? elements.length - 1 : active" - "@keydown.up.prevent" "active --; active = active < 0 ? 0 : active" + "x-transition:leave-end" "!opacity-0 !mt-0" + "x-show " "open" + "x-trap" "open" + "@click.outside" "open=false; console.log('is this ihid')"} + [:input {:type "text" :class (hh/add-class (or (:class params) "") default-input-classes) + "x-model" "search" + "placeholder" (:placeholder params) + "@keydown.down.prevent" "active ++; active = active >= elements.length - 1 ? elements.length - 1 : active" + "@keydown.up.prevent" "active --; active = active < 0 ? 0 : active" "@keydown.enter.prevent" "open = false; value = elements.length > 0 ? $data.elements[active] : {'value': '', label: ''}; console.log('are we here')" - "x-init" "$watch('search', s => { if($el.value.length > 2) {fetch(baseUrl + s).then(data=>data.json()).then(data => {elements = data; active=-1}) }})"}] + "x-init" "$watch('search', s => { if($el.value.length > 2) {fetch(baseUrl + s).then(data=>data.json()).then(data => {elements = data; active=-1}) }})"}] [:div.dropdown-options [:template {:x-for "(element, index) in elements"} - [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-300 [&.active]:dark:bg-primary-700 text-gray-800 dark:text-gray-100" - :href "#" - ":class" "active == index ? 'active' : ''" - "@mouseover" "active = index" - "@mouseout" "active = -1" + [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-300 [&.active]:dark:bg-primary-700 text-gray-800 dark:text-gray-100" + :href "#" + ":class" "active == index ? 'active' : ''" + "@mouseover" "active = index" + "@mouseout" "active = -1" "@click.prevent" "value = element; open=false; " - "x-html" "element.label"}]]] + "x-html" "element.label"}]]] [:template {:x-if "elements.length == 0"} [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "} "No results found"]]]]]) diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 7527004e..a32ba532 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -78,8 +78,9 @@ input[type=number] { "x-transition:leave-end" "!bg-opacity-0"} [:div.flex.place-items-center.place-content-center.w-full.h-full.p-12 - [:div {:class (str "w-full sm:max-w-4xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[80vh]") + [:div {:class (str "w-full sm:max-w-4xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[90vh]") "@click.outside" "open=false" + "x-trap.inert.noscroll" "open" "x-trap.inert" "open" "x-show" "open" "x-transition:enter" "ease-out duration-300" From 9ddbd31cc8ddea1529cc6e23efc03ccb5eb5bb96 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Oct 2023 13:04:42 -0700 Subject: [PATCH 06/34] almost perfect user experience --- resources/public/output.css | 9 ++++ .../auto_ap/ssr/admin/transaction_rules.clj | 45 ++++++++++--------- src/clj/auto_ap/ssr/components/buttons.clj | 17 ++++--- src/clj/auto_ap/ssr/components/radio.clj | 2 +- src/clj/auto_ap/ssr/ui.clj | 2 +- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index c83024f1..72b2faea 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -2094,6 +2094,11 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } +.bg-gray-300 { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); +} + .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -3554,6 +3559,10 @@ input:checked + .toggle-bg { max-width: 56rem; } + .sm\:max-w-2xl { + max-width: 42rem; + } + .sm\:rounded-lg { border-radius: 0.5rem; } diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 2e5d8353..50ddec11 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -55,11 +55,6 @@ ;; as to which one to generate. -;; TODO lots of escaping concerns (urls in javascript), all these weird name filters - -;; TODO better generation of names? - - (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes @@ -411,7 +406,7 @@ ;; TODO dialog is no longer closeable (defn dialog* [& {:keys [entity form-params form-errors]}] (com/modal - {:modal-class "max-w-4xl"} + {:modal-class "max-w-2xl"} (com/modal-card {} [:div.flex [:div.p-2 "Transaction Rule"]] @@ -516,14 +511,14 @@ :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :vendor-search) :id (str "form-vendor-search") + :class "w-96" :value (fc/field-value) :value-fn (some-fn :db/id identity) :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) (fc/with-field :transaction-rule/accounts (list - (com/data-grid {:headers [(com/data-grid-header {} - "Account") + (com/data-grid {:headers [(com/data-grid-header {} "Account") (com/data-grid-header {:class "w-32"} "Location") (com/data-grid-header {:class "w-16"} "%") (com/data-grid-header {:class "w-16"})] @@ -531,24 +526,33 @@ (when @fc/*current* (doall (for [tra fc/*current*] (fc/with-cursor tra - (transaction-rule-account-row* entity tra)))))) + (transaction-rule-account-row* entity tra))))) + (com/data-grid-row + {:class "new-row"} + (com/data-grid-cell {:colspan 4 + :class "bg-gray-100"} + [:div.flex.justify-center + + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :color :secondary + :hx-include "#edit-form" + :hx-ext "rename-params" + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "index" "index"}) + :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") + :hx-target "#edit-form .new-row" + :hx-swap "beforebegin"} + "New account")]))) (com/errors {:errors (fc/field-errors)}))) - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :hx-include "#edit-form" - :hx-ext "rename-params" - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#transaction-rule-account-table tbody" - :hx-swap "beforeend"} - "New account") + (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" :errors (fc/field-errors)} (com/radio {:options (ref->radio-options "transaction-approval-status") :value (fc/field-value) :name (fc/field-name) + :size :small :orientation :horizontal}))) [:div#form-errors (when (:errors fc/*form-errors*) @@ -568,7 +572,7 @@ (let [index (or index 0) ;; TODO schema decode is not working transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] client-id) - :transaction-rule/accounts (conj (into [] (repeat (inc index) {} )) + :transaction-rule/accounts (conj (into [] (repeat index {} )) {:db/id (str (java.util.UUID/randomUUID)) :transaction-rule-account/location "Shared"})}] (html-response @@ -582,7 +586,6 @@ ;; TODO check to see if it should be called "Shared" or "shared" for the value -;; TODO blank location is being allowed ;; TODO hydrate nested types more easily. make it easy to hydrate so you don't do weird sometimes pulls ;; TODO is it possible to make it easy to get a virtual cursor in the case of adding a new row? setting up ;; fake data doesn't feel right - maybe have a "prelude" that's dynamic diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 40574e20..9edd6529 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -98,13 +98,16 @@ (into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)]) (defn a-button- [params & children] - [:a (update params - :class #(cond-> % - true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center") - (= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") - (= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ") - (nil? (:color params)) - (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) + [:a (-> params + (update :class #(cond-> % + true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center") + (= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") + (= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ") + (nil? (:color params)) + (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700") + )) + (assoc :tabindex 0) + (assoc :href (:href params "#"))) [:div.htmx-indicator.flex.items-center (svg/spinner {:class "inline w-4 h-4 text-white"}) [:div.ml-3 "Loading..."]] diff --git a/src/clj/auto_ap/ssr/components/radio.clj b/src/clj/auto_ap/ssr/components/radio.clj index bd27c9bb..17d9bf95 100644 --- a/src/clj/auto_ap/ssr/components/radio.clj +++ b/src/clj/auto_ap/ssr/components/radio.clj @@ -4,7 +4,7 @@ (defn radio- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] [:ul {:class (cond-> "w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white" - (= orientation :horizontal) (-> (hh/add-class "flex gap-8") + (= orientation :horizontal) (-> (hh/add-class "flex gap-2 flex-wrap") (hh/remove-wildcard ["w-" "rounded-lg" "border" "bg-"])))} (for [{:keys [value content]} options] [:li {:class (cond-> "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600" diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index a32ba532..d2ef40b1 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -78,7 +78,7 @@ input[type=number] { "x-transition:leave-end" "!bg-opacity-0"} [:div.flex.place-items-center.place-content-center.w-full.h-full.p-12 - [:div {:class (str "w-full sm:max-w-4xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[90vh]") + [:div {:class (str "w-full sm:max-w-2xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[90vh]") "@click.outside" "open=false" "x-trap.inert.noscroll" "open" "x-trap.inert" "open" From 34f4a12b2e7b86b77ac5e10a7609fa3f045573a3 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Oct 2023 13:25:00 -0700 Subject: [PATCH 07/34] Makes appear logic work right --- .../auto_ap/ssr/admin/transaction_rules.clj | 159 ++++++++++-------- src/clj/auto_ap/ssr/components/inputs.clj | 3 +- src/clj/auto_ap/ssr/components/radio.clj | 6 +- src/clj/auto_ap/ssr/form_cursor.clj | 5 +- src/clj/auto_ap/ssr/hx.clj | 6 + 5 files changed, 107 insertions(+), 72 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 50ddec11..99963ce0 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -423,84 +423,109 @@ (when-let [id (:db/id entity)] (com/hidden {:name "db/id" :value id})) - - (fc/with-field :transaction-rule/client - - (com/validated-field - {:label "Client" - :errors (fc/field-errors)} - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :x-init "$el.focus()" - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :company-search) - :id (str "form-client-search") - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) - - (fc/with-field :transaction-rule/bank-account - (com/validated-field {:label "Bank Account" - :errors (fc/field-errors)} - [:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) - :hx-trigger (hx/trigger-field-change :name "transaction-rule/client" - :from "#edit-form") - :hx-swap "innerHTML" - :hx-ext "rename-params" - :hx-include "#edit-form" - :hx-vals (hx/vals {:name (fc/field-name)}) - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "name" "name"})} - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) - :name (fc/field-name) - :value (fc/field-value)})])) - (fc/with-field :transaction-rule/description (com/validated-field {:label "Description" :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) - :error? (fc/error?) + :error? (fc/error?) + :x-init "$el.focus()" :placeholder "HOME DEPOT" :class "w-96" :value (fc/field-value)}))) + [:div.filters {:x-data (hx/json {:clientFilter (boolean (fc/field-value (:transaction-rule/client fc/*current*))) + :bankAccountFilter (boolean (fc/field-value (:transaction-rule/bank-account fc/*current*))) + :amountFilter (boolean (or (fc/field-value (:transaction-rule/amount-gte fc/*current*)) + (fc/field-value (:transaction-rule/amount-lte fc/*current*)))) + :domFilter (boolean (or (fc/field-value (:transaction-rule/dom-gte fc/*current*)) + (fc/field-value (:transaction-rule/dom-lte fc/*current*))))})} - (com/field {:label "Amount"} - [:div.flex.gap-2 - (fc/with-field :transaction-rule/amount-gte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) + [:div.flex.gap-2.mb-2 + (com/a-button {"@click" "clientFilter=true" + "x-show" "!clientFilter"} "Filter client") + (com/a-button {"@click" "bankAccountFilter=true" + "x-show" "clientFilter && !bankAccountFilter"} "Filter bank account") + (com/a-button {"@click" "amountFilter=true" + "x-show" "!amountFilter"} "Filter amount") + (com/a-button {"@click" "domFilter=true" + "x-show" "!domFilter"} "Filter day of month")] + (fc/with-field :transaction-rule/client + + (com/validated-field + (-> {:label "Client" + :errors (fc/field-errors) + :x-show "clientFilter"} + (hx/alpine-appear)) + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :id (str "form-client-search") + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (fn [c] (cond->> c + (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) + true :client/name))})])) + + (fc/with-field :transaction-rule/bank-account + (com/validated-field + (-> {:label "Bank Account" + :errors (fc/field-errors) + :x-show "bankAccountFilter"} + hx/alpine-appear) + [:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) + :hx-trigger (hx/trigger-field-change :name "transaction-rule/client" + :from "#edit-form") + :hx-swap "innerHTML" + :hx-ext "rename-params" + :hx-include "#edit-form" + :hx-vals (hx/vals {:name (fc/field-name)}) + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "name" "name"})} + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) + :name (fc/field-name) + :value (fc/field-value)})])) + + + + (com/field (-> {:label "Amount" + :x-show "amountFilter"} + hx/alpine-appear) + [:div.flex.gap-2 + (fc/with-field :transaction-rule/amount-gte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})]) + (fc/with-field :transaction-rule/amount-lte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder "<=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})])]) + + (com/field (-> {:label "Day of month" + :x-show "domFilter"} + hx/alpine-appear) + [:div.flex.gap-2 + (fc/with-field :transaction-rule/dom-gte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) :placeholder ">=" :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})]) - (fc/with-field :transaction-rule/amount-lte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) - :placeholder "<=" + :value (fc/field-value)}))) + (fc/with-field :transaction-rule/dom-lte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})])]) - - (com/field {:label "Day of month"} - [:div.flex.gap-2 - (fc/with-field :transaction-rule/dom-gte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}))) - (fc/with-field :transaction-rule/dom-lte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)})))]) + :value (fc/field-value)})))])] [:h2.text-lg "Outcomes"] (fc/with-field :transaction-rule/vendor diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index af06787d..e1de230a 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -193,7 +193,8 @@ c.clearChoices(); [:p.mt-2.text-xs.text-red-600.dark:text-red-500.h-4 (str/join ", " errors)])) (defn field- [params & rest] - [:div {:id (:id params) :class (hh/add-class "group" (:class params))} + [:div (-> params + (update :class #(hh/add-class (or % "") "group" ))) (when (:label params) [:label {:class "block mb-2 text-sm font-medium text-gray-900 dark:text-white"} (:label params)]) rest diff --git a/src/clj/auto_ap/ssr/components/radio.clj b/src/clj/auto_ap/ssr/components/radio.clj index 17d9bf95..e02dc4d5 100644 --- a/src/clj/auto_ap/ssr/components/radio.clj +++ b/src/clj/auto_ap/ssr/components/radio.clj @@ -1,5 +1,6 @@ (ns auto-ap.ssr.components.radio - (:require [auto-ap.ssr.hiccup-helper :as hh])) + (:require [auto-ap.ssr.hiccup-helper :as hh] + [auto-ap.ssr.hx :as hx])) (defn radio- [{:keys [options name title size orientation] :or {size :medium} selected-value :value}] [:h3 {:class "mb-4 font-semibold text-gray-900 dark:text-white"} title] @@ -10,7 +11,8 @@ [:li {:class (cond-> "w-full border-b border-gray-200 rounded-t-lg dark:border-gray-600" (= orientation :horizontal) (-> (hh/remove-wildcard ["w-full" "rounded-"]) (hh/add-class "w-auto shrink-0 block rounded-lg border border-gray-200 dark:border-gray-600 px-3")))} - [:div {:class "flex items-center pl-3"} + [:div {:class (cond-> "flex items-center" + (not= orientation :horizontal) (hh/add-class "pl-3"))} [:input (cond-> {:id (str "list-" name "-" value) :type "radio", :value value diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index 1170afc0..eef97db2 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -26,8 +26,9 @@ ([cursor] (apply path->name2 (cursor/path cursor)))) -(defn field-value [] - @*current*) +(defn field-value + ([] (field-value *current*)) + ([cursor] @cursor)) (defn field-errors ([] diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index d5c59d85..cb5e5c00 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -18,3 +18,9 @@ (defn triggers [& triggers] (str/join ", " triggers)) + +(defn alpine-appear [m] + (assoc m + "x-transition:enter" "transition duration-500" + "x-transition:enter-start" "opacity-0" + "x-transition:enter-end" "opacity-100")) From 998d29690e3c3bde5ebf94f6105f1cfa75c32054 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Oct 2023 20:08:08 -0700 Subject: [PATCH 08/34] animates with shake --- resources/public/output.css | 215 ++++++++---------- .../auto_ap/ssr/admin/transaction_rules.clj | 122 +++++----- src/clj/auto_ap/ssr/components/inputs.clj | 6 +- tailwind.config.js | 16 ++ 4 files changed, 178 insertions(+), 181 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 72b2faea..a0cad0e2 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1147,14 +1147,14 @@ input:checked + .toggle-bg { grid-column-start: 1; } -.m-4 { - margin: 1rem; -} - .m-1 { margin: 0.25rem; } +.m-4 { + margin: 1rem; +} + .mx-2 { margin-left: 0.5rem; margin-right: 0.5rem; @@ -1180,6 +1180,14 @@ input:checked + .toggle-bg { margin-bottom: 1rem; } +.\!mt-0 { + margin-top: 0px !important; +} + +.\!mt-1 { + margin-top: 0.25rem !important; +} + .-mb-1 { margin-bottom: -0.25rem; } @@ -1260,26 +1268,6 @@ input:checked + .toggle-bg { margin-top: 1.25rem; } -.\!mt-0 { - margin-top: 0px !important; -} - -.\!mt-3 { - margin-top: 0.75rem !important; -} - -.mt-3 { - margin-top: 0.75rem; -} - -.\!mt-1 { - margin-top: 0.25rem !important; -} - -.ml-64 { - margin-left: 16rem; -} - .block { display: block; } @@ -1352,10 +1340,6 @@ input:checked + .toggle-bg { height: 24rem; } -.h-\[calc\(100\%-1rem\)\] { - height: calc(100% - 1rem); -} - .h-full { height: 100%; } @@ -1428,14 +1412,14 @@ input:checked + .toggle-bg { width: 24rem; } -.w-full { - width: 100%; -} - .w-auto { width: auto; } +.w-full { + width: 100%; +} + .w-max { width: -moz-max-content; width: max-content; @@ -1497,6 +1481,16 @@ input:checked + .toggle-bg { flex-basis: 25%; } +.\!translate-y-0 { + --tw-translate-y: 0px !important; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; +} + +.\!translate-y-32 { + --tw-translate-y: 8rem !important; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; +} + .-translate-x-1\/2 { --tw-translate-x: -50%; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1532,16 +1526,6 @@ input:checked + .toggle-bg { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.\!translate-y-0 { - --tw-translate-y: 0px !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.\!translate-y-32 { - --tw-translate-y: 8rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - .rotate-180 { --tw-rotate: 180deg; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1565,6 +1549,48 @@ input:checked + .toggle-bg { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } +@keyframes shake { + 0% { + transform: translateX(0px); + } + + 12.5% { + transform: translateX(-5px); + } + + 25% { + transform: translateX(0px); + } + + 37.5% { + transform: translateX(5px); + } + + 50% { + transform: translateX(0px); + } + + 62.5% { + transform: translateX(-5px); + } + + 75% { + transform: translateX(5px); + } + + 87.5% { + transform: translateX(5px); + } + + 100% { + transform: translateX(0px); + } +} + +.animate-shake { + animation: shake 0.5s ease-out 1; +} + @keyframes spin { to { transform: rotate(360deg); @@ -1773,26 +1799,10 @@ input:checked + .toggle-bg { border-color: rgb(243 244 246 / var(--tw-divide-opacity)); } -.place-self-start { - place-self: start; -} - -.place-self-end { - place-self: end; -} - -.self-start { - align-self: flex-start; -} - .self-center { align-self: center; } -.justify-self-start { - justify-self: start; -} - .justify-self-end { justify-self: end; } @@ -1817,10 +1827,6 @@ input:checked + .toggle-bg { overflow-y: auto; } -.overflow-x-hidden { - overflow-x: hidden; -} - .truncate { overflow: hidden; text-overflow: ellipsis; @@ -2094,15 +2100,6 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } -.bg-gray-300 { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - -.bg-opacity-50 { - --tw-bg-opacity: 0.5; -} - .\!bg-opacity-0 { --tw-bg-opacity: 0 !important; } @@ -2115,10 +2112,18 @@ input:checked + .toggle-bg { --tw-bg-opacity: 0.5 !important; } +.bg-opacity-50 { + --tw-bg-opacity: 0.5; +} + .p-1 { padding: 0.25rem; } +.p-12 { + padding: 3rem; +} + .p-2 { padding: 0.5rem; } @@ -2139,10 +2144,6 @@ input:checked + .toggle-bg { padding: 1.5rem; } -.p-12 { - padding: 3rem; -} - .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -2426,23 +2427,10 @@ input:checked + .toggle-bg { color: rgb(114 59 19 / var(--tw-text-opacity)); } -.text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); -} - .underline { text-decoration-line: underline; } -.opacity-0 { - opacity: 0; -} - -.opacity-100 { - opacity: 1; -} - .\!opacity-0 { opacity: 0 !important; } @@ -2451,6 +2439,14 @@ input:checked + .toggle-bg { opacity: 1 !important; } +.opacity-0 { + opacity: 0; +} + +.opacity-100 { + opacity: 1; +} + .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -2528,6 +2524,10 @@ input:checked + .toggle-bg { transition-duration: 100ms; } +.duration-200 { + transition-duration: 200ms; +} + .duration-300 { transition-duration: 300ms; } @@ -2540,8 +2540,8 @@ input:checked + .toggle-bg { transition-duration: 75ms; } -.duration-200 { - transition-duration: 200ms; +.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { + transition-timing-function: cubic-bezier(.3,2.3,.6,1); } .ease-in-out { @@ -2552,10 +2552,6 @@ input:checked + .toggle-bg { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } -.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { - transition-timing-function: cubic-bezier(.3,2.3,.6,1); -} - .htmx-added .fade-in { opacity: 0.0 !important; } @@ -2984,6 +2980,11 @@ input:checked + .toggle-bg { background-color: rgb(73 109 28 / var(--tw-bg-opacity)); } +.hover\:bg-neutral-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(245 245 245 / var(--tw-bg-opacity)); +} + .hover\:bg-primary-100:hover { --tw-bg-opacity: 1; background-color: rgb(228 240 213 / var(--tw-bg-opacity)); @@ -2999,11 +3000,6 @@ input:checked + .toggle-bg { background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.hover\:bg-neutral-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(245 245 245 / var(--tw-bg-opacity)); -} - .hover\:text-blue-600:hover { --tw-text-opacity: 1; color: rgb(0 125 187 / var(--tw-text-opacity)); @@ -3547,18 +3543,10 @@ input:checked + .toggle-bg { display: block; } - .sm\:max-h-\[80vh\] { - max-height: 80vh; - } - .sm\:max-h-\[90vh\] { max-height: 90vh; } - .sm\:max-w-4xl { - max-width: 56rem; - } - .sm\:max-w-2xl { max-width: 42rem; } @@ -3583,10 +3571,6 @@ input:checked + .toggle-bg { } @media (min-width: 768px) { - .md\:inset-0 { - inset: 0px; - } - .md\:ml-2 { margin-left: 0.5rem; } @@ -3688,9 +3672,9 @@ input:checked + .toggle-bg { } } -.\[\&\.active\]\:bg-red-500.active { +.\[\&\.active\]\:bg-primary-300.active { --tw-bg-opacity: 1; - background-color: rgb(255 3 3 / var(--tw-bg-opacity)); + background-color: rgb(175 211 130 / var(--tw-bg-opacity)); } .\[\&\.active\]\:bg-primary-500.active { @@ -3698,11 +3682,6 @@ input:checked + .toggle-bg { background-color: rgb(121 181 46 / var(--tw-bg-opacity)); } -.\[\&\.active\]\:bg-primary-300.active { - --tw-bg-opacity: 1; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)); -} - :is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active { --tw-bg-opacity: 1; background-color: rgb(73 109 28 / var(--tw-bg-opacity)); diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 99963ce0..4b285630 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -47,7 +47,8 @@ [hiccup2.core :as hiccup] [iol-ion.query :refer [ident]] [malli.core :as mc] - [auto-ap.cursor :as cursor])) + [auto-ap.cursor :as cursor] + [auto-ap.ssr.hiccup-helper :as hh])) ;; TODO with dependencies, I really don't like that you have to be ultra specific in what ;; you want to include, and generating the routes and interconnection is weird too. @@ -310,25 +311,26 @@ [{:keys [ name account-location client-locations value]}] (com/select {:options (into [["" ""]] (cond account-location - [[account-location account-location]] + [[account-location account-location]] - (seq client-locations) - (into [["Shared" "Shared"]] - (for [cl client-locations] - [cl cl])) - :else - [["Shared" "Shared"]])) - :name name + (seq client-locations) + (into [["Shared" "Shared"]] + (for [cl client-locations] + [cl cl])) + :else + [["Shared" "Shared"]])) + :name name :value value :class "w-full"})) (defn- account-typeahead* - [{:keys [name value client-id]}] + [{:keys [name value client-id x-model]}] [:div.flex.flex-col (com/typeahead-2 {:name name :placeholder "Search..." :url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id) :id name + :x-model x-model :value value :value-fn (some-fn :db/id identity) :content-fn (fn [value] @@ -338,9 +340,11 @@ (defn- transaction-rule-account-row* [transaction-rule account] - (com/data-grid-row {} + (com/data-grid-row {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) + (fc/field-value (:transaction-rule-account/account account)))})} (let [account-name (fc/field-name (:transaction-rule-account/account account))] (list + (fc/with-field :db/id (com/hidden {:name (fc/field-name) :value (fc/field-value)})) @@ -349,44 +353,34 @@ {} (com/validated-field {:errors (fc/field-errors)} - [:div {:hx-trigger (hx/trigger-field-change :name "transaction-rule/client" - :from "#edit-form") - :hx-include "#edit-form" - :hx-vals (hx/vals {:name account-name}) - :hx-ext "rename-params" - :hx-rename-params-ex (hx/json {:transaction-rule/client "client-id" - :name "name" - account-name "value"}) - :hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead)) - :hx-swap "innerHTML"} - (account-typeahead* {:value (fc/field-value) - :client-id (:db/id (:transaction-rule/client transaction-rule)) - :name (fc/field-name)})]))) + [:div {:hx-trigger "changed" + :hx-target "next div" + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name) + :hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead)) + :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + (account-typeahead* {:value (fc/field-value) + :client-id (:db/id (:transaction-rule/client transaction-rule)) + :name (fc/field-name) + :x-model "accountId" + })))) (fc/with-field :transaction-rule-account/location (com/data-grid-cell {} (com/validated-field - {:errors (fc/field-errors)} - [:div [:div {:hx-trigger (hx/triggers - (hx/trigger-field-change :name "transaction-rule/client" - :from "#edit-form") - (hx/trigger-field-change :name account-name - :from "#edit-form")) - :hx-include "#edit-form" - :hx-vals (hx/vals {:name (fc/field-name)}) - :hx-ext "rename-params" - :hx-rename-params-ex (hx/json {"transaction-rule/client" "client-id" - account-name "account-id" - "name" "name" - (fc/field-name) "value"}) - :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) - :hx-swap "innerHTML"} - (location-select* {:name (fc/field-name) - :account-location (:account/location (cond->> (:transaction-rule-account/account @account) - (nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn) - '[:account/location]))) - :client-locations (:client/locations (:transaction-rule/client transaction-rule)) - :value (fc/field-value)})]]))) + {:errors (fc/field-errors) + :x-data (hx/json {:location (fc/field-value)})} + [:div {:hx-trigger "changed" + :hx-target "next *" + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) ) + :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) + :x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data))"}] + (location-select* {:name (fc/field-name) + :account-location (:account/location (cond->> (:transaction-rule-account/account @account) + (nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn) + '[:account/location]))) + :client-locations (:client/locations (:transaction-rule/client transaction-rule)) + :hx-model "location" + :value (fc/field-value)})))) (fc/with-field :transaction-rule-account/percentage (com/data-grid-cell {} @@ -414,9 +408,12 @@ :hx-swap "outerHTML swap:300ms" :hx-target "#modal-holder" :hx-target-400 "#form-errors .error-content" - :x-trap "true"} + :x-trap "true" + :class "group/form"} form-params) - [:fieldset {:class "hx-disable" :hx-disinherit "hx-target"} + [:fieldset {:class "hx-disable" :hx-disinherit "hx-target" + :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) + (:transaction-rule/client entity))})} (fc/start-form entity form-errors [:div.space-y-1 @@ -461,7 +458,7 @@ :class "w-96" :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :company-search) - :id (str "form-client-search") + :x-model "clientId" :value (fc/field-value) :value-fn (some-fn :db/id identity) :content-fn (fn [c] (cond->> c @@ -472,23 +469,23 @@ (com/validated-field (-> {:label "Bank Account" :errors (fc/field-errors) - :x-show "bankAccountFilter"} + :x-show "bankAccountFilter" + } hx/alpine-appear) - [:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) - :hx-trigger (hx/trigger-field-change :name "transaction-rule/client" - :from "#edit-form") - :hx-swap "innerHTML" - :hx-ext "rename-params" - :hx-include "#edit-form" - :hx-vals (hx/vals {:name (fc/field-name)}) - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "name" "name"})} + [:div.w-96 + [:div#bank-account-changer {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) + :hx-trigger "changed" + :hx-target "next *" + :hx-include "#bank-account-changer" + :hx-swap "innerHTML" + + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) + :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) :name (fc/field-name) :value (fc/field-value)})])) - - (com/field (-> {:label "Amount" :x-show "amountFilter"} hx/alpine-appear) @@ -557,7 +554,6 @@ (com/data-grid-cell {:colspan 4 :class "bg-gray-100"} [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-new-account) :color :secondary @@ -583,7 +579,9 @@ [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content (com/errors {:errors (:errors fc/*form-errors*)})])] - (com/button {:color :primary :form "edit-form" :type "submit" :class "w-32"} + (com/button {:color :primary :form "edit-form" :type "submit" :class (cond-> "w-32" + (seq form-errors) (-> + (hh/add-class "animate-shake")))} "Save")])]] [:div]))) diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index e1de230a..fa9b8f88 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -80,7 +80,10 @@ c.clearChoices(); :active 0 :elements (if (:value params) [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] - [])})} + [])}) + :x-modelable "value.value" + :x-model (:x-model params) + } [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) "@click.prevent" "open = !open;" @@ -95,6 +98,7 @@ c.clearChoices(); (dissoc :content-fn) (dissoc :placeholder) + (dissoc :x-model) (assoc "x-ref" "hidden" :type "hidden" diff --git a/tailwind.config.js b/tailwind.config.js index b2056c91..dc5cc907 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -5,6 +5,22 @@ module.exports = { "./node_modules/flowbite/**/*.js"], theme: { extend: { + "keyframes": { + shake: { + '0%': { transform: 'translateX(0px)' }, + '12.5%': { transform: 'translateX(-5px)' }, + '25%': { transform: 'translateX(0px)' }, + '37.5%': { transform: 'translateX(5px)' }, + '50%': { transform: 'translateX(0px)' }, + '62.5%': { transform: 'translateX(-5px)' }, + '75%': { transform: 'translateX(5px)' }, + '87.5%': { transform: 'translateX(5px)' }, + '100%': { transform: 'translateX(0px)' }, + }, + }, + animation: { + 'shake': 'shake 0.5s ease-out 1', + }, "fontFamily": { "sans": ["Calibri", "ui-sans-serif", "system-ui", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"] From a6032e2be296e42a440613e05660fffe3c89075a Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 06:27:55 -0700 Subject: [PATCH 09/34] progress on updating users --- resources/public/output.css | 4 + .../auto_ap/ssr/admin/transaction_rules.clj | 179 +++++++++--------- src/clj/auto_ap/ssr/components/dialog.clj | 8 +- src/clj/auto_ap/ssr/components/inputs.clj | 16 +- src/clj/auto_ap/ssr/users.clj | 7 +- 5 files changed, 109 insertions(+), 105 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index a0cad0e2..6b7c19ec 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1356,6 +1356,10 @@ input:checked + .toggle-bg { max-height: 100%; } +.max-h-\[90vh\] { + max-height: 90vh; +} + .w-1\/2 { width: 50%; } diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 4b285630..40911e8a 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -59,19 +59,19 @@ (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-table) + :admin-transaction-rule-table) "hx-target" "#transaction-rule-table" "hx-indicator" "#transaction-rule-table"} - [:fieldset.space-y-6 + [:fieldset.space-y-6 (com/field {:label "Vendor"} - (com/typeahead {:name "vendor" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :vendor-search) - :id (str "vendor-search") - :value [(:db/id (:vendor (:parsed-query-params request))) - (:vendor/name (:vendor (:parsed-query-params request)))]})) + (com/typeahead-2 {:name "vendor" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :vendor-search) + :id (str "vendor-search") + :value [(:db/id (:vendor (:parsed-query-params request))) + (:vendor/name (:vendor (:parsed-query-params request)))]})) (com/field {:label "Note"} (com/text-input {:name "note" :id "note" @@ -193,7 +193,7 @@ [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-new-dialog)) :hx-target "#modal-content" - :hx-swap "innerHTML" + :hx-swap "outerHTML" :color :primary} "New Transaction Rule")]) :row-buttons (fn [request entity] @@ -201,7 +201,7 @@ :admin-transaction-rule-edit-dialog :db/id (:db/id entity))) :hx-target "#modal-content" - :hx-swap "innerHTML"} + :hx-swap "outerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -220,7 +220,8 @@ {:key "bank-account" :name "Bank account" :sort-key "bank-account" - :render #(-> % :transaction-rule/bank-account :bank-account/name)} + :render #(-> % :transaction-rule/bank-account :bank-account/name) + :show-starting "lg"} {:key "description" :name "Description" :sort-key "description" @@ -233,7 +234,8 @@ (com/pill {:color :red} (format "more than $%.2f" amount-gte))) (when amount-lte - (com/pill {:color :primary} (format "less than $%.2f" amount-lte)))])} + (com/pill {:color :primary} (format "less than $%.2f" amount-lte)))]) + :show-starting "md"} {:key "note" :name "Note" :sort-key "note" @@ -401,16 +403,17 @@ (defn dialog* [& {:keys [entity form-params form-errors]}] (com/modal {:modal-class "max-w-2xl"} - (com/modal-card - {} - [:div.flex [:div.p-2 "Transaction Rule"]] - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target "#modal-holder" - :hx-target-400 "#form-errors .error-content" - :x-trap "true" - :class "group/form"} - form-params) + + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target "#modal-holder" + :hx-target-400 "#form-errors .error-content" + :x-trap "true" + :class "group/form"} + form-params) + (com/modal-card + {} + [:div.flex [:div.p-2 "Transaction Rule"]] [:fieldset {:class "hx-disable" :hx-disinherit "hx-target" :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) (:transaction-rule/client entity))})} @@ -448,43 +451,42 @@ (fc/with-field :transaction-rule/client (com/validated-field - (-> {:label "Client" - :errors (fc/field-errors) - :x-show "clientFilter"} - (hx/alpine-appear)) - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :company-search) - :x-model "clientId" - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) + (-> {:label "Client" + :errors (fc/field-errors) + :x-show "clientFilter"} + (hx/alpine-appear)) + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :x-model "clientId" + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (fn [c] (cond->> c + (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) + true :client/name))})])) (fc/with-field :transaction-rule/bank-account (com/validated-field - (-> {:label "Bank Account" - :errors (fc/field-errors) - :x-show "bankAccountFilter" - } - hx/alpine-appear) - [:div.w-96 - [:div#bank-account-changer {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) - :hx-trigger "changed" - :hx-target "next *" - :hx-include "#bank-account-changer" - :hx-swap "innerHTML" + (-> {:label "Bank Account" + :errors (fc/field-errors) + :x-show "bankAccountFilter"} + hx/alpine-appear) + [:div.w-96 + [:div#bank-account-changer {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) + :hx-trigger "changed" + :hx-target "next *" + :hx-include "#bank-account-changer" + :hx-swap "innerHTML" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) - :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] - - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) - :name (fc/field-name) - :value (fc/field-value)})])) + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) + :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) + :name (fc/field-name) + :value (fc/field-value)})])) (com/field (-> {:label "Amount" :x-show "amountFilter"} @@ -511,18 +513,18 @@ [:div.flex.gap-2 (fc/with-field :transaction-rule/dom-gte (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}))) + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}))) (fc/with-field :transaction-rule/dom-lte (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)})))])] + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)})))])] [:h2.text-lg "Outcomes"] (fc/with-field :transaction-rule/vendor @@ -549,24 +551,24 @@ (doall (for [tra fc/*current*] (fc/with-cursor tra (transaction-rule-account-row* entity tra))))) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 4 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :color :secondary - :hx-include "#edit-form" - :hx-ext "rename-params" - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New account")]))) + (com/data-grid-row + {:class "new-row"} + (com/data-grid-cell {:colspan 4 + :class "bg-gray-100"} + [:div.flex.justify-center + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :color :secondary + :hx-include "#edit-form" + :hx-ext "rename-params" + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "index" "index"}) + :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") + :hx-target "#edit-form .new-row" + :hx-swap "beforebegin"} + "New account")]))) (com/errors {:errors (fc/field-errors)}))) - + (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" :errors (fc/field-errors)} @@ -578,12 +580,11 @@ [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})])] - (com/button {:color :primary :form "edit-form" :type "submit" :class (cond-> "w-32" - (seq form-errors) (-> - (hh/add-class "animate-shake")))} - "Save")])]] - [:div]))) + (com/errors {:errors (:errors fc/*form-errors*)})])]])] + [:div (com/button {:color :primary :form "edit-form" :type "submit" :class (cond-> "w-32" + (seq form-errors) (-> + (hh/add-class "animate-shake")))} + "Save")])])) ;; TODO Should forms have some kind of helper to render an individual field? saving diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index 937716be..f4ae762d 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -3,15 +3,15 @@ [auto-ap.ssr.hx :as hx])) (defn modal- [params & children] - [:div#modal-content {:class "flex items-center justify-between pb-2"} + [:div#modal-content {:class ""} children]) (defn modal-card- [params header content footer] [:div#modal-card params - [:div {:class "relative bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content"} + [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full"} [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600"} header] - [:div {:class "p-6 space-y-6"} + [:div {:class "p-6 space-y-6 overflow-scroll "} content] - [:div footer]]]) + (when footer [:div {:class "p-4 "} footer])]]) ;; fade-in-settle slide-up-settle duration-300 transition-all diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index fa9b8f88..480854f1 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -77,13 +77,12 @@ c.clearChoices(); (str (:url params) "?q=")) :value {:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))} :search "" - :active 0 - :elements (if (:value params) + :active -1 + :elements (if ((:value-fn params first) (:value params)) [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] [])}) :x-modelable "value.value" - :x-model (:x-model params) - } + :x-model (:x-model params)} [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) "@click.prevent" "open = !open;" @@ -100,16 +99,15 @@ c.clearChoices(); (dissoc :placeholder) (dissoc :x-model) (assoc - "x-ref" "hidden" - :type "hidden" - ":value" "value.value" - :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] + "x-ref" "hidden" + :type "hidden" + ":value" "value.value" + :x-init (hiccup/raw (str "$watch('value', v => $dispatch('change')); "))))] [:div.flex.w-full.justify-items-stretch [:span.flex-grow.text-left {"x-text" "value.label"}] [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-10 mt-1" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index d1ba7b58..2e4df1ac 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -206,7 +206,7 @@ (com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :user-edit-dialog :db/id (:db/id entity))) - :hx-target "#modal-holder" + :hx-target "#modal-content" :hx-swap "outerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes @@ -265,7 +265,7 @@ (html-response (row* identity user {:flash? true}) - :headers {"hx-trigger" "closeModal" + :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#user-table tr[data-id=\"%d\"]" (:db/id user))}))) (defn user-edit-dialog [request] @@ -315,7 +315,8 @@ [:div#form-errors [:span.error-content]] (com/button {:color :primary :type "submit"} "Save")] - [:div])]])))) + [:div])]]) + :headers {"hx-trigger" "modalopen"}))) (def key->handler (apply-middleware-to-all-handlers From fc0392a235d757159520bdfc7b2e50ec4e2d9fa5 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 21:00:04 -0700 Subject: [PATCH 10/34] improvements --- resources/public/output.css | 71 ++++++++++++++++ src/clj/auto_ap/ssr/admin/accounts.clj | 81 +++++++++++-------- .../auto_ap/ssr/admin/transaction_rules.clj | 9 +-- src/clj/auto_ap/ssr/components.clj | 1 + src/clj/auto_ap/ssr/components/buttons.clj | 16 +++- src/clj/auto_ap/ssr/components/dialog.clj | 25 ++++-- src/clj/auto_ap/ssr/components/inputs.clj | 3 +- src/clj/auto_ap/ssr/ui.clj | 28 +++---- src/clj/auto_ap/ssr/users.clj | 19 ++--- 9 files changed, 179 insertions(+), 74 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 6b7c19ec..96983899 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1348,6 +1348,19 @@ input:checked + .toggle-bg { height: 100vh; } +.h-64 { + height: 16rem; +} + +.h-min { + height: -moz-min-content; + height: min-content; +} + +.h-\[90vh\] { + height: 90vh; +} + .max-h-96 { max-height: 24rem; } @@ -1360,6 +1373,14 @@ input:checked + .toggle-bg { max-height: 90vh; } +.max-h-\[100vh\] { + max-height: 100vh; +} + +.max-h-\[80vh\] { + max-height: 80vh; +} + .w-1\/2 { width: 50%; } @@ -1433,6 +1454,23 @@ input:checked + .toggle-bg { width: 100vw; } +.w-min { + width: -moz-min-content; + width: min-content; +} + +.w-8\/12 { + width: 66.666667%; +} + +.w-6\/12 { + width: 50%; +} + +.w-1\/4 { + width: 25%; +} + .max-w-2xl { max-width: 42rem; } @@ -1457,6 +1495,10 @@ input:checked + .toggle-bg { max-width: 1024px; } +.max-w-xs { + max-width: 20rem; +} + .flex-1 { flex: 1 1 0%; } @@ -1481,6 +1523,10 @@ input:checked + .toggle-bg { flex-grow: 1; } +.grow { + flex-grow: 1; +} + .basis-1\/4 { flex-basis: 25%; } @@ -1671,6 +1717,10 @@ input:checked + .toggle-bg { place-items: center; } +.content-center { + align-content: center; +} + .items-start { align-items: flex-start; } @@ -1819,6 +1869,10 @@ input:checked + .toggle-bg { overflow: hidden; } +.overflow-visible { + overflow: visible; +} + .overflow-scroll { overflow: scroll; } @@ -1831,6 +1885,10 @@ input:checked + .toggle-bg { overflow-y: auto; } +.overflow-y-scroll { + overflow-y: scroll; +} + .truncate { overflow: hidden; text-overflow: ellipsis; @@ -2208,6 +2266,11 @@ input:checked + .toggle-bg { padding-bottom: 1.25rem; } +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + .pb-2 { padding-bottom: 0.5rem; } @@ -3543,6 +3606,10 @@ input:checked + .toggle-bg { } @media (min-width: 640px) { + .sm\:m-12 { + margin: 3rem; + } + .sm\:block { display: block; } @@ -3563,6 +3630,10 @@ input:checked + .toggle-bg { padding: 1.5rem; } + .sm\:p-12 { + padding: 3rem; + } + .sm\:py-5 { padding-top: 1.25rem; padding-bottom: 1.25rem; diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 895921b0..f3657e02 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -21,8 +21,8 @@ [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers entity-id - forced-vector html-response + many-entity map->db-id-decoder ref->enum-schema ref->select-options @@ -135,16 +135,16 @@ :action-buttons (fn [request] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-new-dialog)) - :hx-target "#modal-holder" - :hx-swap "outerHTML" + :hx-target "#modal-content" + :hx-swap "innerHTML" :color :primary} "New Account")]) :row-buttons (fn [request entity] [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-edit-dialog :db/id (:db/id entity))) - :hx-target "#modal-holder" - :hx-swap "outerHTML"} + :hx-target "#modal-content" + :hx-swap "innerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -207,22 +207,26 @@ "account_client_override_id" (:db/id o)}))) (html-response (row* identity updated-account {:flash? true}) - :headers {"hx-trigger" "closeModal" + :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#account-table tr[data-id=\"%d\"]" (:db/id updated-account))}))) +;; TODO use cursor +;; TODO index based list not dbid -(defn client-override* [override] +(defn client-override* [override index] [:div.flex.gap-2.mb-2.client-override [:div.w-96 - (com/typeahead {:name (format "account/client-overrides[%s][account-client-override/client]" (:db/id override)) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id (str "account-client-override-" (:db/id override)) - :value [(:db/id (:account-client-override/client override)) - (:client/name (:account-client-override/client override))]})] + (com/hidden {:name (format "account/client-overrides[%s][db/id]" index) + :value (:db/id override)}) + (com/typeahead-2 {:name (format "account/client-overrides[%s][account-client-override/client]" index) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :id (str "account-client-override-" (:db/id override)) + :value [(:db/id (:account-client-override/client override)) + (:client/name (:account-client-override/client override))]})] [:div.w-96 - (com/text-input {:name (format "account/client-overrides[%s][account-client-override/name]" (:db/id override)) + (com/text-input {:name (format "account/client-overrides[%s][account-client-override/name]" index) :class "w-full" :value (:account-client-override/name override)})] [:div (com/a-icon-button {"_" (hiccup/raw "on click halt the event then transition the closest <.client-override />'s opacity to 0 then remove closest <.client-override />") } svg/x)]]) @@ -230,7 +234,7 @@ (defn dialog* [& {:keys [ account form-params]}] (com/modal - {:modal-class "max-w-4xl"} + {} [:form#edit-form (merge {:hx-ext "response-targets" :hx-swap "outerHTML swap:300ms" :hx-target-400 "#form-errors .error-content"} @@ -282,33 +286,37 @@ :options (ref->select-options "account-applicability")})) (com/field {:label "Client Overrides" :id "client-overrides"} - (for [override (:account/client-overrides account)] - (client-override* override))) + (for [[override index] (map vector (:account/client-overrides account) (range))] + (client-override* override index))) (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :hx-target "#client-overrides" - :hx-swap "beforeend"} + :admin-account-client-override-new) + :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") + :hx-target "#client-overrides" + :hx-swap "beforeend"} "New override") [:div#form-errors [:span.error-content]] - (com/button {:color :primary :form "edit-form" :type "submit"} - "Save")] - [:div])]])) + ] + (com/validated-save-button {:errors []} + "Save account"))]])) -(defn new-client-override [_] +(defn new-client-override [{ {:keys [index]} :query-params}] (html-response - (client-override* {:db/id (str (java.util.UUID/randomUUID))}))) + (client-override* {:db/id (str (java.util.UUID/randomUUID))} + index))) (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] (html-response (dialog* :account account :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes - :admin-account-edit-save))})))) + :admin-account-edit-save))}) + :headers {"hx-trigger" "modalopen"}))) (defn account-new-dialog [_] (html-response (dialog* :account nil :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes - :admin-account-new-save))}))) + :admin-account-new-save))}) + :headers {"hx-trigger" "modalopen"})) (def account-schema (mc/schema [:map @@ -320,20 +328,23 @@ [:account/applicability (ref->enum-schema "account-applicability")] [:account/invoice-allowance (ref->enum-schema "allowance")] [:account/vendor-allowance (ref->enum-schema "allowance")] - [:account/client-overrides {:decode/json map->db-id-decoder - :optional true} + [:account/client-overrides {:optional true} [:maybe - (forced-vector [:map - [:db/id [:or entity-id temp-id]] - [:account-client-override/client [:or entity-id :string]] - [:account-client-override/name :string]])]]])) + (many-entity {} + [:db/id [:or entity-id temp-id]] + [:account-client-override/client [:or entity-id :string]] + [:account-client-override/name :string])]]])) (def key->handler (apply-middleware-to-all-handlers (->> {:admin-accounts (helper/page-route grid-page) :admin-account-table (helper/table-route grid-page) - :admin-account-client-override-new (-> new-client-override wrap-admin wrap-client-redirect-unauthenticated) + :admin-account-client-override-new (-> new-client-override + (wrap-schema-decode :query-schema [:map + [:index {:optional true + :default 0} [nat-int? {:default 0}]]]) + wrap-admin wrap-client-redirect-unauthenticated) :admin-account-save (-> account-save (wrap-schema-decode :form-schema account-schema) (wrap-nested-form-params) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 40911e8a..ffe7a84f 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -193,7 +193,7 @@ [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-new-dialog)) :hx-target "#modal-content" - :hx-swap "outerHTML" + :hx-swap "innerHTML" :color :primary} "New Transaction Rule")]) :row-buttons (fn [request entity] @@ -201,7 +201,7 @@ :admin-transaction-rule-edit-dialog :db/id (:db/id entity))) :hx-target "#modal-content" - :hx-swap "outerHTML"} + :hx-swap "innerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -581,10 +581,7 @@ [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content (com/errors {:errors (:errors fc/*form-errors*)})])]])] - [:div (com/button {:color :primary :form "edit-form" :type "submit" :class (cond-> "w-32" - (seq form-errors) (-> - (hh/add-class "animate-shake")))} - "Save")])])) + (com/validated-save-button {:errors form-errors} "Save rule"))])) ;; TODO Should forms have some kind of helper to render an individual field? saving diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index 41fff258..cee70ef2 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -15,6 +15,7 @@ (def breadcrumbs breadcrumbs/breadcrumbs-) (def button buttons/button-) +(def validated-save-button buttons/validated-save-button-) (def a-button buttons/a-button-) (def button-icon buttons/button-icon-) (def icon-button buttons/icon-button-) diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 9edd6529..076945f9 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -1,5 +1,6 @@ (ns auto-ap.ssr.components.buttons - (:require [auto-ap.ssr.svg :as svg])) + (:require [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.hiccup-helper :as hh])) (defn button-icon- [_ i] [:div.h-4.w-4 i]) @@ -170,3 +171,16 @@ :hx-on:click "this.querySelector(\"input\").value = event.target.value; this.querySelector(\"input\").dispatchEvent(new Event('change', {bubbles: true}));"} [:input {:type "hidden" :name name}]] children))) + + +(defn validated-save-button- [{:keys [errors class] :as params} & children] + (button- (-> {:color :primary :form "edit-form" + :type "submit" :class (cond-> (or class "") + true (hh/add-class "w-32") + (seq errors) (hh/add-class "animate-shake"))} + (merge params) + (dissoc :errors)) + (if (seq children) + children + "Save")) + ) diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index f4ae762d..d2109e35 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -1,17 +1,26 @@ (ns auto-ap.ssr.components.dialog (:require [hiccup2.core :as hiccup] - [auto-ap.ssr.hx :as hx])) + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.hiccup-helper :as hh])) (defn modal- [params & children] - [:div#modal-content {:class ""} - children]) + [:div {:class (-> (:class params) + (or "max-w-4xl w-1/4 overflow-visible") + (hh/add-class "h-min")) + "@click.outside" "open=false" + } children]) (defn modal-card- [params header content footer] - [:div#modal-card params - [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full"} - [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600"} header] - [:div {:class "p-6 space-y-6 overflow-scroll "} + [:div#modal-card (update params + :class (fn [c] (-> c + (or "w-full") + ))) + [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col max-h-[80vh]"} + [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"} header] + [:div {:class "px-6 space-y-6 overflow-y-scroll w-full shrink"} + #_[:div.bg-green-300.w-full.h-64 + "hello"] content] - (when footer [:div {:class "p-4 "} footer])]]) + (when footer [:div {:class "p-4 shrink-0"} footer])]]) ;; fade-in-settle slide-up-settle duration-300 transition-all diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 480854f1..2704c2b6 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -82,7 +82,8 @@ c.clearChoices(); [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] [])}) :x-modelable "value.value" - :x-model (:x-model params)} + :x-model (:x-model params) + :class "relative"} [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) "@click.prevent" "open = !open;" diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index d2ef40b1..3cccfa40 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -77,17 +77,17 @@ input[type=number] { "x-transition:leave-start" "!bg-opacity-50" "x-transition:leave-end" "!bg-opacity-0"} - [:div.flex.place-items-center.place-content-center.w-full.h-full.p-12 - [:div {:class (str "w-full sm:max-w-2xl sm:rounded-lg overflow-scroll max-h-full sm:max-h-[90vh]") - "@click.outside" "open=false" - "x-trap.inert.noscroll" "open" - "x-trap.inert" "open" - "x-show" "open" - "x-transition:enter" "ease-out duration-300" - "x-transition:enter-start" "!bg-opacity-0 !translate-y-32" - "x-transition:enter-end" "!bg-opacity-100 !translate-y-0" - "x-transition:leave" "duration-300" - "x-transition:leave-start" "!opacity-100 !translate-y-0" - "x-transition:leave-end" "!opacity-0 !translate-y-32"} - - [:div#modal-content {:class "flex items-center justify-between pb-2"}]]]]]]])) + ;; TODO to get this right i think what needs to happen is to just set this up as having a single + ;; div that is forced to the maximum allowed size. inside that will be a div that just centers + ;; the elements, allowing it to grow as necessar. Then make the modal on the inside of this + ;; div just use flexbox to make the inside part be the part that scrolls + [:div#modal-content {:class (str "inset-0 max-h-[80vh] sm:m-12 flex justify-center items-center shrink h-full") + "x-trap.inert.noscroll" "open" + "x-trap.inert" "open" + "x-show" "open" + "x-transition:enter" "ease-out duration-300" + "x-transition:enter-start" "!bg-opacity-0 !translate-y-32" + "x-transition:enter-end" "!bg-opacity-100 !translate-y-0" + "x-transition:leave" "duration-300" + "x-transition:leave-start" "!opacity-100 !translate-y-0" + "x-transition:leave-end" "!opacity-0 !translate-y-32"}]]]]])) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 2e4df1ac..aad8b8f5 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -71,13 +71,13 @@ {:value "none" :content "None"}]})) (com/field {:label "Client"} - (com/typeahead {:name "client" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id (str "client-search") - :value [(:db/id (:client (:parsed-query-params request))) - (:client/name (:client (:parsed-query-params request)))]}))]]) + (com/typeahead-2 {:name "client" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :id (str "client-search") + :value [(:db/id (:client (:parsed-query-params request))) + (:client/name (:client (:parsed-query-params request)))]}))]]) (def default-read '[:db/id :user/name @@ -207,7 +207,7 @@ :user-edit-dialog :db/id (:db/id entity))) :hx-target "#modal-content" - :hx-swap "outerHTML"} + :hx-swap "innerHTML"} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -281,7 +281,8 @@ :user-edit-save :request-method :put)) :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} + :hx-target-400 "#form-errors .error-content" + :class "w-full"} [:fieldset {:class "hx-disable"} (com/modal-card {} From bd1d603eb62ab1c72b60a165f0cb85c0f0c641f6 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 21:07:58 -0700 Subject: [PATCH 11/34] submit buttons --- resources/public/output.css | 33 --------- src/clj/auto_ap/ssr/admin/accounts.clj | 2 +- src/clj/auto_ap/ssr/users.clj | 95 +++++++++++++------------- 3 files changed, 48 insertions(+), 82 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 96983899..73530dec 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1357,10 +1357,6 @@ input:checked + .toggle-bg { height: min-content; } -.h-\[90vh\] { - height: 90vh; -} - .max-h-96 { max-height: 24rem; } @@ -1373,10 +1369,6 @@ input:checked + .toggle-bg { max-height: 90vh; } -.max-h-\[100vh\] { - max-height: 100vh; -} - .max-h-\[80vh\] { max-height: 80vh; } @@ -1454,19 +1446,6 @@ input:checked + .toggle-bg { width: 100vw; } -.w-min { - width: -moz-min-content; - width: min-content; -} - -.w-8\/12 { - width: 66.666667%; -} - -.w-6\/12 { - width: 50%; -} - .w-1\/4 { width: 25%; } @@ -1495,10 +1474,6 @@ input:checked + .toggle-bg { max-width: 1024px; } -.max-w-xs { - max-width: 20rem; -} - .flex-1 { flex: 1 1 0%; } @@ -1717,10 +1692,6 @@ input:checked + .toggle-bg { place-items: center; } -.content-center { - align-content: center; -} - .items-start { align-items: flex-start; } @@ -3630,10 +3601,6 @@ input:checked + .toggle-bg { padding: 1.5rem; } - .sm\:p-12 { - padding: 3rem; - } - .sm\:py-5 { padding-top: 1.25rem; padding-bottom: 1.25rem; diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index f3657e02..6978f1d5 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -296,7 +296,7 @@ "New override") [:div#form-errors [:span.error-content]] ] - (com/validated-save-button {:errors []} + (com/validated-save-button {:errors []} ;; TODO "Save account"))]])) (defn new-client-override [{ {:keys [index]} :query-params}] diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index aad8b8f5..2b327f95 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -270,54 +270,53 @@ (defn user-edit-dialog [request] (let [user (some-> request - :route-params - :db/id - (#(dc/pull (dc/db conn) default-read %)))] - (html-response - (com/modal - {} - [:form {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full"} - [:fieldset {:class "hx-disable"} - (com/modal-card - {} - [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name user)]] - [:div.space-y-6 - (com/hidden {:name "db/id" - :value (:db/id user)}) - (com/field {:label "Role"} - (com/select {:name "user/role" - :class "w-36" - :autofocus true - :id "role" - :value (name (:user/role user)) - :options [["none" "None"] - ["power-user" "Power user"] - ["manager" "Manager"] - ["admin" "Admin"] - ["user" "User"]]})) - (com/field {:label "Clients"} - (com/typeahead {:name "user/clients" - :class "w-full" - :multiple "multiple" - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id "clients" - :value (map - (fn [client] - [(:db/id client) (:client/name client)]) - (:user/clients user)) - :size :small})) - [:div#form-errors [:span.error-content]] - (com/button {:color :primary :type "submit"} - "Save")] - [:div])]]) - :headers {"hx-trigger" "modalopen"}))) + :route-params + :db/id + (#(dc/pull (dc/db conn) default-read %)))] + (html-response + (com/modal + {} + [:form {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full"} + [:fieldset {:class "hx-disable"} + (com/modal-card + {} + [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name user)]] + [:div.space-y-6 + (com/hidden {:name "db/id" + :value (:db/id user)}) + (com/field {:label "Role"} + (com/select {:name "user/role" + :class "w-36" + :autofocus true + :id "role" + :value (name (:user/role user)) + :options [["none" "None"] + ["power-user" "Power user"] + ["manager" "Manager"] + ["admin" "Admin"] + ["user" "User"]]})) + (com/field {:label "Clients"} + (com/typeahead {:name "user/clients" + :class "w-full" + :multiple "multiple" + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :id "clients" + :value (map + (fn [client] + [(:db/id client) (:client/name client)]) + (:user/clients user)) + :size :small})) + [:div#form-errors [:span.error-content]]] + (com/validated-save-button {:errors []} ;; TODO + "Save user"))]]) + :headers {"hx-trigger" "modalopen"}))) (def key->handler (apply-middleware-to-all-handlers From 76760b7bcfed5fab52438bb87fb4f7f24f956456 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 21:32:36 -0700 Subject: [PATCH 12/34] progress for accounts --- src/clj/auto_ap/ssr/admin/accounts.clj | 189 ++++++++++-------- .../auto_ap/ssr/admin/transaction_rules.clj | 6 +- 2 files changed, 112 insertions(+), 83 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 6978f1d5..28ddfc5e 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -34,7 +34,8 @@ [clojure.string :as str] [datomic.api :as dc] [hiccup2.core :as hiccup] - [malli.core :as mc])) + [malli.core :as mc] + [auto-ap.ssr.form-cursor :as fc])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -213,96 +214,122 @@ ;; TODO use cursor ;; TODO index based list not dbid -(defn client-override* [override index] +(defn client-override* [override] [:div.flex.gap-2.mb-2.client-override [:div.w-96 - (com/hidden {:name (format "account/client-overrides[%s][db/id]" index) - :value (:db/id override)}) - (com/typeahead-2 {:name (format "account/client-overrides[%s][account-client-override/client]" index) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id (str "account-client-override-" (:db/id override)) - :value [(:db/id (:account-client-override/client override)) - (:client/name (:account-client-override/client override))]})] - [:div.w-96 - (com/text-input {:name (format "account/client-overrides[%s][account-client-override/name]" index) - :class "w-full" - :value (:account-client-override/name override)})] - [:div (com/a-icon-button {"_" (hiccup/raw "on click halt the event then transition the closest <.client-override />'s opacity to 0 then remove closest <.client-override />") } svg/x)]]) + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :account-client-override/client + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :value (fc/field-value) + :value-fn :db/id ;; TODO hydration something here + :content-fn :client/name}))] + (fc/with-field :account-client-override/name + [:div.w-96 + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value)})]) + [:div (com/a-icon-button {"_" (hiccup/raw "on click halt the event then transition the closest <.client-override />'s opacity to 0 then remove closest <.client-override />")} svg/x)]]) + +;; TODO each form: +;; elimante typeahead1 +;; work with new dialog +;; use cursor +;; ensure all dialogs are opened the same way +;; form level validation +;; form level validation +;; componentize +;; ensure all dependency oriented stuff works the same way +;; make sure that "new row index" stuff works ok -(defn dialog* [& {:keys [ account form-params]}] +(defn dialog* [& {:keys [account form-params form-errors]}] (com/modal - {} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - form-params) - [:fieldset {:class "hx-disable"} - (com/modal-card - {} - [:div.flex [:div.p-2 "Account"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:account/numeric-code account) " - " (:account/name account)]] - [:div.space-y-6 - (when-let [id (:db/id account)] - (com/hidden {:name "db/id" - :value id})) - - (when (nil? account) - (com/field {:label "Numeric code"} - (com/text-input {:name "account/numeric-code" - :autofocus true - :class "w-32"}))) - (com/field {:label "Name"} - (com/text-input {:name "account/name" - :autofocus true - :class "w-32" - :value (:account/name account)})) - (com/field {:label "Account Type"} - (com/select {:name "account/type" - :class "w-36" - :id "type" - :value (some-> account :account/type name) - :options (ref->select-options "account-type")})) - (com/field {:label "Location"} - (com/text-input {:name "account/location" - :class "w-16" - :value (:account/location account)})) + {} + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} + form-params) + [:fieldset {:class "hx-disable"} + (com/modal-card + {} + [:div.flex [:div.p-2 "Account"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:account/numeric-code account) " - " (:account/name account)]] - (com/field {:label "Invoice Allowance"} - (com/select {:name "account/invoice-allowance" - :value (some-> account :account/invoice-allowance name) - :class "w-36" - :options (ref->select-options "allowance")})) - (com/field {:label "Vendor Allowance"} - (com/select {:name "account/vendor-allowance" - :class "w-36" - :value (some-> account :account/vendor-allowance name) - :options (ref->select-options "allowance")})) - (com/field {:label "Applicability"} - (com/select {:name "account/applicability" - :class "w-36" - :value (some-> account :account/applicability name) - :options (ref->select-options "account-applicability")})) + (fc/start-form + account form-errors + [:div.space-y-1 + (when-let [id (:db/id account)] + (com/hidden {:name "db/id" + :value id})) - (com/field {:label "Client Overrides" :id "client-overrides"} - (for [[override index] (map vector (:account/client-overrides account) (range))] - (client-override* override index))) - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") - :hx-target "#client-overrides" - :hx-swap "beforeend"} - "New override") - [:div#form-errors [:span.error-content]] - ] - (com/validated-save-button {:errors []} ;; TODO - "Save account"))]])) + (fc/with-field :account/numeric-code + (when (nil? (fc/field-value)) + (com/field {:label "Numeric code"} + (com/text-input {:name (fc/field-name) + :autofocus true + :class "w-32"})))) + (fc/with-field :account/name + (com/field {:label "Name"} + (com/text-input {:name (fc/field-name) + :autofocus true + :class "w-32" + :value (fc/field-value)}))) + (fc/with-field :account/type + (com/field {:label "Account Type"} + (com/select {:name (fc/field-name) + :class "w-36" + :id "type" + :value (some-> (fc/field-value) name) + :options (ref->select-options "account-type")}))) + (fc/with-field :account/location + (com/field {:label "Location"} + (com/text-input {:name (fc/field-name) + :class "w-16" + :value (fc/field-value)}))) + + (fc/with-field :account/invoice-allowance + (com/field {:label "Invoice Allowance"} + (com/select {:name (fc/field-name) + :value (some-> (fc/field-value) name) + :class "w-36" + :options (ref->select-options "allowance")}))) + (fc/with-field :account/vendor-allowance + (com/field {:label "Vendor Allowance"} + (com/select {:name (fc/field-name) + :class "w-36" + :value (some-> (fc/field-value) name) + :options (ref->select-options "allowance")}))) + (fc/with-field :account/applicability + (com/field {:label "Applicability"} + (com/select {:name (fc/field-name) + :class "w-36" + :value (some-> (fc/field-value) name) + :options (ref->select-options "account-applicability")}))) + + (fc/with-field :account/client-overrides + (com/field {:label "Client Overrides" :id "client-overrides"} + (when (fc/field-value) + (doall + (for [override fc/*current*] + (fc/with-cursor override + (client-override* override))))))) + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-account-client-override-new) + :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") + :hx-target "#client-overrides" + :hx-swap "beforeend"} + "New override") + [:div#form-errors [:span.error-content]]]) + (com/validated-save-button {:errors []} ;; TODO + "Save account"))]])) (defn new-client-override [{ {:keys [index]} :query-params}] (html-response - (client-override* {:db/id (str (java.util.UUID/randomUUID))} - index))) + (client-override* {:db/id (str (java.util.UUID/randomUUID))}))) (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index ffe7a84f..972ec8a6 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -406,7 +406,7 @@ [:form#edit-form (merge {:hx-ext "response-targets" :hx-swap "outerHTML swap:300ms" - :hx-target "#modal-holder" + :hx-target "#modal-holder" ;; TODO sort :hx-target-400 "#form-errors .error-content" :x-trap "true" :class "group/form"} @@ -414,7 +414,8 @@ (com/modal-card {} [:div.flex [:div.p-2 "Transaction Rule"]] - [:fieldset {:class "hx-disable" :hx-disinherit "hx-target" + [:fieldset {:class "hx-disable" + :hx-disinherit "hx-target" ;; TODO why disinherit :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) (:transaction-rule/client entity))})} @@ -561,6 +562,7 @@ :color :secondary :hx-include "#edit-form" :hx-ext "rename-params" + ;; TODO :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" "index" "index"}) :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") From dd5063c72d04526b10eda9301eae07dfac066eb8 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 21:47:36 -0700 Subject: [PATCH 13/34] account new override --- resources/public/output.css | 33 ++++++++++++++++++++++++++ src/clj/auto_ap/ssr/admin/accounts.clj | 12 +++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 73530dec..96983899 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1357,6 +1357,10 @@ input:checked + .toggle-bg { height: min-content; } +.h-\[90vh\] { + height: 90vh; +} + .max-h-96 { max-height: 24rem; } @@ -1369,6 +1373,10 @@ input:checked + .toggle-bg { max-height: 90vh; } +.max-h-\[100vh\] { + max-height: 100vh; +} + .max-h-\[80vh\] { max-height: 80vh; } @@ -1446,6 +1454,19 @@ input:checked + .toggle-bg { width: 100vw; } +.w-min { + width: -moz-min-content; + width: min-content; +} + +.w-8\/12 { + width: 66.666667%; +} + +.w-6\/12 { + width: 50%; +} + .w-1\/4 { width: 25%; } @@ -1474,6 +1495,10 @@ input:checked + .toggle-bg { max-width: 1024px; } +.max-w-xs { + max-width: 20rem; +} + .flex-1 { flex: 1 1 0%; } @@ -1692,6 +1717,10 @@ input:checked + .toggle-bg { place-items: center; } +.content-center { + align-content: center; +} + .items-start { align-items: flex-start; } @@ -3601,6 +3630,10 @@ input:checked + .toggle-bg { padding: 1.5rem; } + .sm\:p-12 { + padding: 3rem; + } + .sm\:py-5 { padding-top: 1.25rem; padding-bottom: 1.25rem; diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 28ddfc5e..35eca1b0 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -35,7 +35,8 @@ [datomic.api :as dc] [hiccup2.core :as hiccup] [malli.core :as mc] - [auto-ap.ssr.form-cursor :as fc])) + [auto-ap.ssr.form-cursor :as fc] + [clj-time.format :as f])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -328,8 +329,13 @@ "Save account"))]])) (defn new-client-override [{ {:keys [index]} :query-params}] - (html-response - (client-override* {:db/id (str (java.util.UUID/randomUUID))}))) + (let [index (or index 0) + account {:account/client-overrides (conj (into [] (repeat index {})) + {:db/id (str (java.util.UUID/randomUUID))})}] ;; TODO schema decode is not working + (html-response + (fc/start-form account [] + (fc/with-cursor (get-in fc/*current* [:account/client-overrides index]) + (client-override* fc/*current*)))))) (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] From 2f05197f5bf641500258222982014acb60d288c7 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 22 Oct 2023 21:53:47 -0700 Subject: [PATCH 14/34] progress. --- src/clj/auto_ap/ssr/admin/accounts.clj | 75 ++++++++++++++++---------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 35eca1b0..e10eb667 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -15,6 +15,7 @@ [auto-ap.solr :as solr] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] @@ -23,20 +24,17 @@ entity-id html-response many-entity - map->db-id-decoder ref->enum-schema ref->select-options temp-id validation-error - wrap-form-4xx + wrap-form-4xx-2 wrap-schema-decode]] [bidi.bidi :as bidi] [clojure.string :as str] [datomic.api :as dc] [hiccup2.core :as hiccup] - [malli.core :as mc] - [auto-ap.ssr.form-cursor :as fc] - [clj-time.format :as f])) + [malli.core :as mc])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -222,18 +220,20 @@ (com/hidden {:name (fc/field-name) :value (fc/field-value)})) (fc/with-field :account-client-override/client - (com/typeahead-2 {:name (fc/field-name) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :value (fc/field-value) - :value-fn :db/id ;; TODO hydration something here - :content-fn :client/name}))] + (com/validated-field {:errors (fc/field-errors)} + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :value (fc/field-value) + :value-fn :db/id ;; TODO hydration something here + :content-fn :client/name})))] (fc/with-field :account-client-override/name [:div.w-96 - (com/text-input {:name (fc/field-name) - :class "w-full" - :value (fc/field-value)})]) + (com/validated-field {:errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value)}))]) [:div (com/a-icon-button {"_" (hiccup/raw "on click halt the event then transition the closest <.client-override />'s opacity to 0 then remove closest <.client-override />")} svg/x)]]) ;; TODO each form: @@ -269,43 +269,50 @@ (fc/with-field :account/numeric-code (when (nil? (fc/field-value)) - (com/field {:label "Numeric code"} - (com/text-input {:name (fc/field-name) - :autofocus true - :class "w-32"})))) + (com/validated-field {:label "Numeric code" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :autofocus true + :class "w-32"})))) (fc/with-field :account/name - (com/field {:label "Name"} + (com/validated-field {:label "Name" + :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) :autofocus true :class "w-32" :value (fc/field-value)}))) (fc/with-field :account/type - (com/field {:label "Account Type"} + (com/validated-field {:label "Account Type" + :errors (fc/field-errors)} (com/select {:name (fc/field-name) :class "w-36" :id "type" :value (some-> (fc/field-value) name) :options (ref->select-options "account-type")}))) (fc/with-field :account/location - (com/field {:label "Location"} + (com/validated-field {:label "Location" + :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) :class "w-16" :value (fc/field-value)}))) (fc/with-field :account/invoice-allowance - (com/field {:label "Invoice Allowance"} + (com/validated-field {:label "Invoice Allowance" + :errors (fc/field-errors)} (com/select {:name (fc/field-name) :value (some-> (fc/field-value) name) :class "w-36" :options (ref->select-options "allowance")}))) (fc/with-field :account/vendor-allowance - (com/field {:label "Vendor Allowance"} + (com/validated-field {:label "Vendor Allowance" + :errors (fc/field-errors)} (com/select {:name (fc/field-name) :class "w-36" :value (some-> (fc/field-value) name) :options (ref->select-options "allowance")}))) (fc/with-field :account/applicability - (com/field {:label "Applicability"} + (com/validated-field {:label "Applicability" + :errors (fc/field-errors)} (com/select {:name (fc/field-name) :class "w-36" :value (some-> (fc/field-value) name) @@ -351,6 +358,20 @@ :admin-account-new-save))}) :headers {"hx-trigger" "modalopen"})) +(defn account-save-error [request] + ;; TODO hydration + ;; TODO consistency of error handling and passing, on all form examples + (let [entity (some-> request :last-form)] + (html-response (dialog* :account entity + :form-errors (:form-errors request) + :form-params (if (:db/id entity) + {:hx-put (str (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-edit-save))} + {:hx-post (str (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-edit-save))})) + :headers {"hx-retarget" "#edit-form fieldset" + "hx-reselect" "#edit-form fieldset"}))) + (def account-schema (mc/schema [:map [:db/id {:optional true} [:maybe entity-id]] @@ -366,7 +387,7 @@ (many-entity {} [:db/id [:or entity-id temp-id]] [:account-client-override/client [:or entity-id :string]] - [:account-client-override/name :string])]]])) + [:account-client-override/name [:string {:min 2}]])]]])) (def key->handler (apply-middleware-to-all-handlers @@ -381,7 +402,7 @@ :admin-account-save (-> account-save (wrap-schema-decode :form-schema account-schema) (wrap-nested-form-params) - (wrap-form-4xx)) + (wrap-form-4xx-2 account-save-error)) :admin-account-edit-dialog (-> account-edit-dialog (wrap-schema-decode :route-schema [:map [:db/id entity-id]])) :admin-account-new-dialog account-new-dialog}) From 825443ef2c4724fc5478a9f306a69222ef7be6b8 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 10:57:35 -0700 Subject: [PATCH 15/34] Made accounts page look great --- src/clj/auto_ap/ssr/admin/accounts.clj | 235 +++++++----- .../auto_ap/ssr/admin/transaction_rules.clj | 347 +++++++++--------- src/clj/auto_ap/ssr/components/buttons.clj | 4 +- src/clj/auto_ap/ssr/hx.clj | 14 + src/clj/auto_ap/ssr/utils.clj | 2 + 5 files changed, 337 insertions(+), 265 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index e10eb667..ca2af3b1 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -7,6 +7,7 @@ audit-transact conn merge-query + pull-attr pull-many query2]] [auto-ap.query-params :as query-params] @@ -17,17 +18,19 @@ [auto-ap.ssr.components :as com] [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.hx :as hx] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers entity-id + field-validation-error + form-validation-error html-response many-entity ref->enum-schema ref->select-options temp-id - validation-error wrap-form-4xx-2 wrap-schema-decode]] [bidi.bidi :as bidi] @@ -181,7 +184,28 @@ (= :post request-method) (assoc :db/id "new")) _ (cond (= :post request-method) (when-let [extant (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity)))] - (validation-error (format "The code %d is already in use." (:account/numeric-code entity))))) + (field-validation-error (format "The code %d is already in use." (:account/numeric-code entity)) + [:account/numeric-code] + :form form-params)) + ) + ;; TODO the following would work better if the schema was hydrated automatically with needed values + _ (some->> form-params + :account/client-overrides + (group-by :account-client-override/client) + (filter (fn [[client overrides]] + (> (count overrides) 1))) + (map first) + seq + (#(form-validation-error (format "Client(s) %s have more than one override." + (str/join ", " + (map (fn [client] + (format "'%s'" (pull-attr (dc/db conn) + :client/name + (-> client))) + ) %))) + :form form-params)) + + ) {:keys [tempids]} (audit-transact [[:upsert-entity (cond-> entity (:account/numeric-code entity) (assoc :account/code (str (:account/numeric-code entity))))]] (:identity request)) @@ -213,11 +237,21 @@ ;; TODO use cursor ;; TODO index based list not dbid +;; TODO lots of weird edge cases with indexes +;; for example, what happens when you have 0, 1, 2, but then delete 1? +;; what happens when you delete 2 but then add another one? +;; preference is that the field parsing logic does better grouping of what +;; goes with what, building index on the server side +;; not needing to pass index in + (defn client-override* [override] - [:div.flex.gap-2.mb-2.client-override + [:div.flex.gap-2.mb-2.client-override (-> {"x-ref" "p" + :data-key "show" + } + hx/alpine-mount-then-appear) [:div.w-96 (fc/with-field :db/id - (com/hidden {:name (fc/field-name) + (com/hidden {:name (fc/field-name) :value (fc/field-value)})) (fc/with-field :account-client-override/client (com/validated-field {:errors (fc/field-errors)} @@ -226,15 +260,17 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :value (fc/field-value) - :value-fn :db/id ;; TODO hydration something here - :content-fn :client/name})))] + :value-fn (some-fn :db/id identity) ;; TODO better hydration + :content-fn (fn [value] + (:client/name (cond->> value + (nat-int? value) (dc/pull (dc/db conn) [:client/name]))))})))] (fc/with-field :account-client-override/name [:div.w-96 (com/validated-field {:errors (fc/field-errors)} (com/text-input {:name (fc/field-name) :class "w-full" :value (fc/field-value)}))]) - [:div (com/a-icon-button {"_" (hiccup/raw "on click halt the event then transition the closest <.client-override />'s opacity to 0 then remove closest <.client-override />")} svg/x)]]) + [:div (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)]]) ;; TODO each form: ;; elimante typeahead1 @@ -246,94 +282,108 @@ ;; componentize ;; ensure all dependency oriented stuff works the same way ;; make sure that "new row index" stuff works ok +;; TODO figure out when hx-targets are decided +;; ensure that adding a new one results in a new row -(defn dialog* [& {:keys [account form-params form-errors]}] - (com/modal - {} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - form-params) - [:fieldset {:class "hx-disable"} - (com/modal-card - {} - [:div.flex [:div.p-2 "Account"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:account/numeric-code account) " - " (:account/name account)]] +(defn dialog* [& {:keys [entity form-params form-errors]}] + (fc/start-form entity form-errors + [:div {:x-data (hx/json {"accountName" (:account/name entity) + "accountCode" (:account/numeric-code entity)})} + (com/modal + {} + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} + form-params) + [:fieldset {:class "hx-disable"} + (com/modal-card + {} + [:div.flex [:div.p-2 "Account"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 + [:span {:x-text "accountCode"}] + " - " + [:span {:x-text "accountName"}]]] + [:div.space-y-1 + (when-let [id (:db/id entity)] + (com/hidden {:name "db/id" + :value id})) - (fc/start-form - account form-errors - [:div.space-y-1 - (when-let [id (:db/id account)] - (com/hidden {:name "db/id" - :value id})) + (fc/with-field :account/numeric-code + (if (nil? (:db/id entity)) + (com/validated-field {:label "Numeric code" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :x-model "accountCode" + :autofocus true + :class "w-32"})) + (com/hidden {:name (fc/field-name) + :value (fc/field-value)}))) + (fc/with-field :account/name + (com/validated-field {:label "Name" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :x-model "accountName" - (fc/with-field :account/numeric-code - (when (nil? (fc/field-value)) - (com/validated-field {:label "Numeric code" - :errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :autofocus true - :class "w-32"})))) - (fc/with-field :account/name - (com/validated-field {:label "Name" - :errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :autofocus true - :class "w-32" - :value (fc/field-value)}))) - (fc/with-field :account/type - (com/validated-field {:label "Account Type" - :errors (fc/field-errors)} - (com/select {:name (fc/field-name) - :class "w-36" - :id "type" - :value (some-> (fc/field-value) name) - :options (ref->select-options "account-type")}))) - (fc/with-field :account/location - (com/validated-field {:label "Location" - :errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :class "w-16" - :value (fc/field-value)}))) + :class "w-64" + :value (fc/field-value)}))) + (fc/with-field :account/type + (com/validated-field {:label "Account Type" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :class "w-36" + :id "type" + :value (some-> (fc/field-value) name) + :options (ref->select-options "account-type")}))) + (fc/with-field :account/location + (com/validated-field {:label "Location" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-16" + :value (fc/field-value)}))) - (fc/with-field :account/invoice-allowance - (com/validated-field {:label "Invoice Allowance" - :errors (fc/field-errors)} - (com/select {:name (fc/field-name) - :value (some-> (fc/field-value) name) - :class "w-36" - :options (ref->select-options "allowance")}))) - (fc/with-field :account/vendor-allowance - (com/validated-field {:label "Vendor Allowance" - :errors (fc/field-errors)} - (com/select {:name (fc/field-name) - :class "w-36" - :value (some-> (fc/field-value) name) - :options (ref->select-options "allowance")}))) - (fc/with-field :account/applicability - (com/validated-field {:label "Applicability" - :errors (fc/field-errors)} - (com/select {:name (fc/field-name) - :class "w-36" - :value (some-> (fc/field-value) name) - :options (ref->select-options "account-applicability")}))) + [:div.flex.flex-wrap.gap-4 + (fc/with-field :account/invoice-allowance + (com/validated-field {:label "Invoice Allowance" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :value (some-> (fc/field-value) name) + :class "w-36" + :options (ref->select-options "allowance")}))) + (fc/with-field :account/vendor-allowance + (com/validated-field {:label "Vendor Allowance" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :class "w-36" + :value (some-> (fc/field-value) name) + :options (ref->select-options "allowance")})))] + (fc/with-field :account/applicability + (com/validated-field {:label "Applicability" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :class "w-36" + :value (some-> (fc/field-value) name) + :options (ref->select-options "account-applicability")}))) - (fc/with-field :account/client-overrides - (com/field {:label "Client Overrides" :id "client-overrides"} - (when (fc/field-value) - (doall - (for [override fc/*current*] - (fc/with-cursor override - (client-override* override))))))) - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") - :hx-target "#client-overrides" - :hx-swap "beforeend"} - "New override") - [:div#form-errors [:span.error-content]]]) - (com/validated-save-button {:errors []} ;; TODO - "Save account"))]])) + (fc/with-field :account/client-overrides + (com/field {:label "Client Overrides" :id "client-overrides"} + (when (fc/field-value) + (doall + (for [override fc/*current*] + (fc/with-cursor override + (client-override* override))))))) + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-account-client-override-new) + :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") + :hx-target "#client-overrides" + :hx-swap "beforeend"} + "New override") + ] + [:div + [:div [:div#form-errors (when (:errors fc/*form-errors*) + [:span.error-content + (com/errors {:errors (:errors fc/*form-errors*)})])]] + (com/validated-save-button {:errors (seq form-errors)} + "Save account")])]])])) (defn new-client-override [{ {:keys [index]} :query-params}] (let [index (or index 0) @@ -346,14 +396,15 @@ (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] - (html-response (dialog* :account account + (html-response (dialog* :entity account :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes :admin-account-edit-save))}) :headers {"hx-trigger" "modalopen"}))) (defn account-new-dialog [_] - (html-response (dialog* :account nil + (html-response (dialog* :entity {} + :form-errors {} :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes :admin-account-new-save))}) :headers {"hx-trigger" "modalopen"})) @@ -362,7 +413,7 @@ ;; TODO hydration ;; TODO consistency of error handling and passing, on all form examples (let [entity (some-> request :last-form)] - (html-response (dialog* :account entity + (html-response (dialog* :entity entity :form-errors (:form-errors request) :form-params (if (:db/id entity) {:hx-put (str (bidi/path-for ssr-routes/only-routes diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 972ec8a6..93ceadb2 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -401,189 +401,192 @@ ;; TODO dialog is no longer closeable (defn dialog* [& {:keys [entity form-params form-errors]}] - (com/modal - {:modal-class "max-w-2xl"} + (fc/start-form entity form-errors + (com/modal + {:modal-class "max-w-2xl"} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target "#modal-holder" ;; TODO sort - :hx-target-400 "#form-errors .error-content" - :x-trap "true" - :class "group/form"} - form-params) - (com/modal-card - {} - [:div.flex [:div.p-2 "Transaction Rule"]] - [:fieldset {:class "hx-disable" - :hx-disinherit "hx-target" ;; TODO why disinherit - :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) - (:transaction-rule/client entity))})} + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target "#modal-holder" ;; TODO sort + :hx-target-400 "#form-errors .error-content" + :x-trap "true" + :class "group/form"} + form-params) + (com/modal-card + {} + [:div.flex [:div.p-2 "Transaction Rule"]] + [:fieldset {:class "hx-disable" + :hx-disinherit "hx-target" ;; TODO why disinherit + :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) + (:transaction-rule/client entity))})} - (fc/start-form entity form-errors - [:div.space-y-1 - (when-let [id (:db/id entity)] - (com/hidden {:name "db/id" - :value id})) - (fc/with-field :transaction-rule/description - (com/validated-field {:label "Description" - :errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :error? (fc/error?) - :x-init "$el.focus()" - :placeholder "HOME DEPOT" - :class "w-96" - :value (fc/field-value)}))) - [:div.filters {:x-data (hx/json {:clientFilter (boolean (fc/field-value (:transaction-rule/client fc/*current*))) - :bankAccountFilter (boolean (fc/field-value (:transaction-rule/bank-account fc/*current*))) - :amountFilter (boolean (or (fc/field-value (:transaction-rule/amount-gte fc/*current*)) - (fc/field-value (:transaction-rule/amount-lte fc/*current*)))) - :domFilter (boolean (or (fc/field-value (:transaction-rule/dom-gte fc/*current*)) - (fc/field-value (:transaction-rule/dom-lte fc/*current*))))})} + [:div.space-y-1 + (when-let [id (:db/id entity)] + (com/hidden {:name "db/id" + :value id})) + (fc/with-field :transaction-rule/description + (com/validated-field {:label "Description" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :error? (fc/error?) + :x-init "$el.focus()" + :placeholder "HOME DEPOT" + :class "w-96" + :value (fc/field-value)}))) + [:div.filters {:x-data (hx/json {:clientFilter (boolean (fc/field-value (:transaction-rule/client fc/*current*))) + :bankAccountFilter (boolean (fc/field-value (:transaction-rule/bank-account fc/*current*))) + :amountFilter (boolean (or (fc/field-value (:transaction-rule/amount-gte fc/*current*)) + (fc/field-value (:transaction-rule/amount-lte fc/*current*)))) + :domFilter (boolean (or (fc/field-value (:transaction-rule/dom-gte fc/*current*)) + (fc/field-value (:transaction-rule/dom-lte fc/*current*))))})} - [:div.flex.gap-2.mb-2 - (com/a-button {"@click" "clientFilter=true" - "x-show" "!clientFilter"} "Filter client") - (com/a-button {"@click" "bankAccountFilter=true" - "x-show" "clientFilter && !bankAccountFilter"} "Filter bank account") - (com/a-button {"@click" "amountFilter=true" - "x-show" "!amountFilter"} "Filter amount") - (com/a-button {"@click" "domFilter=true" - "x-show" "!domFilter"} "Filter day of month")] - (fc/with-field :transaction-rule/client + [:div.flex.gap-2.mb-2 + (com/a-button {"@click" "clientFilter=true" + "x-show" "!clientFilter"} "Filter client") + (com/a-button {"@click" "bankAccountFilter=true" + "x-show" "clientFilter && !bankAccountFilter"} "Filter bank account") + (com/a-button {"@click" "amountFilter=true" + "x-show" "!amountFilter"} "Filter amount") + (com/a-button {"@click" "domFilter=true" + "x-show" "!domFilter"} "Filter day of month")] + (fc/with-field :transaction-rule/client - (com/validated-field - (-> {:label "Client" - :errors (fc/field-errors) - :x-show "clientFilter"} - (hx/alpine-appear)) - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :error? (fc/error?) - :class "w-96" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :company-search) - :x-model "clientId" - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) + (com/validated-field + (-> {:label "Client" + :errors (fc/field-errors) + :x-show "clientFilter"} + (hx/alpine-appear)) + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :error? (fc/error?) + :class "w-96" + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :company-search) + :x-model "clientId" + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (fn [c] (cond->> c + (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) + true :client/name))})])) - (fc/with-field :transaction-rule/bank-account - (com/validated-field - (-> {:label "Bank Account" - :errors (fc/field-errors) - :x-show "bankAccountFilter"} - hx/alpine-appear) - [:div.w-96 - [:div#bank-account-changer {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) - :hx-trigger "changed" - :hx-target "next *" - :hx-include "#bank-account-changer" - :hx-swap "innerHTML" + (fc/with-field :transaction-rule/bank-account + (com/validated-field + (-> {:label "Bank Account" + :errors (fc/field-errors) + :x-show "bankAccountFilter"} + hx/alpine-appear) + [:div.w-96 + [:div#bank-account-changer {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead) + :hx-trigger "changed" + :hx-target "next *" + :hx-include "#bank-account-changer" + :hx-swap "innerHTML" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) - :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) + :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) - :name (fc/field-name) - :value (fc/field-value)})])) + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) + :name (fc/field-name) + :value (fc/field-value)})])) - (com/field (-> {:label "Amount" - :x-show "amountFilter"} - hx/alpine-appear) - [:div.flex.gap-2 - (fc/with-field :transaction-rule/amount-gte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})]) - (fc/with-field :transaction-rule/amount-lte - [:div.flex.flex-col - (com/money-input {:name (fc/field-name) - :placeholder "<=" - :class "w-24" - :value (fc/field-value)}) - (com/errors {:errors (fc/field-errors)})])]) + (com/field (-> {:label "Amount" + :x-show "amountFilter"} + hx/alpine-appear) + [:div.flex.gap-2 + (fc/with-field :transaction-rule/amount-gte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})]) + (fc/with-field :transaction-rule/amount-lte + [:div.flex.flex-col + (com/money-input {:name (fc/field-name) + :placeholder "<=" + :class "w-24" + :value (fc/field-value)}) + (com/errors {:errors (fc/field-errors)})])]) - (com/field (-> {:label "Day of month" - :x-show "domFilter"} - hx/alpine-appear) - [:div.flex.gap-2 - (fc/with-field :transaction-rule/dom-gte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)}))) - (fc/with-field :transaction-rule/dom-lte - (com/validated-field - {:errors (fc/field-errors)} - (com/int-input {:name (fc/field-name) - :placeholder ">=" - :class "w-24" - :value (fc/field-value)})))])] + (com/field (-> {:label "Day of month" + :x-show "domFilter"} + hx/alpine-appear) + [:div.flex.gap-2 + (fc/with-field :transaction-rule/dom-gte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)}))) + (fc/with-field :transaction-rule/dom-lte + (com/validated-field + {:errors (fc/field-errors)} + (com/int-input {:name (fc/field-name) + :placeholder ">=" + :class "w-24" + :value (fc/field-value)})))])] - [:h2.text-lg "Outcomes"] - (fc/with-field :transaction-rule/vendor - (com/validated-field {:label "Assign Vendor" - :errors (fc/field-errors)} - [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :id (str "form-vendor-search") - :class "w-96" - :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + [:h2.text-lg "Outcomes"] + (fc/with-field :transaction-rule/vendor + (com/validated-field {:label "Assign Vendor" + :errors (fc/field-errors)} + [:div.w-96 + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes :vendor-search) + :id (str "form-vendor-search") + :class "w-96" + :value (fc/field-value) + :value-fn (some-fn :db/id identity) + :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) - (fc/with-field :transaction-rule/accounts - (list - (com/data-grid {:headers [(com/data-grid-header {} "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} - (when @fc/*current* - (doall (for [tra fc/*current*] - (fc/with-cursor tra - (transaction-rule-account-row* entity tra))))) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 4 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :color :secondary - :hx-include "#edit-form" - :hx-ext "rename-params" - ;; TODO - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New account")]))) - (com/errors {:errors (fc/field-errors)}))) + (fc/with-field :transaction-rule/accounts + (list + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})] + :id "transaction-rule-account-table"} + (when @fc/*current* + (doall (for [tra fc/*current*] + (fc/with-cursor tra + (transaction-rule-account-row* entity tra))))) + (com/data-grid-row + {:class "new-row"} + (com/data-grid-cell {:colspan 4 + :class "bg-gray-100"} + [:div.flex.justify-center + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :color :secondary + :hx-include "#edit-form" + :hx-ext "rename-params" + ;; TODO + :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" + "index" "index"}) + :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") + :hx-target "#edit-form .new-row" + :hx-swap "beforebegin"} + "New account")]))) + (com/errors {:errors (fc/field-errors)}))) - (fc/with-field :transaction-rule/transaction-approval-status - (com/validated-field {:label "Approval status" - :errors (fc/field-errors)} - (com/radio {:options (ref->radio-options "transaction-approval-status") - :value (fc/field-value) - :name (fc/field-name) - :size :small - :orientation :horizontal}))) + (fc/with-field :transaction-rule/transaction-approval-status + (com/validated-field {:label "Approval status" + :errors (fc/field-errors)} + (com/radio {:options (ref->radio-options "transaction-approval-status") + :value (fc/field-value) + :name (fc/field-name) + :size :small + :orientation :horizontal}))) - [:div#form-errors (when (:errors fc/*form-errors*) - [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})])]])] - (com/validated-save-button {:errors form-errors} "Save rule"))])) + ;; TODO componentize + ]] + [:div + [:div#form-errors (when (:errors fc/*form-errors*) + [:span.error-content + (com/errors {:errors (:errors fc/*form-errors*)})])] + (com/validated-save-button {:errors form-errors} "Save rule")])]))) ;; TODO Should forms have some kind of helper to render an individual field? saving @@ -592,8 +595,8 @@ ;; pull out the single field to swap (defn new-account [{{:keys [client-id index]} :query-params}] - (let [index (or index 0) ;; TODO schema decode is not working - transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] + (let [index (or index 0) ;; TODO schema decode is not working + transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] client-id) :transaction-rule/accounts (conj (into [] (repeat index {} )) {:db/id (str (java.util.UUID/randomUUID)) diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 076945f9..9df54b67 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -134,7 +134,9 @@ (defn a-icon-button- [params & children] (into - [:a (update params :class str " inline-flex items-center justify-center bg-white dark:bg-gray-600 items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center text-gray-500 hover:text-gray-800 rounded-lg dark:text-gray-400 dark:hover:text-gray-100") + [:a (-> params (update :class str " inline-flex items-center justify-center bg-white dark:bg-gray-600 items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center text-gray-500 hover:text-gray-800 rounded-lg dark:text-gray-400 dark:hover:text-gray-100" + ) + (update :href #(or % ""))) [:div.h-4.w-4 children]])) (defn save-button- [params & children] diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index cb5e5c00..895d024e 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -24,3 +24,17 @@ "x-transition:enter" "transition duration-500" "x-transition:enter-start" "opacity-0" "x-transition:enter-end" "opacity-100")) + +(defn alpine-disappear [m] + (assoc m + "x-transition:leave" "transition duration-500" + "x-transition:leave-start" "opacity-100" + "x-transition:leave-end" "opacity-0")) + +(defn alpine-mount-then-appear [{:keys [data-key] :as params}] + (merge (-> {"x-data" (json {data-key false}) + "x-init" (format "$nextTick(() => %s=true)" (name data-key)) + "x-show" (name data-key)} + alpine-appear + alpine-disappear) + (dissoc params :data-key))) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 6529aebb..b80c08bd 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -146,6 +146,8 @@ (defn keyword->str [k] (subs (str k) 1)) + +;; TODO need to remove or at least remove usages as the form is not included (defn validation-error [m & {:as data}] (throw+ (ex-info m (merge data {:type :validation})))) From dc1fefd30c007c28388f875c009bf15521c0e796 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 11:08:05 -0700 Subject: [PATCH 16/34] accounts and transactions work the same way --- src/clj/auto_ap/ssr/admin/accounts.clj | 10 ++++++---- src/clj/auto_ap/ssr/admin/transaction_rules.clj | 16 +++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index ca2af3b1..87f83db0 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -244,11 +244,12 @@ ;; goes with what, building index on the server side ;; not needing to pass index in +;; TODO decide when cursors are used. other cases it's not, some are (defn client-override* [override] - [:div.flex.gap-2.mb-2.client-override (-> {"x-ref" "p" + [:div.flex.gap-2.mb-2.client-override (-> {:x-ref "p" :data-key "show" - } - hx/alpine-mount-then-appear) + :x-data (hx/json {:show (boolean (not (:new? override)))})} + hx/alpine-mount-then-appear) [:div.w-96 (fc/with-field :db/id (com/hidden {:name (fc/field-name) @@ -388,7 +389,8 @@ (defn new-client-override [{ {:keys [index]} :query-params}] (let [index (or index 0) account {:account/client-overrides (conj (into [] (repeat index {})) - {:db/id (str (java.util.UUID/randomUUID))})}] ;; TODO schema decode is not working + {:db/id (str (java.util.UUID/randomUUID)) + :new? true})}] ;; TODO schema decode is not working (html-response (fc/start-form account [] (fc/with-cursor (get-in fc/*current* [:account/client-overrides index]) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 93ceadb2..fa27b0e5 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -342,8 +342,12 @@ (defn- transaction-rule-account-row* [transaction-rule account] - (com/data-grid-row {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) - (fc/field-value (:transaction-rule-account/account account)))})} + (com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) + (fc/field-value (:transaction-rule-account/account account))) + :show (boolean (not (fc/field-value (:new? account))))}) + :data-key "show" + :x-ref "p"} + hx/alpine-mount-then-appear) (let [account-name (fc/field-name (:transaction-rule-account/account account))] (list @@ -394,10 +398,7 @@ (* 100 ) (long ))})))))) (com/data-grid-cell {:class "align-top"} - (com/a-icon-button - {"_" (hiccup/raw "on click halt the event then transition the closest 's opacity to 0 then remove closest ") - :href "#"} - svg/x)))) + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) ;; TODO dialog is no longer closeable (defn dialog* [& {:keys [entity form-params form-errors]}] @@ -600,7 +601,8 @@ client-id) :transaction-rule/accounts (conj (into [] (repeat index {} )) {:db/id (str (java.util.UUID/randomUUID)) - :transaction-rule-account/location "Shared"})}] + :transaction-rule-account/location "Shared" + :new? true})}] (html-response (fc/start-form transaction-rule [] (fc/with-cursor (get-in fc/*current* [:transaction-rule/accounts index]) From be9d777a1778d917e691b706d7f39b5d58b5a218 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 11:59:14 -0700 Subject: [PATCH 17/34] consistent user experience with new client --- src/clj/auto_ap/ssr/admin/accounts.clj | 91 +++++---- .../auto_ap/ssr/admin/transaction_rules.clj | 2 +- src/clj/auto_ap/ssr/users.clj | 182 ++++++++++++------ src/cljc/auto_ap/ssr_routes.cljc | 1 + 4 files changed, 184 insertions(+), 92 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 87f83db0..6146ef91 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -246,32 +246,35 @@ ;; TODO decide when cursors are used. other cases it's not, some are (defn client-override* [override] - [:div.flex.gap-2.mb-2.client-override (-> {:x-ref "p" - :data-key "show" - :x-data (hx/json {:show (boolean (not (:new? override)))})} - hx/alpine-mount-then-appear) - [:div.w-96 - (fc/with-field :db/id - (com/hidden {:name (fc/field-name) - :value (fc/field-value)})) - (fc/with-field :account-client-override/client - (com/validated-field {:errors (fc/field-errors)} - (com/typeahead-2 {:name (fc/field-name) - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :value (fc/field-value) - :value-fn (some-fn :db/id identity) ;; TODO better hydration - :content-fn (fn [value] - (:client/name (cond->> value - (nat-int? value) (dc/pull (dc/db conn) [:client/name]))))})))] - (fc/with-field :account-client-override/name - [:div.w-96 - (com/validated-field {:errors (fc/field-errors)} - (com/text-input {:name (fc/field-name) - :class "w-full" - :value (fc/field-value)}))]) - [:div (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)]]) + (com/data-grid-row (-> {:x-ref "p" + :data-key "show" + :x-data (hx/json {:show (boolean (not (:new? override)))})} + hx/alpine-mount-then-appear) + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :account-client-override/client + (com/data-grid-cell {} + (com/validated-field {:errors (fc/field-errors)} + (com/typeahead-2 {:name (fc/field-name) + :placeholder "Search..." + :class "w-96" + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :value (fc/field-value) + :value-fn (some-fn :db/id identity) ;; TODO better hydration + :content-fn (fn [value] + (:client/name (cond->> value + (nat-int? value) (dc/pull (dc/db conn) [:client/name]))))})))) + (fc/with-field :account-client-override/name + (com/data-grid-cell + {} + (com/validated-field {:errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-96" + :value (fc/field-value)})))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) ;; TODO each form: ;; elimante typeahead1 @@ -366,18 +369,32 @@ :options (ref->select-options "account-applicability")}))) (fc/with-field :account/client-overrides + (com/field {:label "Client Overrides" :id "client-overrides"} - (when (fc/field-value) - (doall - (for [override fc/*current*] - (fc/with-cursor override - (client-override* override))))))) - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :hx-vals (hiccup/raw "js:{index: document.getElementById('client-overrides').children.length - 1}") - :hx-target "#client-overrides" - :hx-swap "beforeend"} - "New override") + + (com/data-grid {:headers [(com/data-grid-header {} "Client") + (com/data-grid-header {} "Account name") + (com/data-grid-header {})] + :id "client-override-table"} + (when (fc/field-value) + (doall + (for [override fc/*current*] + (fc/with-cursor override + (client-override* override))))) + (com/data-grid-row + {:class "new-row"} + (com/data-grid-cell {:colspan 3 + :class "bg-gray-100"} + [:div.flex.justify-center + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :admin-account-client-override-new) + :color :secondary + :hx-include "#edit-form" + :hx-vals (hiccup/raw "js:{index: countRows(\"#client-override-table\")}") + :hx-target "#edit-form .new-row" + :hx-swap "beforebegin"} + "New override")]))))) + ] [:div [:div [:div#form-errors (when (:errors fc/*form-errors*) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index fa27b0e5..5cd9dcf9 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -549,7 +549,7 @@ (com/data-grid-header {:class "w-16"} "%") (com/data-grid-header {:class "w-16"})] :id "transaction-rule-account-table"} - (when @fc/*current* + (when (fc/field-value) (doall (for [tra fc/*current*] (fc/with-cursor tra (transaction-rule-account-row* entity tra))))) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 2b327f95..46c5ca19 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -14,14 +14,19 @@ :refer [wrap-admin wrap-client-redirect-unauthenticated]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers entity-id - forced-vector html-response + many-entity ref->enum-schema + ref->select-options + wrap-form-4xx-2 wrap-schema-decode]] [auto-ap.time :as atime] [bidi.bidi :as bidi] @@ -29,7 +34,9 @@ [clojure.string :as str] [config.core :refer [env]] [datomic.api :as dc] - [malli.core :as mc])) + [hiccup2.core :as hiccup] + [malli.core :as mc] + [clj-time.format :as f])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -258,79 +265,146 @@ } :session {:identity (dissoc (auth/user->jwt user "FAKE_TOKEN") :exp)}})) +(defn client-row* [client] + (com/data-grid-row (-> {:x-ref "p" + :data-key "show" + :x-data (hx/json {:show (boolean (not (fc/field-value (:new? client))))})} + hx/alpine-mount-then-appear) + (com/data-grid-cell {} + (com/validated-field {:errors (fc/field-errors (:db/id fc/*current*))} + (com/typeahead-2 {:name (fc/field-name (:db/id fc/*current*)) + :class "w-full" + :url (bidi/path-for ssr-routes/only-routes + :company-search) + :value (fc/field-value) + + :value-fn :db/id ;; TODO better hydration + :content-fn (fn [value] + (:client/name (dc/pull (dc/db conn) [:client/name] + (or (:db/id value) + value)))) + :size :small}))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) + +(defn dialog* [{:keys [entity form-params form-errors]}] + (fc/start-form + entity form-errors + (com/modal + {} + [:form#edit-form (merge {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full"} + form-params) + [:fieldset {:class "hx-disable"} + (com/modal-card + {} + [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name entity)]] + [:div.space-y-6 + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :user/role + (com/validated-field {:label "Role" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :class "w-36" + :autofocus true + :value (some->> (fc/field-value) name) + :options (ref->select-options "user-role")}))) + (fc/with-field :user/clients + (com/validated-field {:label "Clients"} + (com/data-grid {:headers [(com/data-grid-header {} "Client") + (com/data-grid-header {} )] + :id "client-table"} + (doall (for [client fc/*current*] + (fc/with-cursor client + (client-row* client)))) + (com/data-grid-row + {:class "new-row"} + (com/data-grid-cell {:colspan 2 + :class "bg-gray-100"} + [:div.flex.justify-center + (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes + :user-client-new) + :color :secondary + :hx-include "#edit-form" + :hx-vals (hiccup/raw "js:{index: countRows(\"#client-table\")}") + :hx-target "#edit-form .new-row" + :hx-swap "beforebegin"} + "New override")]))) + )) + [:div#form-errors [:span.error-content]]] + [:div + [:div [:div#form-errors (when (:errors fc/*form-errors*) + [:span.error-content + (com/errors {:errors (:errors fc/*form-errors*)})])]] + (com/validated-save-button {:errors (seq form-errors)} + "Save user")])]]))) + +;; TODO rename edit-form or make it generic (defn user-edit-save [{:keys [form-params identity] :as request}] - (let [_ @(dc/transact conn [[:upsert-entity form-params]]) + (let [_ @(dc/transact conn [[:upsert-entity form-params]]) user (some-> form-params :db/id (#(dc/pull (dc/db conn) default-read %)))] (html-response (row* identity user {:flash? true}) - :headers {"hx-trigger" "modalclose" + :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#user-table tr[data-id=\"%d\"]" (:db/id user))}))) +(defn user-save-error [request] + ;; TODO hydration + ;; TODO consistency of error handling and passing, on all form examples + (let [entity (some-> request :last-form)] + (html-response (dialog* {:entity entity + :form-errors (:form-errors request)}) + :headers {"hx-retarget" "#edit-form fieldset" + "hx-reselect" "#edit-form fieldset"}))) + (defn user-edit-dialog [request] (let [user (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] (html-response - (com/modal - {} - [:form {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full"} - [:fieldset {:class "hx-disable"} - (com/modal-card - {} - [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name user)]] - [:div.space-y-6 - (com/hidden {:name "db/id" - :value (:db/id user)}) - (com/field {:label "Role"} - (com/select {:name "user/role" - :class "w-36" - :autofocus true - :id "role" - :value (name (:user/role user)) - :options [["none" "None"] - ["power-user" "Power user"] - ["manager" "Manager"] - ["admin" "Admin"] - ["user" "User"]]})) - (com/field {:label "Clients"} - (com/typeahead {:name "user/clients" - :class "w-full" - :multiple "multiple" - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id "clients" - :value (map - (fn [client] - [(:db/id client) (:client/name client)]) - (:user/clients user)) - :size :small})) - [:div#form-errors [:span.error-content]]] - (com/validated-save-button {:errors []} ;; TODO - "Save user"))]]) + (dialog* {:entity user + :form-errors {}}) + :headers {"hx-trigger" "modalopen"}))) +(defn new-client [{ {:keys [index]} :query-params}] + (let [index (or index 0) + account {:user/clients (conj (into [] (repeat index {})) + {:db/id nil + :new? true})}] ;; TODO schema decode is not working + (html-response + (fc/start-form account [] + (fc/with-cursor (get-in fc/*current* [:user/clients index]) + (client-row* fc/*current*)))))) + (def key->handler (apply-middleware-to-all-handlers {:users (helper/page-route grid-page) :user-table (helper/table-route grid-page) :user-edit-save (-> user-edit-save - (wrap-schema-decode - :form-schema (mc/schema - [:map - [:db/id entity-id] - [:user/clients {:optional true} - [:maybe - (forced-vector entity-id)]] - [:user/role (ref->enum-schema "user-role")]]))) + (wrap-schema-decode :form-schema (mc/schema + [:map + [:db/id entity-id] + [:user/clients {:optional true} + [:maybe + (many-entity {} [:db/id entity-id])]] + [:user/role (ref->enum-schema "user-role")]])) + (wrap-nested-form-params) + (wrap-form-4xx-2 user-save-error)) + :user-client-new (-> new-client + (wrap-schema-decode :query-schema [:map + [:index {:optional true + :default 0} [nat-int? {:default 0}]]])) :user-edit-dialog (-> user-edit-dialog (wrap-schema-decode :route-schema (mc/schema [:map [:db/id entity-id]]))) diff --git a/src/cljc/auto_ap/ssr_routes.cljc b/src/cljc/auto_ap/ssr_routes.cljc index cad4d193..7da78c5e 100644 --- a/src/cljc/auto_ap/ssr_routes.cljc +++ b/src/cljc/auto_ap/ssr_routes.cljc @@ -16,6 +16,7 @@ ["/inspect/" [#"\d+" :entity-id] #"/?"] :admin-history-inspect} "/user" {"" {:get :users :put :user-edit-save} + "/client/new" :user-client-new "/table" :user-table "/impersonate" :user-impersonate [[#"\d+" :db/id] "/edit"] {:get :user-edit-dialog}} From 84d6f455ffb4e5ad8b260877b95b136e362d62e6 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 15:02:36 -0700 Subject: [PATCH 18/34] Makes cursor-seq for lists --- src/clj/auto_ap/ssr/admin/accounts.clj | 7 ++----- src/clj/auto_ap/ssr/admin/transaction_rules.clj | 5 +---- src/clj/auto_ap/ssr/form_cursor.clj | 10 ++++++++++ src/clj/auto_ap/ssr/users.clj | 8 ++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 6146ef91..c1ce0feb 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -376,11 +376,8 @@ (com/data-grid-header {} "Account name") (com/data-grid-header {})] :id "client-override-table"} - (when (fc/field-value) - (doall - (for [override fc/*current*] - (fc/with-cursor override - (client-override* override))))) + (fc/cursor-map + #(client-override* %)) (com/data-grid-row {:class "new-row"} (com/data-grid-cell {:colspan 3 diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 5cd9dcf9..16f7f10e 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -549,10 +549,7 @@ (com/data-grid-header {:class "w-16"} "%") (com/data-grid-header {:class "w-16"})] :id "transaction-rule-account-table"} - (when (fc/field-value) - (doall (for [tra fc/*current*] - (fc/with-cursor tra - (transaction-rule-account-row* entity tra))))) + (fc/cursor-map #(transaction-rule-account-row* entity %)) (com/data-grid-row {:class "new-row"} (com/data-grid-cell {:colspan 4 diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index eef97db2..02c65ba4 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -45,3 +45,13 @@ (every? string? errors))))) +(defn cursor-map + ([f] (cursor-map *current* f)) + ([cursor f] + (when (field-value) + (doall + (for [n cursor] + (with-cursor n + (f n))))))) + + diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 46c5ca19..e225fef3 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -322,9 +322,7 @@ (com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid-header {} )] :id "client-table"} - (doall (for [client fc/*current*] - (fc/with-cursor client - (client-row* client)))) + (fc/cursor-map #(client-row* %)) (com/data-grid-row {:class "new-row"} (com/data-grid-cell {:colspan 2 @@ -337,9 +335,7 @@ :hx-vals (hiccup/raw "js:{index: countRows(\"#client-table\")}") :hx-target "#edit-form .new-row" :hx-swap "beforebegin"} - "New override")]))) - )) - [:div#form-errors [:span.error-content]]] + "New override")])))))] [:div [:div [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content From 48347bb8c543c73cc11d3540c8d7caa0b0c33ec5 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 23:46:01 -0700 Subject: [PATCH 19/34] Uses cursors for simplicity, uses common grid bottom --- src/clj/auto_ap/cursor.clj | 9 +++ src/clj/auto_ap/ssr/admin/accounts.clj | 37 ++++------ .../auto_ap/ssr/admin/transaction_rules.clj | 68 ++++++++----------- src/clj/auto_ap/ssr/components.clj | 1 + src/clj/auto_ap/ssr/components/data_grid.clj | 24 ++++++- src/clj/auto_ap/ssr/form_cursor.clj | 13 +++- src/clj/auto_ap/ssr/hx.clj | 6 +- src/clj/auto_ap/ssr/users.clj | 30 +++----- 8 files changed, 98 insertions(+), 90 deletions(-) diff --git a/src/clj/auto_ap/cursor.clj b/src/clj/auto_ap/cursor.clj index 0ff1448d..6a7f25cc 100644 --- a/src/clj/auto_ap/cursor.clj +++ b/src/clj/auto_ap/cursor.clj @@ -125,6 +125,15 @@ [] nil)) +(defn synthetic-cursor [v prefix] + (let [internal-cursor (cursor v)] + (reify ICursor + (path [this] + (into prefix (path internal-cursor))) + (state [this] + (state internal-cursor))))) + + (defn transact! [cursor f] "Changes value beneath cursor by passing it to a single-argument function f. Old value will be passed as function argument. Function diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index c1ce0feb..ef48ae82 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -248,7 +248,8 @@ (defn client-override* [override] (com/data-grid-row (-> {:x-ref "p" :data-key "show" - :x-data (hx/json {:show (boolean (not (:new? override)))})} + :x-data (hx/json {:show (boolean (doto (not (fc/field-value (:new? override))) + println))})} hx/alpine-mount-then-appear) (fc/with-field :db/id (com/hidden {:name (fc/field-name) @@ -378,19 +379,12 @@ :id "client-override-table"} (fc/cursor-map #(client-override* %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 3 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :color :secondary - :hx-include "#edit-form" - :hx-vals (hiccup/raw "js:{index: countRows(\"#client-override-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New override")]))))) + + (com/data-grid-new-row {:colspan 3 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-account-client-override-new)} + "New override")))) ] [:div @@ -401,14 +395,13 @@ "Save account")])]])])) (defn new-client-override [{ {:keys [index]} :query-params}] - (let [index (or index 0) - account {:account/client-overrides (conj (into [] (repeat index {})) - {:db/id (str (java.util.UUID/randomUUID)) - :new? true})}] ;; TODO schema decode is not working - (html-response - (fc/start-form account [] - (fc/with-cursor (get-in fc/*current* [:account/client-overrides index]) - (client-override* fc/*current*)))))) + (html-response + (fc/start-form-with-prefix + [:account/client-overrides (or index 0)] + {:db/id (str (java.util.UUID/randomUUID)) + :new? true} + [] + (client-override* fc/*current*)))) (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 16f7f10e..0b0060e9 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -543,31 +543,18 @@ :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) (fc/with-field :transaction-rule/accounts - (list - (com/data-grid {:headers [(com/data-grid-header {} "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} - (fc/cursor-map #(transaction-rule-account-row* entity %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 4 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :color :secondary - :hx-include "#edit-form" - :hx-ext "rename-params" - ;; TODO - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New account")]))) - (com/errors {:errors (fc/field-errors)}))) + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})] + :id "transaction-rule-account-table"} + (fc/cursor-map #(transaction-rule-account-row* entity %)) + (com/data-grid-new-row {:colspan 4 + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :index (count (fc/field-value)) + :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} + "New account"))) (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" @@ -578,7 +565,6 @@ :size :small :orientation :horizontal}))) - ;; TODO componentize ]] [:div [:div#form-errors (when (:errors fc/*form-errors*) @@ -593,21 +579,21 @@ ;; pull out the single field to swap (defn new-account [{{:keys [client-id index]} :query-params}] - (let [index (or index 0) ;; TODO schema decode is not working - transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] - client-id) - :transaction-rule/accounts (conj (into [] (repeat index {} )) - {:db/id (str (java.util.UUID/randomUUID)) - :transaction-rule-account/location "Shared" - :new? true})}] - (html-response - (fc/start-form transaction-rule [] - (fc/with-cursor (get-in fc/*current* [:transaction-rule/accounts index]) - (transaction-rule-account-row* - ;; TODO store a pointer to the "head " cursor for errors instead of nesting them - ;; makes it so you don't have to do this - transaction-rule - fc/*current*)))))) + (html-response + (fc/start-form-with-prefix + [:transaction-rule/accounts (or index 0)] + {:db/id (str (java.util.UUID/randomUUID)) + :transaction-rule-account/location "Shared" + :new? true} + [] + (transaction-rule-account-row* + ;; TODO store a pointer to the "head " cursor for errors instead of nesting them + ;; makes it so you don't have to do this + + {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] + client-id)} + + fc/*current*)))) ;; TODO check to see if it should be called "Shared" or "shared" for the value diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index cee70ef2..56c410c0 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -59,6 +59,7 @@ (def data-grid-row data-grid/row-) (def data-grid-cell data-grid/cell-) (def data-grid-right-stack-cell data-grid/right-stack-cell-) +(def data-grid-new-row data-grid/new-row-) (defn link [params & children] (into [:a (update params :class str " font-medium text-blue-600 dark:text-blue-500 hover:underline ")] diff --git a/src/clj/auto_ap/ssr/components/data_grid.clj b/src/clj/auto_ap/ssr/components/data_grid.clj index caf91017..f62c7f12 100644 --- a/src/clj/auto_ap/ssr/components/data_grid.clj +++ b/src/clj/auto_ap/ssr/components/data_grid.clj @@ -3,8 +3,10 @@ [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components.card :refer [content-card-]] [auto-ap.ssr.components.paginator :refer [paginator-]] + [auto-ap.ssr.components.buttons :refer [a-button-]] [bidi.bidi :as bidi] - [hiccup2.core :as hiccup])) + [hiccup2.core :as hiccup] + [auto-ap.ssr.hx :as hx])) (defn header- [params & rest] (into [:th.px-4.py-3 {:scope "col" :class (:class params) @@ -103,3 +105,23 @@ [:div {:class "htmx-indicator absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2 overflow-hidden w-full h-full"} [:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" } [:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])]) + +(defn new-row- [{:keys [index colspan tr-params] :as params} & content] + (row- + (merge {:class "new-row" + :x-data (hx/json {:newRowIndex index}) + } + tr-params) + (cell- {:colspan colspan + :class "bg-gray-100"} + [:div.flex.justify-center + (a-button- (merge + (dissoc params :index :colspan) + { + "@click" "$dispatch('newRow', {index: newRowIndex++})" + :color :secondary + :hx-trigger "newRow" + :hx-vals (hiccup/raw "js:{index: event.detail.index}") + :hx-target "closest .new-row" + :hx-swap "beforebegin"}) + content)]))) diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index 02c65ba4..536a3a2f 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -2,17 +2,26 @@ (:require [auto-ap.ssr.utils :refer [path->name2]] [auto-ap.cursor :as cursor])) +(def ^:dynamic *prefix* []) (def ^:dynamic *form-data*) (def ^:dynamic *form-errors*) (def ^:dynamic *prev-cursor* nil) (def ^:dynamic *current* nil) + + (defmacro start-form [form-data errors & rest] `(binding [*form-data* ~form-data *form-errors* (or ~errors {})] - (binding [*current* (cursor/cursor *form-data*)] + (binding [*current* (if (cursor/cursor? *form-data*) + *form-data* + (cursor/cursor *form-data*))] ~@rest))) +(defmacro start-form-with-prefix [prefix form-data errors & rest] + `(binding [*prefix* ~prefix] + (start-form ~form-data ~errors ~@rest))) + (defmacro with-cursor [cursor & rest] `(binding [*current* ~cursor] ~@rest)) @@ -24,7 +33,7 @@ (defn field-name ([] (field-name *current*)) ([cursor] - (apply path->name2 (cursor/path cursor)))) + (apply path->name2 (into (or *prefix* []) (cursor/path cursor))))) (defn field-value ([] (field-value *current*)) diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index 895d024e..0a069362 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -32,9 +32,9 @@ "x-transition:leave-end" "opacity-0")) (defn alpine-mount-then-appear [{:keys [data-key] :as params}] - (merge (-> {"x-data" (json {data-key false}) - "x-init" (format "$nextTick(() => %s=true)" (name data-key)) - "x-show" (name data-key)} + (merge (-> {:x-data (json {data-key false}) + :x-init (format "$nextTick(() => %s=true)" (name data-key)) + :x-show (name data-key)} alpine-appear alpine-disappear) (dissoc params :data-key))) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index e225fef3..e1d90816 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -323,19 +323,11 @@ (com/data-grid-header {} )] :id "client-table"} (fc/cursor-map #(client-row* %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 2 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :user-client-new) - :color :secondary - :hx-include "#edit-form" - :hx-vals (hiccup/raw "js:{index: countRows(\"#client-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New override")])))))] + (com/data-grid-new-row {:colspan 2 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + :user-client-new)} + "Assign new client"))))] [:div [:div [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content @@ -374,14 +366,10 @@ :headers {"hx-trigger" "modalopen"}))) (defn new-client [{ {:keys [index]} :query-params}] - (let [index (or index 0) - account {:user/clients (conj (into [] (repeat index {})) - {:db/id nil - :new? true})}] ;; TODO schema decode is not working - (html-response - (fc/start-form account [] - (fc/with-cursor (get-in fc/*current* [:user/clients index]) - (client-row* fc/*current*)))))) + (html-response + (fc/start-form-with-prefix [:user/clients (or index 0)] {:db/id nil + :new? true} [] + (client-row* fc/*current*)))) (def key->handler (apply-middleware-to-all-handlers From 91f7e79aed465d380e977b3a3ff5b482c359e6b7 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 24 Oct 2023 11:12:31 -0700 Subject: [PATCH 20/34] a lot of streamlining for validation --- src/clj/auto_ap/ssr/admin/accounts.clj | 73 +++++------ .../auto_ap/ssr/admin/transaction_rules.clj | 117 ++++++++---------- src/clj/auto_ap/ssr/components.clj | 1 + src/clj/auto_ap/ssr/components/dialog.clj | 12 +- src/clj/auto_ap/ssr/components/inputs.clj | 6 + src/clj/auto_ap/ssr/users.clj | 94 +++++++------- src/clj/auto_ap/ssr/utils.clj | 26 ++-- 7 files changed, 161 insertions(+), 168 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index ef48ae82..755b5460 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -31,12 +31,12 @@ ref->enum-schema ref->select-options temp-id + wrap-entity wrap-form-4xx-2 wrap-schema-decode]] [bidi.bidi :as bidi] [clojure.string :as str] [datomic.api :as dc] - [hiccup2.core :as hiccup] [malli.core :as mc])) (defn filters [request] @@ -291,16 +291,21 @@ ;; ensure that adding a new one results in a new row -(defn dialog* [& {:keys [entity form-params form-errors]}] - (fc/start-form entity form-errors - [:div {:x-data (hx/json {"accountName" (:account/name entity) - "accountCode" (:account/numeric-code entity)})} +(defn dialog* [{:keys [entity form-params form-errors]}] + (fc/start-form form-params form-errors + [:div {:x-data (hx/json {"accountName" (or (:account/name form-params) (:account/numeric-code entity)) + "accountCode" (or (:account/numeric-code form-params) (:account/numeric-code entity) )}) + :hx-target "this"} (com/modal {} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - form-params) + [:form#edit-form (-> {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} + (assoc (if (:db/id entity) + :hx-put + :hx-post) + (str (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-edit-save)))) [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -318,6 +323,7 @@ (com/validated-field {:label "Numeric code" :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) + :value (fc/field-value) :x-model "accountCode" :autofocus true :class "w-32"})) @@ -388,9 +394,7 @@ ] [:div - [:div [:div#form-errors (when (:errors fc/*form-errors*) - [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})])]] + (com/form-errors {:errors (:errors fc/*form-errors*)}) (com/validated-save-button {:errors (seq form-errors)} "Save account")])]])])) @@ -403,34 +407,15 @@ [] (client-override* fc/*current*)))) -(defn account-edit-dialog [request] - (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] - (html-response (dialog* :entity account - :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes - :admin-account-edit-save))}) - :headers {"hx-trigger" "modalopen"}))) - - -(defn account-new-dialog [_] - (html-response (dialog* :entity {} - :form-errors {} - :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes - :admin-account-new-save))}) +(defn account-dialog [{:keys [entity form-params form-errors]}] + (html-response (dialog* {:entity entity + :form-params (or (when (seq form-params) + form-params) + entity + {}) + :form-errors form-errors}) :headers {"hx-trigger" "modalopen"})) -(defn account-save-error [request] - ;; TODO hydration - ;; TODO consistency of error handling and passing, on all form examples - (let [entity (some-> request :last-form)] - (html-response (dialog* :entity entity - :form-errors (:form-errors request) - :form-params (if (:db/id entity) - {:hx-put (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))} - {:hx-post (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))})) - :headers {"hx-retarget" "#edit-form fieldset" - "hx-reselect" "#edit-form fieldset"}))) (def account-schema (mc/schema [:map @@ -439,14 +424,14 @@ [:account/name [:string {:min 1}]] [:account/location [:maybe :string]] [:account/type (ref->enum-schema "account-type")] - [:account/applicability (ref->enum-schema "account-applicability")] + [:account/applicability (ref->enum-schema "account-applicability")] ; [:account/invoice-allowance (ref->enum-schema "allowance")] [:account/vendor-allowance (ref->enum-schema "allowance")] [:account/client-overrides {:optional true} [:maybe (many-entity {} [:db/id [:or entity-id temp-id]] - [:account-client-override/client [:or entity-id :string]] + [:account-client-override/client entity-id] [:account-client-override/name [:string {:min 2}]])]]])) (def key->handler @@ -460,12 +445,14 @@ :default 0} [nat-int? {:default 0}]]]) wrap-admin wrap-client-redirect-unauthenticated) :admin-account-save (-> account-save + (wrap-entity [:form-params :db/id] default-read) (wrap-schema-decode :form-schema account-schema) (wrap-nested-form-params) - (wrap-form-4xx-2 account-save-error)) - :admin-account-edit-dialog (-> account-edit-dialog + (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) + :admin-account-edit-dialog (-> account-dialog + (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema [:map [:db/id entity-id]])) - :admin-account-new-dialog account-new-dialog}) + :admin-account-new-dialog account-dialog}) (fn [h] (-> h (wrap-admin) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 0b0060e9..841c2160 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -18,9 +18,9 @@ [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.company :refer [bank-account-typeahead*]] [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils @@ -31,24 +31,20 @@ html-response many-entity money - path->name2 percentage ref->enum-schema ref->radio-options regex temp-id + wrap-entity wrap-form-4xx-2 wrap-schema-decode]] [auto-ap.utils :refer [dollars=]] [bidi.bidi :as bidi] - [cheshire.core :as cheshire] [clojure.string :as str] [datomic.api :as dc] - [hiccup2.core :as hiccup] [iol-ion.query :refer [ident]] - [malli.core :as mc] - [auto-ap.cursor :as cursor] - [auto-ap.ssr.hiccup-helper :as hh])) + [malli.core :as mc])) ;; TODO with dependencies, I really don't like that you have to be ultra specific in what ;; you want to include, and generating the routes and interconnection is weird too. @@ -401,25 +397,29 @@ (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) ;; TODO dialog is no longer closeable -(defn dialog* [& {:keys [entity form-params form-errors]}] - (fc/start-form entity form-errors +;; TODO might not need #edit-form id +(defn dialog* [{:keys [entity form-params form-errors]}] + (fc/start-form form-params form-errors (com/modal - {:modal-class "max-w-2xl"} + {:modal-class "max-w-2xl" + :hx-target "this"} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target "#modal-holder" ;; TODO sort - :hx-target-400 "#form-errors .error-content" - :x-trap "true" - :class "group/form"} - form-params) + [:form#edit-form {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :x-trap "true" + :class "group/form" + (if (:db/id entity) + :hx-put + :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} (com/modal-card {} [:div.flex [:div.p-2 "Transaction Rule"]] [:fieldset {:class "hx-disable" :hx-disinherit "hx-target" ;; TODO why disinherit - :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity)) - (:transaction-rule/client entity))})} + :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client form-params)) + (:transaction-rule/client form-params) + (:db/id (:transaction-rule/client entity)))})} [:div.space-y-1 (when-let [id (:db/id entity)] @@ -486,7 +486,7 @@ :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity)) + (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client form-params)) :name (fc/field-name) :value (fc/field-value)})])) @@ -543,18 +543,20 @@ :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) (fc/with-field :transaction-rule/accounts - (com/data-grid {:headers [(com/data-grid-header {} "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} - (fc/cursor-map #(transaction-rule-account-row* entity %)) - (com/data-grid-new-row {:colspan 4 - :hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :index (count (fc/field-value)) - :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} - "New account"))) + (com/validated-field + {:errors (fc/field-errors)} + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})] + :id "transaction-rule-account-table"} + (fc/cursor-map #(transaction-rule-account-row* form-params %)) + (com/data-grid-new-row {:colspan 4 + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :index (count (fc/field-value)) + :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} + "New account")))) (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" @@ -567,10 +569,8 @@ ]] [:div - [:div#form-errors (when (:errors fc/*form-errors*) - [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})])] - (com/validated-save-button {:errors form-errors} "Save rule")])]))) + (com/form-errors {:errors (:errors fc/*form-errors*)}) + (com/validated-save-button {:errors (:errors form-errors)} "Save rule")])]))) ;; TODO Should forms have some kind of helper to render an individual field? saving @@ -619,34 +619,14 @@ :value account :client-id client-id})))) -(defn transaction-rule-edit-dialog [request] - (let [entity (or - (some-> request :last-form) - (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %))))] - (html-response (dialog* :entity entity - :form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger-after-settle" "modalopen"}))) - -(defn transaction-rule-error [request] - (let [entity (some-> request :last-form)] - (html-response (dialog* :entity entity - :form-errors (:form-errors request) - :form-params (if (:db/id entity) - {:hx-put (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))} - {:hx-post (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))})) - :headers {"hx-retarget" "#edit-form fieldset" - "hx-reselect" "#edit-form fieldset"}))) - - -(defn transaction-rule-new-dialog [_] - (html-response (dialog* :entity {} - :form-errors {} - :form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save))}) - :headers {"hx-trigger-after-settle" "modalopen"})) +(defn transaction-dialog [{:keys [entity form-params form-errors]}] + (html-response (dialog* {:entity entity + :form-params (or (when (seq form-params) + form-params) + entity ;; TODO coerce into form params + {}) + :form-errors form-errors}) + :headers {"hx-trigger" "modalopen"})) (def transaction-rule-schema (mc/schema [:map @@ -695,12 +675,15 @@ [:value {:optional true} [:maybe entity-id]]])) :admin-transaction-rule-save (-> transaction-rule-save + (wrap-entity [:form-params :db/id] default-read) (wrap-schema-decode :form-schema transaction-rule-schema) (wrap-nested-form-params) - (wrap-form-4xx-2 transaction-rule-error)) - :admin-transaction-rule-edit-dialog (-> transaction-rule-edit-dialog + (wrap-form-4xx-2 (-> transaction-dialog + (wrap-entity [:form-params :db/id] default-read)))) + :admin-transaction-rule-edit-dialog (-> transaction-dialog + (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema [:map [:db/id entity-id]])) - :admin-transaction-rule-new-dialog transaction-rule-new-dialog}) + :admin-transaction-rule-new-dialog transaction-dialog}) (fn [h] (-> h (wrap-admin) diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index 56c410c0..305afc49 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -37,6 +37,7 @@ (def field inputs/field-) (def validated-field inputs/validated-field-) (def errors inputs/errors-) +(def form-errors inputs/form-errors-) (def left-aside aside/left-aside-) (def company-aside-nav aside/company-aside-nav-) diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index d2109e35..3ee49af6 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -4,11 +4,13 @@ [auto-ap.ssr.hiccup-helper :as hh])) (defn modal- [params & children] - [:div {:class (-> (:class params) - (or "max-w-4xl w-1/4 overflow-visible") - (hh/add-class "h-min")) - "@click.outside" "open=false" - } children]) + [:div (-> params + (update :class #(-> % + (or "max-w-4xl w-1/4 overflow-visible") + (hh/add-class "h-min"))) + + (assoc "@click.outside" "open=false")) + children]) (defn modal-card- [params header content footer] [:div#modal-card (update params diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 2704c2b6..02251640 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -152,6 +152,7 @@ c.clearChoices(); [:input (-> params (dissoc :error?) + (assoc :type "text") (update :class (fnil hh/add-class "") default-input-classes) (update :class #(str % (use-size size))))]) @@ -210,6 +211,11 @@ c.clearChoices(); (when (sequential? errors) (str/join ", " (filter string? errors)))]) +(defn form-errors- [{:keys [errors]}] + [:div#form-errors (when errors + [:span.error-content + (errors- {:errors errors})])]) + (defn validated-field- [params & rest] (field- (cond-> params true (dissoc :errors) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index e1d90816..26f90161 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -26,6 +26,7 @@ many-entity ref->enum-schema ref->select-options + wrap-entity wrap-form-4xx-2 wrap-schema-decode]] [auto-ap.time :as atime] @@ -34,9 +35,7 @@ [clojure.string :as str] [config.core :refer [env]] [datomic.api :as dc] - [hiccup2.core :as hiccup] - [malli.core :as mc] - [clj-time.format :as f])) + [malli.core :as mc])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" @@ -257,14 +256,17 @@ (def table* (partial helper/table* grid-page)) (defn impersonate [request] - (let [user (some-> request :params :db/id (#(dc/pull (dc/db conn) default-read %))) ] + (println (:entity request)) + (if (:entity request) {:status 200 - :headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt user "FAKE_TOKEN") - (:jwt-secret env) - {:alg :hs512})) + :headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt (:entity request) "FAKE_TOKEN") + (:jwt-secret env) + {:alg :hs512})) } - :session {:identity (dissoc (auth/user->jwt user "FAKE_TOKEN") - :exp)}})) + :session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN") + :exp)}} + {:status 404})) + (defn client-row* [client] (com/data-grid-row (-> {:x-ref "p" :data-key "show" @@ -288,19 +290,20 @@ (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -(defn dialog* [{:keys [entity form-params form-errors]}] + +;; TODO hydrate user name +(defn dialog* [{:keys [form-params form-errors entity]}] (fc/start-form - entity form-errors + form-params form-errors (com/modal - {} - [:form#edit-form (merge {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full"} - form-params) + {:hx-target "this"} + [:form#edit-form {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full"} [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -329,9 +332,7 @@ :user-client-new)} "Assign new client"))))] [:div - [:div [:div#form-errors (when (:errors fc/*form-errors*) - [:span.error-content - (com/errors {:errors (:errors fc/*form-errors*)})])]] + (com/form-errors {:errors (:errors fc/*form-errors*)}) (com/validated-save-button {:errors (seq form-errors)} "Save user")])]]))) @@ -348,22 +349,17 @@ (defn user-save-error [request] ;; TODO hydration ;; TODO consistency of error handling and passing, on all form examples - (let [entity (some-> request :last-form)] - (html-response (dialog* {:entity entity - :form-errors (:form-errors request)}) - :headers {"hx-retarget" "#edit-form fieldset" - "hx-reselect" "#edit-form fieldset"}))) + (html-response (dialog* {:form-params (:form-params request) + :entity (:entity request) + :form-errors (:form-errors request)}))) (defn user-edit-dialog [request] - (let [user (some-> request - :route-params - :db/id - (#(dc/pull (dc/db conn) default-read %)))] - (html-response - (dialog* {:entity user - :form-errors {}}) - - :headers {"hx-trigger" "modalopen"}))) + (html-response + (dialog* {:form-params (:entity request) + :entity (:entity request) + :form-errors {}}) + + :headers {"hx-trigger" "modalopen"})) (defn new-client [{ {:keys [index]} :query-params}] (html-response @@ -371,28 +367,34 @@ :new? true} [] (client-row* fc/*current*)))) +(def user-form-schema + (mc/schema + [:map + [:db/id entity-id] + [:user/clients {:optional true} + [:maybe + (many-entity {} [:db/id entity-id])]] + [:user/role (ref->enum-schema "user-role")]])) + (def key->handler (apply-middleware-to-all-handlers {:users (helper/page-route grid-page) :user-table (helper/table-route grid-page) :user-edit-save (-> user-edit-save - (wrap-schema-decode :form-schema (mc/schema - [:map - [:db/id entity-id] - [:user/clients {:optional true} - [:maybe - (many-entity {} [:db/id entity-id])]] - [:user/role (ref->enum-schema "user-role")]])) + (wrap-entity [:form-params :db/id] default-read) + (wrap-schema-decode :form-schema user-form-schema) (wrap-nested-form-params) - (wrap-form-4xx-2 user-save-error)) - :user-client-new (-> new-client + (wrap-form-4xx-2 (wrap-entity user-save-error [:form-params :db/id] default-read))) + :user-client-new (-> new-client (wrap-schema-decode :query-schema [:map [:index {:optional true :default 0} [nat-int? {:default 0}]]])) :user-edit-dialog (-> user-edit-dialog + (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema (mc/schema [:map [:db/id entity-id]]))) :user-impersonate (-> impersonate + (wrap-entity [:params :db/id] default-read) (wrap-schema-decode :params-schema (mc/schema [:map [:db/id entity-id]])))} (fn [h] diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index b80c08bd..6cbdfa0f 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -1,15 +1,15 @@ (ns auto-ap.ssr.utils (:require - [auto-ap.datomic :refer [all-schema]] + [auto-ap.datomic :refer [all-schema conn]] [auto-ap.logging :as alog] [clojure.string :as str] [config.core :refer [env]] + [datomic.api :as dc] [hiccup2.core :as hiccup] [malli.core :as mc] [malli.error :as me] [malli.transform :as mt2] - [slingshot.slingshot :refer [throw+ try+]] - [manifold.time :as mt])) + [slingshot.slingshot :refer [throw+ try+]])) (defn html-response [hiccup & {:keys [status headers oob] :or {status 200 headers {} oob []}}] {:status status @@ -99,7 +99,7 @@ (def entity-id (mc/schema [nat-int? {:error/message "required"} ])) -(def temp-id (mc/schema :string)) +(def temp-id (mc/schema [:string {:min 1}])) (def money (mc/schema [:double])) (def percentage (mc/schema [:double {:decode/arbitrary (fn [x] (some-> x (* 0.01))) :max 1.0 @@ -292,18 +292,18 @@ (:errors (:explain (:error e))))] (alog/warn ::form-4xx :errors errors) (form-handler (assoc request - :last-form (:decoded e) + :form-params (:decoded e) :field-validation-errors errors :form-errors humanized))) #_(html-response [:span.error-content.text-red-500 (:message &throw-context)] :status 400)) (catch [:type :field-validation] e (form-handler (assoc request - :last-form (:form e) + :form-params (:form e) :form-errors (:form-errors e)))) (catch [:type :form-validation] e (form-handler (assoc request - :last-form (:form e) + :form-params (:form e) :form-validation-errors (:form-validation-errors e) :form-errors {:errors (:form-validation-errors e)})))))) @@ -326,3 +326,15 @@ (map (fn [k] (str "[" (k->n k) "]")) rest))))) + + +(defn wrap-entity [handler path read] + (fn wrap-entity-request [request] + (let [entity (some->> + (get-in request path) + (#(if (string? %) (Long/parseLong %) %)) + (dc/pull (dc/db conn) read ))] + (handler (if entity + (assoc request + :entity entity) + request))))) From a8cce0377dce7ba5e7605d563066cfdab4d16ab6 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 24 Oct 2023 11:52:55 -0700 Subject: [PATCH 21/34] lots of progress --- src/clj/auto_ap/square/core3.clj | 8 ++ src/clj/auto_ap/ssr/admin/accounts.clj | 57 +++++----- src/clj/auto_ap/ssr/admin/background_jobs.clj | 32 +++--- .../auto_ap/ssr/admin/transaction_rules.clj | 104 ++++++++---------- src/clj/auto_ap/ssr/components/buttons.clj | 2 +- src/clj/auto_ap/ssr/components/inputs.clj | 6 +- src/clj/auto_ap/ssr/hx.clj | 12 ++ src/clj/auto_ap/ssr/users.clj | 73 ++++++------ src/clj/auto_ap/ssr/utils.clj | 31 ++++-- 9 files changed, 170 insertions(+), 155 deletions(-) diff --git a/src/clj/auto_ap/square/core3.clj b/src/clj/auto_ap/square/core3.clj index d9c1e916..55cdf61a 100644 --- a/src/clj/auto_ap/square/core3.clj +++ b/src/clj/auto_ap/square/core3.clj @@ -767,6 +767,14 @@ (dc/db conn) codes)))) +(defn get-square-client-and-location [code] + (let [[client] (get-square-clients code)] + (some->> client + :client/square-locations + (filter :square-location/client-location) + seq + (conj [client])))) + (defn upsert-locations ([] (apply de/zip diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 755b5460..3e95993e 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -27,6 +27,7 @@ field-validation-error form-validation-error html-response + main-transformer many-entity ref->enum-schema ref->select-options @@ -263,10 +264,7 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :value (fc/field-value) - :value-fn (some-fn :db/id identity) ;; TODO better hydration - :content-fn (fn [value] - (:client/name (cond->> value - (nat-int? value) (dc/pull (dc/db conn) [:client/name]))))})))) + :content-fn #(pull-attr (dc/db conn) :client/name %)})))) (fc/with-field :account-client-override/name (com/data-grid-cell {} @@ -298,14 +296,14 @@ :hx-target "this"} (com/modal {} - [:form#edit-form (-> {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - (assoc (if (:db/id entity) - :hx-put - :hx-post) - (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save)))) + [:form (-> {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} + (assoc (if (:db/id entity) + :hx-put + :hx-post) + (str (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-edit-save)))) [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -323,7 +321,7 @@ (com/validated-field {:label "Numeric code" :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) - :value (fc/field-value) + :value (fc/field-value) :x-model "accountCode" :autofocus true :class "w-32"})) @@ -382,13 +380,13 @@ (com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid-header {} "Account name") (com/data-grid-header {})] - :id "client-override-table"} + :id "client-override-table"} (fc/cursor-map #(client-override* %)) (com/data-grid-new-row {:colspan 3 - :index (count (fc/field-value)) - :hx-get (bidi/path-for ssr-routes/only-routes + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes :admin-account-client-override-new)} "New override")))) @@ -407,17 +405,7 @@ [] (client-override* fc/*current*)))) -(defn account-dialog [{:keys [entity form-params form-errors]}] - (html-response (dialog* {:entity entity - :form-params (or (when (seq form-params) - form-params) - entity - {}) - :form-errors form-errors}) - :headers {"hx-trigger" "modalopen"})) - - -(def account-schema (mc/schema +(def form-schema (mc/schema [:map [:db/id {:optional true} [:maybe entity-id]] [:account/numeric-code {:optional true} [:maybe :int]] @@ -434,6 +422,19 @@ [:account-client-override/client entity-id] [:account-client-override/name [:string {:min 2}]])]]])) +(defn account-dialog [{:keys [entity form-params form-errors]}] + (html-response (dialog* {:entity entity + :form-params (or (when (seq form-params) + form-params) + (when entity + (mc/decode form-schema entity main-transformer)) + {}) + :form-errors form-errors}) + :headers {"hx-trigger" "modalopen"})) + + + + (def key->handler (apply-middleware-to-all-handlers (->> @@ -446,7 +447,7 @@ wrap-admin wrap-client-redirect-unauthenticated) :admin-account-save (-> account-save (wrap-entity [:form-params :db/id] default-read) - (wrap-schema-decode :form-schema account-schema) + (wrap-schema-decode :form-schema form-schema) (wrap-nested-form-params) (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) :admin-account-edit-dialog (-> account-dialog diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index d468010f..58f4bb47 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -184,11 +184,11 @@ (defn job-start-dialog [_] (html-response (com/modal {:modal-class "max-w-4xl"} - [:form#edit-form {:hx-ext "response-targets" - :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start - ) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} + [:form {:hx-ext "response-targets" + :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start + ) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -199,18 +199,18 @@ (com/select {:name "name" :class "w-64" :options [["" ""] - ["yodlee2" "Yodlee Import"] - ["yodlee2-accounts" "Yodlee Account Import"] - ["intuit" "Intuit import"] - ["plaid" "Plaid import"] - ["bulk-journal-import" "Bulk Journal Import"] - ["square2-import-job" "Square2 Import"] - ["register-invoice-import" "Register Invoice Import "] - ["ezcater-upsert" "Upsert recent ezcater orders"] - ["load-historical-sales" "Load Historical Square Sales"] - ["export-backup" "Export Backup"]] + ["yodlee2" "Yodlee Import"] + ["yodlee2-accounts" "Yodlee Account Import"] + ["intuit" "Intuit import"] + ["plaid" "Plaid import"] + ["bulk-journal-import" "Bulk Journal Import"] + ["square2-import-job" "Square2 Import"] + ["register-invoice-import" "Register Invoice Import "] + ["ezcater-upsert" "Upsert recent ezcater orders"] + ["load-historical-sales" "Load Historical Square Sales"] + ["export-backup" "Export Backup"]] :hx-get (bidi/path-for ssr-routes/only-routes - :admin-job-subform) + :admin-job-subform) :hx-target "#sub-form" :hx-swap "innerHTML"})) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 841c2160..383a2f18 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -29,6 +29,7 @@ field-validation-error form-validation-error html-response + main-transformer many-entity money percentage @@ -66,8 +67,9 @@ :url (bidi/path-for ssr-routes/only-routes :vendor-search) :id (str "vendor-search") - :value [(:db/id (:vendor (:parsed-query-params request))) - (:vendor/name (:vendor (:parsed-query-params request)))]})) + :value (:vendor (:parsed-query-params request)) + :value-fn :db/id + :content-fn :vendor/name})) (com/field {:label "Note"} (com/text-input {:name "note" :id "note" @@ -330,12 +332,11 @@ :id name :x-model x-model :value value - :value-fn (some-fn :db/id identity) :content-fn (fn [value] - (:account/name (d-accounts/clientize (cond->> value - (nat-int? value) (dc/pull (dc/db conn) d-accounts/default-read)) + (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value) client-id)))})]) +;; TODO something is making the accountId not change the location for only existing ones? (defn- transaction-rule-account-row* [transaction-rule account] (com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) @@ -363,8 +364,7 @@ (account-typeahead* {:value (fc/field-value) :client-id (:db/id (:transaction-rule/client transaction-rule)) :name (fc/field-name) - :x-model "accountId" - })))) + :x-model "accountId"})))) (fc/with-field :transaction-rule-account/location (com/data-grid-cell {} @@ -396,22 +396,21 @@ (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -;; TODO dialog is no longer closeable -;; TODO might not need #edit-form id +;; TODO background jobs and company 1099 (defn dialog* [{:keys [entity form-params form-errors]}] (fc/start-form form-params form-errors (com/modal {:modal-class "max-w-2xl" :hx-target "this"} - [:form#edit-form {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :x-trap "true" - :class "group/form" - (if (:db/id entity) - :hx-put - :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} + [:form {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :x-trap "true" + :class "group/form" + (if (:db/id entity) + :hx-put + :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} (com/modal-card {} [:div.flex [:div.p-2 "Transaction Rule"]] @@ -465,10 +464,7 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :x-model "clientId" :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) + :content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))})])) (fc/with-field :transaction-rule/bank-account (com/validated-field @@ -536,11 +532,9 @@ (com/typeahead-2 {:name (fc/field-name) :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :id (str "form-vendor-search") :class "w-96" :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + :content-fn #(pull-attr (dc/db conn) :vendor/name %)})])) (fc/with-field :transaction-rule/accounts (com/validated-field @@ -573,11 +567,6 @@ (com/validated-save-button {:errors (:errors form-errors)} "Save rule")])]))) -;; TODO Should forms have some kind of helper to render an individual field? saving -;; could generate the entire form and swap if there are errors -;; but also when you tab out it could call the same function, and just -;; pull out the single field to swap - (defn new-account [{{:keys [client-id index]} :query-params}] (html-response (fc/start-form-with-prefix @@ -598,16 +587,14 @@ ;; TODO check to see if it should be called "Shared" or "shared" for the value ;; TODO hydrate nested types more easily. make it easy to hydrate so you don't do weird sometimes pulls -;; TODO is it possible to make it easy to get a virtual cursor in the case of adding a new row? setting up -;; fake data doesn't feel right - maybe have a "prelude" that's dynamic (defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}] (html-response (location-select* {:name name :value value :account-location (some->> account-id - (pull-attr (dc/db conn) :account/location)) + (pull-attr (dc/db conn) :account/location)) :client-locations (some->> client-id - (pull-attr (dc/db conn) :client/locations))}))) + (pull-attr (dc/db conn) :client/locations))}))) (defn account-typeahead [{{:keys [name value client-id] :as qp} :query-params}] (let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id @@ -619,34 +606,37 @@ :value account :client-id client-id})))) +(def form-schema (mc/schema + [:map + [:db/id {:optional true} [:maybe entity-id]] + [:transaction-rule/client {:optional true} [:maybe entity-id]] + [:transaction-rule/description [:and regex + [:string {:min 3}]]] + [:transaction-rule/bank-account [:maybe entity-id]] + [:transaction-rule/amount-gte {:optional true} [:maybe money]] + [:transaction-rule/amount-lte {:optional true} [:maybe money]] + [:transaction-rule/dom-gte {:optional true} [:maybe :int]] + [:transaction-rule/dom-lte {:optional true} [:maybe :int]] + [:transaction-rule/vendor {:optional true} [:maybe entity-id]] + [:transaction-rule/transaction-approval-status (ref->enum-schema "transaction-approval-status")] + [:transaction-rule/accounts + (many-entity {:min 1} + [:db/id [:or entity-id temp-id]] + [:transaction-rule-account/account entity-id] + [:transaction-rule-account/location [:string {:min 1 :error/message "required"}]] + [:transaction-rule-account/percentage percentage])]])) + (defn transaction-dialog [{:keys [entity form-params form-errors]}] (html-response (dialog* {:entity entity :form-params (or (when (seq form-params) form-params) - entity ;; TODO coerce into form params + (when entity + (mc/decode form-schema entity main-transformer)) ;; TODO coerce into form params {}) :form-errors form-errors}) :headers {"hx-trigger" "modalopen"})) -(def transaction-rule-schema (mc/schema - [:map - [:db/id {:optional true} [:maybe entity-id]] - [:transaction-rule/client {:optional true} [:maybe entity-id]] - [:transaction-rule/description [:and regex - [:string {:min 3}]]] - [:transaction-rule/bank-account [:maybe entity-id]] - [:transaction-rule/amount-gte {:optional true} [:maybe money]] - [:transaction-rule/amount-lte {:optional true} [:maybe money]] - [:transaction-rule/dom-gte {:optional true} [:maybe :int]] - [:transaction-rule/dom-lte {:optional true} [:maybe :int]] - [:transaction-rule/vendor {:optional true} [:maybe entity-id]] - [:transaction-rule/transaction-approval-status (ref->enum-schema "transaction-approval-status")] - [:transaction-rule/accounts - (many-entity {:min 1} - [:db/id [:or entity-id temp-id]] - [:transaction-rule-account/account entity-id] - [:transaction-rule-account/location [:string {:min 1 :error/message "required"}]] - [:transaction-rule-account/percentage percentage])]])) + (def key->handler (apply-middleware-to-all-handlers @@ -676,10 +666,10 @@ [:maybe entity-id]]])) :admin-transaction-rule-save (-> transaction-rule-save (wrap-entity [:form-params :db/id] default-read) - (wrap-schema-decode :form-schema transaction-rule-schema) - (wrap-nested-form-params) - (wrap-form-4xx-2 (-> transaction-dialog - (wrap-entity [:form-params :db/id] default-read)))) + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> transaction-dialog + (wrap-entity [:form-params :db/id] default-read)))) :admin-transaction-rule-edit-dialog (-> transaction-dialog (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema [:map [:db/id entity-id]])) diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 9df54b67..d23281d7 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -176,7 +176,7 @@ (defn validated-save-button- [{:keys [errors class] :as params} & children] - (button- (-> {:color :primary :form "edit-form" + (button- (-> {:color :primary :type "submit" :class (cond-> (or class "") true (hh/add-class "w-32") (seq errors) (hh/add-class "animate-shake"))} diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 02251640..c42f82ed 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -75,11 +75,11 @@ c.clearChoices(); :baseUrl (if (str/includes? (:url params) "?") (str (:url params) "&q=") (str (:url params) "?q=")) - :value {:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))} + :value {:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))} :search "" :active -1 - :elements (if ((:value-fn params first) (:value params)) - [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] + :elements (if ((:value-fn params identity) (:value params)) + [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}] [])}) :x-modelable "value.value" :x-model (:x-model params) diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index 0a069362..370e27b3 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -38,3 +38,15 @@ alpine-appear alpine-disappear) (dissoc params :data-key))) + +(defn bind-alpine-vals [m field->alpine-field] + (assoc m "x-bind:hx-vals" + + (format "JSON.stringify({%s})" + (str/join ", " + (map + (fn [[field alpine-field]] + (format "\"%s\": $data.%s" field alpine-field)) + + field->alpine-field))))) + diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 26f90161..3040f057 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -6,6 +6,7 @@ apply-sort-3 conn merge-query + pull-attr pull-many query2]] [auto-ap.query-params :as query-params] @@ -23,6 +24,7 @@ :refer [apply-middleware-to-all-handlers entity-id html-response + main-transformer many-entity ref->enum-schema ref->select-options @@ -256,13 +258,11 @@ (def table* (partial helper/table* grid-page)) (defn impersonate [request] - (println (:entity request)) (if (:entity request) {:status 200 :headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt (:entity request) "FAKE_TOKEN") (:jwt-secret env) - {:alg :hs512})) - } + {:alg :hs512}))} :session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN") :exp)}} {:status 404})) @@ -279,31 +279,27 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :value (fc/field-value) + :value-fn :db/id - :value-fn :db/id ;; TODO better hydration - :content-fn (fn [value] - (:client/name (dc/pull (dc/db conn) [:client/name] - (or (:db/id value) - value)))) + :content-fn #(pull-attr (dc/db conn) :client/name (:db/id %)) :size :small}))) (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -;; TODO hydrate user name (defn dialog* [{:keys [form-params form-errors entity]}] (fc/start-form form-params form-errors (com/modal {:hx-target "this"} - [:form#edit-form {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full"} + [:form {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full"} [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -321,7 +317,7 @@ :value (some->> (fc/field-value) name) :options (ref->select-options "user-role")}))) (fc/with-field :user/clients - (com/validated-field {:label "Clients"} + (com/validated-field {:label "Clients"} (com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid-header {} )] :id "client-table"} @@ -336,7 +332,6 @@ (com/validated-save-button {:errors (seq form-errors)} "Save user")])]]))) -;; TODO rename edit-form or make it generic (defn user-edit-save [{:keys [form-params identity] :as request}] (let [_ @(dc/transact conn [[:upsert-entity form-params]]) user (some-> form-params :db/id (#(dc/pull (dc/db conn) default-read %)))] @@ -346,18 +341,25 @@ :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#user-table tr[data-id=\"%d\"]" (:db/id user))}))) -(defn user-save-error [request] - ;; TODO hydration - ;; TODO consistency of error handling and passing, on all form examples - (html-response (dialog* {:form-params (:form-params request) - :entity (:entity request) - :form-errors (:form-errors request)}))) -(defn user-edit-dialog [request] +(def form-schema + (mc/schema + [:map + [:db/id entity-id] + [:user/clients {:optional true} + [:maybe + (many-entity {} [:db/id entity-id])]] + [:user/role (ref->enum-schema "user-role")]])) + +(defn user-dialog [{:keys [form-params entity form-errors]}] (html-response - (dialog* {:form-params (:entity request) - :entity (:entity request) - :form-errors {}}) + (dialog* {:form-params (or (when (seq form-params) + form-params) + (when entity + (mc/decode form-schema entity main-transformer)) + {}) + :entity entity + :form-errors form-errors}) :headers {"hx-trigger" "modalopen"})) @@ -367,14 +369,7 @@ :new? true} [] (client-row* fc/*current*)))) -(def user-form-schema - (mc/schema - [:map - [:db/id entity-id] - [:user/clients {:optional true} - [:maybe - (many-entity {} [:db/id entity-id])]] - [:user/role (ref->enum-schema "user-role")]])) + (def key->handler (apply-middleware-to-all-handlers @@ -382,14 +377,14 @@ :user-table (helper/table-route grid-page) :user-edit-save (-> user-edit-save (wrap-entity [:form-params :db/id] default-read) - (wrap-schema-decode :form-schema user-form-schema) + (wrap-schema-decode :form-schema form-schema) (wrap-nested-form-params) - (wrap-form-4xx-2 (wrap-entity user-save-error [:form-params :db/id] default-read))) + (wrap-form-4xx-2 (wrap-entity user-dialog [:form-params :db/id] default-read))) :user-client-new (-> new-client (wrap-schema-decode :query-schema [:map [:index {:optional true :default 0} [nat-int? {:default 0}]]])) - :user-edit-dialog (-> user-edit-dialog + :user-edit-dialog (-> user-dialog (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema (mc/schema [:map [:db/id entity-id]]))) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 6cbdfa0f..ca664017 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -97,7 +97,11 @@ :long empty->nil 'nat-int? empty->nil}})) -(def entity-id (mc/schema [nat-int? {:error/message "required"} ])) +(def entity-id (mc/schema [nat-int? {:error/message "required" + :decode/arbitrary (fn [e] + (if (and (map? e) (:db/id e)) + (:db/id e) + e))} ])) (def temp-id (mc/schema [:string {:min 1}])) (def money (mc/schema [:double])) @@ -116,15 +120,17 @@ (def map->db-id-decoder {:enter (fn [x] - (into [] - (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] - v - #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) - (Long/parseLong k) - (keyword? k) - (name k) - :else - k)))))}) + (if (sequential? x) + x + (into [] + (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] + v + #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) + (Long/parseLong k) + (keyword? k) + (name k) + :else + k))))))}) (defn many-entity [params & keys] (mc/schema @@ -219,7 +225,10 @@ (handler request)))) (defn ref->enum-schema [n] - (into [:enum {:decode/string #(keyword n %)}] + (into [:enum {:decode/string #(if (keyword? %) + % + (keyword n %) + )}] (for [{:db/keys [ident]} (all-schema) :when (= n (namespace ident))] ident))) From d7edf0221cc390cc24a647a627f9c5b4de9d49ec Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 24 Oct 2023 12:29:48 -0700 Subject: [PATCH 22/34] revamp more --- src/clj/auto_ap/ssr/admin/accounts.clj | 19 ++++--------------- src/clj/auto_ap/ssr/users.clj | 3 --- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 3e95993e..3fd9557f 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -136,14 +136,14 @@ :parse-query-params (comp (query-params/parse-key :code query-params/parse-long) (helper/default-parse-query-params grid-page)) - :action-buttons (fn [request] + :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-new-dialog)) :hx-target "#modal-content" :hx-swap "innerHTML" :color :primary} "New Account")]) - :row-buttons (fn [request entity] + :row-buttons (fn [_ entity] [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-edit-dialog :db/id (:db/id entity))) @@ -184,16 +184,15 @@ (let [entity (cond-> form-params (= :post request-method) (assoc :db/id "new")) _ (cond (= :post request-method) - (when-let [extant (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity)))] + (when (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity))) (field-validation-error (format "The code %d is already in use." (:account/numeric-code entity)) [:account/numeric-code] :form form-params)) ) - ;; TODO the following would work better if the schema was hydrated automatically with needed values _ (some->> form-params :account/client-overrides (group-by :account-client-override/client) - (filter (fn [[client overrides]] + (filter (fn [[_ overrides]] (> (count overrides) 1))) (map first) seq @@ -235,16 +234,6 @@ :headers {"hx-trigger" "modalclose" "hx-retarget" (format "#account-table tr[data-id=\"%d\"]" (:db/id updated-account))}))) -;; TODO use cursor -;; TODO index based list not dbid - -;; TODO lots of weird edge cases with indexes -;; for example, what happens when you have 0, 1, 2, but then delete 1? -;; what happens when you delete 2 but then add another one? -;; preference is that the field parsing logic does better grouping of what -;; goes with what, building index on the server side -;; not needing to pass index in - ;; TODO decide when cursors are used. other cases it's not, some are (defn client-override* [override] (com/data-grid-row (-> {:x-ref "p" diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 3040f057..c7f5fec4 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -369,8 +369,6 @@ :new? true} [] (client-row* fc/*current*)))) - - (def key->handler (apply-middleware-to-all-handlers {:users (helper/page-route grid-page) @@ -396,4 +394,3 @@ (-> h (wrap-admin) (wrap-client-redirect-unauthenticated))))) - From f5fd532a31c7aadab7b6585c9dfae0b3517d6332 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 24 Oct 2023 16:59:43 -0700 Subject: [PATCH 23/34] ccount modal --- src/clj/auto_ap/ssr/admin/accounts.clj | 85 ++++----- .../auto_ap/ssr/admin/transaction_rules.clj | 180 +++++++++--------- src/clj/auto_ap/ssr/ui.clj | 13 +- src/clj/auto_ap/ssr/users.clj | 11 +- src/clj/auto_ap/ssr/utils.clj | 58 +++--- 5 files changed, 167 insertions(+), 180 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 3fd9557f..6dad6db6 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -29,8 +29,10 @@ html-response main-transformer many-entity + modal-response ref->enum-schema ref->select-options + strip temp-id wrap-entity wrap-form-4xx-2 @@ -44,8 +46,8 @@ [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes :admin-account-table) - "hx-target" "#account-table" - "hx-indicator" "#account-table"} + "hx-target" "#entity-table" + "hx-indicator" "#entity-table"} [:fieldset.space-y-6 (com/field {:label "Name"} @@ -129,7 +131,7 @@ matching-count])) (def grid-page - (helper/build {:id "account-table" + (helper/build {:id "entity-table" :nav (com/admin-aside-nav) :page-specific-nav filters :fetch-page fetch-page @@ -139,16 +141,12 @@ :action-buttons (fn [_] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-new-dialog)) - :hx-target "#modal-content" - :hx-swap "innerHTML" :color :primary} "New Account")]) :row-buttons (fn [_ entity] [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-account-edit-dialog - :db/id (:db/id entity))) - :hx-target "#modal-content" - :hx-swap "innerHTML"} + :db/id (:db/id entity)))} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -181,31 +179,29 @@ (def table* (partial helper/table* grid-page)) (defn account-save [{:keys [form-params request-method] :as request}] - (let [entity (cond-> form-params - (= :post request-method) (assoc :db/id "new")) - _ (cond (= :post request-method) - (when (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity))) - (field-validation-error (format "The code %d is already in use." (:account/numeric-code entity)) - [:account/numeric-code] - :form form-params)) - ) - _ (some->> form-params - :account/client-overrides - (group-by :account-client-override/client) - (filter (fn [[_ overrides]] - (> (count overrides) 1))) - (map first) - seq - (#(form-validation-error (format "Client(s) %s have more than one override." - (str/join ", " - (map (fn [client] - (format "'%s'" (pull-attr (dc/db conn) - :client/name - (-> client))) - ) %))) - :form form-params)) - - ) + (let [entity (cond-> form-params + (= :post request-method) (assoc :db/id "new")) + _ (cond (= :post request-method) + (when (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity))) + (field-validation-error (format "The code %d is already in use." (:account/numeric-code entity)) + [:account/numeric-code] + :form form-params))) + _ (some->> form-params + :account/client-overrides + (group-by :account-client-override/client) + (filter (fn [[_ overrides]] + (> (count overrides) 1))) + (map first) + seq + (#(form-validation-error (format "Client(s) %s have more than one override." + (str/join ", " + (map (fn [client] + (format "'%s'" (pull-attr (dc/db conn) + :client/name + (-> client))) + ) %))) + :form form-params)) ;; TODO shouldnt need to bubble this through. See if we can eliminate the passing of form and last-form. + ) {:keys [tempids]} (audit-transact [[:upsert-entity (cond-> entity (:account/numeric-code entity) (assoc :account/code (str (:account/numeric-code entity))))]] (:identity request)) @@ -231,8 +227,10 @@ "account_client_override_id" (:db/id o)}))) (html-response (row* identity updated-account {:flash? true}) - :headers {"hx-trigger" "modalclose" - "hx-retarget" (format "#account-table tr[data-id=\"%d\"]" (:db/id updated-account))}))) + :headers (cond-> {"hx-trigger" "modalclose"} + (= :post request-method) (assoc "hx-retarget" "#entity-table tbody" + "hx-reswap" "afterbegin") + (= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-account))))))) ;; TODO decide when cursors are used. other cases it's not, some are (defn client-override* [override] @@ -377,14 +375,14 @@ :index (count (fc/field-value)) :hx-get (bidi/path-for ssr-routes/only-routes :admin-account-client-override-new)} - "New override")))) - - ] + "New override"))))] [:div (com/form-errors {:errors (:errors fc/*form-errors*)}) (com/validated-save-button {:errors (seq form-errors)} "Save account")])]])])) +;; TODO saving new row should att it to the tbody + (defn new-client-override [{ {:keys [index]} :query-params}] (html-response (fc/start-form-with-prefix @@ -398,8 +396,8 @@ [:map [:db/id {:optional true} [:maybe entity-id]] [:account/numeric-code {:optional true} [:maybe :int]] - [:account/name [:string {:min 1}]] - [:account/location [:maybe :string]] + [:account/name [:string {:min 1 :decode/string strip}]] + [:account/location {:optional true} [:maybe [:string {:decode/string strip}]]] [:account/type (ref->enum-schema "account-type")] [:account/applicability (ref->enum-schema "account-applicability")] ; [:account/invoice-allowance (ref->enum-schema "allowance")] @@ -409,17 +407,16 @@ (many-entity {} [:db/id [:or entity-id temp-id]] [:account-client-override/client entity-id] - [:account-client-override/name [:string {:min 2}]])]]])) + [:account-client-override/name [:string {:min 2 :decode/string strip}]])]]])) (defn account-dialog [{:keys [entity form-params form-errors]}] - (html-response (dialog* {:entity entity + (modal-response (dialog* {:entity entity :form-params (or (when (seq form-params) form-params) (when entity (mc/decode form-schema entity main-transformer)) {}) - :form-errors form-errors}) - :headers {"hx-trigger" "modalopen"})) + :form-errors form-errors}))) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 383a2f18..f3c1a92b 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -31,6 +31,7 @@ html-response main-transformer many-entity + modal-response money percentage ref->enum-schema @@ -44,21 +45,14 @@ [bidi.bidi :as bidi] [clojure.string :as str] [datomic.api :as dc] - [iol-ion.query :refer [ident]] [malli.core :as mc])) -;; TODO with dependencies, I really don't like that you have to be ultra specific in what -;; you want to include, and generating the routes and interconnection is weird too. -;; I'm tempted to say to include a full snapshot of the form, and the indicator -;; as to which one to generate. - - (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-table) - "hx-target" "#transaction-rule-table" - "hx-indicator" "#transaction-rule-table"} + "hx-target" "#entity-table" + "hx-indicator" "#entity-table"} [:fieldset.space-y-6 (com/field {:label "Vendor"} @@ -180,7 +174,7 @@ matching-count])) (def grid-page - (helper/build {:id "transaction-rule-table" + (helper/build {:id "entity-table" :nav (com/admin-aside-nav) :page-specific-nav filters :fetch-page fetch-page @@ -190,16 +184,12 @@ :action-buttons (fn [request] [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-new-dialog)) - :hx-target "#modal-content" - :hx-swap "innerHTML" :color :primary} "New Transaction Rule")]) :row-buttons (fn [request entity] [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-dialog - :db/id (:db/id entity))) - :hx-target "#modal-content" - :hx-swap "innerHTML"} + :db/id (:db/id entity)))} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -269,6 +259,7 @@ bank-account-id)) (defn transaction-rule-save [{:keys [form-params request-method identity] :as request}] + (clojure.pprint/pprint form-params) (let [entity (cond-> form-params (= :post request-method) (assoc :db/id "new") true (assoc :transaction-rule/note (entity->note form-params))) @@ -297,13 +288,15 @@ {:keys [tempids]} (audit-transact [[:upsert-entity entity]] (:identity request)) - updated-account (dc/pull (dc/db conn) + updated-rule (dc/pull (dc/db conn) default-read (or (get tempids (:db/id entity)) (:db/id entity)))] (html-response - (row* identity updated-account {:flash? true}) - :headers {"hx-trigger" "modalclose" - "hx-retarget" (format "#transaction-rule-table tr[data-id=\"%d\"]" (:db/id updated-account))}))) + (row* identity updated-rule {:flash? true}) + :headers (cond-> {"hx-trigger" "modalclose"} + (= :post request-method) (assoc "hx-retarget" "#entity-table tbody" + "hx-reswap" "afterbegin") + (= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule))))))) @@ -327,81 +320,84 @@ [{:keys [name value client-id x-model]}] [:div.flex.flex-col (com/typeahead-2 {:name name - :placeholder "Search..." - :url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id) - :id name - :x-model x-model - :value value - :content-fn (fn [value] - (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value) - client-id)))})]) + :placeholder "Search..." + :url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id) + :id name + :x-model x-model + :value value + :content-fn (fn [value] + (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value) + client-id)))})]) -;; TODO something is making the accountId not change the location for only existing ones? (defn- transaction-rule-account-row* [transaction-rule account] - (com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) - (fc/field-value (:transaction-rule-account/account account))) - :show (boolean (not (fc/field-value (:new? account))))}) - :data-key "show" - :x-ref "p"} - hx/alpine-mount-then-appear) - (let [account-name (fc/field-name (:transaction-rule-account/account account))] - (list - - (fc/with-field :db/id - (com/hidden {:name (fc/field-name) - :value (fc/field-value)})) - (fc/with-field :transaction-rule-account/account - (com/data-grid-cell - {} - (com/validated-field - {:errors (fc/field-errors)} - [:div {:hx-trigger "changed" - :hx-target "next div" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name) - :hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead)) - :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] - (account-typeahead* {:value (fc/field-value) - :client-id (:db/id (:transaction-rule/client transaction-rule)) - :name (fc/field-name) - :x-model "accountId"})))) - (fc/with-field :transaction-rule-account/location - (com/data-grid-cell - {} - (com/validated-field - {:errors (fc/field-errors) - :x-data (hx/json {:location (fc/field-value)})} - [:div {:hx-trigger "changed" - :hx-target "next *" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) ) - :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) - :x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data))"}] - (location-select* {:name (fc/field-name) - :account-location (:account/location (cond->> (:transaction-rule-account/account @account) - (nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn) - '[:account/location]))) - :client-locations (:client/locations (:transaction-rule/client transaction-rule)) - :hx-model "location" - :value (fc/field-value)})))) - (fc/with-field :transaction-rule-account/percentage - (com/data-grid-cell - {} - (com/validated-field - {:errors (fc/field-errors)} - (com/money-input {:name (fc/field-name) - :class "w-16" - :value (some-> (fc/field-value) - (* 100 ) - (long ))})))))) - (com/data-grid-cell {:class "align-top"} - (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) + (com/data-grid-row + (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) + (fc/field-value (:transaction-rule-account/account account))) + :show (boolean (not (fc/field-value (:new? account))))}) + :data-key "show" + :x-ref "p"} + hx/alpine-mount-then-appear) + (let [account-name (fc/field-name (:transaction-rule-account/account account))] + (list + + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + (fc/with-field :transaction-rule-account/account + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors)} + [:div {:hx-trigger "changed" + :hx-target "next div" + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name) + :hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead)) + :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + (account-typeahead* {:value (fc/field-value) + :client-id (:db/id (:transaction-rule/client transaction-rule)) + :name (fc/field-name) + :x-model "accountId"})))) + (fc/with-field :transaction-rule-account/location + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors) + :x-data (hx/json {:location (fc/field-value)})} + [:div {:hx-trigger "changed" + :hx-target "next *" + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) ) + :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) + :x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}] + (location-select* {:name (fc/field-name) + :account-location (:account/location (cond->> (:transaction-rule-account/account @account) + (nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn) + '[:account/location]))) + :client-locations (:client/locations (:transaction-rule/client transaction-rule)) + :hx-model "location" + :value (fc/field-value)})))) + (fc/with-field :transaction-rule-account/percentage + (com/data-grid-cell + {} + (com/validated-field + {:errors (fc/field-errors)} + (println "FIELD VALUE IS" (fc/field-value) (some-> (fc/field-value) + (* 100 ) + (long ))) + (com/money-input {:name (fc/field-name) + :class "w-16" + :value (some-> (fc/field-value) + (* 100 ) + (long ))})))))) + (com/data-grid-cell {:class "align-top"} + (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) ;; TODO background jobs and company 1099 (defn dialog* [{:keys [entity form-params form-errors]}] (fc/start-form form-params form-errors (com/modal {:modal-class "max-w-2xl" - :hx-target "this"} + :hx-target "this"} [:form {:hx-ext "response-targets" :hx-swap "outerHTML swap:300ms" @@ -415,7 +411,6 @@ {} [:div.flex [:div.p-2 "Transaction Rule"]] [:fieldset {:class "hx-disable" - :hx-disinherit "hx-target" ;; TODO why disinherit :x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client form-params)) (:transaction-rule/client form-params) (:db/id (:transaction-rule/client entity)))})} @@ -542,8 +537,7 @@ (com/data-grid {:headers [(com/data-grid-header {} "Account") (com/data-grid-header {:class "w-32"} "Location") (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} + (com/data-grid-header {:class "w-16"})]} (fc/cursor-map #(transaction-rule-account-row* form-params %)) (com/data-grid-new-row {:colspan 4 :hx-get (bidi/path-for ssr-routes/only-routes @@ -604,7 +598,8 @@ client-id client-id] (html-response (account-typeahead* {:name name :value account - :client-id client-id})))) + :client-id client-id + :x-model "accountId"})))) (def form-schema (mc/schema [:map @@ -627,14 +622,13 @@ [:transaction-rule-account/percentage percentage])]])) (defn transaction-dialog [{:keys [entity form-params form-errors]}] - (html-response (dialog* {:entity entity + (modal-response (dialog* {:entity entity :form-params (or (when (seq form-params) form-params) (when entity - (mc/decode form-schema entity main-transformer)) ;; TODO coerce into form params + (mc/decode form-schema entity main-transformer)) {}) - :form-errors form-errors}) - :headers {"hx-trigger" "modalopen"})) + :form-errors form-errors}))) diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 3cccfa40..6ab04c9e 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -1,7 +1,8 @@ (ns auto-ap.ssr.ui (:require - [hiccup2.core :as hiccup] - [auto-ap.ssr.hx :as hx])) + [auto-ap.ssr.hx :as hx] + [config.core :refer [env]] + [hiccup2.core :as hiccup])) (defn html-page [hiccup] {:status 200 @@ -27,8 +28,12 @@ [:script {:src "https://unpkg.com/hyperscript.org@0.9.7/dist/_hyperscript.min.js"}] [:script {:src "https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js"}] [:script {:src "https://cdn.plaid.com/link/v2/stable/link-initialize.js"}] - [:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js" - :crossorigin= "anonymous"}] + (if (= "dev" (:dd-env env)) + [:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.js" + :crossorigin= "anonymous"}] + [:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js" + :crossorigin= "anonymous"}]) + [:script {:src "https://unpkg.com/htmx.org/dist/ext/debug.js"}] [:script {:src "/js/htmx-disable.js"}] [:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]] diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index c7f5fec4..0f650dd0 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -26,6 +26,7 @@ html-response main-transformer many-entity + modal-response ref->enum-schema ref->select-options wrap-entity @@ -213,9 +214,7 @@ :hx-vals (format "{\"db/id\": \"%s\"}" (:db/id entity))} "Impersonate") (com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes :user-edit-dialog - :db/id (:db/id entity))) - :hx-target "#modal-content" - :hx-swap "innerHTML"} + :db/id (:db/id entity)))} svg/pencil)]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes :admin)} @@ -352,16 +351,14 @@ [:user/role (ref->enum-schema "user-role")]])) (defn user-dialog [{:keys [form-params entity form-errors]}] - (html-response + (modal-response (dialog* {:form-params (or (when (seq form-params) form-params) (when entity (mc/decode form-schema entity main-transformer)) {}) :entity entity - :form-errors form-errors}) - - :headers {"hx-trigger" "modalopen"})) + :form-errors form-errors}))) (defn new-client [{ {:keys [index]} :query-params}] (html-response diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index ca664017..27685076 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -27,6 +27,16 @@ o)) oob)))}) +(defn modal-response [hiccup & {:as opts}] + (apply html-response + (into + [hiccup] + (mapcat identity + (-> opts + (assoc-in [:headers "hx-trigger"] "modalopen") + (assoc-in [:headers "hx-retarget"] "#modal-content") + (assoc-in [:headers "hx-reswap"] "innerHTML")))))) + (defn wrap-error-response [handler] (fn [request] (try @@ -105,8 +115,11 @@ (def temp-id (mc/schema [:string {:min 1}])) (def money (mc/schema [:double])) -(def percentage (mc/schema [:double {:decode/arbitrary (fn [x] (some-> x (* 0.01))) - :max 1.0 +(def percentage (mc/schema [:double {:decode/string {:enter (fn [x] + (if (and (string? x) (re-find #"^\d+(\.\d+)?$" x)) + (-> x (Double/parseDouble) (* 0.01)) + x))} + :max 1.0 :error/message "1-100"}])) (def regex (mc/schema [:fn {:error/message "not a regex"} @@ -124,13 +137,7 @@ x (into [] (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] - v - #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) - (Long/parseLong k) - (keyword? k) - (name k) - :else - k))))))}) + v))))}) (defn many-entity [params & keys] (mc/schema @@ -174,6 +181,16 @@ (mt2/transformer {:name :arbitrary}) mt2/default-value-transformer)) +(defn strip [s] + (cond (and (string? s) (str/blank? s)) + nil + + (string? s) + (str/trim s) + + :else + s)) + (defn wrap-schema-decode [handler & {:keys [form-schema query-schema route-schema params-schema]}] (fn [{:keys [form-params query-params params] :as request}] (let [request (try @@ -207,7 +224,6 @@ main-transformer))) (catch Exception e (alog/warn ::validation-error :error e) - (throw (ex-info (->> (-> e (ex-data ) :data @@ -251,17 +267,6 @@ -#_(defn namespaceize-decoder [n] - {:exit (fn [m] - (when m - (reduce - (fn [m [k v]] - (if (= k "id") - (assoc m :db/id v) - (assoc m (keyword n (name k)) v))) - m - m)))}) - (defn wrap-form-4xx [handler] (fn [request] @@ -274,17 +279,6 @@ (html-response [:span.error-content.text-red-500 (:message &throw-context)] :status 400))))) -(defn assoc-errors-into-meta [entity errors] - (reduce - (fn add-error [entity {:keys [path message] :as se}] - (if (= (count path) 1) - (with-meta entity (assoc (meta entity) (last path) {:errors message})) - - (update-in entity (butlast path) - (fn [terminal] - (with-meta terminal (assoc (meta terminal) (last path) {:errors message})))))) - entity - errors)) (defn wrap-form-4xx-2 [handler form-handler] (fn [request] From b4ea51df84b7bdd2e6455eeebb4c80801100107c Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 06:46:31 -0700 Subject: [PATCH 24/34] preserves values. --- .../auto_ap/ssr/admin/transaction_rules.clj | 67 ++++++++----------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index f3c1a92b..5f72215d 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -259,7 +259,6 @@ bank-account-id)) (defn transaction-rule-save [{:keys [form-params request-method identity] :as request}] - (clojure.pprint/pprint form-params) (let [entity (cond-> form-params (= :post request-method) (assoc :db/id "new") true (assoc :transaction-rule/note (entity->note form-params))) @@ -330,10 +329,11 @@ client-id)))})]) (defn- transaction-rule-account-row* - [transaction-rule account] + [account client-id client-locations] (com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) (fc/field-value (:transaction-rule-account/account account))) + :location (fc/field-value (:transaction-rule-account/location account)) :show (boolean (not (fc/field-value (:new? account))))}) :data-key "show" :x-ref "p"} @@ -351,11 +351,11 @@ {:errors (fc/field-errors)} [:div {:hx-trigger "changed" :hx-target "next div" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name) + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId, value: event.detail.accountId}" account-name) :hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead)) - :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] + :x-init "$watch('clientId', cid => $dispatch('changed', $data));"}] (account-typeahead* {:value (fc/field-value) - :client-id (:db/id (:transaction-rule/client transaction-rule)) + :client-id client-id :name (fc/field-name) :x-model "accountId"})))) (fc/with-field :transaction-rule-account/location @@ -366,24 +366,21 @@ :x-data (hx/json {:location (fc/field-value)})} [:div {:hx-trigger "changed" :hx-target "next *" - :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) ) + :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || '', value: event.detail.location}" (fc/field-name) ) :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) :x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}] (location-select* {:name (fc/field-name) :account-location (:account/location (cond->> (:transaction-rule-account/account @account) (nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn) '[:account/location]))) - :client-locations (:client/locations (:transaction-rule/client transaction-rule)) - :hx-model "location" + :client-locations client-locations + :x-model "location" :value (fc/field-value)})))) (fc/with-field :transaction-rule-account/percentage (com/data-grid-cell {} (com/validated-field {:errors (fc/field-errors)} - (println "FIELD VALUE IS" (fc/field-value) (some-> (fc/field-value) - (* 100 ) - (long ))) (com/money-input {:name (fc/field-name) :class "w-16" :value (some-> (fc/field-value) @@ -477,7 +474,7 @@ :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name)) :x-init "$watch('clientId', cid => $dispatch('changed', $data))"}] - (bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client form-params)) + (bank-account-typeahead* {:client-id (:transaction-rule/client form-params) :name (fc/field-name) :value (fc/field-value)})])) @@ -534,17 +531,18 @@ (fc/with-field :transaction-rule/accounts (com/validated-field {:errors (fc/field-errors)} - (com/data-grid {:headers [(com/data-grid-header {} "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})]} - (fc/cursor-map #(transaction-rule-account-row* form-params %)) - (com/data-grid-new-row {:colspan 4 - :hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :index (count (fc/field-value)) - :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} - "New account")))) + (let [client-locations (some->> form-params :transaction-rule/client (pull-attr (dc/db conn) :client/locations))] + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})]} + (fc/cursor-map #(transaction-rule-account-row* % (:transaction-rule/client form-params) client-locations)) + (com/data-grid-new-row {:colspan 4 + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :index (count (fc/field-value)) + :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} + "New account"))))) (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" @@ -570,13 +568,9 @@ :new? true} [] (transaction-rule-account-row* - ;; TODO store a pointer to the "head " cursor for errors instead of nesting them - ;; makes it so you don't have to do this - - {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] - client-id)} - - fc/*current*)))) + fc/*current* + client-id + (some->> client-id (pull-attr (dc/db conn) :client/locations) client-id))))) ;; TODO check to see if it should be called "Shared" or "shared" for the value @@ -591,15 +585,10 @@ (pull-attr (dc/db conn) :client/locations))}))) (defn account-typeahead [{{:keys [name value client-id] :as qp} :query-params}] - (let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id - {:account/client-overrides [:db/id - :account-client-override/name - {:account-client-override/client [:db/id :client/name]}]}])) - client-id client-id] - (html-response (account-typeahead* {:name name - :value account - :client-id client-id - :x-model "accountId"})))) + (html-response (account-typeahead* {:name name + :value value + :client-id client-id + :x-model "accountId"}))) (def form-schema (mc/schema [:map From deaad7513c5ebe0323ad7885e90c16164634ad75 Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 12:43:00 -0700 Subject: [PATCH 25/34] Fixes modal, but users still have to say h-full on every element leading to the card --- resources/public/output.css | 137 +++++++++++------- src/clj/auto_ap/ssr/admin/accounts.clj | 8 +- .../auto_ap/ssr/admin/transaction_rules.clj | 3 +- src/clj/auto_ap/ssr/components/dialog.clj | 11 +- src/clj/auto_ap/ssr/components/inputs.clj | 2 +- src/clj/auto_ap/ssr/ui.clj | 11 +- src/clj/auto_ap/ssr/users.clj | 4 +- 7 files changed, 106 insertions(+), 70 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 96983899..a6672f5a 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1155,6 +1155,10 @@ input:checked + .toggle-bg { margin: 1rem; } +.m-12 { + margin: 3rem; +} + .mx-2 { margin-left: 0.5rem; margin-right: 0.5rem; @@ -1332,6 +1336,10 @@ input:checked + .toggle-bg { height: 1.5rem; } +.h-64 { + height: 16rem; +} + .h-8 { height: 2rem; } @@ -1344,47 +1352,43 @@ input:checked + .toggle-bg { height: 100%; } -.h-screen { - height: 100vh; -} - -.h-64 { - height: 16rem; -} - .h-min { height: -moz-min-content; height: min-content; } -.h-\[90vh\] { - height: 90vh; +.h-screen { + height: 100vh; +} + +.h-24 { + height: 6rem; } .max-h-96 { max-height: 24rem; } -.max-h-full { - max-height: 100%; -} - -.max-h-\[90vh\] { - max-height: 90vh; -} - -.max-h-\[100vh\] { - max-height: 100vh; -} - .max-h-\[80vh\] { max-height: 80vh; } +.max-h-full { + max-height: 100%; +} + +.max-h-\[50\%\] { + max-height: 50%; +} + .w-1\/2 { width: 50%; } +.w-1\/4 { + width: 25%; +} + .w-16 { width: 4rem; } @@ -1454,21 +1458,32 @@ input:checked + .toggle-bg { width: 100vw; } -.w-min { - width: -moz-min-content; - width: min-content; +.w-\[900px\] { + width: 900px; } -.w-8\/12 { - width: 66.666667%; +.w-\[1200px\] { + width: 1200px; } -.w-6\/12 { - width: 50%; +.w-\[2900px\] { + width: 2900px; } -.w-1\/4 { - width: 25%; +.min-w-\[25\%\] { + min-width: 25%; +} + +.min-w-\[500px\] { + min-width: 500px; +} + +.min-w-\[450px\] { + min-width: 450px; +} + +.min-w-\[700px\] { + min-width: 700px; } .max-w-2xl { @@ -1495,8 +1510,8 @@ input:checked + .toggle-bg { max-width: 1024px; } -.max-w-xs { - max-width: 20rem; +.max-w-6xl { + max-width: 72rem; } .flex-1 { @@ -1709,18 +1724,10 @@ input:checked + .toggle-bg { flex-wrap: wrap; } -.place-content-center { - place-content: center; -} - .place-items-center { place-items: center; } -.content-center { - align-content: center; -} - .items-start { align-items: flex-start; } @@ -1757,6 +1764,10 @@ input:checked + .toggle-bg { justify-content: space-between; } +.justify-stretch { + justify-content: stretch; +} + .justify-items-stretch { justify-items: stretch; } @@ -1857,6 +1868,10 @@ input:checked + .toggle-bg { align-self: center; } +.self-stretch { + align-self: stretch; +} + .justify-self-end { justify-self: end; } @@ -2148,6 +2163,11 @@ input:checked + .toggle-bg { background-color: rgb(255 230 230 / var(--tw-bg-opacity)); } +.bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(255 3 3 / var(--tw-bg-opacity)); +} + .bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); @@ -2162,6 +2182,11 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } +.bg-yellow-500 { + --tw-bg-opacity: 1; + background-color: rgb(194 120 3 / var(--tw-bg-opacity)); +} + .\!bg-opacity-0 { --tw-bg-opacity: 0 !important; } @@ -2202,8 +2227,8 @@ input:checked + .toggle-bg { padding: 1rem; } -.p-6 { - padding: 1.5rem; +.p-8 { + padding: 2rem; } .px-2 { @@ -2226,6 +2251,11 @@ input:checked + .toggle-bg { padding-right: 1.25rem; } +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + .py-0 { padding-top: 0px; padding-bottom: 0px; @@ -2266,11 +2296,6 @@ input:checked + .toggle-bg { padding-bottom: 1.25rem; } -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} - .pb-2 { padding-bottom: 0.5rem; } @@ -3614,12 +3639,12 @@ input:checked + .toggle-bg { display: block; } - .sm\:max-h-\[90vh\] { - max-height: 90vh; + .sm\:items-center { + align-items: center; } - .sm\:max-w-2xl { - max-width: 42rem; + .sm\:justify-center { + justify-content: center; } .sm\:rounded-lg { @@ -3666,6 +3691,10 @@ input:checked + .toggle-bg { align-items: center; } + .md\:justify-center { + justify-content: center; + } + .md\:space-x-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.75rem * var(--tw-space-x-reverse)); @@ -3677,6 +3706,10 @@ input:checked + .toggle-bg { margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(0px * var(--tw-space-y-reverse)); } + + .md\:p-12 { + padding: 3rem; + } } @media (min-width: 1024px) { diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 6dad6db6..5c913a68 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -280,18 +280,20 @@ (fc/start-form form-params form-errors [:div {:x-data (hx/json {"accountName" (or (:account/name form-params) (:account/numeric-code entity)) "accountCode" (or (:account/numeric-code form-params) (:account/numeric-code entity) )}) - :hx-target "this"} + :hx-target "this" + :class "w-full h-full"} (com/modal {} [:form (-> {:hx-ext "response-targets" :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} + :hx-target-400 "#form-errors .error-content" + :class "h-full"} (assoc (if (:db/id entity) :hx-put :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save)))) - [:fieldset {:class "hx-disable"} + [:fieldset {:class "hx-disable h-full"} (com/modal-card {} [:div.flex [:div.p-2 "Account"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 5f72215d..3d0deb2d 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -400,7 +400,7 @@ :hx-swap "outerHTML swap:300ms" :hx-target-400 "#form-errors .error-content" :x-trap "true" - :class "group/form" + :class "group/form w-full h-full" (if (:db/id entity) :hx-put :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} @@ -574,7 +574,6 @@ ;; TODO check to see if it should be called "Shared" or "shared" for the value -;; TODO hydrate nested types more easily. make it easy to hydrate so you don't do weird sometimes pulls (defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}] (html-response (location-select* {:name name diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index 3ee49af6..0a5f7474 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -5,19 +5,16 @@ (defn modal- [params & children] [:div (-> params - (update :class #(-> % - (or "max-w-4xl w-1/4 overflow-visible") - (hh/add-class "h-min"))) - - (assoc "@click.outside" "open=false")) + (assoc "@click.outside" "open=false") + (update :class (fnil hh/add-class "") "w-full h-full")) children]) (defn modal-card- [params header content footer] [:div#modal-card (update params :class (fn [c] (-> c - (or "w-full") + (or "w-full p-4 h-full") ))) - [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col max-h-[80vh]"} + [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col h-full"} [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"} header] [:div {:class "px-6 space-y-6 overflow-y-scroll w-full shrink"} #_[:div.bg-green-300.w-full.h-64 diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index c42f82ed..61db8e31 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -109,7 +109,7 @@ c.clearChoices(); [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-10 mt-1" + [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-50 mt-1" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" "x-transition:enter-start" "!opacity-0 !mt-0" diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 6ab04c9e..cc7ad535 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -72,7 +72,7 @@ input[type=number] { "@modalopen.document" "open=true" "@modalclose.document" "open=false"} - [:div {:class "bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" + [:div {:class "bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40 md:p-12" "x-show" "open" ":aria-hidden" "!open" "x-transition:enter" "duration-300" @@ -86,7 +86,8 @@ input[type=number] { ;; div that is forced to the maximum allowed size. inside that will be a div that just centers ;; the elements, allowing it to grow as necessar. Then make the modal on the inside of this ;; div just use flexbox to make the inside part be the part that scrolls - [:div#modal-content {:class (str "inset-0 max-h-[80vh] sm:m-12 flex justify-center items-center shrink h-full") + [:div {;;:class (str "sm:m-12 flex justify-center items-center bg-green-500 items-stretch inset-0") + :class "flex h-full w-full justify-stretch md:justify-center items-stretch md:items-center " "x-trap.inert.noscroll" "open" "x-trap.inert" "open" "x-show" "open" @@ -95,4 +96,8 @@ input[type=number] { "x-transition:enter-end" "!bg-opacity-100 !translate-y-0" "x-transition:leave" "duration-300" "x-transition:leave-start" "!opacity-100 !translate-y-0" - "x-transition:leave-end" "!opacity-0 !translate-y-32"}]]]]])) + "x-transition:leave-end" "!opacity-0 !translate-y-32"} + [:div.flex.items-center.justify-center.max-w-6xl {:class "min-w-[700px] max-h-full "} + [:div#modal-content.flex.flex-col.self-stretch {:class "min-w-[700px] md:p-12"} ;;.overflow-scroll + ] + ]]]]]])) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 0f650dd0..7861f1d2 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -298,8 +298,8 @@ :request-method :put)) :hx-swap "outerHTML swap:300ms" :hx-target-400 "#form-errors .error-content" - :class "w-full"} - [:fieldset {:class "hx-disable"} + :class "w-full h-full"} + [:fieldset {:class "hx-disable h-full"} (com/modal-card {} [:div.flex [:div.p-2 "User"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:user/name entity)]] From 3f369360639bad982dbb36ccedb7e5bc98a0080c Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 13:30:40 -0700 Subject: [PATCH 26/34] popper makes it work better. --- src/clj/auto_ap/ssr/components/inputs.clj | 21 +++++++++++++-------- src/clj/auto_ap/ssr/ui.clj | 3 +++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 61db8e31..c0f187f1 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -80,18 +80,22 @@ c.clearChoices(); :active -1 :elements (if ((:value-fn params identity) (:value params)) [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}] - [])}) + []) + :popper nil}) :x-modelable "value.value" :x-model (:x-model params) - :class "relative"} + :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed'})" + } [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) - "@click.prevent" "open = !open;" - "@keydown.enter.prevent.stop" "open = !open;" - "@keydown.down.prevent.stop" "open = true;" - "@keydown.backspace" "value = {value: '', label: '' }" + "@click.prevent" "open = !open; popper.update()" + "@keydown.enter.prevent.stop" "open = !open; popper.update()" + "@keydown.down.prevent.stop" "open = true; popper.update()" + "@keydown.backspace" "value = {value: '', label: '' }" :tabindex 0 - :x-init (:x-init params)} + :x-init (:x-init params) + :x-ref "input" + } [:input (-> params (dissoc :class) (dissoc :value-fn) @@ -109,7 +113,8 @@ c.clearChoices(); [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "absolute bg-gray-50 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-50 mt-1" + [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-50" + "x-ref" "dropdown" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" "x-transition:enter-start" "!opacity-0 !mt-0" diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index cc7ad535..f9eb0bec 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -61,9 +61,12 @@ input[type=number] { -moz-appearance:textfield; /* Firefox */ } "] + [:body {:hx-ext "disable-submit"} contents [:script {:src "/js/flowbite.min.js"}] + + [:div#tooltip.bg-red-500.p-12 {:role "tooltip"}] [:div#modal-holder {:tabindex "-1", :class "fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" "x-show" "open" From 635bf3c26721c4ba630ecee337ec749a67172aa4 Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 13:52:46 -0700 Subject: [PATCH 27/34] uses popper for dropdown. --- resources/input.css | 23 ++++ resources/public/output.css | 132 ++++++---------------- src/clj/auto_ap/ssr/components/inputs.clj | 21 ++-- src/clj/auto_ap/ssr/ui.clj | 7 +- 4 files changed, 75 insertions(+), 108 deletions(-) diff --git a/resources/input.css b/resources/input.css index 921b1ff9..9e3a576e 100644 --- a/resources/input.css +++ b/resources/input.css @@ -165,3 +165,26 @@ .choices[data-type*="select-one"] .choices__button { right:auto !important; } + +.arrow, +.arrow::before { + position: absolute; + width: 24px; + height: 24px; + background: inherit; +} + +.arrow { + visibility: hidden; +} + + +.arrow::before { + visibility: visible; + content: ''; + transform: rotate(45deg); +} + +.arrow { + bottom: -4px; +} diff --git a/resources/public/output.css b/resources/public/output.css index a6672f5a..571f55cd 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1155,10 +1155,6 @@ input:checked + .toggle-bg { margin: 1rem; } -.m-12 { - margin: 3rem; -} - .mx-2 { margin-left: 0.5rem; margin-right: 0.5rem; @@ -1352,43 +1348,22 @@ input:checked + .toggle-bg { height: 100%; } -.h-min { - height: -moz-min-content; - height: min-content; -} - .h-screen { height: 100vh; } -.h-24 { - height: 6rem; -} - .max-h-96 { max-height: 24rem; } -.max-h-\[80vh\] { - max-height: 80vh; -} - .max-h-full { max-height: 100%; } -.max-h-\[50\%\] { - max-height: 50%; -} - .w-1\/2 { width: 50%; } -.w-1\/4 { - width: 25%; -} - .w-16 { width: 4rem; } @@ -1458,30 +1433,6 @@ input:checked + .toggle-bg { width: 100vw; } -.w-\[900px\] { - width: 900px; -} - -.w-\[1200px\] { - width: 1200px; -} - -.w-\[2900px\] { - width: 2900px; -} - -.min-w-\[25\%\] { - min-width: 25%; -} - -.min-w-\[500px\] { - min-width: 500px; -} - -.min-w-\[450px\] { - min-width: 450px; -} - .min-w-\[700px\] { min-width: 700px; } @@ -1494,6 +1445,10 @@ input:checked + .toggle-bg { max-width: 56rem; } +.max-w-6xl { + max-width: 72rem; +} + .max-w-lg { max-width: 32rem; } @@ -1510,10 +1465,6 @@ input:checked + .toggle-bg { max-width: 1024px; } -.max-w-6xl { - max-width: 72rem; -} - .flex-1 { flex: 1 1 0%; } @@ -1538,10 +1489,6 @@ input:checked + .toggle-bg { flex-grow: 1; } -.grow { - flex-grow: 1; -} - .basis-1\/4 { flex-basis: 25%; } @@ -1884,10 +1831,6 @@ input:checked + .toggle-bg { overflow: hidden; } -.overflow-visible { - overflow: visible; -} - .overflow-scroll { overflow: scroll; } @@ -1950,6 +1893,11 @@ input:checked + .toggle-bg { border-top-right-radius: 0.5rem; } +.rounded-b-lg { + border-bottom-right-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; +} + .border { border-width: 1px; } @@ -2163,11 +2111,6 @@ input:checked + .toggle-bg { background-color: rgb(255 230 230 / var(--tw-bg-opacity)); } -.bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(255 3 3 / var(--tw-bg-opacity)); -} - .bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); @@ -2182,11 +2125,6 @@ input:checked + .toggle-bg { background-color: rgb(253 246 178 / var(--tw-bg-opacity)); } -.bg-yellow-500 { - --tw-bg-opacity: 1; - background-color: rgb(194 120 3 / var(--tw-bg-opacity)); -} - .\!bg-opacity-0 { --tw-bg-opacity: 0 !important; } @@ -2207,10 +2145,6 @@ input:checked + .toggle-bg { padding: 0.25rem; } -.p-12 { - padding: 3rem; -} - .p-2 { padding: 0.5rem; } @@ -2227,10 +2161,6 @@ input:checked + .toggle-bg { padding: 1rem; } -.p-8 { - padding: 2rem; -} - .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -2563,6 +2493,12 @@ input:checked + .toggle-bg { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.shadow-2xl { + --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); + --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .outline { outline-style: solid; } @@ -3010,6 +2946,28 @@ input:checked + .toggle-bg { right:auto !important; } +.arrow, +.arrow::before { + position: absolute; + width: 24px; + height: 24px; + background: inherit; +} + +.arrow { + visibility: hidden; +} + +.arrow::before { + visibility: visible; + content: ''; + transform: rotate(45deg); +} + +.arrow { + bottom: -4px; +} + .hover\:scale-105:hover { --tw-scale-x: 1.05; --tw-scale-y: 1.05; @@ -3631,22 +3589,10 @@ input:checked + .toggle-bg { } @media (min-width: 640px) { - .sm\:m-12 { - margin: 3rem; - } - .sm\:block { display: block; } - .sm\:items-center { - align-items: center; - } - - .sm\:justify-center { - justify-content: center; - } - .sm\:rounded-lg { border-radius: 0.5rem; } @@ -3655,10 +3601,6 @@ input:checked + .toggle-bg { padding: 1.5rem; } - .sm\:p-12 { - padding: 3rem; - } - .sm\:py-5 { padding-top: 1.25rem; padding-bottom: 1.25rem; diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index c0f187f1..aeab5789 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -84,7 +84,7 @@ c.clearChoices(); :popper nil}) :x-modelable "value.value" :x-model (:x-model params) - :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed'})" + :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [0, 20]}}})" } [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) @@ -113,7 +113,7 @@ c.clearChoices(); [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-lg py-1 w-max z-50" + [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50" "x-ref" "dropdown" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" @@ -124,15 +124,20 @@ c.clearChoices(); "x-transition:leave-end" "!opacity-0 !mt-0" "x-show " "open" "x-trap" "open" - "@click.outside" "open=false; console.log('is this ihid')"} - [:input {:type "text" :class (hh/add-class (or (:class params) "") default-input-classes) + "@click.outside" "open=false;"} + + [:input {:type "text" + :class (-> (:class params) + (or "") + (hh/add-class default-input-classes) + (hh/replace-wildcard ["rounded" "border"] "border-bottom bg-gray-100 rounded-t-lg w-full")) "x-model" "search" "placeholder" (:placeholder params) "@keydown.down.prevent" "active ++; active = active >= elements.length - 1 ? elements.length - 1 : active" "@keydown.up.prevent" "active --; active = active < 0 ? 0 : active" - "@keydown.enter.prevent" "open = false; value = elements.length > 0 ? $data.elements[active] : {'value': '', label: ''}; console.log('are we here')" + "@keydown.enter.prevent" "open = false; value = elements.length > 0 ? $data.elements[active] : {'value': '', label: ''};" "x-init" "$watch('search', s => { if($el.value.length > 2) {fetch(baseUrl + s).then(data=>data.json()).then(data => {elements = data; active=-1}) }})"}] - [:div.dropdown-options + [:div.dropdown-options {:class "rounded-b-lg overflow-hidden"} [:template {:x-for "(element, index) in elements"} [:li [:a {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-300 [&.active]:dark:bg-primary-700 text-gray-800 dark:text-gray-100" :href "#" @@ -143,9 +148,11 @@ c.clearChoices(); "x-html" "element.label"}]]] [:template {:x-if "elements.length == 0"} [:li {:class "px-4 py-2 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs "} - "No results found"]]]]]) + "No results found"]]] + ]]) +;; TODO fix search modal (defn use-size [size] (if (= :small size) (str " " "text-xs p-2") diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index f9eb0bec..68e01e9a 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -66,7 +66,6 @@ input[type=number] { contents [:script {:src "/js/flowbite.min.js"}] - [:div#tooltip.bg-red-500.p-12 {:role "tooltip"}] [:div#modal-holder {:tabindex "-1", :class "fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" "x-show" "open" @@ -85,11 +84,7 @@ input[type=number] { "x-transition:leave-start" "!bg-opacity-50" "x-transition:leave-end" "!bg-opacity-0"} - ;; TODO to get this right i think what needs to happen is to just set this up as having a single - ;; div that is forced to the maximum allowed size. inside that will be a div that just centers - ;; the elements, allowing it to grow as necessar. Then make the modal on the inside of this - ;; div just use flexbox to make the inside part be the part that scrolls - [:div {;;:class (str "sm:m-12 flex justify-center items-center bg-green-500 items-stretch inset-0") + [:div { :class "flex h-full w-full justify-stretch md:justify-center items-stretch md:items-center " "x-trap.inert.noscroll" "open" "x-trap.inert" "open" From a2d834794f13ee47e1c57801b9d88672afc2008a Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 13:55:31 -0700 Subject: [PATCH 28/34] ring. --- resources/public/output.css | 18 ++++++++++++++++++ src/clj/auto_ap/ssr/components/inputs.clj | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/resources/public/output.css b/resources/public/output.css index 571f55cd..a032d320 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -2513,6 +2513,24 @@ input:checked + .toggle-bg { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } +.ring-4 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.ring-2 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + .blur { --tw-blur: blur(8px); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index aeab5789..aba64d7b 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -113,7 +113,7 @@ c.clearChoices(); [:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"} svg/drop-down]]] - [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50" + [:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 ring-1" "x-ref" "dropdown" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" From 506d2ac78202c383e8a6b4952bebb3c100f82881 Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 15:35:33 -0700 Subject: [PATCH 29/34] Makes background jobs work again --- resources/public/output.css | 3757 +---------------- src/clj/auto_ap/ssr/admin/background_jobs.clj | 189 +- .../auto_ap/ssr/admin/transaction_rules.clj | 5 +- src/clj/auto_ap/ssr/components/dialog.clj | 9 +- src/clj/auto_ap/ssr/components/inputs.clj | 10 +- src/clj/auto_ap/ssr/components/navbar.clj | 5 +- src/clj/auto_ap/ssr/components/page.clj | 1 + src/clj/auto_ap/ssr/search.clj | 8 +- src/clj/auto_ap/ssr/transaction/insights.clj | 10 +- src/clj/auto_ap/ssr/utils.clj | 4 +- 10 files changed, 138 insertions(+), 3860 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index a032d320..60da88b9 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1,3756 +1 @@ -/* -! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #E5E7EB; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -*/ - -html { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: Calibri, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font family by default. -2. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-size: 1em; - /* 2 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9CA3AF; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9CA3AF; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden] { - display: none; -} - -[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6B7280; - border-width: 1px; - border-radius: 0px; - padding-top: 0.5rem; - padding-right: 0.75rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-shadow: 0 0 #0000; -} - -[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #007dbb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #007dbb; -} - -input::-moz-placeholder, textarea::-moz-placeholder { - color: #6B7280; - opacity: 1; -} - -input::placeholder,textarea::placeholder { - color: #6B7280; - opacity: 1; -} - -::-webkit-datetime-edit-fields-wrapper { - padding: 0; -} - -::-webkit-date-and-time-value { - min-height: 1.5em; -} - -select:not([size]) { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - print-color-adjust: exact; -} - -[multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: 0.75rem; - -webkit-print-color-adjust: unset; - print-color-adjust: unset; -} - -[type='checkbox'],[type='radio'] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - print-color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #007dbb; - background-color: #fff; - border-color: #6B7280; - border-width: 1px; - --tw-shadow: 0 0 #0000; -} - -[type='checkbox'] { - border-radius: 0px; -} - -[type='radio'] { - border-radius: 100%; -} - -[type='checkbox']:focus,[type='radio']:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #007dbb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); -} - -[type='checkbox']:checked,[type='radio']:checked,.dark [type='checkbox']:checked,.dark [type='radio']:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); -} - -[type='radio']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); -} - -[type='checkbox']:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='file'] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; -} - -[type='file']:focus { - outline: 1px auto inherit; -} - -input[type=file]::file-selector-button { - color: white; - background: #1F2937; - border: 0; - font-weight: 500; - font-size: 0.875rem; - cursor: pointer; - padding-top: 0.625rem; - padding-bottom: 0.625rem; - padding-left: 2rem; - padding-right: 1rem; - -webkit-margin-start: -1rem; - margin-inline-start: -1rem; - -webkit-margin-end: 1rem; - margin-inline-end: 1rem; -} - -input[type=file]::file-selector-button:hover { - background: #374151; -} - -.dark input[type=file]::file-selector-button { - color: white; - background: #4B5563; -} - -.dark input[type=file]::file-selector-button:hover { - background: #6B7280; -} - -input[type="range"]::-webkit-slider-thumb { - height: 1.25rem; - width: 1.25rem; - background: #007dbb; - border-radius: 9999px; - border: 0; - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; - cursor: pointer; -} - -input[type="range"]:disabled::-webkit-slider-thumb { - background: #9CA3AF; -} - -.dark input[type="range"]:disabled::-webkit-slider-thumb { - background: #6B7280; -} - -input[type="range"]:focus::-webkit-slider-thumb { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); - --tw-ring-opacity: 1px; - --tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity)); -} - -input[type="range"]::-moz-range-thumb { - height: 1.25rem; - width: 1.25rem; - background: #007dbb; - border-radius: 9999px; - border: 0; - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; - cursor: pointer; -} - -input[type="range"]:disabled::-moz-range-thumb { - background: #9CA3AF; -} - -.dark input[type="range"]:disabled::-moz-range-thumb { - background: #6B7280; -} - -input[type="range"]::-moz-range-progress { - background: #009cea; -} - -input[type="range"]::-ms-fill-lower { - background: #009cea; -} - -.toggle-bg:after { - content: ""; - position: absolute; - top: 0.125rem; - left: 0.125rem; - background: white; - border-color: #D1D5DB; - border-width: 1px; - border-radius: 9999px; - height: 1.25rem; - width: 1.25rem; - transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter; - transition-duration: .15s; - box-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); -} - -input:checked + .toggle-bg:after { - transform: translateX(100%);; - border-color: white; -} - -input:checked + .toggle-bg { - background: #007dbb; - border-color: #007dbb; -} - -.tooltip-arrow,.tooltip-arrow:before { - position: absolute; - width: 8px; - height: 8px; - background: inherit; -} - -.tooltip-arrow { - visibility: hidden; -} - -.tooltip-arrow:before { - content: ""; - visibility: visible; - transform: rotate(45deg); -} - -[data-tooltip-style^='light'] + .tooltip > .tooltip-arrow:before { - border-style: solid; - border-color: #e5e7eb; -} - -[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='top'] > .tooltip-arrow:before { - border-bottom-width: 1px; - border-right-width: 1px; -} - -[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='right'] > .tooltip-arrow:before { - border-bottom-width: 1px; - border-left-width: 1px; -} - -[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='bottom'] > .tooltip-arrow:before { - border-top-width: 1px; - border-left-width: 1px; -} - -[data-tooltip-style^='light'] + .tooltip[data-popper-placement^='left'] > .tooltip-arrow:before { - border-top-width: 1px; - border-right-width: 1px; -} - -.tooltip[data-popper-placement^='top'] > .tooltip-arrow { - bottom: -4px; -} - -.tooltip[data-popper-placement^='bottom'] > .tooltip-arrow { - top: -4px; -} - -.tooltip[data-popper-placement^='left'] > .tooltip-arrow { - right: -4px; -} - -.tooltip[data-popper-placement^='right'] > .tooltip-arrow { - left: -4px; -} - -.tooltip.invisible > .tooltip-arrow:before { - visibility: hidden; -} - -[data-popper-arrow],[data-popper-arrow]:before { - position: absolute; - width: 8px; - height: 8px; - background: inherit; -} - -[data-popper-arrow] { - visibility: hidden; -} - -[data-popper-arrow]:before { - content: ""; - visibility: visible; - transform: rotate(45deg); -} - -[data-popper-arrow]:after { - content: ""; - visibility: visible; - transform: rotate(45deg); - position: absolute; - width: 9px; - height: 9px; - background: inherit; -} - -[role="tooltip"] > [data-popper-arrow]:before { - border-style: solid; - border-color: #e5e7eb; -} - -.dark [role="tooltip"] > [data-popper-arrow]:before { - border-style: solid; - border-color: #4b5563; -} - -[role="tooltip"] > [data-popper-arrow]:after { - border-style: solid; - border-color: #e5e7eb; -} - -.dark [role="tooltip"] > [data-popper-arrow]:after { - border-style: solid; - border-color: #4b5563; -} - -[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow]:before { - border-bottom-width: 1px; - border-right-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow]:after { - border-bottom-width: 1px; - border-right-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow]:before { - border-bottom-width: 1px; - border-left-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow]:after { - border-bottom-width: 1px; - border-left-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow]:before { - border-top-width: 1px; - border-left-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow]:after { - border-top-width: 1px; - border-left-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow]:before { - border-top-width: 1px; - border-right-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow]:after { - border-top-width: 1px; - border-right-width: 1px; -} - -[data-popover][role="tooltip"][data-popper-placement^='top'] > [data-popper-arrow] { - bottom: -5px; -} - -[data-popover][role="tooltip"][data-popper-placement^='bottom'] > [data-popper-arrow] { - top: -5px; -} - -[data-popover][role="tooltip"][data-popper-placement^='left'] > [data-popper-arrow] { - right: -5px; -} - -[data-popover][role="tooltip"][data-popper-placement^='right'] > [data-popper-arrow] { - left: -5px; -} - -[role="tooltip"].invisible > [data-popper-arrow]:before { - visibility: hidden; -} - -[role="tooltip"].invisible > [data-popper-arrow]:after { - visibility: hidden; -} - -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(0 156 234 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(0 156 234 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -.container { - width: 100%; -} - -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} - -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} - -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} - -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} - -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} - -.pointer-events-none { - pointer-events: none; -} - -.visible { - visibility: visible; -} - -.invisible { - visibility: hidden; -} - -.collapse { - visibility: collapse; -} - -.static { - position: static; -} - -.fixed { - position: fixed; -} - -.absolute { - position: absolute; -} - -.relative { - position: relative; -} - -.sticky { - position: sticky; -} - -.inset-0 { - inset: 0px; -} - -.inset-y-0 { - top: 0px; - bottom: 0px; -} - -.-right-2 { - right: -0.5rem; -} - -.-top-2 { - top: -0.5rem; -} - -.bottom-0 { - bottom: 0px; -} - -.bottom-\[60px\] { - bottom: 60px; -} - -.left-0 { - left: 0px; -} - -.left-1\/2 { - left: 50%; -} - -.right-0 { - right: 0px; -} - -.right-2 { - right: 0.5rem; -} - -.top-0 { - top: 0px; -} - -.top-2 { - top: 0.5rem; -} - -.top-2\/4 { - top: 50%; -} - -.top-5 { - top: 1.25rem; -} - -.z-10 { - z-index: 10; -} - -.z-20 { - z-index: 20; -} - -.z-30 { - z-index: 30; -} - -.z-40 { - z-index: 40; -} - -.z-50 { - z-index: 50; -} - -.z-\[99\] { - z-index: 99; -} - -.col-span-1 { - grid-column: span 1 / span 1; -} - -.col-span-2 { - grid-column: span 2 / span 2; -} - -.col-span-3 { - grid-column: span 3 / span 3; -} - -.col-span-6 { - grid-column: span 6 / span 6; -} - -.col-start-1 { - grid-column-start: 1; -} - -.m-1 { - margin: 0.25rem; -} - -.m-4 { - margin: 1rem; -} - -.mx-2 { - margin-left: 0.5rem; - margin-right: 0.5rem; -} - -.mx-4 { - margin-left: 1rem; - margin-right: 1rem; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.my-0 { - margin-top: 0px; - margin-bottom: 0px; -} - -.my-4 { - margin-top: 1rem; - margin-bottom: 1rem; -} - -.\!mt-0 { - margin-top: 0px !important; -} - -.\!mt-1 { - margin-top: 0.25rem !important; -} - -.-mb-1 { - margin-bottom: -0.25rem; -} - -.mb-1 { - margin-bottom: 0.25rem; -} - -.mb-2 { - margin-bottom: 0.5rem; -} - -.mb-3 { - margin-bottom: 0.75rem; -} - -.mb-4 { - margin-bottom: 1rem; -} - -.ml-1 { - margin-left: 0.25rem; -} - -.ml-2 { - margin-left: 0.5rem; -} - -.ml-3 { - margin-left: 0.75rem; -} - -.ml-auto { - margin-left: auto; -} - -.mr-1 { - margin-right: 0.25rem; -} - -.mr-10 { - margin-right: 2.5rem; -} - -.mr-16 { - margin-right: 4rem; -} - -.mr-2 { - margin-right: 0.5rem; -} - -.mr-3 { - margin-right: 0.75rem; -} - -.mt-0 { - margin-top: 0px; -} - -.mt-0\.5 { - margin-top: 0.125rem; -} - -.mt-1 { - margin-top: 0.25rem; -} - -.mt-2 { - margin-top: 0.5rem; -} - -.mt-4 { - margin-top: 1rem; -} - -.mt-5 { - margin-top: 1.25rem; -} - -.block { - display: block; -} - -.inline-block { - display: inline-block; -} - -.inline { - display: inline; -} - -.flex { - display: flex; -} - -.inline-flex { - display: inline-flex; -} - -.table { - display: table; -} - -.grid { - display: grid; -} - -.contents { - display: contents; -} - -.hidden { - display: none; -} - -.h-10 { - height: 2.5rem; -} - -.h-3 { - height: 0.75rem; -} - -.h-3\.5 { - height: 0.875rem; -} - -.h-4 { - height: 1rem; -} - -.h-48 { - height: 12rem; -} - -.h-5 { - height: 1.25rem; -} - -.h-6 { - height: 1.5rem; -} - -.h-64 { - height: 16rem; -} - -.h-8 { - height: 2rem; -} - -.h-96 { - height: 24rem; -} - -.h-full { - height: 100%; -} - -.h-screen { - height: 100vh; -} - -.max-h-96 { - max-height: 24rem; -} - -.max-h-full { - max-height: 100%; -} - -.w-1\/2 { - width: 50%; -} - -.w-16 { - width: 4rem; -} - -.w-24 { - width: 6rem; -} - -.w-3 { - width: 0.75rem; -} - -.w-3\.5 { - width: 0.875rem; -} - -.w-32 { - width: 8rem; -} - -.w-36 { - width: 9rem; -} - -.w-4 { - width: 1rem; -} - -.w-48 { - width: 12rem; -} - -.w-5 { - width: 1.25rem; -} - -.w-6 { - width: 1.5rem; -} - -.w-64 { - width: 16rem; -} - -.w-8 { - width: 2rem; -} - -.w-96 { - width: 24rem; -} - -.w-auto { - width: auto; -} - -.w-full { - width: 100%; -} - -.w-max { - width: -moz-max-content; - width: max-content; -} - -.w-screen { - width: 100vw; -} - -.min-w-\[700px\] { - min-width: 700px; -} - -.max-w-2xl { - max-width: 42rem; -} - -.max-w-4xl { - max-width: 56rem; -} - -.max-w-6xl { - max-width: 72rem; -} - -.max-w-lg { - max-width: 32rem; -} - -.max-w-md { - max-width: 28rem; -} - -.max-w-screen-2xl { - max-width: 1536px; -} - -.max-w-screen-lg { - max-width: 1024px; -} - -.flex-1 { - flex: 1 1 0%; -} - -.flex-shrink { - flex-shrink: 1; -} - -.flex-shrink-0 { - flex-shrink: 0; -} - -.shrink { - flex-shrink: 1; -} - -.shrink-0 { - flex-shrink: 0; -} - -.flex-grow { - flex-grow: 1; -} - -.basis-1\/4 { - flex-basis: 25%; -} - -.\!translate-y-0 { - --tw-translate-y: 0px !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.\!translate-y-32 { - --tw-translate-y: 8rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.-translate-x-1\/2 { - --tw-translate-x: -50%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.-translate-x-full { - --tw-translate-x: -100%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.-translate-y-1\/2 { - --tw-translate-y: -50%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.-translate-y-full { - --tw-translate-y: -100%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.translate-x-0 { - --tw-translate-x: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.translate-x-full { - --tw-translate-x: 100%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.translate-y-full { - --tw-translate-y: 100%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.rotate-180 { - --tw-rotate: 180deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.transform-none { - transform: none; -} - -@keyframes pulse { - 50% { - opacity: .5; - } -} - -.animate-pulse { - animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -@keyframes shake { - 0% { - transform: translateX(0px); - } - - 12.5% { - transform: translateX(-5px); - } - - 25% { - transform: translateX(0px); - } - - 37.5% { - transform: translateX(5px); - } - - 50% { - transform: translateX(0px); - } - - 62.5% { - transform: translateX(-5px); - } - - 75% { - transform: translateX(5px); - } - - 87.5% { - transform: translateX(5px); - } - - 100% { - transform: translateX(0px); - } -} - -.animate-shake { - animation: shake 0.5s ease-out 1; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.animate-spin { - animation: spin 1s linear infinite; -} - -.cursor-default { - cursor: default; -} - -.cursor-not-allowed { - cursor: not-allowed; -} - -.cursor-pointer { - cursor: pointer; -} - -.resize { - resize: both; -} - -.list-none { - list-style-type: none; -} - -.appearance-none { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.grid-cols-3 { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} - -.grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)); -} - -.grid-cols-7 { - grid-template-columns: repeat(7, minmax(0, 1fr)); -} - -.flex-row { - flex-direction: row; -} - -.flex-row-reverse { - flex-direction: row-reverse; -} - -.flex-col { - flex-direction: column; -} - -.flex-wrap { - flex-wrap: wrap; -} - -.place-items-center { - place-items: center; -} - -.items-start { - align-items: flex-start; -} - -.items-end { - align-items: flex-end; -} - -.items-center { - align-items: center; -} - -.items-baseline { - align-items: baseline; -} - -.items-stretch { - align-items: stretch; -} - -.justify-start { - justify-content: flex-start; -} - -.justify-end { - justify-content: flex-end; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.justify-stretch { - justify-content: stretch; -} - -.justify-items-stretch { - justify-items: stretch; -} - -.gap-1 { - gap: 0.25rem; -} - -.gap-2 { - gap: 0.5rem; -} - -.gap-4 { - gap: 1rem; -} - -.gap-8 { - gap: 2rem; -} - -.gap-x-4 { - -moz-column-gap: 1rem; - column-gap: 1rem; -} - -.-space-x-px > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(-1px * var(--tw-space-x-reverse)); - margin-left: calc(-1px * calc(1 - var(--tw-space-x-reverse))); -} - -.space-x-1 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.25rem * var(--tw-space-x-reverse)); - margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse))); -} - -.space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.5rem * var(--tw-space-x-reverse)); - margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); -} - -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); -} - -.space-y-1 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); -} - -.space-y-1\.5 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.375rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.375rem * var(--tw-space-y-reverse)); -} - -.space-y-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); -} - -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} - -.space-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); -} - -.space-y-6 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); -} - -.divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); -} - -.divide-gray-100 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(243 244 246 / var(--tw-divide-opacity)); -} - -.self-center { - align-self: center; -} - -.self-stretch { - align-self: stretch; -} - -.justify-self-end { - justify-self: end; -} - -.overflow-auto { - overflow: auto; -} - -.overflow-hidden { - overflow: hidden; -} - -.overflow-scroll { - overflow: scroll; -} - -.overflow-x-auto { - overflow-x: auto; -} - -.overflow-y-auto { - overflow-y: auto; -} - -.overflow-y-scroll { - overflow-y: scroll; -} - -.truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.whitespace-nowrap { - white-space: nowrap; -} - -.rounded { - border-radius: 0.25rem; -} - -.rounded-full { - border-radius: 9999px; -} - -.rounded-lg { - border-radius: 0.5rem; -} - -.rounded-md { - border-radius: 0.375rem; -} - -.rounded-l-lg { - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; -} - -.rounded-r-lg { - border-top-right-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; -} - -.rounded-t { - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; -} - -.rounded-t-lg { - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; -} - -.rounded-b-lg { - border-bottom-right-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; -} - -.border { - border-width: 1px; -} - -.border-0 { - border-width: 0px; -} - -.border-2 { - border-width: 2px; -} - -.border-b { - border-bottom-width: 1px; -} - -.border-r { - border-right-width: 1px; -} - -.border-t { - border-top-width: 1px; -} - -.border-dashed { - border-style: dashed; -} - -.border-blue-300 { - --tw-border-opacity: 1; - border-color: rgb(102 196 242 / var(--tw-border-opacity)); -} - -.border-blue-600 { - --tw-border-opacity: 1; - border-color: rgb(0 125 187 / var(--tw-border-opacity)); -} - -.border-blue-700 { - --tw-border-opacity: 1; - border-color: rgb(0 94 140 / var(--tw-border-opacity)); -} - -.border-gray-100 { - --tw-border-opacity: 1; - border-color: rgb(243 244 246 / var(--tw-border-opacity)); -} - -.border-gray-200 { - --tw-border-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-border-opacity)); -} - -.border-gray-300 { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} - -.border-primary-300 { - --tw-border-opacity: 1; - border-color: rgb(175 211 130 / var(--tw-border-opacity)); -} - -.border-red-300 { - --tw-border-opacity: 1; - border-color: rgb(255 104 104 / var(--tw-border-opacity)); -} - -.border-white { - --tw-border-opacity: 1; - border-color: rgb(255 255 255 / var(--tw-border-opacity)); -} - -.bg-blue-100 { - --tw-bg-opacity: 1; - background-color: rgb(204 235 251 / var(--tw-bg-opacity)); -} - -.bg-blue-200 { - --tw-bg-opacity: 1; - background-color: rgb(153 215 247 / var(--tw-bg-opacity)); -} - -.bg-blue-300 { - --tw-bg-opacity: 1; - background-color: rgb(102 196 242 / var(--tw-bg-opacity)); -} - -.bg-blue-400 { - --tw-bg-opacity: 1; - background-color: rgb(51 176 238 / var(--tw-bg-opacity)); -} - -.bg-blue-50 { - --tw-bg-opacity: 1; - background-color: rgb(230 245 253 / var(--tw-bg-opacity)); -} - -.bg-blue-500 { - --tw-bg-opacity: 1; - background-color: rgb(0 156 234 / var(--tw-bg-opacity)); -} - -.bg-blue-600 { - --tw-bg-opacity: 1; - background-color: rgb(0 125 187 / var(--tw-bg-opacity)); -} - -.bg-blue-700 { - --tw-bg-opacity: 1; - background-color: rgb(0 94 140 / var(--tw-bg-opacity)); -} - -.bg-blue-800 { - --tw-bg-opacity: 1; - background-color: rgb(0 62 94 / var(--tw-bg-opacity)); -} - -.bg-gray-100 { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} - -.bg-gray-200 { - --tw-bg-opacity: 1; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)); -} - -.bg-gray-400 { - --tw-bg-opacity: 1; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)); -} - -.bg-gray-50 { - --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)); -} - -.bg-gray-800 { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); -} - -.bg-gray-900 { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); -} - -.bg-green-100 { - --tw-bg-opacity: 1; - background-color: rgb(228 240 213 / var(--tw-bg-opacity)); -} - -.bg-green-200 { - --tw-bg-opacity: 1; - background-color: rgb(201 225 171 / var(--tw-bg-opacity)); -} - -.bg-green-300 { - --tw-bg-opacity: 1; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)); -} - -.bg-green-400 { - --tw-bg-opacity: 1; - background-color: rgb(148 196 88 / var(--tw-bg-opacity)); -} - -.bg-green-500 { - --tw-bg-opacity: 1; - background-color: rgb(121 181 46 / var(--tw-bg-opacity)); -} - -.bg-green-600 { - --tw-bg-opacity: 1; - background-color: rgb(97 145 37 / var(--tw-bg-opacity)); -} - -.bg-green-700 { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); -} - -.bg-green-800 { - --tw-bg-opacity: 1; - background-color: rgb(48 72 18 / var(--tw-bg-opacity)); -} - -.bg-primary-50 { - --tw-bg-opacity: 1; - background-color: rgb(242 248 234 / var(--tw-bg-opacity)); -} - -.bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(255 205 205 / var(--tw-bg-opacity)); -} - -.bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(255 154 154 / var(--tw-bg-opacity)); -} - -.bg-red-300 { - --tw-bg-opacity: 1; - background-color: rgb(255 104 104 / var(--tw-bg-opacity)); -} - -.bg-red-50 { - --tw-bg-opacity: 1; - background-color: rgb(255 230 230 / var(--tw-bg-opacity)); -} - -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - -.bg-white\/50 { - background-color: rgb(255 255 255 / 0.5); -} - -.bg-yellow-100 { - --tw-bg-opacity: 1; - background-color: rgb(253 246 178 / var(--tw-bg-opacity)); -} - -.\!bg-opacity-0 { - --tw-bg-opacity: 0 !important; -} - -.\!bg-opacity-100 { - --tw-bg-opacity: 1 !important; -} - -.\!bg-opacity-50 { - --tw-bg-opacity: 0.5 !important; -} - -.bg-opacity-50 { - --tw-bg-opacity: 0.5; -} - -.p-1 { - padding: 0.25rem; -} - -.p-2 { - padding: 0.5rem; -} - -.p-2\.5 { - padding: 0.625rem; -} - -.p-3 { - padding: 0.75rem; -} - -.p-4 { - padding: 1rem; -} - -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} - -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} - -.px-5 { - padding-left: 1.25rem; - padding-right: 1.25rem; -} - -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} - -.py-0 { - padding-top: 0px; - padding-bottom: 0px; -} - -.py-0\.5 { - padding-top: 0.125rem; - padding-bottom: 0.125rem; -} - -.py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; -} - -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} - -.py-2\.5 { - padding-top: 0.625rem; - padding-bottom: 0.625rem; -} - -.py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; -} - -.py-4 { - padding-top: 1rem; - padding-bottom: 1rem; -} - -.py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; -} - -.pb-2 { - padding-bottom: 0.5rem; -} - -.pb-3 { - padding-bottom: 0.75rem; -} - -.pl-10 { - padding-left: 2.5rem; -} - -.pl-11 { - padding-left: 2.75rem; -} - -.pl-2 { - padding-left: 0.5rem; -} - -.pl-3 { - padding-left: 0.75rem; -} - -.pr-2 { - padding-right: 0.5rem; -} - -.pr-2\.5 { - padding-right: 0.625rem; -} - -.pt-16 { - padding-top: 4rem; -} - -.pt-2 { - padding-top: 0.5rem; -} - -.pt-5 { - padding-top: 1.25rem; -} - -.pt-8 { - padding-top: 2rem; -} - -.text-left { - text-align: left; -} - -.text-center { - text-align: center; -} - -.text-right { - text-align: right; -} - -.align-baseline { - vertical-align: baseline; -} - -.align-top { - vertical-align: top; -} - -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} - -.text-base { - font-size: 1rem; - line-height: 1.5rem; -} - -.text-lg { - font-size: 1.125rem; - line-height: 1.75rem; -} - -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} - -.text-xl { - font-size: 1.25rem; - line-height: 1.75rem; -} - -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - -.font-bold { - font-weight: 700; -} - -.font-medium { - font-weight: 500; -} - -.font-normal { - font-weight: 400; -} - -.font-semibold { - font-weight: 600; -} - -.uppercase { - text-transform: uppercase; -} - -.italic { - font-style: italic; -} - -.leading-6 { - line-height: 1.5rem; -} - -.leading-9 { - line-height: 2.25rem; -} - -.leading-none { - line-height: 1; -} - -.leading-tight { - line-height: 1.25; -} - -.text-black { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); -} - -.text-blue-400 { - --tw-text-opacity: 1; - color: rgb(51 176 238 / var(--tw-text-opacity)); -} - -.text-blue-600 { - --tw-text-opacity: 1; - color: rgb(0 125 187 / var(--tw-text-opacity)); -} - -.text-blue-800 { - --tw-text-opacity: 1; - color: rgb(0 62 94 / var(--tw-text-opacity)); -} - -.text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); -} - -.text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -.text-gray-600 { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); -} - -.text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.text-gray-800 { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - -.text-green-800 { - --tw-text-opacity: 1; - color: rgb(48 72 18 / var(--tw-text-opacity)); -} - -.text-primary-600 { - --tw-text-opacity: 1; - color: rgb(97 145 37 / var(--tw-text-opacity)); -} - -.text-red-500 { - --tw-text-opacity: 1; - color: rgb(255 3 3 / var(--tw-text-opacity)); -} - -.text-red-600 { - --tw-text-opacity: 1; - color: rgb(204 2 2 / var(--tw-text-opacity)); -} - -.text-red-800 { - --tw-text-opacity: 1; - color: rgb(102 1 1 / var(--tw-text-opacity)); -} - -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -.text-yellow-800 { - --tw-text-opacity: 1; - color: rgb(114 59 19 / var(--tw-text-opacity)); -} - -.underline { - text-decoration-line: underline; -} - -.\!opacity-0 { - opacity: 0 !important; -} - -.\!opacity-100 { - opacity: 1 !important; -} - -.opacity-0 { - opacity: 0; -} - -.opacity-100 { - opacity: 1; -} - -.shadow { - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-lg { - --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-sm { - --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-2xl { - --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); - --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.outline { - outline-style: solid; -} - -.outline-0 { - outline-width: 0px; -} - -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.ring-4 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.ring-2 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.ring-1 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.blur { - --tw-blur: blur(8px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} - -.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, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.transition-all { - transition-property: all; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.transition-opacity { - transition-property: opacity; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.transition-transform { - transition-property: transform; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.duration-100 { - transition-duration: 100ms; -} - -.duration-200 { - transition-duration: 200ms; -} - -.duration-300 { - transition-duration: 300ms; -} - -.duration-500 { - transition-duration: 500ms; -} - -.duration-75 { - transition-duration: 75ms; -} - -.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\] { - transition-timing-function: cubic-bezier(.3,2.3,.6,1); -} - -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} - -.ease-out { - transition-timing-function: cubic-bezier(0, 0, 0.2, 1); -} - -.htmx-added .fade-in { - opacity: 0.0 !important; -} - -.htmx-added.fade-in { - opacity: 0.0 !important; -} - -.fade-in { - opacity: 1.0; -} - -.htmx-settling .fade-in-settle { - opacity: 0.0 !important; -} - -.htmx-settling.fade-in-settle { - opacity: 0.0 !important; -} - -.fade-in-settle { - opacity: 1.0; -} - -.htmx-settling .slide-up-settle { - --tw-translate-y: 1.25rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.htmx-settling.slide-up-settle { - --tw-translate-y: 1.25rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.slide-up-settle { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.htmx-added .slide-up { - --tw-translate-y: 1.25rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.hidden .slide-up { - --tw-translate-y: 1.25rem !important; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important; -} - -.slide-up { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.live-added { - animation: pulse-green 300ms 2; - animation-direction: alternate; - animation-timing-function: ease-in-out; -} - -.dark .live-added { - animation: pulse-dark-green 300ms 2 !important; - animation-direction: alternate; - animation-timing-function: ease-in-out; -} - -/* -.live-added { - @apply bg-white; -} -*/ - -@keyframes pulse-green { - 0% { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - - 100% { - --tw-bg-opacity: 1; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)); - } - - :is(.dark 100%) { - --tw-bg-opacity: 1; - background-color: rgb(153 2 2 / var(--tw-bg-opacity)); - } -} - -@keyframes pulse-dark-green { - :is(.dark 0%) { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); - } - - 100% { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); - } -} - -.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { - display: inherit !important; -} - -.htmx-indicator { - display: none; -} - -.htmx-request .htmx-indicator-hidden { - display: none !important; -} - -.htmx-indicator-hidden { - display: inherit; -} - -.htmx-swapping .fade-out { - opacity: 0.0 !important; -} - -.fade-out { - opacity: 1.0; -} - -.min-h-content { - min-height: calc(100vh - 4em); -} - -.choices { - margin-bottom: 0px !important; - border-width: 0px !important; -} - -.choices__list--multiple { -} - -.choices__inner { - display: block !important; - width: 100% !important; - border-radius: 0.5rem !important; - border-width: 1px !important; - --tw-border-opacity: 1 !important; - border-color: rgb(209 213 219 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)) !important; - padding: 0.25rem !important; - font-size: 0.875rem !important; - line-height: 1.25rem !important; - --tw-text-opacity: 1 !important; - color: rgb(17 24 39 / var(--tw-text-opacity)) !important; -} - -.choices__inner:focus { - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -.group.has-error .choices__inner { - --tw-border-opacity: 1 !important; - border-color: rgb(255 3 3 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(255 230 230 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(51 1 1 / var(--tw-text-opacity)) !important; -} - -.group.has-error .choices__inner::-moz-placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(153 2 2 / var(--tw-placeholder-opacity)) !important; -} - -.group.has-error .choices__inner::placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(153 2 2 / var(--tw-placeholder-opacity)) !important; -} - -.group.has-error .choices__inner:focus { - --tw-border-opacity: 1 !important; - border-color: rgb(255 3 3 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(255 3 3 / var(--tw-ring-opacity)) !important; -} - -:is(.dark .choices__inner) { - --tw-border-opacity: 1 !important; - border-color: rgb(75 85 99 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(255 255 255 / var(--tw-text-opacity)) !important; -} - -:is(.dark .choices__inner)::-moz-placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)) !important; -} - -:is(.dark .choices__inner)::placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)) !important; -} - -:is(.dark .choices__inner:focus) { - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -.group.has-error :is(.dark .choices__inner) { - --tw-border-opacity: 1 !important; - border-color: rgb(255 3 3 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(255 3 3 / var(--tw-text-opacity)) !important; -} - -.group.has-error :is(.dark .choices__inner)::-moz-placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(255 3 3 / var(--tw-placeholder-opacity)) !important; -} - -.group.has-error :is(.dark .choices__inner)::placeholder { - --tw-placeholder-opacity: 1 !important; - color: rgb(255 3 3 / var(--tw-placeholder-opacity)) !important; -} - -.choices:focus-within .choices__inner { - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -:is(.dark .choices:focus-within .choices__inner) { - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -.choices:focus-within .choices__inner { - outline: 2px solid transparent !important; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #007dbb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #007dbb; -} - -.choices__inner .choices__input { - margin: 0px !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)) !important; -} - -:is(.dark .choices__inner .choices__input) { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(255 255 255 / var(--tw-text-opacity)) !important; -} - -.choices__inner .choices__item { - white-space: nowrap !important; - border-radius: 0.25rem !important; - --tw-border-opacity: 1 !important; - border-color: rgb(156 163 175 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)) !important; - padding-left: 0.5rem !important; - padding-right: 0.5rem !important; - padding-top: 0.125rem !important; - padding-bottom: 0.125rem !important; - font-size: 0.75rem !important; - line-height: 1rem !important; - font-weight: 500 !important; - --tw-text-opacity: 1 !important; - color: rgb(48 72 18 / var(--tw-text-opacity)) !important; -} - -:is(.dark .choices__inner .choices__item) { - --tw-bg-opacity: 1 !important; - background-color: rgb(24 36 9 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(175 211 130 / var(--tw-text-opacity)) !important; -} - -.choices__list--dropdown { - border-radius: 0.5rem !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)) !important; - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1) !important; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color) !important; - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow) !important; -} - -:is(.dark .choices__list--dropdown) { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; -} - -.choices__list--dropdown .choices__item--selectable.is-highlighted { - --tw-bg-opacity: 1 !important; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(48 72 18 / var(--tw-text-opacity)) !important; -} - -:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted) { - --tw-bg-opacity: 1 !important; - background-color: rgb(24 36 9 / var(--tw-bg-opacity)) !important; - --tw-text-opacity: 1 !important; - color: rgb(175 211 130 / var(--tw-text-opacity)) !important; -} - -.choices[data-type*="select-multiple"] .choices__button { - --tw-border-opacity: 1 !important; - border-color: rgb(107 114 128 / var(--tw-border-opacity)) !important; -} - -.choices[data-type*="select-multiple"] .choices__button:focus { - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -.choices__inner .choices__item:focus-within { - border-color: rgb(107 114 128 / var(--tw-border-opacity)) !important; - --tw-border-opacity: 1 !important; - border-color: rgb(0 156 234 / var(--tw-border-opacity)) !important; - --tw-bg-opacity: 1 !important; - background-color: rgb(121 181 46 / var(--tw-bg-opacity)) !important; - --tw-ring-opacity: 1 !important; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)) !important; -} - -.choices__list--single .choices__item { - display: flex !important; - width: auto !important; -} - -.choices__list--single { - width: auto !important; -} - -.choices__list--single button { - position: relative !important; - margin: 0px !important; - display: block !important; - height: auto !important; -} - -.choices[data-type*="select-one"] .choices__button { - right:auto !important; -} - -.arrow, -.arrow::before { - position: absolute; - width: 24px; - height: 24px; - background: inherit; -} - -.arrow { - visibility: hidden; -} - -.arrow::before { - visibility: visible; - content: ''; - transform: rotate(45deg); -} - -.arrow { - bottom: -4px; -} - -.hover\:scale-105:hover { - --tw-scale-x: 1.05; - --tw-scale-y: 1.05; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.hover\:scale-110:hover { - --tw-scale-x: 1.1; - --tw-scale-y: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.hover\:border-gray-300:hover { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} - -.hover\:bg-blue-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(102 196 242 / var(--tw-bg-opacity)); -} - -.hover\:bg-blue-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(0 125 187 / var(--tw-bg-opacity)); -} - -.hover\:bg-blue-800:hover { - --tw-bg-opacity: 1; - background-color: rgb(0 62 94 / var(--tw-bg-opacity)); -} - -.hover\:bg-gray-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} - -.hover\:bg-gray-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)); -} - -.hover\:bg-green-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(228 240 213 / var(--tw-bg-opacity)); -} - -.hover\:bg-green-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)); -} - -.hover\:bg-green-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(97 145 37 / var(--tw-bg-opacity)); -} - -.hover\:bg-green-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); -} - -.hover\:bg-neutral-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(245 245 245 / var(--tw-bg-opacity)); -} - -.hover\:bg-primary-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(228 240 213 / var(--tw-bg-opacity)); -} - -.hover\:bg-red-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(255 104 104 / var(--tw-bg-opacity)); -} - -.hover\:bg-white:hover { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - -.hover\:text-blue-600:hover { - --tw-text-opacity: 1; - color: rgb(0 125 187 / var(--tw-text-opacity)); -} - -.hover\:text-gray-600:hover { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); -} - -.hover\:text-gray-700:hover { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.hover\:text-gray-800:hover { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.hover\:text-gray-900:hover { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - -.hover\:text-primary-700:hover { - --tw-text-opacity: 1; - color: rgb(73 109 28 / var(--tw-text-opacity)); -} - -.hover\:underline:hover { - text-decoration-line: underline; -} - -.focus\:z-10:focus { - z-index: 10; -} - -.focus\:border-blue-500:focus { - --tw-border-opacity: 1; - border-color: rgb(0 156 234 / var(--tw-border-opacity)); -} - -.focus\:border-primary-500:focus { - --tw-border-opacity: 1; - border-color: rgb(121 181 46 / var(--tw-border-opacity)); -} - -.focus\:bg-neutral-100:focus { - --tw-bg-opacity: 1; - background-color: rgb(245 245 245 / var(--tw-bg-opacity)); -} - -.focus\:text-green-700:focus { - --tw-text-opacity: 1; - color: rgb(73 109 28 / var(--tw-text-opacity)); -} - -.focus\:outline-none:focus { - outline: 2px solid transparent; - outline-offset: 2px; -} - -.focus\:ring-2:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.focus\:ring-4:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.focus\:ring-blue-200:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(153 215 247 / var(--tw-ring-opacity)); -} - -.focus\:ring-blue-300:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(102 196 242 / var(--tw-ring-opacity)); -} - -.focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)); -} - -.focus\:ring-gray-200:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity)); -} - -.focus\:ring-gray-300:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); -} - -.focus\:ring-green-200:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(201 225 171 / var(--tw-ring-opacity)); -} - -.focus\:ring-green-300:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(175 211 130 / var(--tw-ring-opacity)); -} - -.focus\:ring-green-700:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(73 109 28 / var(--tw-ring-opacity)); -} - -.focus\:ring-primary-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity)); -} - -.focus\:ring-red-200:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(255 154 154 / var(--tw-ring-opacity)); -} - -.group:hover .group-hover\:scale-110 { - --tw-scale-x: 1.1; - --tw-scale-y: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - -.group:hover .group-hover\:text-blue-500 { - --tw-text-opacity: 1; - color: rgb(0 156 234 / var(--tw-text-opacity)); -} - -.group:hover .group-hover\:text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:border-red-500 { - --tw-border-opacity: 1; - border-color: rgb(255 3 3 / var(--tw-border-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:bg-red-50 { - --tw-bg-opacity: 1; - background-color: rgb(255 230 230 / var(--tw-bg-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:text-red-900 { - --tw-text-opacity: 1; - color: rgb(51 1 1 / var(--tw-text-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(153 2 2 / var(--tw-placeholder-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(153 2 2 / var(--tw-placeholder-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus { - --tw-border-opacity: 1; - border-color: rgb(255 3 3 / var(--tw-border-opacity)); -} - -.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(255 3 3 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:block) { - display: block; -} - -:is(.dark .dark\:hidden) { - display: none; -} - -:is(.dark .dark\:divide-gray-600) > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-divide-opacity)); -} - -:is(.dark .dark\:border-blue-500) { - --tw-border-opacity: 1; - border-color: rgb(0 156 234 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:border-gray-500) { - --tw-border-opacity: 1; - border-color: rgb(107 114 128 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:border-gray-600) { - --tw-border-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:border-gray-700) { - --tw-border-opacity: 1; - border-color: rgb(55 65 81 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:border-gray-900) { - --tw-border-opacity: 1; - border-color: rgb(17 24 39 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:border-transparent) { - border-color: transparent; -} - -:is(.dark .dark\:bg-blue-600) { - --tw-bg-opacity: 1; - background-color: rgb(0 125 187 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-blue-700) { - --tw-bg-opacity: 1; - background-color: rgb(0 94 140 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-blue-900) { - --tw-bg-opacity: 1; - background-color: rgb(0 31 47 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-gray-600) { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-gray-700) { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-gray-800) { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-gray-800\/50) { - background-color: rgb(31 41 55 / 0.5); -} - -:is(.dark .dark\:bg-gray-900) { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-green-600) { - --tw-bg-opacity: 1; - background-color: rgb(97 145 37 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-green-700) { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-green-900) { - --tw-bg-opacity: 1; - background-color: rgb(24 36 9 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-red-700) { - --tw-bg-opacity: 1; - background-color: rgb(153 2 2 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-red-900) { - --tw-bg-opacity: 1; - background-color: rgb(51 1 1 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-yellow-900) { - --tw-bg-opacity: 1; - background-color: rgb(99 49 18 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:bg-opacity-80) { - --tw-bg-opacity: 0.8; -} - -:is(.dark .dark\:text-blue-200) { - --tw-text-opacity: 1; - color: rgb(153 215 247 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-blue-300) { - --tw-text-opacity: 1; - color: rgb(102 196 242 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-blue-400) { - --tw-text-opacity: 1; - color: rgb(51 176 238 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-blue-500) { - --tw-text-opacity: 1; - color: rgb(0 156 234 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-100) { - --tw-text-opacity: 1; - color: rgb(243 244 246 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-200) { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-300) { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-400) { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-50) { - --tw-text-opacity: 1; - color: rgb(249 250 251 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-gray-500) { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-green-300) { - --tw-text-opacity: 1; - color: rgb(175 211 130 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-red-300) { - --tw-text-opacity: 1; - color: rgb(255 104 104 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-red-400) { - --tw-text-opacity: 1; - color: rgb(255 53 53 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-red-500) { - --tw-text-opacity: 1; - color: rgb(255 3 3 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-white) { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:text-yellow-300) { - --tw-text-opacity: 1; - color: rgb(250 202 21 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); -} - -:is(.dark .dark\:placeholder-gray-400)::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); -} - -:is(.dark .dark\:ring-offset-gray-700) { - --tw-ring-offset-color: #374151; -} - -:is(.dark .dark\:ring-offset-gray-800) { - --tw-ring-offset-color: #1F2937; -} - -:is(.dark .dark\:hover\:bg-blue-600:hover) { - --tw-bg-opacity: 1; - background-color: rgb(0 125 187 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-blue-700:hover) { - --tw-bg-opacity: 1; - background-color: rgb(0 94 140 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-gray-600:hover) { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-gray-700:hover) { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-gray-800:hover) { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-green-600:hover) { - --tw-bg-opacity: 1; - background-color: rgb(97 145 37 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-green-700:hover) { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:bg-red-600:hover) { - --tw-bg-opacity: 1; - background-color: rgb(204 2 2 / var(--tw-bg-opacity)); -} - -:is(.dark .dark\:hover\:text-blue-500:hover) { - --tw-text-opacity: 1; - color: rgb(0 156 234 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:hover\:text-gray-100:hover) { - --tw-text-opacity: 1; - color: rgb(243 244 246 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:hover\:text-gray-300:hover) { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:hover\:text-white:hover) { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:focus\:border-blue-500:focus) { - --tw-border-opacity: 1; - border-color: rgb(0 156 234 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:focus\:border-primary-500:focus) { - --tw-border-opacity: 1; - border-color: rgb(121 181 46 / var(--tw-border-opacity)); -} - -:is(.dark .dark\:focus\:text-white:focus) { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -:is(.dark .dark\:focus\:ring-blue-500:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(0 156 234 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-blue-600:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(0 125 187 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-blue-800:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(0 62 94 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-gray-600:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-green-500:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-green-800:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(48 72 18 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-primary-500:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-primary-600:focus) { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(97 145 37 / var(--tw-ring-opacity)); -} - -:is(.dark .dark\:focus\:ring-offset-gray-700:focus) { - --tw-ring-offset-color: #374151; -} - -:is(.dark .group:hover .dark\:group-hover\:text-white) { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500) { - --tw-border-opacity: 1; - border-color: rgb(255 3 3 / var(--tw-border-opacity)); -} - -.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700) { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); -} - -.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500) { - --tw-text-opacity: 1; - color: rgb(255 3 3 / var(--tw-text-opacity)); -} - -.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(255 3 3 / var(--tw-placeholder-opacity)); -} - -.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(255 3 3 / var(--tw-placeholder-opacity)); -} - -@media (min-width: 640px) { - .sm\:block { - display: block; - } - - .sm\:rounded-lg { - border-radius: 0.5rem; - } - - .sm\:p-6 { - padding: 1.5rem; - } - - .sm\:py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; - } - - .sm\:text-sm { - font-size: 0.875rem; - line-height: 1.25rem; - } -} - -@media (min-width: 768px) { - .md\:ml-2 { - margin-left: 0.5rem; - } - - .md\:mr-24 { - margin-right: 6rem; - } - - .md\:table-cell { - display: table-cell; - } - - .md\:flex-row { - flex-direction: row; - } - - .md\:items-center { - align-items: center; - } - - .md\:justify-center { - justify-content: center; - } - - .md\:space-x-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.75rem * var(--tw-space-x-reverse)); - margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); - } - - .md\:space-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0px * var(--tw-space-y-reverse)); - } - - .md\:p-12 { - padding: 3rem; - } -} - -@media (min-width: 1024px) { - .lg\:block { - display: block; - } - - .lg\:flex { - display: flex; - } - - .lg\:table-cell { - display: table-cell; - } - - .lg\:hidden { - display: none; - } - - .lg\:w-96 { - width: 24rem; - } - - .lg\:translate-x-0 { - --tw-translate-x: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - - .lg\:flex-row { - flex-direction: row; - } - - .lg\:items-center { - align-items: center; - } - - .lg\:justify-end { - justify-content: flex-end; - } - - .lg\:justify-between { - justify-content: space-between; - } - - .lg\:space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - } - - .lg\:space-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0px * var(--tw-space-y-reverse)); - } - - .lg\:px-5 { - padding-left: 1.25rem; - padding-right: 1.25rem; - } - - .lg\:pl-3 { - padding-left: 0.75rem; - } - - .lg\:pl-64 { - padding-left: 16rem; - } -} - -.\[\&\.active\]\:bg-primary-300.active { - --tw-bg-opacity: 1; - background-color: rgb(175 211 130 / var(--tw-bg-opacity)); -} - -.\[\&\.active\]\:bg-primary-500.active { - --tw-bg-opacity: 1; - background-color: rgb(121 181 46 / var(--tw-bg-opacity)); -} - -:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active { - --tw-bg-opacity: 1; - background-color: rgb(73 109 28 / var(--tw-bg-opacity)); -} +/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index 58f4bb47..ec1ecdfc 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -2,24 +2,28 @@ (:require [amazonica.aws.ecs :as ecs] [auto-ap.logging :as alog] + [clojure.string :as str] [auto-ap.routes.utils :refer [wrap-admin wrap-client-redirect-unauthenticated]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers + entity-id + form-validation-error html-response - validation-error - wrap-form-4xx + modal-response + wrap-form-4xx-2 wrap-schema-decode]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as coerce] [clj-time.core :as time] - [clojure.string :as str] - [config.core :refer [env]]) + [malli.core :as mc] + [auto-ap.ssr.hx :as hx]) (:import (com.amazonaws.services.ecs.model AssignPublicIp))) @@ -57,8 +61,8 @@ false)) (defn ecs-task->job [task] - - {:status (condp = (:last-status task) + {:arn (:task-arn task) + :status (condp = (:last-status task) "RUNNING" :running "PENDING" :pending "PROVISIONING" :pending @@ -78,13 +82,11 @@ (def grid-page (helper/build {:id "job-table" + :id-fn :arn :nav (com/admin-aside-nav) :fetch-page fetch-page :action-buttons (fn [request] - [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes - :admin-job-start-dialog)) - :hx-target "#modal-holder" - :hx-swap "outerHTML" + [(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-job-start-dialog)) :color :primary} "Run job")]) :breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes @@ -151,86 +153,119 @@ (str "_" (:dd-env env))) (dissoc form-params :name))] {:message (str "task " (str new-job) " started.")}) - (validation-error "This job is already running"))) + (form-validation-error "This job is already running" + :form form-params))) -(defn subform [{{:strs [name]} :query-params }] - (html-response (cond (= "bulk-journal-import" name) - [:div (com/field {:label "Url"} - [:div.flex.place-items-center.gap-2 - [:pre.text-xs.mr-1 "s3://data.prod.app.integreatconsult.com/bulk-import/"] - (com/text-input {:placeholder "ledger-data.csv" - :name "ledger-url"} )])] - (= "register-invoice-import" name) - [:div (com/field {:label "Url"} +(defn subform* [{:keys [name]}] + (into [:div {:class "fade-in-settle transition"}] + (cond (= "bulk-journal-import" name) + [(fc/with-field :ledger-url + (com/validated-field {:label "Url" + :errors (fc/field-errors)} + [:div.flex.place-items-center.gap-2 + [:pre.text-xs.mr-1 "s3://data.prod.app.integreatconsult.com/bulk-import/"] + (com/text-input {:placeholder "ledger-data.csv" + :name (fc/field-name) + :value (fc/field-value)} )]))] + (= "register-invoice-import" name) + [ + (fc/with-field :invoice-url + (com/validated-field {:label "Url" + :errors (fc/field-errors)} [:div.flex.place-items-center.gap-2 [:pre.text-xs.mr-1 "s3://data.prod.app.integreatconsult.com/bulk-import/"] (com/text-input {:placeholder "invoice-data.csv" - :name "invoice-url"} )])] - (= "load-historical-sales" name) - [:div - (com/field {:label "Client"} - (com/typeahead {:name "client" - :placeholder "Search..." - :url (bidi/path-for ssr-routes/only-routes - :company-search) - :id (str "client-search")})) - (com/field {:label "Days to load"} - (com/text-input {:placeholder "60" - :name "days"} ))] - :else [:div])) + :name (fc/field-name) + :value (fc/field-value)} )]))] + (= "load-historical-sales" name) + [ + (fc/with-field :client + (com/validated-field {:label "Client" + :errors (fc/field-errors)} + (com/typeahead-2 {:name (fc/field-name) + :value (fc/field-value) + :placeholder "Search..." + :url (bidi/path-for ssr-routes/only-routes + :company-search)}))) + (fc/with-field :days + (com/validated-field {:label "Days to load" + :errors (fc/field-errors)} + (com/text-input {:placeholder "60" + :name (fc/field-name) + :value (fc/field-value)} )))] + :else nil)) + ) -(defn job-start-dialog [_] - (html-response (com/modal - {:modal-class "max-w-4xl"} - [:form {:hx-ext "response-targets" - :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start - ) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - [:fieldset {:class "hx-disable"} - (com/modal-card - {} - [:div.flex [:div.p-2 "New job"] ] - [:div.space-y-6 +(defn subform [{{:keys [name]} :query-params }] + (html-response + (fc/start-form {} nil + (subform* {:name name})))) - (com/field {:label "Job"} - (com/select {:name "name" - :class "w-64" - :options [["" ""] - ["yodlee2" "Yodlee Import"] - ["yodlee2-accounts" "Yodlee Account Import"] - ["intuit" "Intuit import"] - ["plaid" "Plaid import"] - ["bulk-journal-import" "Bulk Journal Import"] - ["square2-import-job" "Square2 Import"] - ["register-invoice-import" "Register Invoice Import "] - ["ezcater-upsert" "Upsert recent ezcater orders"] - ["load-historical-sales" "Load Historical Square Sales"] - ["export-backup" "Export Backup"]] - :hx-get (bidi/path-for ssr-routes/only-routes - :admin-job-subform) - :hx-target "#sub-form" - :hx-swap "innerHTML"})) +(defn job-start-dialog [{:keys [form-errors form-params] :as request}] + (fc/start-form (or form-params {}) form-errors + (modal-response + (com/modal ;; TODO we need a cleaner way to have forms that wrap the whole. In this cas + {} + [:form {:hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start) + :class "h-full w-full" + "x-on:htmx:response-error" "unexpectedError=true" + "x-on:htmx:before-request" "unexpectedError=false" + :x-data (hx/json {:unexpectedError false})} + [:fieldset {:class "hx-disable h-full w-full"} + (com/modal-card {} + [:div.m-2 "New job"] + [:div.space-y-6 - [:div#sub-form] - [:div#form-errors [:span.error-content]] - (com/button {:color :primary :form "edit-form" :type "submit"} - "Run")] - [:div])]]))) + (fc/with-field :name + (com/validated-field {:label "Job" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :value (fc/field-value) + :class "w-64" + :options [["" ""] + ["yodlee2" "Yodlee Import"] + ["yodlee2-accounts" "Yodlee Account Import"] + ["intuit" "Intuit import"] + ["plaid" "Plaid import"] + ["bulk-journal-import" "Bulk Journal Import"] + ["square2-import-job" "Square2 Import"] + ["register-invoice-import" "Register Invoice Import "] + ["ezcater-upsert" "Upsert recent ezcater orders"] + ["load-historical-sales" "Load Historical Square Sales"] + ["export-backup" "Export Backup"]] + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-job-subform) + :hx-target "#sub-form" + :hx-swap "innerHTML"}))) + + [:div#sub-form (subform* {:name (fc/with-field :name (fc/field-value))}) ]] + [:div + [:div#5xx-error.bg-red-100.mb-2.p-1 {:x-show "unexpectedError"} + "An unexpected error has occured."] + (com/form-errors {:errors (:errors fc/*form-errors*)}) + (com/validated-save-button {:errors form-errors} "Run job")])]])))) + +(def form-schema (mc/schema [:map + [:name [:string {:min 1}]] + [:ledger-url {:optional true} [:string {:min 1}]] + [:invoice-url {:optional true} [:string {:min 1}]] + [:client {:optional true} entity-id] + [:days {:optional true} [:int {:min 1 :max 120}]] + ])) (def key->handler (apply-middleware-to-all-handlers (->> - {:admin-jobs (helper/page-route grid-page) - :admin-job-table (helper/table-route grid-page) - :admin-job-subform (-> subform (wrap-schema-decode :query-schema [:map [:name :string]])) - :admin-job-start (-> job-start - (wrap-schema-decode :form-schema [:map [:name :string]]) - (wrap-nested-form-params) - (wrap-form-4xx)) - :admin-job-start-dialog job-start-dialog}) + {:admin-jobs (helper/page-route grid-page) + :admin-job-table (helper/table-route grid-page) + :admin-job-subform (-> subform (wrap-schema-decode :query-schema [:map [:name {:optional true} [:maybe :string]]])) + :admin-job-start (-> job-start + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 job-start-dialog)) + :admin-job-start-dialog job-start-dialog}) (fn [h] (-> h (wrap-admin) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 3d0deb2d..87e02b7f 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -397,10 +397,9 @@ :hx-target "this"} [:form {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" :hx-target-400 "#form-errors .error-content" :x-trap "true" - :class "group/form w-full h-full" + :class "w-full h-full" (if (:db/id entity) :hx-put :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} @@ -556,7 +555,7 @@ ]] [:div (com/form-errors {:errors (:errors fc/*form-errors*)}) - (com/validated-save-button {:errors (:errors form-errors)} "Save rule")])]))) + (com/validated-save-button {:errors form-errors} "Save rule")])]))) (defn new-account [{{:keys [client-id index]} :query-params}] diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index 0a5f7474..e6fc4e47 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -1,7 +1,6 @@ (ns auto-ap.ssr.components.dialog - (:require [hiccup2.core :as hiccup] - [auto-ap.ssr.hx :as hx] - [auto-ap.ssr.hiccup-helper :as hh])) + (:require + [auto-ap.ssr.hiccup-helper :as hh])) (defn modal- [params & children] [:div (-> params @@ -12,7 +11,8 @@ (defn modal-card- [params header content footer] [:div#modal-card (update params :class (fn [c] (-> c - (or "w-full p-4 h-full") + (or "") + (hh/add-class "w-full p-4 h-full") ))) [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col h-full"} [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"} header] @@ -22,4 +22,3 @@ content] (when footer [:div {:class "p-4 shrink-0"} footer])]]) -;; fade-in-settle slide-up-settle duration-300 transition-all diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index aba64d7b..acc46704 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -84,7 +84,7 @@ c.clearChoices(); :popper nil}) :x-modelable "value.value" :x-model (:x-model params) - :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [0, 20]}}})" + :x-init "popper = Popper.createPopper($refs.input, $refs.dropdown, {placement: 'bottom-start', strategy: 'fixed', modifiers: {name: 'offset', options: {offset: [0, 10]}}})" } [:a {:class (-> (hh/add-class (or (:class params) "") default-input-classes) (hh/add-class "cursor-pointer")) @@ -117,11 +117,11 @@ c.clearChoices(); "x-ref" "dropdown" "@keydown.escape" "open = false; value = {value: '', label: '' }" "x-transition:enter" "ease-[cubic-bezier(.3,2.3,.6,1)] duration-200" - "x-transition:enter-start" "!opacity-0 !mt-0" - "x-transition:enter-end" "!opacity-1 !mt-1" + "x-transition:enter-start" "!opacity-0" + "x-transition:enter-end" "!opacity-1" "x-transition:leave" "ease-out duration-200" - "x-transition:leave-start" "!opacity-1 !mt-1" - "x-transition:leave-end" "!opacity-0 !mt-0" + "x-transition:leave-start" "!opacity-1" + "x-transition:leave-end" "!opacity-0" "x-show " "open" "x-trap" "open" "@click.outside" "open=false;"} diff --git a/src/clj/auto_ap/ssr/components/navbar.clj b/src/clj/auto_ap/ssr/components/navbar.clj index e08d9c73..0c66b351 100644 --- a/src/clj/auto_ap/ssr/components/navbar.clj +++ b/src/clj/auto_ap/ssr/components/navbar.clj @@ -24,10 +24,7 @@ (when (is-admin? identity) [:button.mt-1.lg:w-96.relative.hidden.lg:block {:class "bg-gray-50 hover:bg-gray-200 dark:hover:bg-gray-700 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 w-full pl-10 py-4 pr-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 gap-4 " - :hx-get (bidi/path-for ssr-routes/only-routes - :search) - :hx-target "#modal-holder" - :hx-swap "outerHTML"} + :hx-get (bidi/path-for ssr-routes/only-routes :search)} [:div {:class "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-gray-500"} [:div.w-4.h-4 svg/search] [:span.ml-2 "Search"]]]) diff --git a/src/clj/auto_ap/ssr/components/page.clj b/src/clj/auto_ap/ssr/components/page.clj index 7afa7c3a..dc7840ec 100644 --- a/src/clj/auto_ap/ssr/components/page.clj +++ b/src/clj/auto_ap/ssr/components/page.clj @@ -49,4 +49,5 @@ (into [:div.p-4] children)]] + ]) diff --git a/src/clj/auto_ap/ssr/search.clj b/src/clj/auto_ap/ssr/search.clj index 45cbee37..045e68cf 100644 --- a/src/clj/auto_ap/ssr/search.clj +++ b/src/clj/auto_ap/ssr/search.clj @@ -2,7 +2,7 @@ (:require [auto-ap.graphql.utils :refer [can-see-client?]] [auto-ap.solr :as solr] - [auto-ap.ssr.utils :refer [html-response]] + [auto-ap.ssr.utils :refer [html-response modal-response]] [auto-ap.time :as atime] [clojure.string :as str] [com.brunobonacci.mulog :as mu] @@ -130,11 +130,11 @@ :form (:form-params request)) (if-let [q (get (:form-params request) "q")] (html-response (search-results* q (:identity request))) - (html-response + (modal-response (com/modal {} - (com/modal-card {} + (com/modal-card {:class "w-full h-full"} [:div.p-2 "Search"] - [:div#search.overflow-auto.space-y-6.p-2.h-96 + [:div#search.overflow-auto.space-y-6.p-2.w-full (com/text-input {:id "search-input" :type "search" diff --git a/src/clj/auto_ap/ssr/transaction/insights.clj b/src/clj/auto_ap/ssr/transaction/insights.clj index 78eb6ef9..dc1920da 100644 --- a/src/clj/auto_ap/ssr/transaction/insights.clj +++ b/src/clj/auto_ap/ssr/transaction/insights.clj @@ -1,21 +1,21 @@ (ns auto-ap.ssr.transaction.insights (:require [auto-ap.client-routes :as client-routes] - [auto-ap.datomic :refer [conn pull-attr visible-clients]] + [auto-ap.datomic :refer [conn visible-clients]] [auto-ap.rule-matching :refer [spread-cents]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.ui :refer [base-page]] - [auto-ap.ssr.utils :refer [html-response]] + [auto-ap.ssr.utils :refer [html-response modal-response]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [cemerick.url :as url] [clj-http.client :as http] [clj-time.coerce :as coerce] [datomic.api :as dc] - [iol-ion.tx :refer [random-tempid]] - [hiccup2.core :as hiccup])) + [hiccup2.core :as hiccup] + [iol-ion.tx :refer [random-tempid]])) (def pull-expr [:transaction/description-original :db/id @@ -238,7 +238,7 @@ pull-expr (Long/parseLong transaction-id)) similar (pinecone-similarity-list transaction-id)] - (html-response + (modal-response (com/modal {} (com/modal-card {:style {:width "900px"}} [:div.flex [:div.p-2 "Similar Transactions"]] diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 27685076..1e17b887 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -322,7 +322,9 @@ (defn path->name2 [k & rest] (let [k->n (fn [k] (if (keyword? k) - (str (namespace k) "/" (name k)) + (str (when (namespace k) + (str (namespace k) "/")) + (name k)) k))] (str (k->n k) (str/join "" From 351864da1bf8ee3cadb8341d289a7008a15fac01 Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 25 Oct 2023 15:47:27 -0700 Subject: [PATCH 30/34] transaction insights dialog. --- resources/public/output.css | 2 +- src/clj/auto_ap/ssr/transaction/insights.clj | 76 +++++++++++--------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 60da88b9..1b73f9c7 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1 +1 @@ -/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file +/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/transaction/insights.clj b/src/clj/auto_ap/ssr/transaction/insights.clj index dc1920da..3515306f 100644 --- a/src/clj/auto_ap/ssr/transaction/insights.clj +++ b/src/clj/auto_ap/ssr/transaction/insights.clj @@ -55,7 +55,7 @@ [(>= ?d ?starting)]] :args [(dc/db conn) - (iol-ion.query/recent-date 120) + (iol-ion.query/recent-date 300) (map :db/id clients) pull-expr]}) @@ -234,43 +234,49 @@ :hide-actions? true "_" (hiccup/raw "init transition opacity to 0 over 500ms then remove me"))))) (defn explain [{:keys [identity session] {:keys [transaction-id]} :route-params}] - (let [r (dc/pull (dc/db conn) + (let [r (dc/pull (dc/db conn) pull-expr (Long/parseLong transaction-id)) - similar (pinecone-similarity-list transaction-id)] + similar (pinecone-similarity-list transaction-id)] (modal-response - (com/modal {} - (com/modal-card {:style {:width "900px"}} - [:div.flex [:div.p-2 "Similar Transactions"]] - [:table.w-full - [:thead - [:tr - [:td "Date"] - [:td "Description"] - [:td "Amount"] - [:td "Vendor"] - [:td "Account"] - [:td "Score"]]] - [:tbody - [:tr - [:th.text-left (some-> r :transaction/date coerce/to-date-time (atime/unparse-local atime/normal-date))] - [:th.text-left (-> r :transaction/description-original)] - [:th.text-left (if (> (-> r :transaction/amount) 0.0) - [:div.tag.is-success.is-light (str "$" (Math/round (:transaction/amount r)))] - [:div.tag.is-danger.is-light (str "$" (Math/round (:transaction/amount r)))])] - [:th] - [:th] - [:th.text-left]] - (take 10 - (for [{:keys [amount date description vendor-name numeric-code score]} similar] - [:tr - [:td (subs date 0 10)] - [:td description] - [:td (some->> amount double (format "$%.2f"))] - [:td vendor-name] - [:td numeric-code] - [:td (format "%.1f%%" (* 100 (double score)))]]))]] - [:div]))))) + (com/modal {} + (com/modal-card {:style {:width "900px"}} + [:div.flex [:div.p-2 "Similar Transactions"]] + (com/data-grid {:headers [(com/data-grid-header {:name "Date" + :key "date"}) + (com/data-grid-header {:name "Description" + :key "description"}) + (com/data-grid-header {:name "Amount" + :key "amount"}) + (com/data-grid-header {:name "Vendor" + :key "vendor"}) + (com/data-grid-header {:name "Account" + :key "account"}) + (com/data-grid-header {:name "Score" + :key "score"})]} + + (com/data-grid-row {:class "bg-primary-200"} + (com/data-grid-cell {:class "text-left font-bold"} (some-> r :transaction/date coerce/to-date-time (atime/unparse-local atime/normal-date))) + (com/data-grid-cell {:class "text-left font-bold"} (-> r :transaction/description-original) ) + (com/data-grid-cell {:class "font-bold"} (if (> (-> r :transaction/amount) 0.0) + [:div.tag.is-success.is-light (str "$" (Math/round (:transaction/amount r)))] + [:div.tag.is-danger.is-light (str "$" (Math/round (:transaction/amount r)))])) + (com/data-grid-cell {}) + (com/data-grid-cell {}) + (com/data-grid-cell {})) + + (com/data-grid-row {} + (take 10 + (for [{:keys [amount date description vendor-name numeric-code score]} similar] + (com/data-grid-row + {} + (com/data-grid-cell {:class "text-left"} (subs date 0 10)) + (com/data-grid-cell {:class "text-left"} description ) + (com/data-grid-cell {} (some->> amount double (format "$%.2f"))) + (com/data-grid-cell {} vendor-name) + (com/data-grid-cell {} numeric-code) + (com/data-grid-cell {} (format "%.1f%%" (* 100 (double score))))))))) + [:div]))))) (defn transaction-rows* [{:keys [clients identity after]}] (let [recommendations (transaction-recommendations identity clients :after after)] From 8c3d792b28a2468fd29456f51cc8cb50c8a718b1 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 26 Oct 2023 11:04:44 -0700 Subject: [PATCH 31/34] company 1099 works --- resources/public/output.css | 2 +- src/clj/auto_ap/ssr/company/company_1099.clj | 330 ++++++++++++------- src/clj/auto_ap/ssr/components/aside.clj | 174 +++------- src/clj/auto_ap/ssr/components/navbar.clj | 3 +- src/clj/auto_ap/ssr/components/page.clj | 20 +- src/clj/auto_ap/ssr/core.clj | 5 +- src/clj/auto_ap/ssr/form_cursor.clj | 9 + src/clj/auto_ap/ssr/utils.clj | 17 +- 8 files changed, 279 insertions(+), 281 deletions(-) diff --git a/resources/public/output.css b/resources/public/output.css index 1b73f9c7..6bb05656 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1 +1 @@ -/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file +/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.w-72{width:18rem}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.-translate-x-0,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-0{--tw-translate-x:-0px}.rotate-180{--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(255 3 3/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/company/company_1099.clj b/src/clj/auto_ap/ssr/company/company_1099.clj index f994d169..fdbb27bb 100644 --- a/src/clj/auto_ap/ssr/company/company_1099.clj +++ b/src/clj/auto_ap/ssr/company/company_1099.clj @@ -1,17 +1,32 @@ (ns auto-ap.ssr.company.company-1099 (:require - [auto-ap.datomic :refer [apply-pagination-raw conn remove-nils]] - [auto-ap.graphql.utils - :refer [assert-can-see-client extract-client-ids is-admin?]] + [auto-ap.datomic :refer [apply-pagination-raw conn]] + [auto-ap.graphql.utils :refer [assert-can-see-client]] + [auto-ap.routes.utils + :refer [wrap-client-redirect-unauthenticated wrap-secure]] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] + [auto-ap.ssr.form-cursor :as fc] [auto-ap.ssr.grid-page-helper :as helper] + [auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]] [auto-ap.ssr.svg :as svg] - [auto-ap.ssr.utils :refer [form-data->map html-response path->name]] + [auto-ap.ssr.utils + :refer [apply-middleware-to-all-handlers + entity-id + html-response + main-transformer + modal-response + ref->enum-schema + ref->select-options + strip + wrap-entity + wrap-form-4xx-2 + wrap-schema-decode]] [bidi.bidi :as bidi] - [cemerick.url :as url] [clojure.string :as str] - [datomic.api :as dc])) + [datomic.api :as dc] + [hiccup.util :refer [url]] + [malli.core :as mc])) (def vendor-read '[:db/id :vendor/name @@ -74,7 +89,7 @@ (def grid-page (helper/build - {:id "vendor-table" + {:id "entity-table" :nav (com/company-aside-nav) :id-fn (comp :db/id second) :fetch-page fetch-page @@ -89,14 +104,10 @@ :entity-name "Vendors" :route :company-1099-vendor-table :row-buttons (fn [request e] - [(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes + [(com/icon-button {:hx-get (url (bidi/path-for ssr-routes/only-routes :company-1099-vendor-dialog :vendor-id (:db/id (second e))) - "?" - (url/map->query {:client-id (:db/id (first e))})) - :hx-ext "debug" - :hx-target "#modal-holder" - :hx-swap "outerHTML"} + {:client-id (:db/id (first e))})} svg/pencil)]) :headers [{:key "Client" :name "Client" @@ -161,117 +172,200 @@ (def table* (partial helper/table* grid-page)) (def row* (partial helper/row* grid-page)) -(defn vendor-save [{:keys [form-params identity route-params query-params] :as request}] - (let [client-id (Long/parseLong (get query-params "client-id")) - vendor-id (Long/parseLong (:vendor-id route-params))] - (assert-can-see-client identity client-id) - @(dc/transact conn [(remove-nils - (-> (form-data->map form-params) - (assoc :db/id (Long/parseLong (:vendor-id route-params))) - (update :vendor/legal-entity-1099-type #(some->> % not-empty (keyword "legal-entity-1099-type"))) - (update :vendor/legal-entity-tin-type #(some->> % not-empty (keyword "legal-entity-tin-type")))))]) - (html-response +(defn vendor-save [{:keys [form-params identity route-params query-params request-method] :as request + {:keys [vendor-id]} :route-params + {:keys [client-id]} :query-params}] - (row* identity [(dc/pull (dc/db conn) [:db/id :client/code] client-id) - (dc/pull (dc/db conn) vendor-read vendor-id) - (sum-for-client-vendor client-id vendor-id) - ] {:flash? true}) - :headers {"hx-trigger" "closeModal"}))) + (assert-can-see-client identity client-id) + @(dc/transact conn [[:upsert-entity (assoc form-params :db/id (:vendor-id route-params))]]) + (html-response -(defn vendor-dialog [request] - (let [vendor (dc/pull (dc/db conn) '[* {:vendor/legal-entity-1099-type [:db/ident] - :vendor/legal-entity-tin-type [:db/ident]}] (Long/parseLong (:vendor-id (:params request))))] ;; TODO perms - (html-response + (row* identity [(dc/pull (dc/db conn) [:db/id :client/code] client-id) + (dc/pull (dc/db conn) vendor-read vendor-id) + (sum-for-client-vendor client-id vendor-id) + ] {:flash? true}) + :headers {"hx-trigger" "modalclose" + "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" vendor-id)})) + +(def default-vendor-read '[* {[:vendor/legal-entity-1099-type :xform iol-ion.query/ident] [:db/ident] + [:vendor/legal-entity-tin-type :xform iol-ion.query/ident] [:db/ident]}]) + + +(def form-schema (mc/schema [:map + [:vendor/address {:default {} } + [:maybe + [:map + [:db/id {:optional true} [:maybe entity-id]] + [:address/street1 {:optional true} [:maybe [:string {:decode/string strip}]]] + [:address/street2 {:optional true} [:maybe [:string {:decode/string strip}]]] + [:address/city {:optional true} [:maybe [:string {:decode/string strip}]]] + [:address/state {:optional true} [:maybe [:string {:decode/string strip}]]] + [:address/zip {:optional true} [:maybe [:re { :error/message "invalid zip" + :decode/string strip} #"^(\d{5}|)$"]]]]]] + [:vendor/legal-entity-name {:optional true} [:maybe [:string {:decode/string strip}]]] + [:vendor/legal-entity-first-name {:optional true} [:maybe [:string {:decode/string strip}]]] + [:vendor/legal-entity-middle-name {:optional true} [:maybe [:string {:decode/string strip}]]] + [:vendor/legal-entity-last-name {:optional true} [:maybe [:string {:decode/string strip}]]] + [:vendor/legal-entity-tin {:optional true} [:maybe [:string {:decode/string strip}]]] + [:vendor/legal-entity-tin-type {:optional true} [:maybe (ref->enum-schema "legal-entity-tin-type")]] + [:vendor/legal-entity-1099-type {:optional true} [:maybe (ref->enum-schema "legal-entity-1099-type")]]])) + +(defn vendor-dialog [{{:keys [client-id]} :query-params {:keys [vendor-id]} :route-params :keys [entity form-params form-errors]}] + (fc/start-form (or (when (seq form-params) + form-params) + (when entity + (mc/decode form-schema entity main-transformer)) + {}) + form-errors + (modal-response (com/modal {} - [:form {:hx-post (str (bidi/path-for ssr-routes/only-routes - :company-1099-vendor-save - :request-method :post - :vendor-id (Long/parseLong (:vendor-id (:params request)))) - "?" - (url/map->query {:client-id (:client-id (:params request))})) - :hx-target (format "#vendor-table tr[data-id=\"%d\"]" (:db/id vendor)) - :hx-swap "outerHTML swap:300ms"} - [:fieldset {:class "hx-disable"} + [:form {:hx-post (url (bidi/path-for ssr-routes/only-routes + :company-1099-vendor-save + :request-method :post + :vendor-id vendor-id) + {:client-id client-id}) + :class "w-full h-full max-w-2xl" + :hx-swap "outerHTML swap:300ms"} + + [:fieldset {:class "hx-disable w-full h-full"} (com/modal-card {} - [:div.flex [:div.p-2 "Vendor 1099 Info"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:vendor/name vendor)]] - [:div.space-y-6 - [:div.grid.grid-cols-6.gap-4 - - [:h4.text-xl.border-b.col-span-6 "Address"] - [:div.col-span-6 - (com/field {:label "Street 1"} - (com/text-input {:name (path->name [:vendor/address :address/street1]) - :value (-> vendor :vendor/address :address/street1) - :placeholder "1700 Pennsylvania Ave" - :autofocus true}))] - [:div.col-span-6 - (com/field {:label "Street 2"} - (com/text-input {:name (path->name [:vendor/address :address/street2]) - :value (-> vendor :vendor/address :address/street2) - :placeholder "Suite 200"}))] - [:div.col-span-3 - (com/field {:label "City"} - (com/text-input {:name (path->name [:vendor/address :address/city]) - :value (-> vendor :vendor/address :address/city) - :placeholder "Cupertino"}))] - [:div.col-span-1 - (com/field {:label "State"} - (com/text-input {:name (path->name [:vendor/address :address/state]) - :value (-> vendor :vendor/address :address/state) - :placeholder "CA"}))] - [:div.col-span-2 - (com/field {:label "Zip"} - (com/text-input {:name (path->name [:vendor/address :address/zip]) - :value (-> vendor :vendor/address :address/zip) - :placeholder "98102"}))] - [:h4.text-xl.border-b.col-span-6 "Legal Entity"] - [:div.col-span-6 - (com/field {:label "Legal Entity Name"} - (com/text-input {:name (path->name [:vendor/legal-entity-name]) - :value (-> vendor :vendor/legal-entity-name) - :placeholder "Good Restaurant LLC"}))] - [:div.col-span-6.text-center " - OR -"] - [:div.col-span-2 - (com/field {:label "First Name"} - (com/text-input {:name (path->name [:vendor/legal-entity-first-name]) - :value (-> vendor :vendor/legal-entity-first-name) - :placeholder "John"}))] - [:div.col-span-2 - (com/field {:label "Middle Name"} - (com/text-input {:name (path->name [:vendor/legal-entity-middle-name]) - :value (-> vendor :vendor/legal-entity-middle-name) - :placeholder "C."}))] - [:div.col-span-2 - (com/field {:label "Last Name"} - (com/text-input {:name (path->name [:vendor/legal-entity-last-name]) - :value (-> vendor :vendor/legal-entity-last-name) - :placeholder "Riley"}))] - [:div.col-span-2 - (com/field {:label "TIN"} - (com/text-input {:name (path->name [:vendor/legal-entity-tin]) - :value (-> vendor :vendor/legal-entity-tin) - :placeholder "John"}))] - [:div.col-span-2 - (com/field {:label "TIN Type"} - (com/select {:name (path->name [:vendor/legal-entity-tin-type]) - :allow-blank? true - :value (some-> vendor :vendor/legal-entity-tin-type :db/ident name) - :options [["ein" "EIN"] - ["ssn" "SSN"]]}))] - [:div.col-span-2 - (com/field {:label "1099 Type"} - (com/select {:name (path->name [:vendor/legal-entity-1099-type]) - :allow-blank? true - :value (some-> vendor :vendor/legal-entity-1099-type :db/ident name) - :options [["none" "None"] - ["misc" "Misc"] - ["landlord" "Landlord"]]}))] - [:div.col-span-6 - (com/button {:color :primary} - "Save")]]] - [:div])]])))) + [:div.flex [:div.p-2 "Vendor 1099 Info"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:vendor/name entity)]] + [:div.grid.grid-cols-6.gap-x-4.gap-y-2 + + (fc/with-field :vendor/address ;; TODO support default + (list [:h4.text-xl.border-b.col-span-6 "Address"] + [:div.col-span-6 + (fc/with-field :db/id + (com/hidden {:name (fc/field-name) + :value (fc/field-value)})) + + (fc/with-field :address/street1 + (com/validated-field {:label "Street 1" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "1700 Pennsylvania Ave" + :autofocus true})))] + [:div.col-span-6 + (fc/with-field :address/street2 + (com/validated-field {:label "Street 2" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "Suite 200"})))] + [:div.col-span-3 + (fc/with-field :address/city + (com/validated-field {:label "City" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "Cupertino"})))] + [:div.col-span-1 + (fc/with-field :address/state + (com/validated-field {:label "State" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "CA"})))] + [:div.col-span-2 + (fc/with-field :address/zip + (com/validated-field {:label "Zip" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "98102"})))])) + + [:h4.text-xl.border-b.col-span-6 "Legal Entity"] + [:div.col-span-6 + (fc/with-field :vendor/legal-entity-name + (com/validated-field {:label "Legal Entity Name" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :class "w-full" + :value (fc/field-value) + :placeholder "Good Restaurant LLC"})))] + [:div.col-span-6.text-center " - OR -"] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-first-name + (com/validated-field {:label "First Name" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :value (fc/field-value) + :placeholder "John"})))] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-middle-name + (com/validated-field {:label "Middle Name" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :value (fc/field-value) + :placeholder "C."})))] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-last-name + (com/validated-field {:label "Last Name" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :value (fc/field-value) + :placeholder "Riley"})))] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-tin + (com/validated-field {:label "TIN" + :errors (fc/field-errors)} + (com/text-input {:name (fc/field-name) + :value (fc/field-value) + :placeholder "John"})))] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-tin-type + (com/validated-field {:label "TIN Type" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :allow-blank? true + :value (some-> (fc/field-value) name) + :options [["ein" "EIN"] + ["ssn" "SSN"]]})))] + [:div.col-span-2 + (fc/with-field :vendor/legal-entity-1099-type + (com/validated-field {:label "1099 Type" + :errors (fc/field-errors)} + (com/select {:name (fc/field-name) + :allow-blank? true + :value (some-> (fc/field-value) name) ;; TODO use ref stuff + :options (ref->select-options "legal-entity-1099-type")})))]] + [:div + (com/form-errors {:errors (:errors fc/*form-errors*)}) + (com/validated-save-button {:errors form-errors} "Save rule")])]])))) (def vendor-table (helper/table-route grid-page)) (def page (helper/page-route grid-page)) + +(def key->handler + (apply-middleware-to-all-handlers + (->> + { + :company-1099 page + :company-1099-vendor-table vendor-table + :company-1099-vendor-dialog (-> vendor-dialog + (wrap-entity [:route-params :vendor-id] default-vendor-read) + (wrap-schema-decode :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]])) + :company-1099-vendor-save (-> vendor-save + (wrap-entity [:form-params :db/id] default-vendor-read) + (wrap-schema-decode :form-schema form-schema + :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]]) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> vendor-dialog + (wrap-entity [:form-params :db/id] default-vendor-read) + (wrap-entity [:route-params :vendor-id] default-vendor-read) + (wrap-schema-decode :route-schema [:map [:vendor-id entity-id]] + :query-schema [:map [:client-id entity-id]]))))}) + (fn [h] + (-> h + (wrap-secure) + (wrap-client-redirect-unauthenticated))))) diff --git a/src/clj/auto_ap/ssr/components/aside.clj b/src/clj/auto_ap/ssr/components/aside.clj index 4410027e..7cad9ff8 100644 --- a/src/clj/auto_ap/ssr/components/aside.clj +++ b/src/clj/auto_ap/ssr/components/aside.clj @@ -3,7 +3,9 @@ [hiccup2.core :as hiccup] [bidi.bidi :as bidi] [auto-ap.ssr-routes :as ssr-routes] - [auto-ap.client-routes :as client-routes])) + [auto-ap.client-routes :as client-routes] + [auto-ap.ssr.hx :as hx] + [auto-ap.ssr.hiccup-helper :as hh])) (defn menu-button- [params & children] [:div @@ -13,140 +15,47 @@ (update :class str " cursor-pointer flex items-center p-2 w-full text-xs text-gray-600 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700") (assoc :hx-indicator "find .htmx-indicator") (assoc :hx-boost "true") - (assoc :hx-select "#app-contents") - (assoc :hx-target "#app-contents") - (assoc :hx-swap "outerHTML")) + (assoc :hx-select "#app") + (assoc :hx-target "#app") + (assoc :hx-swap "innerHTML")) (when (:icon params) [:span {:class "flex-shrink-0 w-6 h-6 text-gray-400 transition duration-75 group-hover:text-blue-500 dark:text-gray-400 group-hover:scale-110 dark:group-hover:text-white mr-3"} (:icon params)]) (into [:span {:class "flex-1 text-left whitespace-nowrap text-gray-600 dark:text-white"}] children) - (when (:data-collapse-toggle params) + (when (get params "@click") [:svg {:aria-hidden "true", :class "w-6 h-6", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:fill-rule "evenodd", :d "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", :clip-rule "evenodd"}]]) [:div.htmx-indicator.flex.items-center (svg/spinner-primary {:class "inline w-4 h-4 text-white"})]]]) (defn sub-menu- [params & children] - [:ul {:id (:id params) :class "hidden py-2 space-y-1.5"} + [:ul (update params + :class (fnil hh/add-class "")"py-2 space-y-1.5") (for [c children] [:li (update-in c [1 1 :class ] str " flex items-center p-2 pl-11 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")])]) (defn left-aside- [{:keys [nav page-specific]} & children] - [:aside {:id "left-nav", :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform -translate-x-full lg:translate-x-0", :aria-labelledby "left-nav" :aria-hidden "true" - "_" (hiccup/raw "init call initSidebarToggle()")} + [:aside {:id "left-nav", + :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform -translate-x-full lg:translate-x-0", + "x-transition:enter" "transition duration-500" + "x-transition:enter-start" "lg:-translate-x-full" + "x-transition:enter-end" " lg:translate-x-0" + "x-transition:leave" "transition duration-500" + "x-transition:leave-start" "lg:translate-x-0" + "x-transition:leave-end" " lg:-translate-x-full" + + :aria-labelledby "left-nav" + :x-show "leftNavShow" + ":aria-hidden" "leftNavShow ? 'false' : 'true'"} [:div {:class "overflow-y-auto py-5 px-3 h-full bg-gray-50 border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700"} nav - [:ul {:class "pt-5 mt-5 space-y-2 border-t border-gray-200 dark:border-gray-700"} - #_[:li - [:a {:href "#", :class "flex items-center p-2 text-base font-normal text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"} - [:svg {:aria-hidden "true", :class "flex-shrink-0 w-6 h-6 text-gray-400 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} - [:path {:d "M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"}] - [:path {:fill-rule "evenodd", :d "M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z", :clip-rule "evenodd"}]] - [:span {:class "ml-3"} "Docs"]]] - #_[:li - [:a {:href "#", :class "flex items-center p-2 text-base font-normal text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"} - [:svg {:aria-hidden "true", :class "flex-shrink-0 w-6 h-6 text-gray-400 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} - [:path {:d "M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"}]] - [:span {:class "ml-3"} "Components"]]] - #_[:li - [:a {:href "#", :class "flex items-center p-2 text-base font-normal text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"} - [:svg {:aria-hidden "true", :class "flex-shrink-0 w-6 h-6 text-gray-400 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} - [:path {:fill-rule "evenodd", :d "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-2 0c0 .993-.241 1.929-.668 2.754l-1.524-1.525a3.997 3.997 0 00.078-2.183l1.562-1.562C15.802 8.249 16 9.1 16 10zm-5.165 3.913l1.58 1.58A5.98 5.98 0 0110 16a5.976 5.976 0 01-2.516-.552l1.562-1.562a4.006 4.006 0 001.789.027zm-4.677-2.796a4.002 4.002 0 01-.041-2.08l-.08.08-1.53-1.533A5.98 5.98 0 004 10c0 .954.223 1.856.619 2.657l1.54-1.54zm1.088-6.45A5.974 5.974 0 0110 4c.954 0 1.856.223 2.657.619l-1.54 1.54a4.002 4.002 0 00-2.346.033L7.246 4.668zM12 10a2 2 0 11-4 0 2 2 0 014 0z", :clip-rule "evenodd"}]] - [:span {:class "ml-3"} "Help"]]]] - page-specific] - #_[:div {:class "hidden absolute bottom-0 left-0 justify-center p-4 space-x-4 w-full lg:flex bg-white dark:bg-gray-800 z-20 border-r border-gray-200 dark:border-gray-700"} - [:a {:href "#", :class "inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600"} - [:svg {:aria-hidden "true", :class "w-6 h-6", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} - [:path {:d "M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z"}]]] - [:a {:href "#", :data-tooltip-target "tooltip-settings", :class "inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 dark:hover:text-white hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"} - [:svg {:aria-hidden "true", :class "w-6 h-6", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} - [:path {:fill-rule "evenodd", :d "M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z", :clip-rule "evenodd"}]]] - [:div {:id "tooltip-settings", :role "tooltip", :class "inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 transition-opacity duration-300 tooltip"} "Settings page"] - [:button {:type "button", :data-dropdown-toggle "language-dropdown", :class "inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:hover:text-white dark:text-gray-400 hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"} - [:svg {:aria-hidden "true", :class "h-5 w-5 rounded-full mt-0.5", :xmlns "http://www.w3.org/2000/svg", :xmlns:xlink "http://www.w3.org/1999/xlink", :viewbox "0 0 3900 3900"} - [:path {:fill "#b22234", :d "M0 0h7410v3900H0z"}] - [:path {:d "M0 450h7410m0 600H0m0 600h7410m0 600H0m0 600h7410m0 600H0", :stroke "#fff", :stroke-width "300"}] - [:path {:fill "#3c3b6e", :d "M0 0h2964v2100H0z"}] - [:g {:fill "#fff"} - [:g {:id "d"} - [:g {:id "c"} - [:g {:id "e"} - [:g {:id "b"} - [:path {:id "a", :d "M247 90l70.534 217.082-184.66-134.164h228.253L176.466 307.082z"}] - [:use {:xlink:href "#a", :y "420"}] - [:use {:xlink:href "#a", :y "840"}] - [:use {:xlink:href "#a", :y "1260"}]] - [:use {:xlink:href "#a", :y "1680"}]] - [:use {:xlink:href "#b", :x "247", :y "210"}]] - [:use {:xlink:href "#c", :x "494"}]] - [:use {:xlink:href "#d", :x "988"}] - [:use {:xlink:href "#c", :x "1976"}] - [:use {:xlink:href "#e", :x "2470"}]]]] - [:div {:class "hidden z-50 my-4 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700", :id "language-dropdown"} - [:ul {:class "py-1", :role "none"} - [:li - [:a {:href "#", :class "block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600", :role "menuitem"} - [:div {:class "inline-flex items-center"} - [:svg {:aria-hidden "true", :class "h-3.5 w-3.5 rounded-full mr-2", :xmlns "http://www.w3.org/2000/svg", :id "flag-icon-css-us", :viewbox "0 0 512 512"} - [:g {:fill-rule "evenodd"} - [:g {:stroke-width "1pt"} - [:path {:fill "#bd3d44", :d "M0 0h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0z", :transform "scale(3.9385)"}] - [:path {:fill "#fff", :d "M0 10h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0z", :transform "scale(3.9385)"}]] - [:path {:fill "#192f5d", :d "M0 0h98.8v70H0z", :transform "scale(3.9385)"}] - [:path {:fill "#fff", :d "M8.2 3l1 2.8H12L9.7 7.5l.9 2.7-2.4-1.7L6 10.2l.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7L74 8.5l-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 7.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 24.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 21.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 38.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 35.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 52.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 49.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 66.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 63.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9z", :transform "scale(3.9385)"}]]] " \n English (US)"]]] - [:li - [:a {:href "#", :class "block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-white dark:hover:bg-gray-600", :role "menuitem"} - [:div {:class "inline-flex items-center"} - [:svg {:aria-hidden "true", :class "h-3.5 w-3.5 rounded-full mr-2", :xmlns "http://www.w3.org/2000/svg", :id "flag-icon-css-de", :viewbox "0 0 512 512"} - [:path {:fill "#ffce00", :d "M0 341.3h512V512H0z"}] - [:path {:d "M0 0h512v170.7H0z"}] - [:path {:fill "#d00", :d "M0 170.7h512v170.6H0z"}]]]]] - [:li - [:a {:href "#", :class "block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-white dark:hover:bg-gray-600", :role "menuitem"} - [:div {:class "inline-flex items-center"} - [:svg {:aria-hidden "true", :class "h-3.5 w-3.5 rounded-full mr-2", :xmlns "http://www.w3.org/2000/svg", :id "flag-icon-css-it", :viewbox "0 0 512 512"} - [:g {:fill-rule "evenodd", :stroke-width "1pt"} - [:path {:fill "#fff", :d "M0 0h512v512H0z"}] - [:path {:fill "#009246", :d "M0 0h170.7v512H0z"}] - [:path {:fill "#ce2b37", :d "M341.3 0H512v512H341.3z"}]]]]]] - [:li - [:a {:href "#", :class "block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600", :role "menuitem"} - [:div {:class "inline-flex items-center"} - [:svg {:aria-hidden "true", :class "h-3.5 w-3.5 rounded-full mr-2", :xmlns "http://www.w3.org/2000/svg", :xmlns:xlink "http://www.w3.org/1999/xlink", :id "flag-icon-css-cn", :viewbox "0 0 512 512"} - [:defs - [:path {:id "a", :fill "#ffde00", :d "M1-.3L-.7.8 0-1 .6.8-1-.3z"}]] - [:path {:fill "#de2910", :d "M0 0h512v512H0z"}] - [:use {:width "30", :height "20", :transform "matrix(76.8 0 0 76.8 128 128)", :xlink:href "#a"}] - [:use {:width "30", :height "20", :transform "rotate(-121 142.6 -47) scale(25.5827)", :xlink:href "#a"}] - [:use {:width "30", :height "20", :transform "rotate(-98.1 198 -82) scale(25.6)", :xlink:href "#a"}] - [:use {:width "30", :height "20", :transform "rotate(-74 272.4 -114) scale(25.6137)", :xlink:href "#a"}] - [:use {:width "30", :height "20", :transform "matrix(16 -19.968 19.968 16 256 230.4)", :xlink:href "#a"}]] "中文 (繁體)"]]]]]] - [:script {:lang "text/javascript"} - (hiccup/raw " - function initSidebarToggle() { - var $targetEl = document.getElementById('left-nav'); - - var $triggerEl = document.getElementById('left-nav-toggle'); - - var options = { - onCollapse: () => { - document.getElementById('main-content').classList.remove('lg:pl-64') - }, - onExpand: () => { - document.getElementById('main-content').classList.add('lg:pl-64') - }, - onToggle: () => { - } - }; - - var collapse = new Collapse($targetEl, $triggerEl, options); - } -")]]) + + page-specific]]) (defn main-aside-nav- [] [:ul {:class "space-y-1"} @@ -155,12 +64,11 @@ (menu-button- {:icon svg/pie :href "/"} "Dashboard")] - [:li - (menu-button- {:aria-controls "dropdown-invoices", - :data-collapse-toggle "dropdown-invoices" + [:li {:x-data (hx/json {:open false})} + (menu-button- {"@click" "open = !open" :icon svg/accounting-invoice-mail} "Invoices") - (sub-menu- {:id "dropdown-invoices"} + (sub-menu- {:x-show "open"} (menu-button- {:href (bidi/path-for client-routes/routes :invoices)} "All") @@ -173,12 +81,11 @@ (menu-button- {:href (bidi/path-for client-routes/routes :voided-invoices)} "Voided"))] - [:li - (menu-button- {:aria-controls "dropdown-sales", - :data-collapse-toggle "dropdown-sales" - :icon svg/receipt-register-1} + [:li {:x-data (hx/json {:open false})} + (menu-button- {:icon svg/receipt-register-1 + "@click" "open = !open"} "Sales") - (sub-menu- {:id "dropdown-sales"} + (sub-menu- {:x-show "open"} (menu-button- {:href (str (bidi/path-for ssr-routes/only-routes :pos-sales) "?date-range=week")} "Sales") @@ -197,12 +104,11 @@ "?date-range=week")} "Cash drawer shifts") #_(menu-button- {:href "Sales"} "Cash Shifts") #_(menu-button- {:href "Sales"} "Tenders"))] - [:li - (menu-button- {:aria-controls "dropdown-payments" - :data-collapse-toggle "dropdown-payments" + [:li {:x-data (hx/json {:open false})} + (menu-button- {"@click" "open = !open" :icon svg/payments} "Payments") - (sub-menu- {:id "dropdown-payments"} + (sub-menu- {:x-show "open"} (menu-button- {:href (bidi/path-for client-routes/routes :payments)} "All") (menu-button- {:href (bidi/path-for client-routes/routes @@ -212,13 +118,12 @@ (menu-button- {:href (bidi/path-for client-routes/routes :payments)} "Voided"))] - [:li - (menu-button- {:aria-controls "dropdown-transactions" - :data-collapse-toggle "dropdown-transactions" + [:li {:x-data (hx/json {:open false})} + (menu-button- {"@click" "open = !open" :icon svg/bank} "Transactions") - (sub-menu- {:id "dropdown-transactions"} + (sub-menu- {:x-show "open"} (menu-button- {:href (bidi/path-for client-routes/routes :transactions)} "All") (menu-button- {:href (bidi/path-for client-routes/routes @@ -229,12 +134,11 @@ :approved-transactions)} "Approved") (menu-button- {:href (bidi/path-for ssr-routes/only-routes :transaction-insights)} "Insights"))] - [:li - (menu-button- {:aria-controls "dropdown-ledger" - :data-collapse-toggle "dropdown-ledger" + [:li {:x-data (hx/json {:open false})} + (menu-button- {"@click" "open = !open" :icon svg/receipt} "Ledger") - (sub-menu- {:id "dropdown-ledger"} + (sub-menu- {:x-show "open"} (menu-button- {:href (bidi/path-for client-routes/routes :ledger)} "Register") (menu-button- {:href (bidi/path-for client-routes/routes diff --git a/src/clj/auto_ap/ssr/components/navbar.clj b/src/clj/auto_ap/ssr/components/navbar.clj index 0c66b351..3759e741 100644 --- a/src/clj/auto_ap/ssr/components/navbar.clj +++ b/src/clj/auto_ap/ssr/components/navbar.clj @@ -13,7 +13,8 @@ [:div {:class "px-3 py-3 lg:px-5 lg:pl-3"} [:div {:class "flex items-center justify-between"} [:div {:class "flex items-center justify-start"} - [:button {:aria-controls "left-nav", :id "left-nav-toggle" :type "button", :class "inline-flex items-center p-2 mt-2 ml-2 mr-2 text-sm text-gray-500 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"} + [:button {:aria-controls "left-nav", :id "left-nav-toggle" :type "button", :class "inline-flex items-center p-2 mt-2 ml-2 mr-2 text-sm text-gray-500 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" + "@click" "leftNavShow = !leftNavShow"} [:span {:class "sr-only"} "Open sidebar"] [:svg {:class "w-6 h-6", :aria-hidden "true", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"} [:path {:clip-rule "evenodd", :fill-rule "evenodd", :d "M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"}]]] diff --git a/src/clj/auto_ap/ssr/components/page.clj b/src/clj/auto_ap/ssr/components/page.clj index dc7840ec..0fbcdaef 100644 --- a/src/clj/auto_ap/ssr/components/page.clj +++ b/src/clj/auto_ap/ssr/components/page.clj @@ -3,20 +3,26 @@ [auto-ap.ssr.components.aside :refer [left-aside-]] [auto-ap.ssr.components.navbar :refer [navbar-]] [hiccup2.core :as hiccup] - [auto-ap.ssr.svg :as svg])) + [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.hx :as hx])) (defn page- [{:keys [nav page-specific client client-selection identity app-params] :or {app-params {}}} & children] [:div#app {"_" (hiccup/raw " on notification put event.detail.value into #notification-details then add .htmx-added to #notification-holder then remove .hidden from #notification-holder then wait 30ms then remove .htmx-added from #notification-holder on htmx:responseError put event.detail.xhr.response into #error-details then add .htmx-added to #error-holder then remove .hidden from #error-holder then wait 30ms then remove .htmx-added from #error-holder" - )} + ) + :x-data (hx/json {:leftNavShow true})} (navbar- {:client-selection client-selection - :client client - :identity identity}) - [:div#app-contents.flex.pt-16.overflow-hidden (assoc app-params :hx-disinherit "*") - (left-aside- {:nav nav + :client client + :identity identity}) + [:div#app-contents.flex.pt-16.overflow-hidden (assoc app-params + :hx-disinherit "*" + :x-init "leftNavShow = true") + (left-aside- {:nav nav :page-specific page-specific}) - [:div#main-content {:class "relative w-full h-full lg:pl-64 overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content " + [:div#main-content {:class "relative w-full h-full overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content lg:pl-64" + ":class" "leftNavShow ? 'lg:pl-64' : ''" + :x-effect "leftNavShow ? $el.classList.add('lg:pl-64') : $el.classList.remove('lg:pl-64')" } [:div#notification-holder.hidden [:div.fixed.top-0.right-0.left-0.z-30.mx-auto.max-w-screen-lg.w-screen-lg.my-0.pt-8.rounded-lg diff --git a/src/clj/auto_ap/ssr/core.clj b/src/clj/auto_ap/ssr/core.clj index 0935bbd0..d4eeaa9c 100644 --- a/src/clj/auto_ap/ssr/core.clj +++ b/src/clj/auto_ap/ssr/core.clj @@ -46,10 +46,6 @@ :bank-account-typeahead (wrap-client-redirect-unauthenticated (wrap-secure company/bank-account-typeahead)) :company (wrap-client-redirect-unauthenticated (wrap-secure company/page)) - :company-1099 (wrap-client-redirect-unauthenticated (wrap-secure company-1099/page)) - :company-1099-vendor-table (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-table)) - :company-1099-vendor-dialog (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-dialog)) - :company-1099-vendor-save (wrap-client-redirect-unauthenticated (wrap-secure company-1099/vendor-save)) :company-plaid (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/page)) :company-plaid-table (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/table)) :company-plaid-link (wrap-client-redirect-unauthenticated (wrap-secure company-plaid/link)) @@ -76,6 +72,7 @@ :transaction-insight-explain (wrap-client-redirect-unauthenticated (wrap-admin insights/explain)) :admin-ezcater-xls (wrap-client-redirect-unauthenticated (wrap-admin ezcater-xls/page)) :search (wrap-client-redirect-unauthenticated (wrap-secure search/dialog-contents))} + (into company-1099/key->handler) (into pos-sales/key->handler) (into pos-expected-deposits/key->handler) (into pos-tenders/key->handler) diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index 536a3a2f..00921e5e 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -30,6 +30,15 @@ `(with-cursor (get *current* ~field ) ~@rest)) +(defmacro with-field-default [field default & rest] + `(let [next-cursor# (get *current* ~field ) + next-cursor# (if (nil? @next-cursor#) + (cursor/update! next-cursor# default) + next-cursor#)] + (with-cursor next-cursor# + ~@rest))) + + (defn field-name ([] (field-name *current*)) ([cursor] diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 1e17b887..080fd2cc 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -243,7 +243,8 @@ (defn ref->enum-schema [n] (into [:enum {:decode/string #(if (keyword? %) % - (keyword n %) + (when (not-empty %) + (keyword n %)) )}] (for [{:db/keys [ident]} (all-schema) :when (= n (namespace ident))] @@ -266,20 +267,6 @@ {:value (name ident) :content (str/replace (str/capitalize (name ident)) "-" " ")}))) - - -(defn wrap-form-4xx [handler] - (fn [request] - (try+ - (handler request) - - - (catch [:type :validation] e - (alog/warn ::form-4xx :error e) - (html-response [:span.error-content.text-red-500 (:message &throw-context)] - :status 400))))) - - (defn wrap-form-4xx-2 [handler form-handler] (fn [request] (try+ From 5ed23f26be7acd2ea3dd66b1047d62a4009a7afc Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 26 Oct 2023 15:54:41 -0700 Subject: [PATCH 32/34] fixes --- src/clj/auto_ap/cursor.clj | 1 - src/clj/auto_ap/ssr/admin/accounts.clj | 19 +-------- src/clj/auto_ap/ssr/admin/background_jobs.clj | 2 +- .../auto_ap/ssr/admin/transaction_rules.clj | 10 ++--- src/clj/auto_ap/ssr/company.clj | 2 +- src/clj/auto_ap/ssr/company/company_1099.clj | 23 ++++++++--- src/clj/auto_ap/ssr/company/yodlee.clj | 1 - src/clj/auto_ap/ssr/components.clj | 3 +- src/clj/auto_ap/ssr/components/inputs.clj | 40 +------------------ src/clj/auto_ap/ssr/form_cursor.clj | 8 +--- src/clj/auto_ap/ssr/pos/refunds.clj | 16 ++------ src/clj/auto_ap/ssr/users.clj | 4 +- src/clj/auto_ap/ssr/utils.clj | 8 ++-- 13 files changed, 37 insertions(+), 100 deletions(-) diff --git a/src/clj/auto_ap/cursor.clj b/src/clj/auto_ap/cursor.clj index 6a7f25cc..4247b9f5 100644 --- a/src/clj/auto_ap/cursor.clj +++ b/src/clj/auto_ap/cursor.clj @@ -1,7 +1,6 @@ (ns auto-ap.cursor (:import (clojure.lang IDeref Atom ILookup Counted IFn AFn Indexed ISeq Seqable))) -; TODO not sure if these methods are needed at all; ICursor is used solely as a marker right now (defprotocol ICursor (path [cursor]) (state [cursor])) diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 5c913a68..53061b12 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -232,7 +232,6 @@ "hx-reswap" "afterbegin") (= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-account))))))) -;; TODO decide when cursors are used. other cases it's not, some are (defn client-override* [override] (com/data-grid-row (-> {:x-ref "p" :data-key "show" @@ -245,7 +244,7 @@ (fc/with-field :account-client-override/client (com/data-grid-cell {} (com/validated-field {:errors (fc/field-errors)} - (com/typeahead-2 {:name (fc/field-name) + (com/typeahead {:name (fc/field-name) :placeholder "Search..." :class "w-96" :url (bidi/path-for ssr-routes/only-routes @@ -262,20 +261,6 @@ (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -;; TODO each form: -;; elimante typeahead1 -;; work with new dialog -;; use cursor -;; ensure all dialogs are opened the same way -;; form level validation -;; form level validation -;; componentize -;; ensure all dependency oriented stuff works the same way -;; make sure that "new row index" stuff works ok -;; TODO figure out when hx-targets are decided -;; ensure that adding a new one results in a new row - - (defn dialog* [{:keys [entity form-params form-errors]}] (fc/start-form form-params form-errors [:div {:x-data (hx/json {"accountName" (or (:account/name form-params) (:account/numeric-code entity)) @@ -383,8 +368,6 @@ (com/validated-save-button {:errors (seq form-errors)} "Save account")])]])])) -;; TODO saving new row should att it to the tbody - (defn new-client-override [{ {:keys [index]} :query-params}] (html-response (fc/start-form-with-prefix diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index ec1ecdfc..f09879bd 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -182,7 +182,7 @@ (fc/with-field :client (com/validated-field {:label "Client" :errors (fc/field-errors)} - (com/typeahead-2 {:name (fc/field-name) + (com/typeahead {:name (fc/field-name) :value (fc/field-value) :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 87e02b7f..734a3aac 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -56,7 +56,7 @@ [:fieldset.space-y-6 (com/field {:label "Vendor"} - (com/typeahead-2 {:name "vendor" + (com/typeahead {:name "vendor" :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :vendor-search) @@ -318,7 +318,7 @@ (defn- account-typeahead* [{:keys [name value client-id x-model]}] [:div.flex.flex-col - (com/typeahead-2 {:name name + (com/typeahead {:name name :placeholder "Search..." :url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id) :id name @@ -389,7 +389,6 @@ (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -;; TODO background jobs and company 1099 (defn dialog* [{:keys [entity form-params form-errors]}] (fc/start-form form-params form-errors (com/modal @@ -448,7 +447,7 @@ :x-show "clientFilter"} (hx/alpine-appear)) [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) + (com/typeahead {:name (fc/field-name) :error? (fc/error?) :class "w-96" :placeholder "Search..." @@ -520,7 +519,7 @@ (com/validated-field {:label "Assign Vendor" :errors (fc/field-errors)} [:div.w-96 - (com/typeahead-2 {:name (fc/field-name) + (com/typeahead {:name (fc/field-name) :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :vendor-search) :class "w-96" @@ -572,7 +571,6 @@ (some->> client-id (pull-attr (dc/db conn) :client/locations) client-id))))) -;; TODO check to see if it should be called "Shared" or "shared" for the value (defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}] (html-response (location-select* {:name name diff --git a/src/clj/auto_ap/ssr/company.clj b/src/clj/auto_ap/ssr/company.clj index 075bae63..aa1a19d2 100644 --- a/src/clj/auto_ap/ssr/company.clj +++ b/src/clj/auto_ap/ssr/company.clj @@ -108,7 +108,7 @@ (defn bank-account-typeahead* [{:keys [client-id name value]}] (if client-id - (com/typeahead-2 {:name name + (com/typeahead {:name name :class "w-96" :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :bank-account-search diff --git a/src/clj/auto_ap/ssr/company/company_1099.clj b/src/clj/auto_ap/ssr/company/company_1099.clj index fdbb27bb..ecf21bf2 100644 --- a/src/clj/auto_ap/ssr/company/company_1099.clj +++ b/src/clj/auto_ap/ssr/company/company_1099.clj @@ -176,8 +176,20 @@ {:keys [vendor-id]} :route-params {:keys [client-id]} :query-params}] + (assert-can-see-client identity client-id) - @(dc/transact conn [[:upsert-entity (assoc form-params :db/id (:vendor-id route-params))]]) + + @(dc/transact conn [[:upsert-entity (-> form-params + (assoc :db/id (:vendor-id route-params)) + (update :vendor/address (fn [a] + (if (or (:address/street1 a) + (:address/street2 a) + (:address/city a) + (:address/state a) + (:address/zip a) + (:db/id a)) + a + nil)) ))]]) (html-response (row* identity [(dc/pull (dc/db conn) [:db/id :client/code] client-id) @@ -192,7 +204,7 @@ (def form-schema (mc/schema [:map - [:vendor/address {:default {} } + [:vendor/address {:default {}} [:maybe [:map [:db/id {:optional true} [:maybe entity-id]] @@ -234,7 +246,8 @@ [:div.flex [:div.p-2 "Vendor 1099 Info"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:vendor/name entity)]] [:div.grid.grid-cols-6.gap-x-4.gap-y-2 - (fc/with-field :vendor/address ;; TODO support default + (fc/with-field-default :vendor/address {} + (println "ADDRESS" fc/*current*) (list [:h4.text-xl.border-b.col-span-6 "Address"] [:div.col-span-6 (fc/with-field :db/id @@ -335,11 +348,11 @@ :errors (fc/field-errors)} (com/select {:name (fc/field-name) :allow-blank? true - :value (some-> (fc/field-value) name) ;; TODO use ref stuff + :value (some-> (fc/field-value) name) :options (ref->select-options "legal-entity-1099-type")})))]] [:div (com/form-errors {:errors (:errors fc/*form-errors*)}) - (com/validated-save-button {:errors form-errors} "Save rule")])]])))) + (com/validated-save-button {:errors form-errors} "Save vendor")])]])))) (def vendor-table (helper/table-route grid-page)) (def page (helper/page-route grid-page)) diff --git a/src/clj/auto_ap/ssr/company/yodlee.clj b/src/clj/auto_ap/ssr/company/yodlee.clj index 699c40fa..7bae6fa2 100644 --- a/src/clj/auto_ap/ssr/company/yodlee.clj +++ b/src/clj/auto_ap/ssr/company/yodlee.clj @@ -208,7 +208,6 @@ fastlink.open({fastLinkURL: '%s', (def page (helper/page-route grid-page)) (def table (helper/table-route grid-page)) -;; TODO delete-after-settle (defn refresh-provider-account [{:keys [form-params identity]}] (let [provider-account (dc/pull (dc/db conn) default-read (some-> (get form-params "id") not-empty Long/parseLong))] (yodlee/refresh-provider-account (:client/code (:yodlee-provider-account/client provider-account)) diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index 305afc49..8187030d 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -31,8 +31,7 @@ (def date-input inputs/date-input-) (def hidden inputs/hidden-) (def select inputs/select-) -(def typeahead inputs/typeahead-) -(def typeahead-2 inputs/typeahead-2-) +(def typeahead inputs/tytypeahead- (def field-errors inputs/field-errors-) (def field inputs/field-) (def validated-field inputs/validated-field-) diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index acc46704..8bfb07db 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -32,45 +32,8 @@ (:allow-blank? params) (conj [:option {:value "" :selected (not (:value params))} ""]))] children)) + (defn typeahead- [params] - [:select (-> params - (dissoc :url) - (dissoc :value) - (dissoc :value-fn) - (dissoc :content-fn)) - (for [value (if (:multiple params) - (:value params) - [(:value params)]) - :when ((:value-fn params first) value)] - [:option {:value ((:value-fn params first) value) :selected true} ((:content-fn params second) value)]) - - [:script {:lang "javascript"} - (hiccup/raw (format " -(function () { -var element = document.getElementById('%s'); -var c = new Choices(element, {removeItems: true, removeItemButton:true, searchFloor: 3, searchPlaceholderValue: '%s'}); -let baseUrl = '%s'; - -element.addEventListener('search', function (e) { - let fullUrl = baseUrl + (baseUrl.includes(\"?\") ? \"&\" : \"?\") + \"q=\" + e.detail.value; - let data = fetch(fullUrl) - .then(res => res.json()) - .then(data => { - c.setChoices(data, 'value', 'label', true) - }); -}); -element.addEventListener('choice', function (e) { -c.clearChoices(); - }) -})(); - -" - (:id params) - (:placeholder params) - (:url params) - ))]]) - -(defn typeahead-2- [params] [:div {:x-data (hx/json {:open false :baseUrl (if (str/includes? (:url params) "?") (str (:url params) "&q=") @@ -152,7 +115,6 @@ c.clearChoices(); ]]) -;; TODO fix search modal (defn use-size [size] (if (= :small size) (str " " "text-xs p-2") diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index 00921e5e..b1617452 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -31,12 +31,8 @@ ~@rest)) (defmacro with-field-default [field default & rest] - `(let [next-cursor# (get *current* ~field ) - next-cursor# (if (nil? @next-cursor#) - (cursor/update! next-cursor# default) - next-cursor#)] - (with-cursor next-cursor# - ~@rest))) + `(with-cursor (get *current* ~field ~default) + ~@rest)) (defn field-name diff --git a/src/clj/auto_ap/ssr/pos/refunds.clj b/src/clj/auto_ap/ssr/pos/refunds.clj index 49f741b1..2651307e 100644 --- a/src/clj/auto_ap/ssr/pos/refunds.clj +++ b/src/clj/auto_ap/ssr/pos/refunds.clj @@ -8,25 +8,15 @@ merge-query pull-many query2]] - [auto-ap.graphql.utils :refer [extract-client-ids]] - [auto-ap.routes.utils - :refer [wrap-client-redirect-unauthenticated wrap-secure]] - [auto-ap.ssr.pos.common :refer [date-range-field* processor-field* total-field*]] + [auto-ap.query-params :as query-params] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components :as com] [auto-ap.ssr.grid-page-helper :as helper] - [auto-ap.ssr.svg :as svg] + [auto-ap.ssr.pos.common :refer [date-range-field* total-field*]] [auto-ap.time :as atime] [bidi.bidi :as bidi] [clj-time.coerce :as c] - [datomic.api :as dc] - [clojure.set :as set] - [auto-ap.query-params :as query-params] - [malli.core :as m])) - -;; TODO refunds -;; always should be fast -;; make params parsing composable + [datomic.api :as dc])) (defn filters [request] [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 7861f1d2..7d481140 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -80,7 +80,7 @@ {:value "none" :content "None"}]})) (com/field {:label "Client"} - (com/typeahead-2 {:name "client" + (com/typeahead {:name "client" :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :company-search) @@ -273,7 +273,7 @@ hx/alpine-mount-then-appear) (com/data-grid-cell {} (com/validated-field {:errors (fc/field-errors (:db/id fc/*current*))} - (com/typeahead-2 {:name (fc/field-name (:db/id fc/*current*)) + (com/typeahead {:name (fc/field-name (:db/id fc/*current*)) :class "w-full" :url (bidi/path-for ssr-routes/only-routes :company-search) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 080fd2cc..80479333 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -102,7 +102,8 @@ (defn parse-empty-as-nil [] (mt2/transformer {:decoders - {:double empty->nil + {:string empty->nil + :double empty->nil :int empty->nil :long empty->nil 'nat-int? empty->nil}})) @@ -160,10 +161,7 @@ (subs (str k) 1)) -;; TODO need to remove or at least remove usages as the form is not included -(defn validation-error [m & {:as data}] - (throw+ (ex-info m (merge data {:type :validation})))) - +;; TODO make this bubble the form data automatically (defn field-validation-error [m path & {:as data}] (throw+ (ex-info m (merge data {:type :field-validation :form-errors (assoc-in {} path [m])})))) From 7f7458d54ae7bcaa64b7c608ba50ddb47ba26998 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 26 Oct 2023 21:23:52 -0700 Subject: [PATCH 33/34] Makes testing of transaction rules work --- resources/input.css | 23 +++ resources/public/output.css | 2 +- .../auto_ap/ssr/admin/transaction_rules.clj | 173 +++++++++++++++--- src/clj/auto_ap/ssr/components.clj | 2 +- src/clj/auto_ap/ssr/components/aside.clj | 3 +- src/clj/auto_ap/ssr/components/buttons.clj | 5 +- src/clj/auto_ap/ssr/components/dialog.clj | 4 +- src/clj/auto_ap/ssr/nested_form_params.clj | 4 +- src/clj/auto_ap/ssr/pos/common.clj | 3 - src/clj/auto_ap/ssr/ui.clj | 6 +- src/clj/auto_ap/ssr/utils.clj | 9 + src/cljc/auto_ap/ssr_routes.cljc | 2 + 12 files changed, 196 insertions(+), 40 deletions(-) diff --git a/resources/input.css b/resources/input.css index 9e3a576e..0f061e61 100644 --- a/resources/input.css +++ b/resources/input.css @@ -26,6 +26,29 @@ } + +.htmx-added.swipe-left-swap , .htmx-added .swipe-left-swap{ + @apply opacity-100 !important; + @apply scale-100 !important; + @apply -translate-x-1/2 !important; + +} + +.htmx-added.swipe-left-swap , .htmx-added .swipe-left-swap{ + @apply opacity-100; + @apply scale-100; + @apply translate-x-0; + +} +.htmx-settling.htmx-added .swipe-left-swap, .htmx-settling.htmx-added.swipe-left-swap{ + + @apply opacity-0 !important; + @apply scale-75 !important; + @apply translate-x-1/2 !important; + +} + + .htmx-settling .slide-up-settle { @apply translate-y-5 !important; } diff --git a/resources/public/output.css b/resources/public/output.css index 6bb05656..740c8b37 100644 --- a/resources/public/output.css +++ b/resources/public/output.css @@ -1 +1 @@ -/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-4{margin:1rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mt-0{margin-top:0!important}.\!mt-1{margin-top:.25rem!important}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.w-72{width:18rem}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.-translate-x-0,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-0{--tw-translate-x:-0px}.rotate-180{--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\!scale-100{--tw-scale-x:1!important;--tw-scale-y:1!important}.\!scale-100,.\!scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!scale-50{--tw-scale-x:.5!important;--tw-scale-y:.5!important}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(255 3 3/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file +/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Calibri,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select:not([size]){background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#007dbb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark [type=checkbox]:checked,.dark [type=radio]:checked,[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate,[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto inherit}input[type=file]::file-selector-button{color:#fff;background:#1f2937;border:0;font-weight:500;font-size:.875rem;cursor:pointer;padding:.625rem 1rem .625rem 2rem;-webkit-margin-start:-1rem;margin-inline-start:-1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}input[type=file]::file-selector-button:hover{background:#374151}.dark input[type=file]::file-selector-button{color:#fff;background:#4b5563}.dark input[type=file]::file-selector-button:hover{background:#6b7280}input[type=range]::-webkit-slider-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-webkit-slider-thumb{background:#9ca3af}.dark input[type=range]:disabled::-webkit-slider-thumb{background:#6b7280}input[type=range]:focus::-webkit-slider-thumb{outline:2px solid #0000;outline-offset:2px;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:1px;--tw-ring-color:rgb(164 202 254/var(--tw-ring-opacity))}input[type=range]::-moz-range-thumb{height:1.25rem;width:1.25rem;background:#007dbb;border-radius:9999px;border:0;appearance:none;-moz-appearance:none;-webkit-appearance:none;cursor:pointer}input[type=range]:disabled::-moz-range-thumb{background:#9ca3af}.dark input[type=range]:disabled::-moz-range-thumb{background:#6b7280}input[type=range]::-moz-range-progress{background:#009cea}input[type=range]::-ms-fill-lower{background:#009cea}.toggle-bg:after{content:"";position:absolute;top:.125rem;left:.125rem;background:#fff;border-color:#d1d5db;border-width:1px;border-radius:9999px;height:1.25rem;width:1.25rem;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;box-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}input:checked+.toggle-bg:after{transform:translateX(100%);;border-color:#fff}input:checked+.toggle-bg{background:#007dbb;border-color:#007dbb}.tooltip-arrow,.tooltip-arrow:before{position:absolute;width:8px;height:8px;background:inherit}.tooltip-arrow{visibility:hidden}.tooltip-arrow:before{content:"";visibility:visible;transform:rotate(45deg)}[data-tooltip-style^=light]+.tooltip>.tooltip-arrow:before{border-style:solid;border-color:#e5e7eb}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=top]>.tooltip-arrow:before{border-bottom-width:1px;border-right-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=right]>.tooltip-arrow:before{border-bottom-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=bottom]>.tooltip-arrow:before{border-top-width:1px;border-left-width:1px}[data-tooltip-style^=light]+.tooltip[data-popper-placement^=left]>.tooltip-arrow:before{border-top-width:1px;border-right-width:1px}.tooltip[data-popper-placement^=top]>.tooltip-arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.tooltip-arrow{top:-4px}.tooltip[data-popper-placement^=left]>.tooltip-arrow{right:-4px}.tooltip[data-popper-placement^=right]>.tooltip-arrow{left:-4px}.tooltip.invisible>.tooltip-arrow:before{visibility:hidden}[data-popper-arrow],[data-popper-arrow]:before{position:absolute;width:8px;height:8px;background:inherit}[data-popper-arrow]{visibility:hidden}[data-popper-arrow]:after,[data-popper-arrow]:before{content:"";visibility:visible;transform:rotate(45deg)}[data-popper-arrow]:after{position:absolute;width:9px;height:9px;background:inherit}[role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:before{border-style:solid;border-color:#4b5563}[role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#e5e7eb}.dark [role=tooltip]>[data-popper-arrow]:after{border-style:solid;border-color:#4b5563}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]:before{border-bottom-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]:before{border-bottom-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]:before{border-top-width:1px;border-left-width:1px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:after,[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]:before{border-top-width:1px;border-right-width:1px}[data-popover][role=tooltip][data-popper-placement^=top]>[data-popper-arrow]{bottom:-5px}[data-popover][role=tooltip][data-popper-placement^=bottom]>[data-popper-arrow]{top:-5px}[data-popover][role=tooltip][data-popper-placement^=left]>[data-popper-arrow]{right:-5px}[data-popover][role=tooltip][data-popper-placement^=right]>[data-popper-arrow]{left:-5px}[role=tooltip].invisible>[data-popper-arrow]:after,[role=tooltip].invisible>[data-popper-arrow]:before{visibility:hidden}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#009cea80;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-\[60px\]{bottom:60px}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.top-2\/4{top:50%}.top-5{top:1.25rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[99\]{z-index:99}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.col-start-1{grid-column-start:1}.m-1{margin:.25rem}.m-2{margin:.5rem}.m-4{margin:1rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-4{margin-top:1rem;margin-bottom:1rem}.-mb-1{margin-bottom:-.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-10{margin-right:2.5rem}.mr-16{margin-right:4rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.ml-4{margin-left:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.w-1\/2{width:50%}.w-16{width:4rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-screen{width:100vw}.min-w-\[700px\]{min-width:700px}.max-w-2xl{max-width:42rem}.max-w-6xl{max-width:72rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.basis-1\/4{flex-basis:25%}.\!translate-y-0{--tw-translate-y:0px!important}.\!translate-y-0,.\!translate-y-32{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.\!translate-y-32{--tw-translate-y:8rem!important}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.-translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-full{--tw-translate-y:100%}.rotate-180,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform-none{transform:none}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shake{0%{transform:translateX(0)}12.5%{transform:translateX(-5px)}25%{transform:translateX(0)}37.5%{transform:translateX(5px)}50%{transform:translateX(0)}62.5%{transform:translateX(-5px)}75%{transform:translateX(5px)}87.5%{transform:translateX(5px)}to{transform:translateX(0)}}.animate-shake{animation:shake .5s ease-out 1}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.justify-items-stretch{justify-items:stretch}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.self-center{align-self:center}.self-stretch{align-self:stretch}.justify-self-end{justify-self:end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-right-radius:.5rem}.rounded-b-lg,.rounded-l-lg{border-bottom-left-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-dashed{border-style:dashed}.border-blue-300{--tw-border-opacity:1;border-color:rgb(102 196 242/var(--tw-border-opacity))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(0 125 187/var(--tw-border-opacity))}.border-blue-700{--tw-border-opacity:1;border-color:rgb(0 94 140/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-primary-300{--tw-border-opacity:1;border-color:rgb(175 211 130/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(255 104 104/var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(204 235 251/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(153 215 247/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(51 176 238/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(230 245 253/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(0 156 234/var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}.bg-blue-800{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-green-300{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(148 196 88/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.bg-green-800{--tw-bg-opacity:1;background-color:rgb(48 72 18/var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgb(201 225 171/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(242 248 234/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(255 205 205/var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(255 154 154/var(--tw-bg-opacity))}.bg-red-300{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(253 246 178/var(--tw-bg-opacity))}.\!bg-opacity-0{--tw-bg-opacity:0!important}.\!bg-opacity-100{--tw-bg-opacity:1!important}.\!bg-opacity-50{--tw-bg-opacity:0.5!important}.bg-opacity-50{--tw-bg-opacity:0.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-11{padding-left:2.75rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:initial}.align-top{vertical-align:top}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(0 62 94/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(48 72 18/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(97 145 37/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(204 2 2/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(102 1 1/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(114 59 19/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.\!opacity-0{opacity:0!important}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.outline-0{outline-width:0}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-\[cubic-bezier\(\.3\2c 2\.3\2c \.6\2c 1\)\]{transition-timing-function:cubic-bezier(.3,2.3,.6,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.htmx-added .fade-in,.htmx-added.fade-in{opacity:0!important}.fade-in{opacity:1}.htmx-settling .fade-in-settle,.htmx-settling.fade-in-settle{opacity:0!important}.fade-in-settle{opacity:1}.htmx-added .swipe-left-swap,.htmx-added.swipe-left-swap{--tw-translate-x:-50%!important;opacity:1;--tw-scale-x:1;--tw-scale-y:1;--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.htmx-settling.htmx-added .swipe-left-swap,.htmx-settling.htmx-added.swipe-left-swap{opacity:0!important;--tw-scale-x:.75!important;--tw-scale-y:.75!important;--tw-translate-x:50%!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.htmx-settling .slide-up-settle,.htmx-settling.slide-up-settle{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up-settle{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hidden .slide-up,.htmx-added .slide-up{--tw-translate-y:1.25rem!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.slide-up{--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.live-added{animation:pulse-green .3s 2;animation-direction:alternate;animation-timing-function:ease-in-out}.dark .live-added{animation:pulse-dark-green .3s 2!important;animation-direction:alternate;animation-timing-function:ease-in-out}@keyframes pulse-green{0%{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}:is(.dark to){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}}@keyframes pulse-dark-green{:is(.dark 0%){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}to{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{display:inherit!important}.htmx-indicator{display:none}.htmx-request .htmx-indicator-hidden{display:none!important}.htmx-indicator-hidden{display:inherit}.htmx-swapping .fade-out{opacity:0!important}.fade-out{opacity:1}.min-h-content{min-height:calc(100vh - 4em)}.choices{margin-bottom:0!important;border-width:0!important}.choices__inner{display:block!important;width:100%!important;border-radius:.5rem!important;border-width:1px!important;--tw-border-opacity:1!important;border-color:rgb(209 213 219/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:.25rem!important;font-size:.875rem!important;line-height:1.25rem!important;--tw-text-opacity:1!important;color:rgb(17 24 39/var(--tw-text-opacity))!important}.choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error .choices__inner{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(255 230 230/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(51 1 1/var(--tw-text-opacity))!important}.group.has-error .choices__inner::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner::placeholder{--tw-placeholder-opacity:1!important;color:rgb(153 2 2/var(--tw-placeholder-opacity))!important}.group.has-error .choices__inner:focus{--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))!important}:is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(75 85 99/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}:is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(156 163 175/var(--tw-placeholder-opacity))!important}:is(.dark .choices__inner:focus){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.group.has-error :is(.dark .choices__inner){--tw-border-opacity:1!important;border-color:rgb(255 3 3/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 3 3/var(--tw-text-opacity))!important}.group.has-error :is(.dark .choices__inner)::-moz-placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.group.has-error :is(.dark .choices__inner)::placeholder{--tw-placeholder-opacity:1!important;color:rgb(255 3 3/var(--tw-placeholder-opacity))!important}.choices:focus-within .choices__inner,:is(.dark .choices:focus-within .choices__inner){--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices:focus-within .choices__inner{outline:2px solid #0000!important;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#007dbb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#007dbb}.choices__inner .choices__input{margin:0!important;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}:is(.dark .choices__inner .choices__input){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity))!important}.choices__inner .choices__item{white-space:nowrap!important;border-radius:.25rem!important;--tw-border-opacity:1!important;border-color:rgb(156 163 175/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;padding:.125rem .5rem!important;font-size:.75rem!important;line-height:1rem!important;font-weight:500!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__inner .choices__item){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices__list--dropdown{border-radius:.5rem!important;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}:is(.dark .choices__list--dropdown){--tw-bg-opacity:1!important;background-color:rgb(55 65 81/var(--tw-bg-opacity))!important}.choices__list--dropdown .choices__item--selectable.is-highlighted{--tw-bg-opacity:1!important;background-color:rgb(175 211 130/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(48 72 18/var(--tw-text-opacity))!important}:is(.dark .choices__list--dropdown .choices__item--selectable.is-highlighted){--tw-bg-opacity:1!important;background-color:rgb(24 36 9/var(--tw-bg-opacity))!important;--tw-text-opacity:1!important;color:rgb(175 211 130/var(--tw-text-opacity))!important}.choices[data-type*=select-multiple] .choices__button{--tw-border-opacity:1!important;border-color:rgb(107 114 128/var(--tw-border-opacity))!important}.choices[data-type*=select-multiple] .choices__button:focus{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__inner .choices__item:focus-within{--tw-border-opacity:1!important;border-color:rgb(0 156 234/var(--tw-border-opacity))!important;--tw-bg-opacity:1!important;background-color:rgb(121 181 46/var(--tw-bg-opacity))!important;--tw-ring-opacity:1!important;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))!important}.choices__list--single .choices__item{display:flex!important;width:auto!important}.choices__list--single{width:auto!important}.choices__list--single button{position:relative!important;margin:0!important;display:block!important;height:auto!important}.choices[data-type*=select-one] .choices__button{right:auto!important}.arrow,.arrow:before{position:absolute;width:24px;height:24px;background:inherit}.arrow{visibility:hidden}.arrow:before{visibility:visible;content:"";transform:rotate(45deg)}.arrow{bottom:-4px}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-blue-300:hover{--tw-bg-opacity:1;background-color:rgb(102 196 242/var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}.hover\:bg-blue-800:hover{--tw-bg-opacity:1;background-color:rgb(0 62 94/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-green-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}.hover\:bg-neutral-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(228 240 213/var(--tw-bg-opacity))}.hover\:bg-red-300:hover{--tw-bg-opacity:1;background-color:rgb(255 104 104/var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(0 125 187/var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-primary-700:hover{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:z-10:focus{z-index:10}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}.focus\:bg-neutral-100:focus{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity))}.focus\:text-green-700:focus{--tw-text-opacity:1;color:rgb(73 109 28/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-2:focus,.focus\:ring-4:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(153 215 247/var(--tw-ring-opacity))}.focus\:ring-blue-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(102 196 242/var(--tw-ring-opacity))}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.focus\:ring-green-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(201 225 171/var(--tw-ring-opacity))}.focus\:ring-green-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(175 211 130/var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(73 109 28/var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 154 154/var(--tw-ring-opacity))}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-500{--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:border-red-500{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:bg-red-50{--tw-bg-opacity:1;background-color:rgb(255 230 230/var(--tw-bg-opacity))}.group.has-error .group-\[\.has-error\]\:text-red-900{--tw-text-opacity:1;color:rgb(51 1 1/var(--tw-text-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:placeholder-red-700::placeholder{--tw-placeholder-opacity:1;color:rgb(153 2 2/var(--tw-placeholder-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error .group-\[\.has-error\]\:focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 3 3/var(--tw-ring-opacity))}:is(.dark .dark\:block){display:block}:is(.dark .dark\:hidden){display:none}:is(.dark .dark\:divide-gray-600)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(75 85 99/var(--tw-divide-opacity))}:is(.dark .dark\:border-blue-500){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-500){--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}:is(.dark .dark\:border-transparent){border-color:#0000}:is(.dark .dark\:bg-blue-600){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-700){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:bg-blue-900){--tw-bg-opacity:1;background-color:rgb(0 31 47/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1f293780}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-600){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-700){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-900){--tw-bg-opacity:1;background-color:rgb(24 36 9/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-700){--tw-bg-opacity:1;background-color:rgb(153 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:bg-red-900){--tw-bg-opacity:1;background-color:rgb(51 1 1/var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-900){--tw-bg-opacity:1;background-color:rgb(99 49 18/var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-80){--tw-bg-opacity:0.8}:is(.dark .dark\:text-blue-200){--tw-text-opacity:1;color:rgb(153 215 247/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-300){--tw-text-opacity:1;color:rgb(102 196 242/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-400){--tw-text-opacity:1;color:rgb(51 176 238/var(--tw-text-opacity))}:is(.dark .dark\:text-blue-500){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-100){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-50){--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}:is(.dark .dark\:text-green-300){--tw-text-opacity:1;color:rgb(175 211 130/var(--tw-text-opacity))}:is(.dark .dark\:text-red-300){--tw-text-opacity:1;color:rgb(255 104 104/var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(255 53 53/var(--tw-text-opacity))}:is(.dark .dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-300){--tw-text-opacity:1;color:rgb(250 202 21/var(--tw-text-opacity))}:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:placeholder-gray-400)::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175/var(--tw-placeholder-opacity))}:is(.dark .dark\:ring-offset-gray-700){--tw-ring-offset-color:#374151}:is(.dark .dark\:ring-offset-gray-800){--tw-ring-offset-color:#1f2937}:is(.dark .dark\:hover\:bg-blue-600:hover){--tw-bg-opacity:1;background-color:rgb(0 125 187/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-blue-700:hover){--tw-bg-opacity:1;background-color:rgb(0 94 140/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-600:hover){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-600:hover){--tw-bg-opacity:1;background-color:rgb(97 145 37/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-green-700:hover){--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-red-600:hover){--tw-bg-opacity:1;background-color:rgb(204 2 2/var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(0 156 234/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-white:hover){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-blue-500:focus){--tw-border-opacity:1;border-color:rgb(0 156 234/var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-500:focus){--tw-border-opacity:1;border-color:rgb(121 181 46/var(--tw-border-opacity))}:is(.dark .dark\:focus\:text-white:focus){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-blue-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 156 234/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 125 187/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-blue-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(0 62 94/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-gray-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-green-800:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(48 72 18/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-500:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(121 181 46/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity:1;--tw-ring-color:rgb(97 145 37/var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-offset-gray-700:focus){--tw-ring-offset-color:#374151}:is(.dark .group:hover .dark\:group-hover\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:border-red-500){--tw-border-opacity:1;border-color:rgb(255 3 3/var(--tw-border-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:bg-gray-700){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:text-red-500){--tw-text-opacity:1;color:rgb(255 3 3/var(--tw-text-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}.group.has-error :is(.dark .group-\[\.has-error\]\:dark\:placeholder-red-500)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 3 3/var(--tw-placeholder-opacity))}@media (min-width:640px){.sm\:block{display:block}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-6{padding:1.5rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:ml-2{margin-left:.5rem}.md\:mr-24{margin-right:6rem}.md\:table-cell{display:table-cell}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.75rem*var(--tw-space-x-reverse));margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)))}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:p-12{padding:3rem}}@media (min-width:1024px){.lg\:block{display:block}.lg\:table-cell{display:table-cell}.lg\:hidden{display:none}.lg\:w-96{width:24rem}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:pl-3{padding-left:.75rem}.lg\:pl-64{padding-left:16rem}}.\[\&\.active\]\:bg-primary-300.active{--tw-bg-opacity:1;background-color:rgb(175 211 130/var(--tw-bg-opacity))}.\[\&\.active\]\:bg-primary-500.active{--tw-bg-opacity:1;background-color:rgb(121 181 46/var(--tw-bg-opacity))}:is(.dark .\[\&\.active\]\:dark\:bg-primary-700).active{--tw-bg-opacity:1;background-color:rgb(73 109 28/var(--tw-bg-opacity))} \ No newline at end of file diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 734a3aac..c5a9c0bc 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -41,6 +41,7 @@ wrap-entity wrap-form-4xx-2 wrap-schema-decode]] + [auto-ap.time :as atime] [auto-ap.utils :refer [dollars=]] [bidi.bidi :as bidi] [clojure.string :as str] @@ -258,33 +259,31 @@ (set)) bank-account-id)) +(defn validate-transaction-rule [form-params] + (doseq [[{:transaction-rule-account/keys [account location]} i] (map vector (:transaction-rule/accounts form-params) (range)) + :let [account-location (pull-attr (dc/db conn) :account/location account)] + :when (and account-location (not= account-location location))] + (field-validation-error (str "must be " account-location) + [:transaction-rule/accounts i :transaction-rule-account/location] + :form form-params)) + + (let [total (reduce + 0.0 (map :transaction-rule-account/percentage (:transaction-rule/accounts form-params)))] + (when-not (dollars= 1.0 total) + (form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total))) + :form form-params))) + + (when (and (:transaction-rule/bank-account form-params) + (not (bank-account-belongs-to-client? (:transaction-rule/bank-account form-params) + (:transaction-rule/client form-params)))) + (field-validation-error "does not belong to client" + [:transaction-rule/bank-account] + :form form-params))) + (defn transaction-rule-save [{:keys [form-params request-method identity] :as request}] + (validate-transaction-rule form-params) (let [entity (cond-> form-params (= :post request-method) (assoc :db/id "new") true (assoc :transaction-rule/note (entity->note form-params))) - _ (doseq [[{:transaction-rule-account/keys [account location]} i] (map vector (:transaction-rule/accounts entity) (range)) - :let [account-location (pull-attr (dc/db conn) :account/location account)] - :when (and account-location (not= account-location location))] - (field-validation-error (str "must be " account-location) - [:transaction-rule/accounts i :transaction-rule-account/location] - :form form-params)) - - total (reduce + - 0.0 - (map :transaction-rule-account/percentage - (:transaction-rule/accounts entity))) - _ (when-not (dollars= 1.0 total) - (form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total))) - :form form-params)) - - _ (when (and (:transaction-rule/bank-account entity) - (not (bank-account-belongs-to-client? (:transaction-rule/bank-account entity) - (:transaction-rule/client entity)))) - (field-validation-error "does not belong to client" - [:transaction-rule/bank-account] - :form form-params)) - - {:keys [tempids]} (audit-transact [[:upsert-entity entity]] (:identity request)) updated-rule (dc/pull (dc/db conn) @@ -295,7 +294,112 @@ :headers (cond-> {"hx-trigger" "modalclose"} (= :post request-method) (assoc "hx-retarget" "#entity-table tbody" "hx-reswap" "afterbegin") - (= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule))))))) + (= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule)) + "hx-reswap" "outerHTML"))))) + + + +(def transaction-read '[{:transaction/client [:client/name] + :transaction/bank-account [:bank-account/name]} + :transaction/description-original + [:transaction/date :xform clj-time.coerce/from-date]]) + +(defn transaction-rule-test [{:keys [form-params request-method identity] :as request + {:transaction-rule/keys [description client bank-account amount-lte amount-gte dom-lte dom-gte yodlee-merchant]} :form-params}] + (validate-transaction-rule form-params) + (let [valid-clients (extract-client-ids (:clients request) + client) + query (cond-> {:query {:find ['(pull ?e read)] + :in ['$ 'read] + :where []} + :args [(dc/db conn) transaction-read]} + description + (merge-query {:query {:in ['?descr] + :where ['[(iol-ion.query/->pattern ?descr) ?description-regex]]} + :args [description]}) + + valid-clients + (merge-query {:query {:in ['[?xx ...]] + :where ['[?e :transaction/client ?xx]]} + :args [(set valid-clients)]}) + + bank-account + (merge-query {:query {:in ['?bank-account-id] + :where ['[?e :transaction/bank-account ?bank-account-id]]} + :args [bank-account]}) + + description + (merge-query {:query {:where ['[?e :transaction/description-original ?do] + '[(re-find ?description-regex ?do)]]}}) + + amount-gte + (merge-query {:query {:in ['?amount-gte] + :where ['[?e :transaction/amount ?ta] + '[(>= ?ta ?amount-gte)]]} + :args [amount-gte]}) + + amount-lte + (merge-query {:query {:in ['?amount-lte] + :where ['[?e :transaction/amount ?ta] + '[(<= ?ta ?amount-lte)]]} + :args [amount-lte]}) + + dom-lte + (merge-query {:query {:in ['?dom-lte] + :where ['[?e :transaction/date ?transaction-date] + '[(iol-ion.query/dom ?transaction-date) ?dom] + '[(<= ?dom ?dom-lte)]]} + :args [dom-lte]}) + + dom-gte + (merge-query {:query {:in ['?dom-gte] + :where ['[?e :transaction/date ?transaction-date] + '[(iol-ion.query/dom ?transaction-date) ?dom] + '[(>= ?dom ?dom-gte)]]} + :args [dom-gte]}) + + client + (merge-query {:query {:in ['?client-id] + :where ['[?e :transaction/client ?client-id]]} + :args [client]}) + + + true + (merge-query {:query {:where ['[?e :transaction/id]]}})) + results (->> + (query2 query) + (map first))] + + (html-response + (com/modal-card {:class "fade-in transition duration-300"} + [:div.p-2.flex.space-x-4 [:div "Transaction Rule"] [:div ">"] [:div "Results"] [:div.ml-4.relative (com/badge {} (count results))]] + (com/data-grid + {:headers [(com/data-grid-header {} "Client") + (com/data-grid-header {} "Bank") + (com/data-grid-header {} "Date") + (com/data-grid-header {} "Description")]} + (for [r (take 15 results)] + (com/data-grid-row + {} + (com/data-grid-cell {} (-> r :transaction/client :client/name)) + (com/data-grid-cell {} (-> r :transaction/bank-account :bank-account/name)) + (com/data-grid-cell {} (some-> r :transaction/date (atime/unparse-local atime/normal-date))) + (com/data-grid-cell {} (some-> r :transaction/description-original ))))) + [:div + (com/button (cond-> {:color :primary + :hx-vals (hx/json (:raw-form-params request)) + } + (:db/id form-params) (assoc :hx-put (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-save)) + (not (:db/id form-params)) (assoc :hx-post (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-save))) + "Save") + (com/button {:hx-vals (hx/json (:raw-form-params request)) + :hx-put (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-filled-account + )} "Back") + ]) + :headers (-> {} + (assoc "hx-retarget" ".modal-card") + (assoc "hx-reswap" "outerHTML"))))) @@ -366,6 +470,7 @@ :x-data (hx/json {:location (fc/field-value)})} [:div {:hx-trigger "changed" :hx-target "next *" + :hx-swap "outerHTML" :hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || '', value: event.detail.location}" (fc/field-name) ) :hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select) :x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}] @@ -554,7 +659,11 @@ ]] [:div (com/form-errors {:errors (:errors fc/*form-errors*)}) - (com/validated-save-button {:errors form-errors} "Save rule")])]))) + (com/validated-save-button {:errors form-errors} "Save rule") + (com/validated-save-button {:errors form-errors :color :secondary + :hx-post (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-test)} + + "Test rule")])]))) (defn new-account [{{:keys [client-id index]} :query-params}] @@ -607,6 +716,7 @@ [:transaction-rule-account/percentage percentage])]])) (defn transaction-dialog [{:keys [entity form-params form-errors]}] + (clojure.pprint/pprint form-params) (modal-response (dialog* {:entity entity :form-params (or (when (seq form-params) form-params) @@ -649,6 +759,19 @@ (wrap-nested-form-params) (wrap-form-4xx-2 (-> transaction-dialog (wrap-entity [:form-params :db/id] default-read)))) + + :admin-transaction-rule-test (-> transaction-rule-test + (wrap-entity [:form-params :db/id] default-read) + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> transaction-dialog + (wrap-entity [:form-params :db/id] default-read)))) + :admin-transaction-rule-filled-account (-> transaction-dialog + (wrap-entity [:form-params :db/id] default-read) + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> transaction-dialog + (wrap-entity [:form-params :db/id] default-read)))) :admin-transaction-rule-edit-dialog (-> transaction-dialog (wrap-entity [:route-params :db/id] default-read) (wrap-schema-decode :route-schema [:map [:db/id entity-id]])) diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index 8187030d..7e01d7c7 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -31,7 +31,7 @@ (def date-input inputs/date-input-) (def hidden inputs/hidden-) (def select inputs/select-) -(def typeahead inputs/tytypeahead- +(def typeahead inputs/typeahead-) (def field-errors inputs/field-errors-) (def field inputs/field-) (def validated-field inputs/validated-field-) diff --git a/src/clj/auto_ap/ssr/components/aside.clj b/src/clj/auto_ap/ssr/components/aside.clj index 7cad9ff8..075e7163 100644 --- a/src/clj/auto_ap/ssr/components/aside.clj +++ b/src/clj/auto_ap/ssr/components/aside.clj @@ -214,8 +214,7 @@ [:li (menu-button- {:icon svg/cog - :href (bidi/path-for client-routes/routes - :admin-rules)} + :href (bidi/path-for ssr-routes/only-routes :admin-transaction-rules)} "Rules")] [:li diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index d23281d7..ee276f37 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -176,7 +176,7 @@ (defn validated-save-button- [{:keys [errors class] :as params} & children] - (button- (-> {:color :primary + (button- (-> {:color (or (:color params) :primary) :type "submit" :class (cond-> (or class "") true (hh/add-class "w-32") (seq errors) (hh/add-class "animate-shake"))} @@ -184,5 +184,4 @@ (dissoc :errors)) (if (seq children) children - "Save")) - ) + "Save"))) diff --git a/src/clj/auto_ap/ssr/components/dialog.clj b/src/clj/auto_ap/ssr/components/dialog.clj index e6fc4e47..572a98d4 100644 --- a/src/clj/auto_ap/ssr/components/dialog.clj +++ b/src/clj/auto_ap/ssr/components/dialog.clj @@ -9,10 +9,10 @@ children]) (defn modal-card- [params header content footer] - [:div#modal-card (update params + [:div (update params :class (fn [c] (-> c (or "") - (hh/add-class "w-full p-4 h-full") + (hh/add-class "w-full p-4 h-full modal-card") ))) [:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col h-full"} [:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"} header] diff --git a/src/clj/auto_ap/ssr/nested_form_params.clj b/src/clj/auto_ap/ssr/nested_form_params.clj index 1fa4648e..83286aa5 100644 --- a/src/clj/auto_ap/ssr/nested_form_params.clj +++ b/src/clj/auto_ap/ssr/nested_form_params.clj @@ -64,7 +64,9 @@ (nested-params-request request {})) ([request options] (let [parse (:key-parser options parse-nested-keys)] - (update-in request [:form-params] nest-params parse)))) + (-> request + (assoc :raw-form-params (:form-params request)) + (update-in [:form-params] nest-params parse))))) (defn wrap-nested-form-params "Middleware to converts a flat map of parameters into a nested map. diff --git a/src/clj/auto_ap/ssr/pos/common.clj b/src/clj/auto_ap/ssr/pos/common.clj index ef37e0af..97022a42 100644 --- a/src/clj/auto_ap/ssr/pos/common.clj +++ b/src/clj/auto_ap/ssr/pos/common.clj @@ -3,9 +3,6 @@ [auto-ap.time :as atime] [auto-ap.ssr.svg :as svg])) -;; TODO make date-input take clj date -;; TODO make total fields take decimals - (defn date-range-field* [request] [:div#date-range {} (com/field {:label "Date Range"} diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 68e01e9a..f0fe6ed0 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -33,7 +33,9 @@ :crossorigin= "anonymous"}] [:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js" :crossorigin= "anonymous"}]) - + + [:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/ext/class-tools.js" :crossorigin= "anonymous"}] + [:script {:src "https://unpkg.com/htmx.org/dist/ext/debug.js"}] [:script {:src "/js/htmx-disable.js"}] [:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]] @@ -62,7 +64,7 @@ input[type=number] { } "] - [:body {:hx-ext "disable-submit"} + [:body {:hx-ext "disable-submit, class-tools"} contents [:script {:src "/js/flowbite.min.js"}] diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 80479333..13b53c0d 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -37,6 +37,15 @@ (assoc-in [:headers "hx-retarget"] "#modal-content") (assoc-in [:headers "hx-reswap"] "innerHTML")))))) +(defn next-step-modal-response [hiccup & {:as opts}] + (apply html-response + (into + [hiccup] + (mapcat identity + (-> opts + (assoc-in [:headers "hx-retarget"] "#modal-content") + (assoc-in [:headers "hx-reswap"] "innerHTML")))))) + (defn wrap-error-response [handler] (fn [request] (try diff --git a/src/cljc/auto_ap/ssr_routes.cljc b/src/cljc/auto_ap/ssr_routes.cljc index 7da78c5e..bddbcebc 100644 --- a/src/cljc/auto_ap/ssr_routes.cljc +++ b/src/cljc/auto_ap/ssr_routes.cljc @@ -37,9 +37,11 @@ :put :admin-transaction-rule-save :post :admin-transaction-rule-save} "/table" :admin-transaction-rule-table + "/account/filled" :admin-transaction-rule-filled-account "/account/new" :admin-transaction-rule-new-account "/account/location-select" :admin-transaction-rule-location-select "/account/typeahead" :admin-transaction-rule-account-typeahead + "/test" :admin-transaction-rule-test "/new" {:get :admin-transaction-rule-new-dialog} [[#"\d+" :db/id] "/edit"] :admin-transaction-rule-edit-dialog }} From 58c34715e2b2910051b703ded162c615f96c3db9 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 26 Oct 2023 21:24:35 -0700 Subject: [PATCH 34/34] moves youngs market to RNDC --- src/clj/auto_ap/parse/templates.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clj/auto_ap/parse/templates.clj b/src/clj/auto_ap/parse/templates.clj index ab43ca87..181e6639 100644 --- a/src/clj/auto_ap/parse/templates.clj +++ b/src/clj/auto_ap/parse/templates.clj @@ -254,7 +254,7 @@ :total [:trim-commas-and-negate nil]}} ;; Young's Market Co new statement - {:vendor "Youngs Market" + {:vendor "RNDC" :keywords [#"(YOUNG'S MARKET COMPANY|Young.*Statement)"] :extract {:date #"([0-9]+/[0-9]+/[0-9]+)" :customer-identifier #"Customer Name +([\w ]+)" @@ -266,7 +266,7 @@ :multi-match? #"^[0-9]+.*\$?([0-9,]+\.[0-9]+).*\$?([0-9,]+\.[0-9]+)"} ;; Young's Market Co - INVOICE - {:vendor "Youngs Market" + {:vendor "RNDC" :keywords [#"P.O.Box 743564"] :extract {:date #"(?:INVOICE|CREDIT) DATE\n(?:.*?)(\S+)\n" #_#_:customer-identifier #"(?:INVOICE|CREDIT) DATE\n [0-9]+\s+(.*?)\s{2,}"