django-admin-react 0.2.0a3__tar.gz → 0.2.0a4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/PKG-INFO +1 -1
  2. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/inlines.py +21 -1
  3. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/serializers.py +18 -3
  4. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/list.py +8 -4
  5. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/static/admin_react/.vite/manifest.json +2 -2
  6. django_admin_react-0.2.0a4/django_admin_react/static/admin_react/assets/index-Cf63Q57m.css +1 -0
  7. django_admin_react-0.2.0a4/django_admin_react/static/admin_react/assets/index-Ch1wOBLJ.js +9 -0
  8. django_admin_react-0.2.0a4/django_admin_react/static/admin_react/assets/index-Ch1wOBLJ.js.map +1 -0
  9. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/static/admin_react/index.html +2 -2
  10. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/templates/admin_react/index.html +7 -0
  11. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/pyproject.toml +1 -1
  12. django_admin_react-0.2.0a3/django_admin_react/static/admin_react/assets/index-BOdTCQF7.js +0 -9
  13. django_admin_react-0.2.0a3/django_admin_react/static/admin_react/assets/index-BOdTCQF7.js.map +0 -1
  14. django_admin_react-0.2.0a3/django_admin_react/static/admin_react/assets/index-BgIZIHRa.css +0 -1
  15. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/LICENSE +0 -0
  16. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/README.md +0 -0
  17. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/README.md +0 -0
  18. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/__init__.py +0 -0
  19. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/README.md +0 -0
  20. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/__init__.py +0 -0
  21. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/dates.py +0 -0
  22. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/filters.py +0 -0
  23. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/inlines_write.py +0 -0
  24. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/panels.py +0 -0
  25. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/permissions.py +0 -0
  26. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/registry.py +0 -0
  27. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/urls.py +0 -0
  28. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/README.md +0 -0
  29. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/__init__.py +0 -0
  30. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/actions.py +0 -0
  31. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/auth.py +0 -0
  32. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/autocomplete.py +0 -0
  33. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/bulk.py +0 -0
  34. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/create.py +0 -0
  35. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/create_form.py +0 -0
  36. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/delete_preview.py +0 -0
  37. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/destroy.py +0 -0
  38. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/detail.py +0 -0
  39. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/history.py +0 -0
  40. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/registry.py +0 -0
  41. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/schema.py +0 -0
  42. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/views/update.py +0 -0
  43. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/api/writes.py +0 -0
  44. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/apps.py +0 -0
  45. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/audit.py +0 -0
  46. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/conf.py +0 -0
  47. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/pwa.py +0 -0
  48. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/templates/admin_react/README.md +0 -0
  49. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/templates/admin_react/login.html +0 -0
  50. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/templates/admin_react/sw.js +0 -0
  51. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/urls.py +0 -0
  52. {django_admin_react-0.2.0a3 → django_admin_react-0.2.0a4}/django_admin_react/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-admin-react
3
- Version: 0.2.0a3
3
+ Version: 0.2.0a4
4
4
  Summary: A drop-in React single-page admin for Django, driven entirely by ModelAdmin.
5
5
  License: MIT
6
6
  Keywords: django,admin,react,spa,tailwind
@@ -32,9 +32,11 @@ from django.db.models import ManyToManyField
32
32
  from django.db.models import Model
33
33
  from django.http import HttpRequest
34
34
 
35
+ from django_admin_react.api.serializers import field_type_for
35
36
  from django_admin_react.api.serializers import filter_sensitive
36
37
  from django_admin_react.api.serializers import is_sensitive_field_name
37
38
  from django_admin_react.api.serializers import label_for
39
+ from django_admin_react.api.serializers import safe_get_field
38
40
  from django_admin_react.api.serializers import serialize_fk_value
39
41
  from django_admin_react.api.serializers import serialize_value
40
42
 
@@ -192,7 +194,17 @@ def _fields_meta(
192
194
  visible_fields: list[str],
193
195
  request: HttpRequest,
194
196
  ) -> list[dict[str, Any]]:
