pcm-shared-components 2.1.405 → 2.1.407
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.
- package/dist/components/Reservation/AnimalVehicleDetailsEditor/AnimalFieldsOnceBlock.js +64 -147
- package/dist/components/Reservation/AnimalVehicleDetailsEditor/fieldTypeControl.js +122 -5
- package/dist/components/Reservation/AnimalVehicleDetailsEditor/index.js +12 -4
- package/dist/components/Reservation/animalFieldDrift.js +8 -10
- package/dist/languages/en/translations.json +3 -1
- package/dist/languages/es/translations.json +3 -1
- package/dist/languages/fr/translations.json +3 -1
- package/dist/styles/tailwind.css +1 -1
- package/package.json +1 -1
|
@@ -1,155 +1,65 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Typography
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
4
|
import { ThemeProvider } from '@mui/system';
|
|
5
5
|
import { createTheme, useTheme } from '@mui/material/styles';
|
|
6
6
|
import * as i18nextLocal from 'i18next';
|
|
7
7
|
import { renderFieldTypeControl } from './fieldTypeControl';
|
|
8
8
|
|
|
9
|
-
// Collapsed height for a notice block before it needs a "View full ..." link. A handful of lines
|
|
10
|
-
// of admin-entered text/markup fits inside this without ever showing the link at all; anything
|
|
11
|
-
// longer gets clipped here and offered in full through the dialog below.
|
|
12
|
-
const NOTICE_COLLAPSED_MAX_HEIGHT = 160;
|
|
13
|
-
|
|
14
|
-
// Field-type controls this block ever renders inline (everything else -- 'notice' -- gets its own
|
|
15
|
-
// read-only display, not a live input control).
|
|
16
|
-
const INPUT_FIELD_TYPES = ['text', 'select', 'select_multiple', 'number', 'textarea', 'yes_no', 'date'];
|
|
17
|
-
|
|
18
9
|
// Full-width field types, same rule AnimalVehicleDetailsEditor's per-item grid uses for its
|
|
19
|
-
// non-orphan fields (a dropdown/textarea/multi-select reads badly squeezed into a half column
|
|
20
|
-
// This block skips that component's
|
|
21
|
-
// index.jsx) -- once-per-reservation
|
|
22
|
-
// measurement machinery needed to keep a large
|
|
23
|
-
// carrying here too.
|
|
24
|
-
const isFullWidthField = field => ['select', 'textarea', 'select_multiple'].includes(field.type);
|
|
10
|
+
// non-orphan fields (a dropdown/textarea/multi-select reads badly squeezed into a half column, and
|
|
11
|
+
// a notice's rich text + checkbox needs the same full row). This block skips that component's
|
|
12
|
+
// further wrapped-label-promotion pass (labelRefs/wrappedKeys in index.jsx) -- once-per-reservation
|
|
13
|
+
// fields are typically a handful at most, so the extra measurement machinery needed to keep a large
|
|
14
|
+
// tab-per-animal grid's columns aligned isn't worth carrying here too.
|
|
15
|
+
const isFullWidthField = field => ['select', 'textarea', 'select_multiple', 'notice'].includes(field.type);
|
|
25
16
|
|
|
26
|
-
// `once_per_reservation
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
17
|
+
// `once_per_reservation` is read from the field object itself first (the flat, "normalized" shape
|
|
18
|
+
// this block's `fields` prop expects -- the same convention AnimalVehicleDetailsEditor's
|
|
19
|
+
// `fieldConfig` already uses for label/options/unit/placeholder: the caller resolves the raw
|
|
20
|
+
// lot_animal_fields.meta payload into flat props before handing fields to either component). A
|
|
21
|
+
// `field.meta.<key>` fallback is also accepted so a caller who instead passes the meta object
|
|
22
|
+
// through unflattened still works.
|
|
32
23
|
const readFieldProp = (field, key) => field[key] !== undefined ? field[key] : field.meta?.[key];
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const contentHtml = readFieldProp(field, 'content_html') || '';
|
|
49
|
-
|
|
50
|
-
// Measured after mount/paint (useLayoutEffect, not useEffect) so the "View full ..." link never
|
|
51
|
-
// flashes in for a heartbeat on content that turns out to fit -- same reasoning
|
|
52
|
-
// AnimalVehicleDetailsEditor's own label-wrap measurement (wrappedKeys, index.jsx) already uses.
|
|
53
|
-
// Re-checked on window resize too: the height bound is fixed in CSS, but at a narrower viewport
|
|
54
|
-
// the same HTML can wrap onto more lines and start overflowing where it didn't before.
|
|
55
|
-
useLayoutEffect(() => {
|
|
56
|
-
const checkOverflow = () => {
|
|
57
|
-
const el = contentRef.current;
|
|
58
|
-
if (!el) return;
|
|
59
|
-
setOverflowing(el.scrollHeight > el.clientHeight);
|
|
60
|
-
};
|
|
61
|
-
checkOverflow();
|
|
62
|
-
window.addEventListener('resize', checkOverflow);
|
|
63
|
-
return () => window.removeEventListener('resize', checkOverflow);
|
|
64
|
-
}, [contentHtml]);
|
|
65
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
66
|
-
className: "flex flex-col",
|
|
67
|
-
style: {
|
|
68
|
-
gap: 4
|
|
69
|
-
}
|
|
70
|
-
}, /*#__PURE__*/React.createElement(Typography, {
|
|
71
|
-
variant: "body2",
|
|
72
|
-
sx: {
|
|
73
|
-
fontWeight: 500
|
|
74
|
-
}
|
|
75
|
-
}, field.label), /*#__PURE__*/React.createElement(Paper, {
|
|
76
|
-
variant: "outlined",
|
|
77
|
-
sx: {
|
|
78
|
-
p: 1.5,
|
|
79
|
-
borderRadius: 1,
|
|
80
|
-
bgcolor: 'action.hover',
|
|
81
|
-
maxHeight: NOTICE_COLLAPSED_MAX_HEIGHT,
|
|
82
|
-
overflow: 'hidden'
|
|
83
|
-
}
|
|
84
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
85
|
-
ref: contentRef,
|
|
86
|
-
dangerouslySetInnerHTML: {
|
|
87
|
-
__html: contentHtml
|
|
88
|
-
}
|
|
89
|
-
})), overflowing && /*#__PURE__*/React.createElement(Button, {
|
|
90
|
-
size: "small",
|
|
91
|
-
onClick: () => setDialogOpen(true),
|
|
92
|
-
sx: {
|
|
93
|
-
alignSelf: 'flex-start',
|
|
94
|
-
textTransform: 'none',
|
|
95
|
-
minWidth: 0,
|
|
96
|
-
p: 0
|
|
97
|
-
}
|
|
98
|
-
}, i18next.t('animal.view_full_field', {
|
|
99
|
-
label: field.label
|
|
100
|
-
})), /*#__PURE__*/React.createElement(Dialog, {
|
|
101
|
-
open: dialogOpen,
|
|
102
|
-
onClose: () => setDialogOpen(false),
|
|
103
|
-
maxWidth: "sm",
|
|
104
|
-
fullWidth: true,
|
|
105
|
-
scroll: "paper"
|
|
106
|
-
}, /*#__PURE__*/React.createElement(DialogTitle, null, field.label), /*#__PURE__*/React.createElement(DialogContent, {
|
|
107
|
-
dividers: true
|
|
108
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
109
|
-
dangerouslySetInnerHTML: {
|
|
110
|
-
__html: contentHtml
|
|
111
|
-
}
|
|
112
|
-
})), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
|
|
113
|
-
onClick: () => setDialogOpen(false)
|
|
114
|
-
}, i18next.t('common.app.close')))));
|
|
115
|
-
};
|
|
116
|
-
NoticeFieldBlock.propTypes = {
|
|
117
|
-
field: PropTypes.shape({
|
|
118
|
-
key: PropTypes.string.isRequired,
|
|
119
|
-
label: PropTypes.string.isRequired,
|
|
120
|
-
content_html: PropTypes.string,
|
|
121
|
-
meta: PropTypes.object
|
|
122
|
-
}).isRequired,
|
|
123
|
-
i18next: PropTypes.any.isRequired
|
|
25
|
+
// Same type-aware required-field wording as AnimalVehicleDetailsEditor's tab-per-animal grid
|
|
26
|
+
// (index.jsx, this directory) -- duplicated rather than shared, matching the small amount of
|
|
27
|
+
// tolerated duplication already elsewhere in this feature (e.g. each host app keeps its own copy
|
|
28
|
+
// for its live-preview sandbox). Falls back to animal.required_error for text/textarea. 'notice'
|
|
29
|
+
// gets its own message rather than the generic one -- its required-satisfying condition is
|
|
30
|
+
// stricter than every other type (see isFieldAnswered below): only a CHECKED "I have read this"
|
|
31
|
+
// box counts, so "please fill this in" would read wrong for what's actually a checkbox.
|
|
32
|
+
const REQUIRED_ERROR_KEY_BY_TYPE = {
|
|
33
|
+
select: 'animal.required_error_select',
|
|
34
|
+
select_multiple: 'animal.required_error_select_multiple',
|
|
35
|
+
number: 'animal.required_error_number',
|
|
36
|
+
date: 'animal.required_error_date',
|
|
37
|
+
yes_no: 'animal.required_error_yes_no',
|
|
38
|
+
notice: 'animal.required_error_notice'
|
|
124
39
|
};
|
|
125
40
|
|
|
126
41
|
/**
|
|
127
42
|
* Flat, non-tabbed block for a lot's "once per reservation" animal fields: no tabs, no per-animal
|
|
128
43
|
* chrome, no add/remove -- these are single shared values/notices for the whole reservation, not
|
|
129
|
-
* one row per animal. Renders
|
|
44
|
+
* one row per animal. Renders any field (any type, including 'notice') whose config opts into
|
|
45
|
+
* `once_per_reservation` -- reuses the exact same `renderFieldTypeControl` that
|
|
46
|
+
* AnimalVehicleDetailsEditor's tab-per-animal grid uses (see fieldTypeControl.jsx, this directory),
|
|
47
|
+
* so a once-per-reservation field looks and behaves identically to its per-animal counterpart, type
|
|
48
|
+
* for type. `once_per_reservation` is independent of `type` -- a 'notice' field can be either
|
|
49
|
+
* once-per-reservation (rendered here) or per-animal (rendered in the tab grid instead), exactly
|
|
50
|
+
* like any other field type.
|
|
130
51
|
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* counterpart.
|
|
136
|
-
* - Any `field_type === 'notice'` field -- a read-only sanitized-HTML display, never an input.
|
|
137
|
-
* `once_per_reservation` doesn't apply to notices (they're never per-animal to begin with) and
|
|
138
|
-
* is ignored for this type.
|
|
139
|
-
*
|
|
140
|
-
* `fields` does NOT need to be pre-filtered: this component filters internally (any field that is
|
|
141
|
-
* neither a notice nor once_per_reservation is silently skipped), so it's safe to pass the lot's
|
|
142
|
-
* whole field list straight through. Passing an already-filtered subset works identically, since
|
|
143
|
-
* the filter is idempotent.
|
|
52
|
+
* `fields` does NOT need to be pre-filtered: this component filters internally (any field whose
|
|
53
|
+
* `once_per_reservation` isn't `true` is silently skipped), so it's safe to pass the lot's whole
|
|
54
|
+
* field list straight through. Passing an already-filtered subset works identically, since the
|
|
55
|
+
* filter is idempotent.
|
|
144
56
|
*
|
|
145
57
|
* Two usage modes, both through this one component:
|
|
146
58
|
* - Editable (staff/guest edit flow): pass `onChange`. Inputs render live and call
|
|
147
59
|
* `onChange(field.key, newValue)`.
|
|
148
|
-
* - Read-only (review screen): omit `onChange` entirely. Every
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* block's "View full ..." link/dialog behaves identically in both modes, since it was never an
|
|
152
|
-
* input.
|
|
60
|
+
* - Read-only (review screen): omit `onChange` entirely. Every control renders disabled (MUI's own
|
|
61
|
+
* disabled/read-only appearance) instead of interactive -- there is no second "read-only
|
|
62
|
+
* variant" component to import, this is the same export either way.
|
|
153
63
|
*
|
|
154
64
|
* ## Importing the component in your project
|
|
155
65
|
*
|
|
@@ -165,13 +75,15 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
165
75
|
fields,
|
|
166
76
|
values,
|
|
167
77
|
onChange,
|
|
78
|
+
isFieldAnswered,
|
|
168
79
|
className,
|
|
169
80
|
theme,
|
|
170
81
|
i18next
|
|
171
82
|
} = props;
|
|
172
83
|
const compTheme = theme || useTheme();
|
|
173
84
|
const defaultTheme = createTheme(compTheme);
|
|
174
|
-
const
|
|
85
|
+
const requiredErrorText = fieldType => i18next.t(REQUIRED_ERROR_KEY_BY_TYPE[fieldType] || 'animal.required_error');
|
|
86
|
+
const relevantFields = fields.filter(field => readFieldProp(field, 'once_per_reservation') === true);
|
|
175
87
|
if (relevantFields.length === 0) return null;
|
|
176
88
|
return /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
177
89
|
theme: defaultTheme
|
|
@@ -185,16 +97,15 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
185
97
|
gridAutoFlow: 'row dense'
|
|
186
98
|
}
|
|
187
99
|
}, relevantFields.map(field => {
|
|
188
|
-
if (field.type === 'notice') {
|
|
189
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
190
|
-
key: field.key,
|
|
191
|
-
className: "col-span-full"
|
|
192
|
-
}, /*#__PURE__*/React.createElement(NoticeFieldBlock, {
|
|
193
|
-
field: field,
|
|
194
|
-
i18next: i18next
|
|
195
|
-
}));
|
|
196
|
-
}
|
|
197
100
|
const rawValue = values?.[field.key] ?? (field.type === 'select_multiple' ? [] : '');
|
|
101
|
+
// Required-and-not-yet-answered gets the same red label + control error state the
|
|
102
|
+
// per-animal grid already shows (index.jsx, this directory) -- this block previously
|
|
103
|
+
// hardcoded error: false/helperText: '' unconditionally, so a required once-per-
|
|
104
|
+
// reservation field (e.g. a mandatory "I have read this" notice, or a required yes_no
|
|
105
|
+
// asked once) never visibly indicated it was outstanding. isFieldAnswered is supplied
|
|
106
|
+
// by the caller (same prop AnimalVehicleDetailsEditor already requires), since it's
|
|
107
|
+
// app-specific logic this shared package doesn't own.
|
|
108
|
+
const showError = field.required && !isFieldAnswered(field.type, rawValue);
|
|
198
109
|
const labelText = field.required ? `${field.label} *` : field.label;
|
|
199
110
|
return /*#__PURE__*/React.createElement("div", {
|
|
200
111
|
key: field.key,
|
|
@@ -203,7 +114,8 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
203
114
|
variant: "body2",
|
|
204
115
|
sx: {
|
|
205
116
|
fontWeight: 500,
|
|
206
|
-
mb: 0.5
|
|
117
|
+
mb: 0.5,
|
|
118
|
+
color: showError ? 'error.main' : 'text.primary'
|
|
207
119
|
}
|
|
208
120
|
}, labelText), renderFieldTypeControl({
|
|
209
121
|
field,
|
|
@@ -213,8 +125,8 @@ export const AnimalFieldsOnceBlock = props => {
|
|
|
213
125
|
// consumer's own event wiring calls it directly in a test.
|
|
214
126
|
onChange: onChange ? newValue => onChange(field.key, newValue) : () => {},
|
|
215
127
|
disabled: !onChange,
|
|
216
|
-
error:
|
|
217
|
-
helperText: '',
|
|
128
|
+
error: showError,
|
|
129
|
+
helperText: showError ? requiredErrorText(field.type) : '',
|
|
218
130
|
i18next
|
|
219
131
|
}));
|
|
220
132
|
}))));
|
|
@@ -231,8 +143,9 @@ AnimalFieldsOnceBlock.propTypes = {
|
|
|
231
143
|
/** The lot's field configs -- does not need to be pre-filtered, see the component doc above.
|
|
232
144
|
* Normalized to the same flat shape AnimalVehicleDetailsEditor's `fieldConfig` already uses
|
|
233
145
|
* (label/options/unit/placeholder resolved by the caller), plus this feature's two additions:
|
|
234
|
-
* `once_per_reservation` (
|
|
235
|
-
*
|
|
146
|
+
* `once_per_reservation` (any type, independently admin-configurable) and `content_html` (type
|
|
147
|
+
* 'notice' only, read inside fieldTypeControl.jsx's notice control). Both are also read from
|
|
148
|
+
* `field.meta.<key>` as a fallback if a caller passes the meta object through unflattened. */
|
|
236
149
|
fields: PropTypes.arrayOf(PropTypes.shape({
|
|
237
150
|
key: PropTypes.string.isRequired,
|
|
238
151
|
label: PropTypes.string.isRequired,
|
|
@@ -252,6 +165,10 @@ AnimalFieldsOnceBlock.propTypes = {
|
|
|
252
165
|
/** (fieldKey, value) => void. Omit entirely to render every input control disabled/read-only
|
|
253
166
|
* (review-screen usage) -- see the component doc above. */
|
|
254
167
|
onChange: PropTypes.func,
|
|
168
|
+
/** (fieldType, value) => boolean. Same function each host app already passes into
|
|
169
|
+
* AnimalVehicleDetailsEditor's isFieldAnswered prop -- required so a required-but-unanswered
|
|
170
|
+
* once-per-reservation field can show the same red label/error state the per-animal grid does. */
|
|
171
|
+
isFieldAnswered: PropTypes.func.isRequired,
|
|
255
172
|
/** Classes applied to the component's own wrapper div. */
|
|
256
173
|
className: PropTypes.string,
|
|
257
174
|
/** Theme object to use on this component, if none provided then the MUI5 theme provider theme is used. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { TextField, InputAdornment, MenuItem, ToggleButton, ToggleButtonGroup, Checkbox, ListItemText, Chip } from '@mui/material';
|
|
2
|
+
import React, { useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { TextField, InputAdornment, MenuItem, ToggleButton, ToggleButtonGroup, Checkbox, ListItemText, Chip, FormControlLabel, FormHelperText, Paper, Button, Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
|
4
4
|
|
|
5
5
|
// A native <input type="date"> only opens its calendar popup on its own when the browser's tiny
|
|
6
6
|
// built-in icon is clicked -- clicking anywhere else in the field just places the text caret
|
|
@@ -18,10 +18,116 @@ export const openNativeDatePicker = e => {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
// Collapsed height for a notice's rich-text content before it needs a "View full ..." link. A
|
|
22
|
+
// handful of lines of admin-entered text/markup fits inside this without ever showing the link at
|
|
23
|
+
// all; anything longer gets clipped here and offered in full through the dialog below.
|
|
24
|
+
const NOTICE_COLLAPSED_MAX_HEIGHT = 160;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The control for a `notice` field: the admin's sanitized rich text inside a bounded-height
|
|
28
|
+
* container (only overflowing content gets a "View full {label}" link that opens the rest in a
|
|
29
|
+
* Dialog), plus a single "I have read this" checkbox whose checked state IS the field's value --
|
|
30
|
+
* stored the same way a `yes_no` field's boolean value is. Not exported -- only reached through
|
|
31
|
+
* `renderFieldTypeControl`'s `notice` case below, same as every other type-specific control in
|
|
32
|
+
* this switch.
|
|
33
|
+
*
|
|
34
|
+
* The field's own label is deliberately NOT rendered in here: both call sites
|
|
35
|
+
* (AnimalVehicleDetailsEditor's per-item grid and AnimalFieldsOnceBlock's flat layout) already
|
|
36
|
+
* render `field.label` above whatever control this function returns, same as for every other type.
|
|
37
|
+
*/
|
|
38
|
+
const NoticeFieldControl = ({
|
|
39
|
+
field,
|
|
40
|
+
value,
|
|
41
|
+
onChange,
|
|
42
|
+
disabled,
|
|
43
|
+
error,
|
|
44
|
+
helperText,
|
|
45
|
+
i18next
|
|
46
|
+
}) => {
|
|
47
|
+
const contentRef = useRef(null);
|
|
48
|
+
const [overflowing, setOverflowing] = useState(false);
|
|
49
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
50
|
+
// Already HTML-sanitized server-side before this ever reaches the client -- safe to render as-is.
|
|
51
|
+
// `field.meta.content_html` fallback covers a caller passing the raw meta object through
|
|
52
|
+
// unflattened, same convention this feature's other `field.<key>` reads already follow.
|
|
53
|
+
const contentHtml = field.content_html !== undefined ? field.content_html : field.meta?.content_html || '';
|
|
54
|
+
|
|
55
|
+
// Measured after mount/paint (useLayoutEffect, not useEffect) so the "View full ..." link never
|
|
56
|
+
// flashes in for a heartbeat on content that turns out to fit. Re-checked on window resize too:
|
|
57
|
+
// the height bound is fixed in CSS, but at a narrower viewport the same HTML can wrap onto more
|
|
58
|
+
// lines and start overflowing where it didn't before.
|
|
59
|
+
useLayoutEffect(() => {
|
|
60
|
+
const checkOverflow = () => {
|
|
61
|
+
const el = contentRef.current;
|
|
62
|
+
if (!el) return;
|
|
63
|
+
setOverflowing(el.scrollHeight > el.clientHeight);
|
|
64
|
+
};
|
|
65
|
+
checkOverflow();
|
|
66
|
+
window.addEventListener('resize', checkOverflow);
|
|
67
|
+
return () => window.removeEventListener('resize', checkOverflow);
|
|
68
|
+
}, [contentHtml]);
|
|
69
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
70
|
+
className: "flex flex-col",
|
|
71
|
+
style: {
|
|
72
|
+
gap: 4
|
|
73
|
+
}
|
|
74
|
+
}, /*#__PURE__*/React.createElement(Paper, {
|
|
75
|
+
variant: "outlined",
|
|
76
|
+
sx: {
|
|
77
|
+
p: 1.5,
|
|
78
|
+
borderRadius: 1,
|
|
79
|
+
bgcolor: 'action.hover',
|
|
80
|
+
maxHeight: NOTICE_COLLAPSED_MAX_HEIGHT,
|
|
81
|
+
overflow: 'hidden'
|
|
82
|
+
}
|
|
83
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
84
|
+
ref: contentRef,
|
|
85
|
+
dangerouslySetInnerHTML: {
|
|
86
|
+
__html: contentHtml
|
|
87
|
+
}
|
|
88
|
+
})), overflowing && /*#__PURE__*/React.createElement(Button, {
|
|
89
|
+
size: "small",
|
|
90
|
+
disabled: disabled,
|
|
91
|
+
onClick: () => setDialogOpen(true),
|
|
92
|
+
sx: {
|
|
93
|
+
alignSelf: 'flex-start',
|
|
94
|
+
textTransform: 'none',
|
|
95
|
+
minWidth: 0,
|
|
96
|
+
p: 0
|
|
97
|
+
}
|
|
98
|
+
}, i18next.t('animal.view_full_field', {
|
|
99
|
+
label: field.label
|
|
100
|
+
})), /*#__PURE__*/React.createElement(Dialog, {
|
|
101
|
+
open: dialogOpen,
|
|
102
|
+
onClose: () => setDialogOpen(false),
|
|
103
|
+
maxWidth: "sm",
|
|
104
|
+
fullWidth: true,
|
|
105
|
+
scroll: "paper"
|
|
106
|
+
}, /*#__PURE__*/React.createElement(DialogTitle, null, field.label), /*#__PURE__*/React.createElement(DialogContent, {
|
|
107
|
+
dividers: true
|
|
108
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
109
|
+
dangerouslySetInnerHTML: {
|
|
110
|
+
__html: contentHtml
|
|
111
|
+
}
|
|
112
|
+
})), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
|
|
113
|
+
onClick: () => setDialogOpen(false)
|
|
114
|
+
}, i18next.t('common.app.close')))), /*#__PURE__*/React.createElement(FormControlLabel, {
|
|
115
|
+
control: /*#__PURE__*/React.createElement(Checkbox, {
|
|
116
|
+
checked: value === true,
|
|
117
|
+
onChange: e => onChange(e.target.checked),
|
|
118
|
+
disabled: disabled,
|
|
119
|
+
color: error ? 'error' : 'primary'
|
|
120
|
+
}),
|
|
121
|
+
label: i18next.t('animal.read_notice_confirmation')
|
|
122
|
+
}), helperText && /*#__PURE__*/React.createElement(FormHelperText, {
|
|
123
|
+
error: error
|
|
124
|
+
}, helperText));
|
|
125
|
+
};
|
|
126
|
+
|
|
21
127
|
/**
|
|
22
128
|
* Renders the single form control for one {field, value, onChange} triple across every field type
|
|
23
|
-
* this feature knows about: text / number / select / select_multiple / textarea / yes_no / date
|
|
24
|
-
* (unknown/legacy types fall back to plain text, same as before). Pulled out of the per-item field
|
|
129
|
+
* this feature knows about: text / number / select / select_multiple / textarea / yes_no / date /
|
|
130
|
+
* notice (unknown/legacy types fall back to plain text, same as before). Pulled out of the per-item field
|
|
25
131
|
* grid in `index.jsx` (AnimalVehicleDetailsEditor's tab-per-animal editor) so
|
|
26
132
|
* `AnimalFieldsOnceBlock`'s flat once-per-reservation layout, in the same directory, can render the
|
|
27
133
|
* exact same controls without a second copy of this switch. Both call sites feed it the same shape
|
|
@@ -40,7 +146,8 @@ export const openNativeDatePicker = e => {
|
|
|
40
146
|
* Only `key`/`type` and the type-specific extras are read here; `label`/`required` are the
|
|
41
147
|
* caller's concern (rendered outside this function).
|
|
42
148
|
* @param {*} params.value - Current value, already shaped for `field.type` (string for
|
|
43
|
-
* text/select/number/date, array for select_multiple, boolean|null for yes_no
|
|
149
|
+
* text/select/number/date, array for select_multiple, boolean|null for yes_no/notice -- for
|
|
150
|
+
* notice this is the "I have read this" checkbox's checked state, not the (read-only) content).
|
|
44
151
|
* @param {(value: *) => void} params.onChange - Called with the new value in that same shape.
|
|
45
152
|
* Callers needing an (itemId, key, value) or (key, value) signature wrap it, e.g.
|
|
46
153
|
* `(v) => onFieldChange(item.id, field.key, v)`.
|
|
@@ -158,6 +265,16 @@ export const renderFieldTypeControl = ({
|
|
|
158
265
|
value: "no"
|
|
159
266
|
}, i18next.t('common.app.no')));
|
|
160
267
|
}
|
|
268
|
+
case 'notice':
|
|
269
|
+
return /*#__PURE__*/React.createElement(NoticeFieldControl, {
|
|
270
|
+
field: field,
|
|
271
|
+
value: value,
|
|
272
|
+
onChange: onChange,
|
|
273
|
+
disabled: disabled,
|
|
274
|
+
error: error,
|
|
275
|
+
helperText: helperText,
|
|
276
|
+
i18next: i18next
|
|
277
|
+
});
|
|
161
278
|
case 'date':
|
|
162
279
|
// Native date input, not each host app's own local DateTimeField wrapper -- this component
|
|
163
280
|
// can't depend on either app's app-local component tree. Value is a plain 'YYYY-MM-DD'
|
|
@@ -47,12 +47,17 @@ const KEYS = {
|
|
|
47
47
|
// select an option" reads very differently from "please enter a number". Not itemType-specific:
|
|
48
48
|
// a select field is a select field whether it belongs to an animal or a vehicle. Falls back to
|
|
49
49
|
// animal.required_error for text/textarea, where the generic "fill this in" copy already fits.
|
|
50
|
+
// 'notice' gets its own message (animal.required_error_notice) rather than the generic one --
|
|
51
|
+
// its required-satisfying condition is stricter than every other type (see isFieldAnswered,
|
|
52
|
+
// injected by the caller): only a CHECKED "I have read this" box counts, so "please fill this in"
|
|
53
|
+
// would read wrong for what's actually a checkbox.
|
|
50
54
|
const REQUIRED_ERROR_KEY_BY_TYPE = {
|
|
51
55
|
select: 'animal.required_error_select',
|
|
52
56
|
select_multiple: 'animal.required_error_select_multiple',
|
|
53
57
|
number: 'animal.required_error_number',
|
|
54
58
|
date: 'animal.required_error_date',
|
|
55
|
-
yes_no: 'animal.required_error_yes_no'
|
|
59
|
+
yes_no: 'animal.required_error_yes_no',
|
|
60
|
+
notice: 'animal.required_error_notice'
|
|
56
61
|
};
|
|
57
62
|
|
|
58
63
|
/**
|
|
@@ -224,7 +229,7 @@ export const AnimalVehicleDetailsEditor = props => {
|
|
|
224
229
|
return nextWrapped;
|
|
225
230
|
});
|
|
226
231
|
}, [fieldConfig, wrappedKeys]);
|
|
227
|
-
const isFullWidthField = f => ['select', 'textarea', 'select_multiple'].includes(f.type) || wrappedKeys.has(f.key);
|
|
232
|
+
const isFullWidthField = f => ['select', 'textarea', 'select_multiple', 'notice'].includes(f.type) || wrappedKeys.has(f.key);
|
|
228
233
|
return /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
229
234
|
theme: defaultTheme
|
|
230
235
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -617,11 +622,14 @@ AnimalVehicleDetailsEditor.propTypes = {
|
|
|
617
622
|
key: PropTypes.string.isRequired,
|
|
618
623
|
label: PropTypes.string.isRequired,
|
|
619
624
|
required: PropTypes.bool,
|
|
620
|
-
type: PropTypes.oneOf(['text', 'number', 'select', 'select_multiple', 'textarea', 'yes_no', 'date']),
|
|
625
|
+
type: PropTypes.oneOf(['text', 'number', 'select', 'select_multiple', 'textarea', 'yes_no', 'date', 'notice']),
|
|
621
626
|
options: PropTypes.arrayOf(PropTypes.string),
|
|
622
627
|
unit: PropTypes.string,
|
|
623
628
|
placeholder: PropTypes.string,
|
|
624
|
-
maxLength: PropTypes.number
|
|
629
|
+
maxLength: PropTypes.number,
|
|
630
|
+
/** Type 'notice' only -- the admin's sanitized rich text, read inside fieldTypeControl.jsx's
|
|
631
|
+
* notice control. */
|
|
632
|
+
content_html: PropTypes.string
|
|
625
633
|
})),
|
|
626
634
|
/** (type, value) => boolean. Injected rather than owned internally, so each host app's existing
|
|
627
635
|
* "has this field actually been answered" rule (yes_no's `false` counts, etc.) stays authoritative. */
|
|
@@ -39,16 +39,14 @@ export const classifyAnimalFieldValue = (fieldConfig, rawValue) => {
|
|
|
39
39
|
options
|
|
40
40
|
} = fieldConfig;
|
|
41
41
|
|
|
42
|
-
// notice
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// field was retyped to 'notice'
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
if (type === 'notice') return 'unanswered';
|
|
51
|
-
if (type === 'yes_no') {
|
|
42
|
+
// notice's control is a single "I have read this" checkbox, whose checked state IS the field's
|
|
43
|
+
// value -- stored as a real boolean in field_values, exactly like yes_no. Same classification as
|
|
44
|
+
// yes_no below: a stored `true`/`false` is 'answered' (a stray non-boolean leftover from before
|
|
45
|
+
// the field was retyped to/from 'notice' is 'drifted' rather than silently treated as answered),
|
|
46
|
+
// anything else is 'unanswered'. This is drift-detection shape-matching only -- it does NOT decide
|
|
47
|
+
// whether an unchecked (`false`) box satisfies a *required* notice, which is a stricter rule than
|
|
48
|
+
// yes_no's (see isFieldAnswered, injected by each caller, not this function).
|
|
49
|
+
if (type === 'yes_no' || type === 'notice') {
|
|
52
50
|
if (typeof rawValue === 'boolean') return 'answered';
|
|
53
51
|
return hasWrongShapeContent(rawValue) ? 'drifted' : 'unanswered';
|
|
54
52
|
}
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"required_error": "Please fill this in.",
|
|
20
20
|
"required_for_guests": "Required for guests",
|
|
21
21
|
"section_intro": "Please tell us a bit about each animal traveling with you.",
|
|
22
|
+
"read_notice_confirmation": "I have read this",
|
|
23
|
+
"required_error_notice": "Please confirm you have read this.",
|
|
22
24
|
"required_error_select": "Please select an option.",
|
|
23
25
|
"required_error_select_multiple": "Please select at least one option.",
|
|
24
26
|
"required_error_number": "Please enter a number.",
|
|
@@ -2469,7 +2471,7 @@
|
|
|
2469
2471
|
"ask_once_per_reservation": "Ask once per reservation",
|
|
2470
2472
|
"once_per_reservation_helper": "Shown once for the whole reservation instead of once per animal.",
|
|
2471
2473
|
"notice_content_label": "Notice content",
|
|
2472
|
-
"
|
|
2474
|
+
"notice_empty_hint": "Add your notice text above to see it here.",
|
|
2473
2475
|
"options_label": "Options",
|
|
2474
2476
|
"add_option": "Add Option",
|
|
2475
2477
|
"unit_label": "Unit",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"required_error": "Por favor, complete este campo.",
|
|
20
20
|
"required_for_guests": "Requerido para huéspedes",
|
|
21
21
|
"section_intro": "Por favor, cuéntenos un poco sobre cada animal que viaja con usted.",
|
|
22
|
+
"read_notice_confirmation": "He leído esto",
|
|
23
|
+
"required_error_notice": "Por favor, confirme que ha leído esto.",
|
|
22
24
|
"required_error_select": "Por favor, seleccione una opción.",
|
|
23
25
|
"required_error_select_multiple": "Por favor, seleccione al menos una opción.",
|
|
24
26
|
"required_error_number": "Por favor, ingrese un número.",
|
|
@@ -2469,7 +2471,7 @@
|
|
|
2469
2471
|
"ask_once_per_reservation": "Preguntar una sola vez por reserva",
|
|
2470
2472
|
"once_per_reservation_helper": "Se muestra una sola vez para toda la reserva, en lugar de una vez por animal.",
|
|
2471
2473
|
"notice_content_label": "Contenido del aviso",
|
|
2472
|
-
"
|
|
2474
|
+
"notice_empty_hint": "Agregue el texto de su aviso arriba para verlo aquí.",
|
|
2473
2475
|
"options_label": "Opciones",
|
|
2474
2476
|
"add_option": "Agregar opción",
|
|
2475
2477
|
"unit_label": "Unidad",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"required_error": "Veuillez remplir ce champ.",
|
|
20
20
|
"required_for_guests": "Requis pour les clients",
|
|
21
21
|
"section_intro": "Merci de nous donner quelques informations sur chaque animal qui vous accompagne.",
|
|
22
|
+
"read_notice_confirmation": "J'ai lu ceci",
|
|
23
|
+
"required_error_notice": "Veuillez confirmer que vous avez lu ceci.",
|
|
22
24
|
"required_error_select": "Veuillez sélectionner une option.",
|
|
23
25
|
"required_error_select_multiple": "Veuillez sélectionner au moins une option.",
|
|
24
26
|
"required_error_number": "Veuillez entrer un nombre.",
|
|
@@ -2469,7 +2471,7 @@
|
|
|
2469
2471
|
"ask_once_per_reservation": "Demander une seule fois par réservation",
|
|
2470
2472
|
"once_per_reservation_helper": "Affiché une seule fois pour toute la réservation, plutôt que pour chaque animal.",
|
|
2471
2473
|
"notice_content_label": "Contenu de l'avis",
|
|
2472
|
-
"
|
|
2474
|
+
"notice_empty_hint": "Ajoutez le texte de votre avis ci-dessus pour le voir ici.",
|
|
2473
2475
|
"options_label": "Options",
|
|
2474
2476
|
"add_option": "Ajouter une option",
|
|
2475
2477
|
"unit_label": "Unité",
|
package/dist/styles/tailwind.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
*,::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-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:#2196f380;--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: }.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-top-2{top:-.2rem}.-top-6{top:-.6rem}.bottom-0{bottom:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.top-20{top:2rem}.top-64{top:6.4rem}.z-10{z-index:10}.z-99{z-index:99}.col-span-full{grid-column:1/-1}.m-10{margin:1rem}.m-12{margin:1.2rem}.m-24{margin:2.4rem}.m-4{margin:.4rem}.m-6{margin:.6rem}.m-auto{margin:auto}.mx-0{margin-left:0;margin-right:0}.mx-12{margin-left:1.2rem;margin-right:1.2rem}.mx-2{margin-left:.2rem;margin-right:.2rem}.mx-4{margin-left:.4rem;margin-right:.4rem}.mx-6{margin-left:.6rem;margin-right:.6rem}.mx-8{margin-left:.8rem;margin-right:.8rem}.mx-auto{margin-left:auto;margin-right:auto}.my-12{margin-top:1.2rem;margin-bottom:1.2rem}.my-24{margin-top:2.4rem;margin-bottom:2.4rem}.my-4{margin-top:.4rem;margin-bottom:.4rem}.my-6{margin-top:.6rem;margin-bottom:.6rem}.my-auto{margin-top:auto;margin-bottom:auto}.-ml-10{margin-left:-1rem}.mb-0{margin-bottom:0}.mb-12{margin-bottom:1.2rem}.mb-2{margin-bottom:.2rem}.mb-24{margin-bottom:2.4rem}.mb-6{margin-bottom:.6rem}.mb-8{margin-bottom:.8rem}.ml-0{margin-left:0}.ml-1{margin-left:.1rem}.ml-12{margin-left:1.2rem}.ml-24{margin-left:2.4rem}.ml-6{margin-left:.6rem}.ml-8{margin-left:.8rem}.mr-0{margin-right:0}.mr-12{margin-right:1.2rem}.mr-24{margin-right:2.4rem}.mr-6{margin-right:.6rem}.mt-0{margin-top:0}.mt-12{margin-top:1.2rem}.mt-24{margin-top:2.4rem}.mt-4{margin-top:.4rem}.mt-6{margin-top:.6rem}.mt-auto{margin-top:auto}.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}.hidden{display:none}.h-136{height:13.6rem}.h-200{height:20rem}.h-24{height:2.4rem}.h-400{height:40rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-32{max-height:3.2rem}.max-h-512{max-height:51.2rem}.min-h-160{min-height:16rem}.min-h-224{min-height:22.4rem}.min-h-256{min-height:25.6rem}.w-1\/2{width:50%}.w-2\/5{width:40%}.w-24{width:2.4rem}.w-3\/4{width:75%}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.max-w-min{max-width:-moz-min-content;max-width:min-content}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.grow{flex-grow:1}.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))}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,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}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-4{gap:.4rem}.gap-6{gap:.6rem}.space-x-10>: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-10>: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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overscroll-none{overscroll-behavior:none}.truncate{overflow:hidden;white-space:nowrap}.overflow-ellipsis,.truncate{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.4rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.8rem}.rounded-md{border-radius:.6rem}.rounded-t-md{border-top-left-radius:.6rem;border-top-right-radius:.6rem}.rounded-bl-lg{border-bottom-left-radius:.8rem}.rounded-br-lg{border-bottom-right-radius:.8rem}.rounded-tl-lg{border-top-left-radius:.8rem}.rounded-tr-lg{border-top-right-radius:.8rem}.border{border-width:1px}.border-2{border-width:2px}.border-t-8{border-top-width:8px}.border-transparent{border-color:#0000}.bg-black{--tw-bg-opacity:1;background-color:rgb(34 41 47/var(--tw-bg-opacity,1))}.bg-blue{--tw-bg-opacity:1;background-color:rgb(33 150 243/var(--tw-bg-opacity,1))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(66 66 66/var(--tw-bg-opacity,1))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(67 160 71/var(--tw-bg-opacity,1))}.bg-grey-100{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-grey-200{--tw-bg-opacity:1;background-color:rgb(238 238 238/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-100\/50{background-color:#fff9c480}.bg-cover{background-size:cover}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-10{padding:1rem}.p-12{padding:1.2rem}.p-24{padding:2.4rem}.p-6{padding:.6rem}.px-2{padding-left:.2rem;padding-right:.2rem}.px-4{padding-left:.4rem;padding-right:.4rem}.px-6{padding-left:.6rem;padding-right:.6rem}.px-8{padding-left:.8rem;padding-right:.8rem}.py-2{padding-top:.2rem;padding-bottom:.2rem}.py-4{padding-top:.4rem;padding-bottom:.4rem}.py-6{padding-top:.6rem;padding-bottom:.6rem}.pb-4{padding-bottom:.4rem}.pl-0{padding-left:0}.pl-4{padding-left:.4rem}.pl-8{padding-left:.8rem}.pr-0{padding-right:0}.pr-6{padding-right:.6rem}.pt-0{padding-top:0}.pt-12{padding-top:1.2rem}.pt-4{padding-top:.4rem}.text-left{text-align:left}.text-center{text-align:center}.font-sans{font-family:Muli,Roboto,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-serif{font-family:Georgia,Cambria,Times New Roman,Times,serif}.text-14{font-size:1.4rem}.text-16{font-size:1.6rem}.text-17{font-size:1.7rem}.text-24,.text-2xl{font-size:2.4rem}.text-2xl{line-height:3.2rem}.text-32{font-size:3.2rem}.text-4xl{font-size:3.6rem;line-height:4rem}.text-5xl{font-size:4.8rem;line-height:1}.text-6xl{font-size:6rem;line-height:1}.text-base{font-size:1.6rem;line-height:2.4rem}.text-sm{font-size:1.4rem;line-height:2rem}.text-xl{font-size:2rem;line-height:2.8rem}.font-500{font-weight:500}.font-600{font-weight:600}.font-800{font-weight:800}.font-900{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.leading-none{line-height:1}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.text-gray-300{--tw-text-opacity:1;color:rgb(224 224 224/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(158 158 158/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(117 117 117/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(97 97 97/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(67 160 71/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(56 142 60/var(--tw-text-opacity,1))}.text-grey-800{--tw-text-opacity:1;color:rgb(66 66 66/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(251 140 0/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}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.decoration-gray-500{text-decoration-color:#9e9e9e}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px 0 #0000000f;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-1{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-1{--tw-shadow:0px 2px 1px -1px #0003,0px 1px 1px 0px #00000024,0px 1px 3px 0px #0000001f;--tw-shadow-colored:0px 2px 1px -1px var(--tw-shadow-color),0px 1px 1px 0px var(--tw-shadow-color),0px 1px 3px 0px var(--tw-shadow-color)}.shadow-2{--tw-shadow:0px 3px 1px -2px #0003,0px 2px 2px 0px #00000024,0px 1px 5px 0px #0000001f;--tw-shadow-colored:0px 3px 1px -2px var(--tw-shadow-color),0px 2px 2px 0px var(--tw-shadow-color),0px 1px 5px 0px var(--tw-shadow-color)}.shadow-2,.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 -1px #0000000f;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -1px 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)}.blur{--tw-blur:blur(8px)}.blur,.contrast-0{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)}.contrast-0{--tw-contrast:contrast(0)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f)}.drop-shadow,.drop-shadow-none{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)}.drop-shadow-none{--tw-drop-shadow:drop-shadow(0 0 #0000)}.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:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,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}.duration-300{transition-duration:.3s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:translate-y-1:hover{--tw-translate-y:0.1rem}.hover\:rotate-3:hover,.hover\:translate-y-1: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\:rotate-3:hover{--tw-rotate:3deg}.hover\:skew-y-3:hover{--tw-skew-y:3deg}.hover\:scale-105:hover,.hover\:skew-y-3: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-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:list-disc:hover{list-style-type:disc}.hover\:bg-gray-100\/75:hover{background-color:#f5f5f5bf}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(56 142 60/var(--tw-bg-opacity,1))}.hover\:bg-grey-300:hover{--tw-bg-opacity:1;background-color:rgb(224 224 224/var(--tw-bg-opacity,1))}.hover\:bg-indigo-100\/25:hover{background-color:#c5cae940}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(97 97 97/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:brightness-75:hover{--tw-brightness:brightness(.75)}.hover\:brightness-75:hover,.hover\:drop-shadow-2xl:hover{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)}.hover\:drop-shadow-2xl:hover{--tw-drop-shadow:drop-shadow(0 25px 25px #00000026)}.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);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-green-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(76 175 80/var(--tw-ring-opacity,1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}@media (min-width:600px){.sm\:p-8{padding:.8rem}}@media (min-width:960px){.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:ml-12{margin-left:1.2rem}.md\:flex{display:flex}.md\:hidden{display:none}.md\:max-w-288{max-width:28.8rem}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:pt-0{padding-top:0}}@media (prefers-color-scheme:dark){.dark\:text-gray-500{--tw-text-opacity:1;color:rgb(158 158 158/var(--tw-text-opacity,1))}.dark\:text-green-500{--tw-text-opacity:1;color:rgb(76 175 80/var(--tw-text-opacity,1))}.dark\:text-orange-500{--tw-text-opacity:1;color:rgb(255 152 0/var(--tw-text-opacity,1))}}
|
|
1
|
+
*,::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-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:#2196f380;--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: }.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-top-2{top:-.2rem}.-top-6{top:-.6rem}.bottom-0{bottom:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.top-20{top:2rem}.top-64{top:6.4rem}.z-10{z-index:10}.z-99{z-index:99}.col-span-full{grid-column:1/-1}.m-10{margin:1rem}.m-12{margin:1.2rem}.m-24{margin:2.4rem}.m-4{margin:.4rem}.m-6{margin:.6rem}.m-auto{margin:auto}.mx-0{margin-left:0;margin-right:0}.mx-12{margin-left:1.2rem;margin-right:1.2rem}.mx-2{margin-left:.2rem;margin-right:.2rem}.mx-4{margin-left:.4rem;margin-right:.4rem}.mx-6{margin-left:.6rem;margin-right:.6rem}.mx-8{margin-left:.8rem;margin-right:.8rem}.mx-auto{margin-left:auto;margin-right:auto}.my-12{margin-top:1.2rem;margin-bottom:1.2rem}.my-24{margin-top:2.4rem;margin-bottom:2.4rem}.my-4{margin-top:.4rem;margin-bottom:.4rem}.my-6{margin-top:.6rem;margin-bottom:.6rem}.my-auto{margin-top:auto;margin-bottom:auto}.-ml-10{margin-left:-1rem}.mb-0{margin-bottom:0}.mb-12{margin-bottom:1.2rem}.mb-2{margin-bottom:.2rem}.mb-24{margin-bottom:2.4rem}.mb-6{margin-bottom:.6rem}.mb-8{margin-bottom:.8rem}.ml-0{margin-left:0}.ml-1{margin-left:.1rem}.ml-12{margin-left:1.2rem}.ml-24{margin-left:2.4rem}.ml-6{margin-left:.6rem}.ml-8{margin-left:.8rem}.mr-0{margin-right:0}.mr-12{margin-right:1.2rem}.mr-24{margin-right:2.4rem}.mr-6{margin-right:.6rem}.mt-0{margin-top:0}.mt-12{margin-top:1.2rem}.mt-24{margin-top:2.4rem}.mt-4{margin-top:.4rem}.mt-6{margin-top:.6rem}.mt-auto{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-136{height:13.6rem}.h-200{height:20rem}.h-24{height:2.4rem}.h-400{height:40rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-32{max-height:3.2rem}.max-h-512{max-height:51.2rem}.min-h-160{min-height:16rem}.min-h-224{min-height:22.4rem}.min-h-256{min-height:25.6rem}.w-1\/2{width:50%}.w-2\/5{width:40%}.w-24{width:2.4rem}.w-3\/4{width:75%}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.max-w-min{max-width:-moz-min-content;max-width:min-content}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.grow{flex-grow:1}.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))}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,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}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-4{gap:.4rem}.gap-6{gap:.6rem}.space-x-10>: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-10>: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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overscroll-none{overscroll-behavior:none}.truncate{overflow:hidden;white-space:nowrap}.overflow-ellipsis,.truncate{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.4rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.8rem}.rounded-md{border-radius:.6rem}.rounded-t-md{border-top-left-radius:.6rem;border-top-right-radius:.6rem}.rounded-bl-lg{border-bottom-left-radius:.8rem}.rounded-br-lg{border-bottom-right-radius:.8rem}.rounded-tl-lg{border-top-left-radius:.8rem}.rounded-tr-lg{border-top-right-radius:.8rem}.border{border-width:1px}.border-2{border-width:2px}.border-t-8{border-top-width:8px}.border-transparent{border-color:#0000}.bg-black{--tw-bg-opacity:1;background-color:rgb(34 41 47/var(--tw-bg-opacity,1))}.bg-blue{--tw-bg-opacity:1;background-color:rgb(33 150 243/var(--tw-bg-opacity,1))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(66 66 66/var(--tw-bg-opacity,1))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(67 160 71/var(--tw-bg-opacity,1))}.bg-grey-100{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-grey-200{--tw-bg-opacity:1;background-color:rgb(238 238 238/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-100\/50{background-color:#fff9c480}.bg-cover{background-size:cover}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-10{padding:1rem}.p-12{padding:1.2rem}.p-24{padding:2.4rem}.p-6{padding:.6rem}.px-2{padding-left:.2rem;padding-right:.2rem}.px-4{padding-left:.4rem;padding-right:.4rem}.px-6{padding-left:.6rem;padding-right:.6rem}.px-8{padding-left:.8rem;padding-right:.8rem}.py-2{padding-top:.2rem;padding-bottom:.2rem}.py-4{padding-top:.4rem;padding-bottom:.4rem}.py-6{padding-top:.6rem;padding-bottom:.6rem}.pb-4{padding-bottom:.4rem}.pl-0{padding-left:0}.pl-4{padding-left:.4rem}.pl-8{padding-left:.8rem}.pr-0{padding-right:0}.pr-6{padding-right:.6rem}.pt-0{padding-top:0}.pt-12{padding-top:1.2rem}.pt-4{padding-top:.4rem}.text-left{text-align:left}.text-center{text-align:center}.font-sans{font-family:Muli,Roboto,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-serif{font-family:Georgia,Cambria,Times New Roman,Times,serif}.text-14{font-size:1.4rem}.text-16{font-size:1.6rem}.text-17{font-size:1.7rem}.text-24,.text-2xl{font-size:2.4rem}.text-2xl{line-height:3.2rem}.text-32{font-size:3.2rem}.text-4xl{font-size:3.6rem;line-height:4rem}.text-5xl{font-size:4.8rem;line-height:1}.text-6xl{font-size:6rem;line-height:1}.text-base{font-size:1.6rem;line-height:2.4rem}.text-sm{font-size:1.4rem;line-height:2rem}.text-xl{font-size:2rem;line-height:2.8rem}.font-500{font-weight:500}.font-600{font-weight:600}.font-800{font-weight:800}.font-900{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.leading-none{line-height:1}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.text-gray-300{--tw-text-opacity:1;color:rgb(224 224 224/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(158 158 158/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(117 117 117/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(97 97 97/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(67 160 71/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(56 142 60/var(--tw-text-opacity,1))}.text-grey-800{--tw-text-opacity:1;color:rgb(66 66 66/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(251 140 0/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}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.decoration-gray-500{text-decoration-color:#9e9e9e}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px 0 #0000000f;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-1{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-1{--tw-shadow:0px 2px 1px -1px #0003,0px 1px 1px 0px #00000024,0px 1px 3px 0px #0000001f;--tw-shadow-colored:0px 2px 1px -1px var(--tw-shadow-color),0px 1px 1px 0px var(--tw-shadow-color),0px 1px 3px 0px var(--tw-shadow-color)}.shadow-2{--tw-shadow:0px 3px 1px -2px #0003,0px 2px 2px 0px #00000024,0px 1px 5px 0px #0000001f;--tw-shadow-colored:0px 3px 1px -2px var(--tw-shadow-color),0px 2px 2px 0px var(--tw-shadow-color),0px 1px 5px 0px var(--tw-shadow-color)}.shadow-2,.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 -1px #0000000f;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -1px 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)}.blur{--tw-blur:blur(8px)}.blur,.contrast-0{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)}.contrast-0{--tw-contrast:contrast(0)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f)}.drop-shadow,.drop-shadow-none{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)}.drop-shadow-none{--tw-drop-shadow:drop-shadow(0 0 #0000)}.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:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,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}.duration-300{transition-duration:.3s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:translate-y-1:hover{--tw-translate-y:0.1rem}.hover\:rotate-3:hover,.hover\:translate-y-1: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\:rotate-3:hover{--tw-rotate:3deg}.hover\:skew-y-3:hover{--tw-skew-y:3deg}.hover\:scale-105:hover,.hover\:skew-y-3: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-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:list-disc:hover{list-style-type:disc}.hover\:bg-gray-100\/75:hover{background-color:#f5f5f5bf}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(56 142 60/var(--tw-bg-opacity,1))}.hover\:bg-grey-300:hover{--tw-bg-opacity:1;background-color:rgb(224 224 224/var(--tw-bg-opacity,1))}.hover\:bg-indigo-100\/25:hover{background-color:#c5cae940}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(97 97 97/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:brightness-75:hover{--tw-brightness:brightness(.75)}.hover\:brightness-75:hover,.hover\:drop-shadow-2xl:hover{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)}.hover\:drop-shadow-2xl:hover{--tw-drop-shadow:drop-shadow(0 25px 25px #00000026)}.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);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-green-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(76 175 80/var(--tw-ring-opacity,1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}@media (min-width:600px){.sm\:p-8{padding:.8rem}}@media (min-width:960px){.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:ml-12{margin-left:1.2rem}.md\:flex{display:flex}.md\:hidden{display:none}.md\:max-w-288{max-width:28.8rem}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:pt-0{padding-top:0}}@media (prefers-color-scheme:dark){.dark\:text-gray-500{--tw-text-opacity:1;color:rgb(158 158 158/var(--tw-text-opacity,1))}.dark\:text-green-500{--tw-text-opacity:1;color:rgb(76 175 80/var(--tw-text-opacity,1))}.dark\:text-orange-500{--tw-text-opacity:1;color:rgb(255 152 0/var(--tw-text-opacity,1))}}
|