195
- """Per-field metadata for the inline header — minimal shape."""
197
+ """Per-field metadata for the inline header.
198
+
199
+ Carries ``type`` + ``required`` (in addition to ``name`` / ``label``
200
+ / ``readonly``) so the SPA can render a *typed* input per inline
201
+ field in edit mode — the prerequisite for inline editing (#54
202
+ write-half UI). ``type`` reuses the same closed vocabulary
203
+ (``field_type_for``) the top-level detail descriptor uses, so the
204
+ frontend can route inline fields through the same ``FieldInput``
205
+ component. Additive — existing read-only consumers ignore the new
206
+ keys.
207
+ """
196
208
  readonly = set(inline.get_readonly_fields(request, None) or ())
197
209
  out: list[dict[str, Any]] = []
198
210
  for name in visible_fields:
@@ -200,11 +212,19 @@ def _fields_meta(
200
212
  label = label_for_field(name, child_model, inline)
201
213
  except Exception: # pragma: no cover
202
214
  label = name
215
+ model_field = safe_get_field(child_model, name)
216
+ field_type = field_type_for(model_field) if model_field is not None else "unsupported"
217
+ # ``required`` mirrors the form layer: a field is required when
218
+ # it is not ``blank``. ``safe_get_field`` returning ``None`` (a
219
+ # method-only ``list_display`` entry) → not required / unsupported.
220
+ required = bool(model_field is not None and not getattr(model_field, "blank", True))
203
221
  out.append(
204
222
  {
205
223
  "name": name,
206
224
  "label": str(label),
207
225
  "readonly": name in readonly,
226
+ "type": field_type,
227
+ "required": required,
208
228
  }
209
229
  )
210
230
  return out
@@ -196,11 +196,26 @@ def _serialize_range_value(value: Any, field: Field | None) -> dict[str, Any]:
196
196
  }
197
197
 
198
198
 
199
- def serialize_fk_value(value: Model | None) -> dict[str, Any] | None:
200
- """Serialize an FK as ``{"id": pk, "label": str(obj)}`` or ``None``."""
199
+ def serialize_fk_value(value: Model | None, *, admin_site: Any = None) -> dict[str, Any] | None:
200
+ """Serialize an FK as ``{"id": pk, "label": str(obj)}`` or ``None``.
201
+
202
+ When ``admin_site`` is provided **and** the related model is
203
+ registered on it, the envelope also carries
204
+ ``to: {"app_label": <real>, "model_name": ...}`` so the SPA can
205
+ render the cell as a navigable link to the related object's detail
206
+ page (#184). The target is **omitted** when the related model isn't
207
+ registered — surfacing a link the detail endpoint would 404 on (and
208
+ leaking adjacency to an unregistered model) is the exact posture
209
+ #89 removed from filter descriptors. ``app_label`` is the real
210
+ ``_meta.app_label`` the detail URL resolves against.
211
+ """
201
212
  if value is None:
202
213
  return None
203
- return {"id": value.pk, "label": label_for(value)}
214
+ out: dict[str, Any] = {"id": value.pk, "label": label_for(value)}
215
+ if admin_site is not None and type(value) in getattr(admin_site, "_registry", {}):
216
+ meta = value._meta
217
+ out["to"] = {"app_label": meta.app_label, "model_name": meta.model_name}
218
+ return out
204
219
 
205
220
 
206
221
  def label_for(obj: Model) -> str:
@@ -112,7 +112,10 @@ class ListView(View):
112
112
  list_display = list(model_admin.get_list_display(request))
113
113
  columns = _columns_payload(model_admin, list_display, request)
114
114
 
115
- results = [_row_for(obj, model_admin, list_display, request) for obj in queryset[start:end]]
115
+ results = [
116
+ _row_for(obj, model_admin, list_display, request, admin_site)
117
+ for obj in queryset[start:end]
118
+ ]
116
119
 
117
120
  body: dict[str, Any] = {
118
121
  "app_label": model._meta.app_label,
@@ -267,6 +270,7 @@ def _row_for(
267
270
  model_admin: ModelAdmin,
268
271
  list_display: list[str],
269
272
  request: HttpRequest,
273
+ admin_site: Any = None,
270
274
  ) -> dict[str, Any]:
271
275
  """Build one ``results[]`` entry for the list response.
272
276
 
@@ -283,11 +287,11 @@ def _row_for(
283
287
  _f, _attr, value = lookup_field(name, obj, model_admin)
284
288
  except Exception: # pragma: no cover — defensive
285
289
  value = ""
286
- fields[name] = _serialize_list_value(obj, name, value)
290
+ fields[name] = _serialize_list_value(obj, name, value, admin_site)
287
291
  return {"pk": obj.pk, "label": label_for(obj), "fields": fields}
288
292
 
289
293
 
290
- def _serialize_list_value(obj: Model, name: str, value: Any) -> Any:
294
+ def _serialize_list_value(obj: Model, name: str, value: Any, admin_site: Any = None) -> Any:
291
295
  """Serialize a single ``list_display`` cell.
292
296
 
293
297
  FK fields go through the FK envelope (``{"id", "label"}``);
@@ -300,5 +304,5 @@ def _serialize_list_value(obj: Model, name: str, value: Any) -> Any:
300
304
  """
301
305
  model_field = safe_get_field(obj, name)
302
306
  if isinstance(model_field, ForeignKey):
303
- return serialize_fk_value(value)
307
+ return serialize_fk_value(value, admin_site=admin_site)
304
308
  return serialize_value(value, field=model_field)
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "index.html": {
3
- "file": "assets/index-BOdTCQF7.js",
3
+ "file": "assets/index-Ch1wOBLJ.js",
4
4
  "name": "index",
5
5
  "src": "index.html",
6
6
  "isEntry": true,
7
7
  "css": [
8
- "assets/index-BgIZIHRa.css"
8
+ "assets/index-Cf63Q57m.css"
9
9
  ]
10
10
  }
11
11
  }
@@ -0,0 +1 @@
1
+ *,: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(59 130 246 / .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: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::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(59 130 246 / .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: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}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,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}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-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-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,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}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.left-0{left:0}.top-0{top:0}.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-\[100\]{z-index:100}.col-span-2{grid-column:span 2 / span 2}.-ml-2{margin-left:-.5rem}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.block{display: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-14{height:3.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.max-h-60{max-height:15rem}.max-h-\[85vh\]{max-height:85vh}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-72{width:18rem}.w-full{width:100%}.min-w-48{min-width:12rem}.min-w-full{min-width:100%}.max-w-\[16rem\]{max-width:16rem}.max-w-full{max-width:100%}.max-w-prose{max-width:65ch}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(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)) skew(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)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(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 * calc(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 * 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, 1))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity, 1))}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-t-xl{border-top-left-radius:.75rem;border-top-right-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-blue-600{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-600{--tw-border-opacity: 1;border-color:rgb(220 38 38 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-black\/50{background-color:#00000080}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pr-3{padding-right:.75rem}.pt-1{padding-top:.25rem}.pt-20{padding-top:5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.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-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.tracking-wide{letter-spacing:.025em}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.placeholder-gray-500::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.placeholder-gray-500::placeholder{--tw-placeholder-opacity: 1;color:rgb(107 114 128 / var(--tw-placeholder-opacity, 1))}.opacity-25{opacity:.25}.opacity-40{opacity:.4}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(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-sm{--tw-shadow: 0 1px 2px 0 rgb(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-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.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-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;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-200{transition-duration:.2s}html,body,#root{height:100%}.hover\:bg-blue-100:hover{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-800:hover{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1: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(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)}.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-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity, 1))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:640px){.sm\:max-w-md{max-width:28rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:rounded-xl{border-radius:.75rem}}@media(min-width:768px){.md\:static{position:static}.md\:z-auto{z-index:auto}.md\:hidden{display:none}.md\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.md\:pt-6{padding-top:1.5rem}}@media(min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}