@planetaexo/design-system 0.37.3 → 0.37.5

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/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import * as React8 from 'react';
1
+ import * as React28 from 'react';
2
2
  import { useState, useRef, useCallback, useEffect } from 'react';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { XIcon, ChevronDownIcon, CalendarIcon, SearchIcon, ChevronRightIcon, ArrowLeftIcon, CheckCircle2Icon, MapIcon, LogOutIcon, UsersIcon, CreditCardIcon, AlertCircleIcon, MinusIcon, PlusIcon, CircleCheckIcon, ChevronLeftIcon, HomeIcon, SailboatIcon, CarIcon, WavesIcon, FootprintsIcon, InfoIcon, ClockIcon, CheckIcon, ChevronUpIcon, UserIcon, MenuIcon, SunIcon, MoonIcon, MapPinIcon, PackageIcon, SparklesIcon, BackpackIcon, BedDoubleIcon, UtensilsIcon, ReceiptIcon, Loader2Icon, SendIcon, CheckCircleIcon, MailIcon, PhoneIcon, MessageCircleIcon, CompassIcon, UserPlusIcon, ExternalLinkIcon, CopyIcon, PencilIcon, Trash2Icon, UserMinusIcon, AlertTriangleIcon, ZoomInIcon, StarIcon, LayoutGridIcon } from 'lucide-react';
7
+ import { XIcon, ChevronDownIcon, CalendarIcon, SearchIcon, ChevronRightIcon, ArrowLeftIcon, CheckCircle2Icon, MapIcon, LogOutIcon, UsersIcon, CreditCardIcon, AlertCircleIcon, MinusIcon, PlusIcon, CircleCheckIcon, SlidersHorizontalIcon, ChevronLeftIcon, HomeIcon, SailboatIcon, CarIcon, WavesIcon, FootprintsIcon, InfoIcon, ClockIcon, CheckIcon, ChevronUpIcon, MenuIcon, UserIcon, SunIcon, MoonIcon, MapPinIcon, PackageIcon, BedDoubleIcon, UtensilsIcon, CompassIcon, BackpackIcon, CherryIcon, ReceiptIcon, Loader2Icon, SendIcon, CheckCircleIcon, MailIcon, PhoneIcon, MessageCircleIcon, UserPlusIcon, ExternalLinkIcon, CopyIcon, PencilIcon, Trash2Icon, UserMinusIcon, AlertTriangleIcon, ZoomInIcon, StarIcon, TwitterIcon, YoutubeIcon, LinkedinIcon, InstagramIcon, FacebookIcon, ArrowRightIcon, LayoutGridIcon } from 'lucide-react';
8
8
  import { Separator as Separator$1 } from '@base-ui/react/separator';
9
9
  import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
10
10
  import { Button as Button$1 } from '@base-ui/react/button';
@@ -81,7 +81,7 @@ var buttonVariants = cva(
81
81
  }
82
82
  }
83
83
  );
84
- var Button = React8.forwardRef(
84
+ var Button = React28.forwardRef(
85
85
  (_a, ref) => {
86
86
  var _b = _a, { className, variant, size } = _b, props = __objRest(_b, ["className", "variant", "size"]);
87
87
  return /* @__PURE__ */ jsx(
@@ -165,6 +165,10 @@ function Dialog(_a) {
165
165
  var props = __objRest(_a, []);
166
166
  return /* @__PURE__ */ jsx(Dialog$1.Root, __spreadValues({ "data-slot": "dialog" }, props));
167
167
  }
168
+ function DialogTrigger(_a) {
169
+ var props = __objRest(_a, []);
170
+ return /* @__PURE__ */ jsx(Dialog$1.Trigger, __spreadValues({ "data-slot": "dialog-trigger" }, props));
171
+ }
168
172
  function DialogPortal(_a) {
169
173
  var props = __objRest(_a, []);
170
174
  return /* @__PURE__ */ jsx(Dialog$1.Portal, __spreadValues({ "data-slot": "dialog-portal" }, props));
@@ -302,10 +306,10 @@ function DialogDescription(_a) {
302
306
  }, props)
303
307
  );
304
308
  }
305
- var FloatingInput = React8.forwardRef(
309
+ var FloatingInput = React28.forwardRef(
306
310
  (_a, ref) => {
307
311
  var _b = _a, { label, error, id, className, required } = _b, props = __objRest(_b, ["label", "error", "id", "className", "required"]);
308
- const inputId = id != null ? id : React8.useId();
312
+ const inputId = id != null ? id : React28.useId();
309
313
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
310
314
  /* @__PURE__ */ jsx(
311
315
  "input",
@@ -345,10 +349,10 @@ var FloatingInput = React8.forwardRef(
345
349
  }
346
350
  );
347
351
  FloatingInput.displayName = "FloatingInput";
348
- var FloatingSelect = React8.forwardRef(
352
+ var FloatingSelect = React28.forwardRef(
349
353
  (_a, ref) => {
350
354
  var _b = _a, { label, error, id, className, required, children, value } = _b, props = __objRest(_b, ["label", "error", "id", "className", "required", "children", "value"]);
351
- const inputId = id != null ? id : React8.useId();
355
+ const inputId = id != null ? id : React28.useId();
352
356
  const hasValue = typeof value === "string" ? value !== "" : value !== void 0 && value !== null;
353
357
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
354
358
  /* @__PURE__ */ jsx(
@@ -612,11 +616,11 @@ function PhoneCountrySelect({
612
616
  disabled
613
617
  }) {
614
618
  var _a;
615
- const [open, setOpen] = React8.useState(false);
616
- const containerRef = React8.useRef(null);
617
- const listRef = React8.useRef(null);
619
+ const [open, setOpen] = React28.useState(false);
620
+ const containerRef = React28.useRef(null);
621
+ const listRef = React28.useRef(null);
618
622
  const selected = (_a = PHONE_COUNTRIES.find((c) => c.code === value)) != null ? _a : PHONE_COUNTRIES[0];
619
- React8.useEffect(() => {
623
+ React28.useEffect(() => {
620
624
  if (!open) return;
621
625
  const handler = (e) => {
622
626
  var _a2;
@@ -627,7 +631,7 @@ function PhoneCountrySelect({
627
631
  document.addEventListener("mousedown", handler);
628
632
  return () => document.removeEventListener("mousedown", handler);
629
633
  }, [open]);
630
- React8.useEffect(() => {
634
+ React28.useEffect(() => {
631
635
  if (!open || !listRef.current) return;
632
636
  const activeEl = listRef.current.querySelector("[data-selected=true]");
633
637
  activeEl == null ? void 0 : activeEl.scrollIntoView({ block: "nearest" });
@@ -897,8 +901,8 @@ function CalendarDayButton(_a) {
897
901
  "locale"
898
902
  ]);
899
903
  const defaultClassNames = getDefaultClassNames();
900
- const ref = React8.useRef(null);
901
- React8.useEffect(() => {
904
+ const ref = React28.useRef(null);
905
+ React28.useEffect(() => {
902
906
  var _a2;
903
907
  if (modifiers.focused) (_a2 = ref.current) == null ? void 0 : _a2.focus();
904
908
  }, [modifiers.focused]);
@@ -929,16 +933,16 @@ function BirthDateField({
929
933
  className,
930
934
  disabled
931
935
  }) {
932
- const [open, setOpen] = React8.useState(false);
933
- const [text, setText] = React8.useState(
936
+ const [open, setOpen] = React28.useState(false);
937
+ const [text, setText] = React28.useState(
934
938
  value ? format(value, "dd/MM/yyyy") : ""
935
939
  );
936
- const containerRef = React8.useRef(null);
937
- const inputId = React8.useId();
938
- React8.useEffect(() => {
940
+ const containerRef = React28.useRef(null);
941
+ const inputId = React28.useId();
942
+ React28.useEffect(() => {
939
943
  setText(value ? format(value, "dd/MM/yyyy") : "");
940
944
  }, [value]);
941
- React8.useEffect(() => {
945
+ React28.useEffect(() => {
942
946
  if (!open) return;
943
947
  const handler = (e) => {
944
948
  var _a;
@@ -1147,14 +1151,14 @@ function CountrySearchField({
1147
1151
  }) {
1148
1152
  var _a;
1149
1153
  const list = countries != null ? countries : COUNTRIES;
1150
- const [query, setQuery] = React8.useState("");
1151
- const [open, setOpen] = React8.useState(false);
1152
- const containerRef = React8.useRef(null);
1153
- const searchRef = React8.useRef(null);
1154
+ const [query, setQuery] = React28.useState("");
1155
+ const [open, setOpen] = React28.useState(false);
1156
+ const containerRef = React28.useRef(null);
1157
+ const searchRef = React28.useRef(null);
1154
1158
  const selected = list.find((c) => c.code === value);
1155
1159
  const isFloated = open || !!selected;
1156
1160
  const filtered = query.trim() ? list.filter((c) => c.name.toLowerCase().includes(query.toLowerCase())) : list;
1157
- React8.useEffect(() => {
1161
+ React28.useEffect(() => {
1158
1162
  if (!open) return;
1159
1163
  const handler = (e) => {
1160
1164
  var _a2;
@@ -1268,7 +1272,7 @@ function AdventureCard({
1268
1272
  }) {
1269
1273
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1270
1274
  const isControlled = (_b = (_a = adventure.optionals) == null ? void 0 : _a.some((o) => o.onCheckedChange !== void 0)) != null ? _b : false;
1271
- const [checkedInternal, setCheckedInternal] = React8.useState(
1275
+ const [checkedInternal, setCheckedInternal] = React28.useState(
1272
1276
  new Set((_d = (_c = adventure.optionals) == null ? void 0 : _c.filter((o) => o.defaultChecked).map((o) => o.id)) != null ? _d : [])
1273
1277
  );
1274
1278
  const isChecked = (opt) => {
@@ -1666,7 +1670,7 @@ function BookingShell({
1666
1670
  return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-border bg-card overflow-hidden", children: [
1667
1671
  /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-5 py-4 bg-muted/20", children: [
1668
1672
  /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-heading mb-2", children: title }),
1669
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: steps.map((label, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
1673
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: steps.map((label, i) => /* @__PURE__ */ jsxs(React28.Fragment, { children: [
1670
1674
  /* @__PURE__ */ jsx(
1671
1675
  "span",
1672
1676
  {
@@ -1865,7 +1869,7 @@ function TermsSection({
1865
1869
  termsContent
1866
1870
  }) {
1867
1871
  var _a;
1868
- const [modalOpen, setModalOpen] = React8.useState(false);
1872
+ const [modalOpen, setModalOpen] = React28.useState(false);
1869
1873
  const i18n = (_a = TERMS_I18N[locale]) != null ? _a : TERMS_I18N.en;
1870
1874
  return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border p-4 flex flex-col gap-3", children: [
1871
1875
  /* @__PURE__ */ jsx("p", { className: "text-xs font-bold text-muted-foreground font-heading uppercase tracking-widest", children: title }),
@@ -2003,9 +2007,9 @@ function BookingWizard({
2003
2007
  }) {
2004
2008
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T;
2005
2009
  const wizardSteps = WIZARD_STEPS_FN(labels);
2006
- const [step, setStep] = React8.useState("responsible");
2007
- const [error, setError] = React8.useState(null);
2008
- const [responsible, setResponsible] = React8.useState({
2010
+ const [step, setStep] = React28.useState("responsible");
2011
+ const [error, setError] = React28.useState(null);
2012
+ const [responsible, setResponsible] = React28.useState({
2009
2013
  firstName: "",
2010
2014
  lastName: "",
2011
2015
  email: "",
@@ -2024,7 +2028,7 @@ function BookingWizard({
2024
2028
  return s + ((_b2 = (_a2 = a.slots) == null ? void 0 : _a2.children) != null ? _b2 : 0);
2025
2029
  }, 0);
2026
2030
  const totalPax = totalAdults + totalChildren;
2027
- const [travellers, setTravellers] = React8.useState(
2031
+ const [travellers, setTravellers] = React28.useState(
2028
2032
  Array.from({ length: Math.max(totalPax, 1) }, () => ({
2029
2033
  firstName: "",
2030
2034
  lastName: "",
@@ -2032,9 +2036,9 @@ function BookingWizard({
2032
2036
  email: ""
2033
2037
  }))
2034
2038
  );
2035
- const [payAmount, setPayAmount] = React8.useState("full");
2036
- const [payMethod, setPayMethod] = React8.useState("stripe");
2037
- const [termsAccepted, setTermsAccepted] = React8.useState(false);
2039
+ const [payAmount, setPayAmount] = React28.useState("full");
2040
+ const [payMethod, setPayMethod] = React28.useState("stripe");
2041
+ const [termsAccepted, setTermsAccepted] = React28.useState(false);
2038
2042
  const setR = (k, v) => setResponsible((p) => __spreadProps(__spreadValues({}, p), { [k]: v }));
2039
2043
  const setT = (i, k, v) => setTravellers((prev) => prev.map((t, idx) => idx === i ? __spreadProps(__spreadValues({}, t), { [k]: v }) : t));
2040
2044
  const setTDob = (i, v) => setTravellers((prev) => prev.map((t, idx) => idx === i ? __spreadProps(__spreadValues({}, t), { dateOfBirth: v }) : t));
@@ -2262,7 +2266,7 @@ function Offer({
2262
2266
  className
2263
2267
  }) {
2264
2268
  var _a, _b, _c;
2265
- const [showBooking, setShowBooking] = React8.useState(false);
2269
+ const [showBooking, setShowBooking] = React28.useState(false);
2266
2270
  const isShowingCheckout = !confirmedState && (!!checkoutSlot || internalDemoCheckout && showBooking);
2267
2271
  const handleBook = () => {
2268
2272
  if (!checkoutSlot && !externalBookingFlow && internalDemoCheckout) {
@@ -2629,7 +2633,7 @@ function AdventureSection({
2629
2633
  labels
2630
2634
  }) {
2631
2635
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
2632
- const [detailsOpen, setDetailsOpen] = React8.useState(false);
2636
+ const [detailsOpen, setDetailsOpen] = React28.useState(false);
2633
2637
  const handleCopyUrl = (url) => {
2634
2638
  if (onCopyFormLink) {
2635
2639
  onCopyFormLink(url);
@@ -3141,8 +3145,8 @@ function AddTravellerDialog({
3141
3145
  errorMessage
3142
3146
  }) {
3143
3147
  var _a, _b, _c, _d, _e;
3144
- const [form, setForm] = React8.useState(() => createInitialAddFormData(config));
3145
- React8.useEffect(() => {
3148
+ const [form, setForm] = React28.useState(() => createInitialAddFormData(config));
3149
+ React28.useEffect(() => {
3146
3150
  if (open) {
3147
3151
  setForm(createInitialAddFormData(config));
3148
3152
  }
@@ -3202,7 +3206,7 @@ function EditTravellerDialog({
3202
3206
  errorMessage
3203
3207
  }) {
3204
3208
  var _a, _b, _c, _d, _e;
3205
- const [form, setForm] = React8.useState(() => ({
3209
+ const [form, setForm] = React28.useState(() => ({
3206
3210
  firstName: "",
3207
3211
  lastName: "",
3208
3212
  email: "",
@@ -3211,7 +3215,7 @@ function EditTravellerDialog({
3211
3215
  birthDate: "",
3212
3216
  personType: "ADULT"
3213
3217
  }));
3214
- React8.useEffect(() => {
3218
+ React28.useEffect(() => {
3215
3219
  var _a2, _b2, _c2, _d2, _e2, _f;
3216
3220
  if (open && traveller) {
3217
3221
  setForm({
@@ -3546,48 +3550,48 @@ function BookingDetails({
3546
3550
  const hasSubmitAddTraveller = !!onSubmitAddTraveller;
3547
3551
  const hasSubmitEditTraveller = !!onSubmitEditTraveller;
3548
3552
  const hasConfirmRemoveTraveller = !!onConfirmRemoveTraveller;
3549
- const [addModalState, setAddModalState] = React8.useState({
3553
+ const [addModalState, setAddModalState] = React28.useState({
3550
3554
  open: false,
3551
3555
  adventureId: null
3552
3556
  });
3553
- const [editModalState, setEditModalState] = React8.useState({ open: false, adventureId: null, traveller: null });
3554
- const [deleteModalState, setDeleteModalState] = React8.useState({ open: false, adventureId: null, traveller: null });
3555
- const [resendInviteDialogState, setResendInviteDialogState] = React8.useState({ open: false, traveller: null });
3556
- const handleRequestOpenAddModal = React8.useCallback((adventureId) => {
3557
+ const [editModalState, setEditModalState] = React28.useState({ open: false, adventureId: null, traveller: null });
3558
+ const [deleteModalState, setDeleteModalState] = React28.useState({ open: false, adventureId: null, traveller: null });
3559
+ const [resendInviteDialogState, setResendInviteDialogState] = React28.useState({ open: false, traveller: null });
3560
+ const handleRequestOpenAddModal = React28.useCallback((adventureId) => {
3557
3561
  setAddModalState({ open: true, adventureId });
3558
3562
  }, []);
3559
- const handleRequestOpenEditModal = React8.useCallback(
3563
+ const handleRequestOpenEditModal = React28.useCallback(
3560
3564
  (adventureId, traveller) => {
3561
3565
  setEditModalState({ open: true, adventureId, traveller });
3562
3566
  },
3563
3567
  []
3564
3568
  );
3565
- const handleRequestOpenDeleteModal = React8.useCallback(
3569
+ const handleRequestOpenDeleteModal = React28.useCallback(
3566
3570
  (adventureId, traveller) => {
3567
3571
  setDeleteModalState({ open: true, adventureId, traveller });
3568
3572
  },
3569
3573
  []
3570
3574
  );
3571
- const handleRequestOpenResendInviteDialog = React8.useCallback(
3575
+ const handleRequestOpenResendInviteDialog = React28.useCallback(
3572
3576
  (traveller) => {
3573
3577
  setResendInviteDialogState({ open: true, traveller });
3574
3578
  },
3575
3579
  []
3576
3580
  );
3577
- const closeAddModal = React8.useCallback(() => {
3581
+ const closeAddModal = React28.useCallback(() => {
3578
3582
  setAddModalState({ open: false, adventureId: null });
3579
3583
  }, []);
3580
- const closeEditModal = React8.useCallback(() => {
3584
+ const closeEditModal = React28.useCallback(() => {
3581
3585
  setEditModalState({ open: false, adventureId: null, traveller: null });
3582
3586
  }, []);
3583
- const closeDeleteModal = React8.useCallback(() => {
3587
+ const closeDeleteModal = React28.useCallback(() => {
3584
3588
  setDeleteModalState({ open: false, adventureId: null, traveller: null });
3585
3589
  }, []);
3586
- const closeResendInviteDialog = React8.useCallback(() => {
3590
+ const closeResendInviteDialog = React28.useCallback(() => {
3587
3591
  setResendInviteDialogState({ open: false, traveller: null });
3588
3592
  }, []);
3589
- const submitInFlightRef = React8.useRef(false);
3590
- const handleAddSubmit = React8.useCallback(
3593
+ const submitInFlightRef = React28.useRef(false);
3594
+ const handleAddSubmit = React28.useCallback(
3591
3595
  async (adventureId, data) => {
3592
3596
  if (!onSubmitAddTraveller) return;
3593
3597
  if (submitInFlightRef.current) return;
@@ -3602,7 +3606,7 @@ function BookingDetails({
3602
3606
  },
3603
3607
  [onSubmitAddTraveller, closeAddModal]
3604
3608
  );
3605
- const handleEditSubmit = React8.useCallback(
3609
+ const handleEditSubmit = React28.useCallback(
3606
3610
  async (adventureId, travellerId, data) => {
3607
3611
  if (!onSubmitEditTraveller) return;
3608
3612
  if (submitInFlightRef.current) return;
@@ -3617,7 +3621,7 @@ function BookingDetails({
3617
3621
  },
3618
3622
  [onSubmitEditTraveller, closeEditModal]
3619
3623
  );
3620
- const handleDeleteConfirm = React8.useCallback(
3624
+ const handleDeleteConfirm = React28.useCallback(
3621
3625
  async (adventureId, travellerId) => {
3622
3626
  if (!onConfirmRemoveTraveller) return;
3623
3627
  if (submitInFlightRef.current) return;
@@ -3958,6 +3962,12 @@ ${content}
3958
3962
  </body>
3959
3963
  </html>`;
3960
3964
  }
3965
+ function constrainItineraryImages(html) {
3966
+ return html.replace(/<img\b[^>]*>/gi, (tag) => {
3967
+ const withoutStyle = tag.replace(/\sstyle\s*=\s*("[^"]*"|'[^']*')/gi, "");
3968
+ return withoutStyle.replace(/<img\b/i, '<img style="max-width:100%;height:auto"');
3969
+ });
3970
+ }
3961
3971
  var DEFAULT_LABELS = {
3962
3972
  travellersHeading: "TRAVELLERS",
3963
3973
  detailsHeading: "DETAILS",
@@ -4344,7 +4354,7 @@ function BookingAdventureCard({
4344
4354
  lineHeight: "1.4",
4345
4355
  margin: 0
4346
4356
  },
4347
- dangerouslySetInnerHTML: { __html: description }
4357
+ dangerouslySetInnerHTML: { __html: constrainItineraryImages(description) }
4348
4358
  }
4349
4359
  ) : itinerary.map((line, i) => /* @__PURE__ */ jsx(
4350
4360
  "p",
@@ -5091,7 +5101,7 @@ function BookingCreatedEmail({
5091
5101
  }, children: i + 1 }) }),
5092
5102
  /* @__PURE__ */ jsx("td", { style: { verticalAlign: "top" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "14px", color: emailTokens.bodyText, lineHeight: "1.6", margin: 0 }, children: step }) })
5093
5103
  ] }) }) }, i)) }),
5094
- nextStepsImportant && nextStepsImportant.trim().length > 0 && /* @__PURE__ */ jsx("p", { style: { marginBottom: "32px", fontSize: "14px", color: emailTokens.foreground, lineHeight: "1.6" }, children: nextStepsImportant.split("\n").map((line, idx, arr) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
5104
+ nextStepsImportant && nextStepsImportant.trim().length > 0 && /* @__PURE__ */ jsx("p", { style: { marginBottom: "32px", fontSize: "14px", color: emailTokens.foreground, lineHeight: "1.6" }, children: nextStepsImportant.split("\n").map((line, idx, arr) => /* @__PURE__ */ jsxs(React28.Fragment, { children: [
5095
5105
  idx === 0 ? /* @__PURE__ */ jsx("strong", { children: line }) : line,
5096
5106
  idx < arr.length - 1 ? /* @__PURE__ */ jsx("br", {}) : null
5097
5107
  ] }, idx)) })
@@ -6460,11 +6470,11 @@ function DatePickerField({
6460
6470
  fromDate,
6461
6471
  className
6462
6472
  }) {
6463
- const [open, setOpen] = React8.useState(false);
6464
- const containerRef = React8.useRef(null);
6465
- const [calendarWidth, setCalendarWidth] = React8.useState();
6473
+ const [open, setOpen] = React28.useState(false);
6474
+ const containerRef = React28.useRef(null);
6475
+ const [calendarWidth, setCalendarWidth] = React28.useState();
6466
6476
  const hasValue = !!value;
6467
- React8.useEffect(() => {
6477
+ React28.useEffect(() => {
6468
6478
  if (!containerRef.current) return;
6469
6479
  const observer = new ResizeObserver(([entry]) => {
6470
6480
  setCalendarWidth(entry.contentRect.width);
@@ -6573,7 +6583,7 @@ function BookingForm({
6573
6583
  subtitle = "Free enquiry \u2013 no commitment",
6574
6584
  className
6575
6585
  }) {
6576
- const [values, setValues] = React8.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
6586
+ const [values, setValues] = React28.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
6577
6587
  const set = (key, value) => setValues((prev) => __spreadProps(__spreadValues({}, prev), { [key]: value }));
6578
6588
  const handleSubmit = (e) => {
6579
6589
  e.preventDefault();
@@ -7110,11 +7120,11 @@ function FloatingTextarea({
7110
7120
  }
7111
7121
  function SelectField({ field, value, onChange, error, disabled }) {
7112
7122
  var _a, _b, _c;
7113
- const [open, setOpen] = React8.useState(false);
7114
- const containerRef = React8.useRef(null);
7123
+ const [open, setOpen] = React28.useState(false);
7124
+ const containerRef = React28.useRef(null);
7115
7125
  const options = (_a = field.options) != null ? _a : [];
7116
7126
  const selectedOpt = (_b = options.find((o) => o.value === value)) != null ? _b : null;
7117
- React8.useEffect(() => {
7127
+ React28.useEffect(() => {
7118
7128
  if (!open) return;
7119
7129
  const handleOutside = (e) => {
7120
7130
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -7503,11 +7513,11 @@ function RegistrationForm({
7503
7513
  readOnly = false
7504
7514
  }) {
7505
7515
  var _a;
7506
- const L = React8.useMemo(
7516
+ const L = React28.useMemo(
7507
7517
  () => __spreadValues(__spreadValues({}, DEFAULT_LABELS9), labels != null ? labels : {}),
7508
7518
  [labels]
7509
7519
  );
7510
- const sortedFields = React8.useMemo(
7520
+ const sortedFields = React28.useMemo(
7511
7521
  () => [...fields].sort((a, b) => {
7512
7522
  var _a2, _b;
7513
7523
  return ((_a2 = a.order) != null ? _a2 : 0) - ((_b = b.order) != null ? _b : 0);
@@ -7515,7 +7525,7 @@ function RegistrationForm({
7515
7525
  [fields]
7516
7526
  );
7517
7527
  const isControlled = values !== void 0;
7518
- const [internal, setInternal] = React8.useState(
7528
+ const [internal, setInternal] = React28.useState(
7519
7529
  () => initializeValues(
7520
7530
  sortedFields,
7521
7531
  defaultValues != null ? defaultValues : {},
@@ -7523,9 +7533,9 @@ function RegistrationForm({
7523
7533
  includeTerms
7524
7534
  )
7525
7535
  );
7526
- const [submitAttempted, setSubmitAttempted] = React8.useState(false);
7527
- const [validationErrors, setValidationErrors] = React8.useState({});
7528
- React8.useEffect(() => {
7536
+ const [submitAttempted, setSubmitAttempted] = React28.useState(false);
7537
+ const [validationErrors, setValidationErrors] = React28.useState({});
7538
+ React28.useEffect(() => {
7529
7539
  if (isControlled) return;
7530
7540
  setInternal((prev) => {
7531
7541
  const next = initializeValues(
@@ -7582,7 +7592,7 @@ function RegistrationForm({
7582
7592
  const termsError = submitAttempted && termsEnabled && !termsAccepted;
7583
7593
  const firstErrorFieldId = Object.keys(fieldErrors)[0];
7584
7594
  const scrollTargetId = firstErrorFieldId ? `rf-${firstErrorFieldId}` : termsError ? "rf-terms" : null;
7585
- React8.useEffect(() => {
7595
+ React28.useEffect(() => {
7586
7596
  if (!submitAttempted || !scrollTargetId) return;
7587
7597
  const timer = setTimeout(() => {
7588
7598
  const elem = document.getElementById(scrollTargetId);
@@ -8044,10 +8054,10 @@ var OTPCodeInput = ({
8044
8054
  id,
8045
8055
  required
8046
8056
  }) => {
8047
- const baseId = id != null ? id : React8.useId();
8048
- const inputRef = React8.useRef(null);
8049
- const [focused, setFocused] = React8.useState(false);
8050
- const digits = React8.useMemo(() => {
8057
+ const baseId = id != null ? id : React28.useId();
8058
+ const inputRef = React28.useRef(null);
8059
+ const [focused, setFocused] = React28.useState(false);
8060
+ const digits = React28.useMemo(() => {
8051
8061
  const arr = value.split("").slice(0, length);
8052
8062
  while (arr.length < length) arr.push("");
8053
8063
  return arr;
@@ -8145,7 +8155,7 @@ function Checkbox(_a) {
8145
8155
  __spreadProps(__spreadValues({
8146
8156
  "data-slot": "checkbox",
8147
8157
  className: cn(
8148
- "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
8158
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground data-indeterminate:border-primary data-indeterminate:bg-primary data-indeterminate:text-primary-foreground dark:data-checked:bg-primary",
8149
8159
  className
8150
8160
  )
8151
8161
  }, props), {
@@ -8154,16 +8164,13 @@ function Checkbox(_a) {
8154
8164
  {
8155
8165
  "data-slot": "checkbox-indicator",
8156
8166
  className: "grid place-content-center text-current transition-none [&>svg]:size-3.5",
8157
- children: /* @__PURE__ */ jsx(
8158
- CheckIcon,
8159
- {}
8160
- )
8167
+ children: props.indeterminate ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {})
8161
8168
  }
8162
8169
  )
8163
8170
  })
8164
8171
  );
8165
8172
  }
8166
- var AccordionVariantContext = React8.createContext("default");
8173
+ var AccordionVariantContext = React28.createContext("default");
8167
8174
  function Accordion(_a) {
8168
8175
  var _b = _a, { className, variant = "default" } = _b, props = __objRest(_b, ["className", "variant"]);
8169
8176
  return /* @__PURE__ */ jsx(AccordionVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsx(
@@ -8181,7 +8188,7 @@ function Accordion(_a) {
8181
8188
  }
8182
8189
  function AccordionItem(_a) {
8183
8190
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
8184
- const variant = React8.useContext(AccordionVariantContext);
8191
+ const variant = React28.useContext(AccordionVariantContext);
8185
8192
  return /* @__PURE__ */ jsx(
8186
8193
  Accordion$1.Item,
8187
8194
  __spreadValues({
@@ -8202,7 +8209,7 @@ function AccordionTrigger(_a) {
8202
8209
  "className",
8203
8210
  "children"
8204
8211
  ]);
8205
- const variant = React8.useContext(AccordionVariantContext);
8212
+ const variant = React28.useContext(AccordionVariantContext);
8206
8213
  return /* @__PURE__ */ jsx(Accordion$1.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
8207
8214
  Accordion$1.Trigger,
8208
8215
  __spreadProps(__spreadValues({
@@ -8256,7 +8263,7 @@ function AccordionContent(_a) {
8256
8263
  "className",
8257
8264
  "children"
8258
8265
  ]);
8259
- const variant = React8.useContext(AccordionVariantContext);
8266
+ const variant = React28.useContext(AccordionVariantContext);
8260
8267
  return /* @__PURE__ */ jsx(
8261
8268
  Accordion$1.Panel,
8262
8269
  __spreadProps(__spreadValues({
@@ -8279,6 +8286,187 @@ function AccordionContent(_a) {
8279
8286
  })
8280
8287
  );
8281
8288
  }
8289
+ function getLeafIds(item) {
8290
+ var _a;
8291
+ if (!((_a = item.children) == null ? void 0 : _a.length)) return [item.id];
8292
+ return item.children.flatMap(getLeafIds);
8293
+ }
8294
+ function getDefaultExpandedIds(items) {
8295
+ const out = [];
8296
+ const walk = (list) => {
8297
+ var _a;
8298
+ for (const i of list) {
8299
+ if ((_a = i.children) == null ? void 0 : _a.length) {
8300
+ if (i.defaultExpanded) out.push(i.id);
8301
+ walk(i.children);
8302
+ }
8303
+ }
8304
+ };
8305
+ walk(items);
8306
+ return out;
8307
+ }
8308
+ function getAllItemIds(items) {
8309
+ return items.flatMap(
8310
+ (i) => {
8311
+ var _a;
8312
+ return ((_a = i.children) == null ? void 0 : _a.length) ? [i.id, ...getAllItemIds(i.children)] : [i.id];
8313
+ }
8314
+ );
8315
+ }
8316
+ function findItemById(items, id) {
8317
+ var _a;
8318
+ for (const item of items) {
8319
+ if (item.id === id) return item;
8320
+ if ((_a = item.children) == null ? void 0 : _a.length) {
8321
+ const found = findItemById(item.children, id);
8322
+ if (found) return found;
8323
+ }
8324
+ }
8325
+ return void 0;
8326
+ }
8327
+ function resolveGroups(groups) {
8328
+ return groups.map((g) => {
8329
+ var _a;
8330
+ if (!g.scopeItemId) return g;
8331
+ const node = findItemById(g.items, g.scopeItemId);
8332
+ return __spreadProps(__spreadValues({}, g), { items: (_a = node == null ? void 0 : node.children) != null ? _a : [] });
8333
+ }).filter((g) => g.items.length > 0);
8334
+ }
8335
+ function FilterItemsList({
8336
+ items,
8337
+ groupId,
8338
+ groupSelected,
8339
+ onToggle,
8340
+ onBulkToggle,
8341
+ idPrefix,
8342
+ depth = 0,
8343
+ parentAsHeader = false,
8344
+ expandedItems,
8345
+ onToggleExpanded
8346
+ }) {
8347
+ return /* @__PURE__ */ jsx(
8348
+ "ul",
8349
+ {
8350
+ className: cn(
8351
+ "flex flex-col gap-0.5",
8352
+ !parentAsHeader && depth > 0 && "mt-0.5 ml-6 border-l border-border pl-3"
8353
+ ),
8354
+ children: items.map((item) => {
8355
+ var _a, _b;
8356
+ const isParent = !!((_a = item.children) == null ? void 0 : _a.length);
8357
+ const checkboxId = `${idPrefix}-${groupId}-${item.id}`;
8358
+ if (!isParent) {
8359
+ const checked = groupSelected.includes(item.id);
8360
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
8361
+ "label",
8362
+ {
8363
+ htmlFor: checkboxId,
8364
+ className: "flex cursor-pointer items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50",
8365
+ children: [
8366
+ /* @__PURE__ */ jsx(
8367
+ Checkbox,
8368
+ {
8369
+ id: checkboxId,
8370
+ checked,
8371
+ onCheckedChange: () => onToggle(item.id),
8372
+ className: "shrink-0"
8373
+ }
8374
+ ),
8375
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-foreground font-ui", children: item.label }),
8376
+ item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8377
+ "(",
8378
+ item.count,
8379
+ ")"
8380
+ ] })
8381
+ ]
8382
+ }
8383
+ ) }, item.id);
8384
+ }
8385
+ if (parentAsHeader) {
8386
+ return /* @__PURE__ */ jsxs("li", { className: cn(depth > 0 && "mt-1"), children: [
8387
+ /* @__PURE__ */ jsx("p", { className: "px-1 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: item.label }),
8388
+ /* @__PURE__ */ jsx(
8389
+ FilterItemsList,
8390
+ {
8391
+ items: item.children,
8392
+ groupId,
8393
+ groupSelected,
8394
+ onToggle,
8395
+ onBulkToggle,
8396
+ idPrefix,
8397
+ depth: depth + 1,
8398
+ parentAsHeader: true,
8399
+ expandedItems,
8400
+ onToggleExpanded
8401
+ }
8402
+ )
8403
+ ] }, item.id);
8404
+ }
8405
+ const leafIds = item.children.flatMap(getLeafIds);
8406
+ const selectedLeaves = leafIds.filter((id) => groupSelected.includes(id));
8407
+ const allSelected = leafIds.length > 0 && selectedLeaves.length === leafIds.length;
8408
+ const someSelected = selectedLeaves.length > 0 && !allSelected;
8409
+ const isExpanded = (_b = expandedItems == null ? void 0 : expandedItems.has(item.id)) != null ? _b : false;
8410
+ const panelId = `${checkboxId}-children`;
8411
+ return /* @__PURE__ */ jsxs("li", { children: [
8412
+ /* @__PURE__ */ jsxs("div", { className: "group/parent flex items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50", children: [
8413
+ /* @__PURE__ */ jsx(
8414
+ Checkbox,
8415
+ {
8416
+ id: checkboxId,
8417
+ checked: allSelected,
8418
+ indeterminate: someSelected,
8419
+ onCheckedChange: () => onBulkToggle(leafIds, !allSelected),
8420
+ className: "shrink-0"
8421
+ }
8422
+ ),
8423
+ /* @__PURE__ */ jsxs(
8424
+ "button",
8425
+ {
8426
+ type: "button",
8427
+ onClick: () => onToggleExpanded == null ? void 0 : onToggleExpanded(item.id),
8428
+ "aria-expanded": isExpanded,
8429
+ "aria-controls": panelId,
8430
+ className: "flex flex-1 items-center gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm cursor-pointer",
8431
+ children: [
8432
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-bold text-foreground font-ui", children: item.label }),
8433
+ item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8434
+ "(",
8435
+ item.count,
8436
+ ")"
8437
+ ] }),
8438
+ /* @__PURE__ */ jsx(
8439
+ ChevronDownIcon,
8440
+ {
8441
+ className: cn(
8442
+ "h-4 w-4 text-muted-foreground transition-transform",
8443
+ isExpanded && "rotate-180"
8444
+ )
8445
+ }
8446
+ )
8447
+ ]
8448
+ }
8449
+ )
8450
+ ] }),
8451
+ isExpanded && /* @__PURE__ */ jsx("div", { id: panelId, children: /* @__PURE__ */ jsx(
8452
+ FilterItemsList,
8453
+ {
8454
+ items: item.children,
8455
+ groupId,
8456
+ groupSelected,
8457
+ onToggle,
8458
+ onBulkToggle,
8459
+ idPrefix,
8460
+ depth: depth + 1,
8461
+ expandedItems,
8462
+ onToggleExpanded
8463
+ }
8464
+ ) })
8465
+ ] }, item.id);
8466
+ })
8467
+ }
8468
+ );
8469
+ }
8282
8470
  function FilterPanel({
8283
8471
  groups,
8284
8472
  value,
@@ -8286,15 +8474,32 @@ function FilterPanel({
8286
8474
  onClearAll,
8287
8475
  alwaysShowClear = false,
8288
8476
  title = "Filters",
8289
- className
8477
+ className,
8478
+ variant = "sidebar",
8479
+ sortOptions,
8480
+ sort,
8481
+ onSortChange
8290
8482
  }) {
8291
- const [internalValue, setInternalValue] = React8.useState(
8483
+ var _a, _b;
8484
+ const resolvedGroups = React28.useMemo(() => resolveGroups(groups), [groups]);
8485
+ const [internalValue, setInternalValue] = React28.useState(
8292
8486
  () => Object.fromEntries(groups.map((g) => [g.id, []]))
8293
8487
  );
8294
8488
  const selected = value != null ? value : internalValue;
8489
+ const [expandedItems, setExpandedItems] = React28.useState(
8490
+ () => new Set(groups.flatMap((g) => getDefaultExpandedIds(g.items)))
8491
+ );
8492
+ const toggleExpanded = React28.useCallback((id) => {
8493
+ setExpandedItems((prev) => {
8494
+ const next = new Set(prev);
8495
+ if (next.has(id)) next.delete(id);
8496
+ else next.add(id);
8497
+ return next;
8498
+ });
8499
+ }, []);
8295
8500
  const handleToggle = (groupId, itemId) => {
8296
- var _a;
8297
- const current = (_a = selected[groupId]) != null ? _a : [];
8501
+ var _a2;
8502
+ const current = (_a2 = selected[groupId]) != null ? _a2 : [];
8298
8503
  const next = current.includes(itemId) ? current.filter((id) => id !== itemId) : [...current, itemId];
8299
8504
  const nextValue = __spreadProps(__spreadValues({}, selected), { [groupId]: next });
8300
8505
  if (onChange) {
@@ -8303,8 +8508,24 @@ function FilterPanel({
8303
8508
  setInternalValue(nextValue);
8304
8509
  }
8305
8510
  };
8511
+ const handleBulkToggle = (groupId, itemIds, select) => {
8512
+ var _a2;
8513
+ const current = (_a2 = selected[groupId]) != null ? _a2 : [];
8514
+ const next = select ? Array.from(/* @__PURE__ */ new Set([...current, ...itemIds])) : current.filter((id) => !itemIds.includes(id));
8515
+ const nextValue = __spreadProps(__spreadValues({}, selected), { [groupId]: next });
8516
+ if (onChange) {
8517
+ onChange(nextValue);
8518
+ } else {
8519
+ setInternalValue(nextValue);
8520
+ }
8521
+ };
8306
8522
  const handleClearAll = () => {
8307
- const cleared = Object.fromEntries(groups.map((g) => [g.id, []]));
8523
+ var _a2;
8524
+ const cleared = __spreadValues({}, selected);
8525
+ for (const g of resolvedGroups) {
8526
+ const visible = new Set(getAllItemIds(g.items));
8527
+ cleared[g.id] = ((_a2 = selected[g.id]) != null ? _a2 : []).filter((id) => !visible.has(id));
8528
+ }
8308
8529
  if (onChange) {
8309
8530
  onChange(cleared);
8310
8531
  } else {
@@ -8312,9 +8533,289 @@ function FilterPanel({
8312
8533
  }
8313
8534
  onClearAll == null ? void 0 : onClearAll();
8314
8535
  };
8315
- const totalSelected = Object.values(selected).flat().length;
8536
+ const totalSelected = resolvedGroups.reduce((sum, g) => {
8537
+ var _a2;
8538
+ const visible = new Set(getAllItemIds(g.items));
8539
+ return sum + ((_a2 = selected[g.id]) != null ? _a2 : []).filter((id) => visible.has(id)).length;
8540
+ }, 0);
8316
8541
  const showClear = alwaysShowClear || totalSelected > 0;
8317
- const defaultOpenValues = groups.filter((g) => g.defaultOpen).map((g) => g.id);
8542
+ const defaultOpenValues = resolvedGroups.filter((g) => g.defaultOpen).map((g) => g.id);
8543
+ if (resolvedGroups.length === 0) return null;
8544
+ if (variant === "horizontal") {
8545
+ const activeSort = (_a = sortOptions == null ? void 0 : sortOptions.find((o) => o.id === sort)) != null ? _a : sortOptions == null ? void 0 : sortOptions[0];
8546
+ const drawerGroups = /* @__PURE__ */ jsx(Accordion, { defaultValue: defaultOpenValues, className: "flex flex-col gap-2", children: resolvedGroups.map((group) => {
8547
+ var _a2;
8548
+ const groupSelected = (_a2 = selected[group.id]) != null ? _a2 : [];
8549
+ return /* @__PURE__ */ jsxs(
8550
+ AccordionItem,
8551
+ {
8552
+ value: group.id,
8553
+ className: "border-0 border-b border-border last:border-b-0",
8554
+ children: [
8555
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "px-0 py-3.5 hover:no-underline transition-colors", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2.5", children: [
8556
+ group.icon && /* @__PURE__ */ jsx("span", { className: "text-primary shrink-0", children: group.icon }),
8557
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-foreground font-ui", children: group.label }),
8558
+ groupSelected.length > 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[9px] font-bold text-primary-foreground", children: groupSelected.length })
8559
+ ] }) }),
8560
+ /* @__PURE__ */ jsx(AccordionContent, { className: "px-4 pb-3 pt-1", children: /* @__PURE__ */ jsx(
8561
+ FilterItemsList,
8562
+ {
8563
+ items: group.items,
8564
+ groupId: group.id,
8565
+ groupSelected,
8566
+ onToggle: (id) => handleToggle(group.id, id),
8567
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8568
+ idPrefix: "mobile-filter",
8569
+ expandedItems,
8570
+ onToggleExpanded: toggleExpanded
8571
+ }
8572
+ ) })
8573
+ ]
8574
+ },
8575
+ group.id
8576
+ );
8577
+ }) });
8578
+ return /* @__PURE__ */ jsxs("div", { className: cn("contents", className), children: [
8579
+ /* @__PURE__ */ jsxs("div", { className: "flex sm:hidden items-center gap-2", children: [
8580
+ /* @__PURE__ */ jsxs(Dialog, { children: [
8581
+ /* @__PURE__ */ jsxs(
8582
+ DialogTrigger,
8583
+ {
8584
+ render: /* @__PURE__ */ jsx(
8585
+ "button",
8586
+ {
8587
+ type: "button",
8588
+ className: cn(
8589
+ "flex-1 inline-flex items-center justify-between gap-2 rounded-xl border-2 border-foreground bg-background px-4 py-3",
8590
+ "text-sm font-ui font-bold text-foreground transition-colors hover:bg-muted",
8591
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8592
+ )
8593
+ }
8594
+ ),
8595
+ children: [
8596
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
8597
+ title,
8598
+ totalSelected > 0 && /* @__PURE__ */ jsx("span", { className: "inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary px-1.5 text-[10px] font-bold text-primary-foreground", children: totalSelected })
8599
+ ] }),
8600
+ /* @__PURE__ */ jsx(SlidersHorizontalIcon, { className: "h-4 w-4 text-foreground" })
8601
+ ]
8602
+ }
8603
+ ),
8604
+ /* @__PURE__ */ jsx(
8605
+ DialogContent,
8606
+ {
8607
+ className: cn(
8608
+ "p-0 sm:max-w-md",
8609
+ "max-w-none w-screen h-screen sm:h-auto sm:max-h-[90vh] rounded-none sm:rounded-2xl"
8610
+ ),
8611
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full max-h-[90vh]", children: [
8612
+ /* @__PURE__ */ jsx(DialogTitle, { className: "px-5 py-4 text-lg font-bold font-heading border-b border-border", children: title }),
8613
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-5 py-3", children: drawerGroups }),
8614
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 px-5 py-4 border-t border-border", children: [
8615
+ /* @__PURE__ */ jsx(
8616
+ "button",
8617
+ {
8618
+ type: "button",
8619
+ onClick: handleClearAll,
8620
+ className: "text-sm font-ui font-semibold text-muted-foreground underline underline-offset-2 hover:text-foreground",
8621
+ children: "Clear all"
8622
+ }
8623
+ ),
8624
+ /* @__PURE__ */ jsxs(
8625
+ DialogClose,
8626
+ {
8627
+ render: /* @__PURE__ */ jsx(
8628
+ "button",
8629
+ {
8630
+ type: "button",
8631
+ className: "inline-flex items-center justify-center rounded-full bg-foreground text-background px-6 py-2.5 text-sm font-ui font-bold hover:bg-foreground/90 transition-colors"
8632
+ }
8633
+ ),
8634
+ children: [
8635
+ "Show ",
8636
+ totalSelected > 0 ? `(${totalSelected})` : "",
8637
+ " results"
8638
+ ]
8639
+ }
8640
+ )
8641
+ ] })
8642
+ ] })
8643
+ }
8644
+ )
8645
+ ] }),
8646
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
8647
+ /* @__PURE__ */ jsxs(
8648
+ PopoverTrigger,
8649
+ {
8650
+ render: /* @__PURE__ */ jsx(
8651
+ "button",
8652
+ {
8653
+ type: "button",
8654
+ className: cn(
8655
+ "inline-flex items-center gap-1.5 rounded-xl border border-border bg-background px-4 py-3",
8656
+ "text-sm font-ui font-bold text-foreground transition-colors hover:bg-muted",
8657
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8658
+ )
8659
+ }
8660
+ ),
8661
+ children: [
8662
+ "Sort",
8663
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" })
8664
+ ]
8665
+ }
8666
+ ),
8667
+ /* @__PURE__ */ jsx(PopoverContent, { align: "end", sideOffset: 6, className: "w-52", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 p-0.5", children: sortOptions.map((opt) => /* @__PURE__ */ jsx(
8668
+ "button",
8669
+ {
8670
+ type: "button",
8671
+ onClick: () => onSortChange == null ? void 0 : onSortChange(opt.id),
8672
+ className: cn(
8673
+ "flex items-center px-2 py-1.5 rounded-md text-sm text-left",
8674
+ opt.id === (activeSort == null ? void 0 : activeSort.id) ? "bg-muted text-foreground font-semibold" : "text-foreground/80 hover:bg-muted"
8675
+ ),
8676
+ children: opt.label
8677
+ },
8678
+ opt.id
8679
+ )) }) })
8680
+ ] })
8681
+ ] }),
8682
+ /* @__PURE__ */ jsxs("div", { className: "hidden sm:flex items-center gap-2 flex-wrap", children: [
8683
+ resolvedGroups.map((group) => {
8684
+ var _a2, _b2;
8685
+ const selectedCount = ((_a2 = selected[group.id]) != null ? _a2 : []).length;
8686
+ const isActive = selectedCount > 0;
8687
+ return /* @__PURE__ */ jsxs(Popover, { children: [
8688
+ /* @__PURE__ */ jsxs(
8689
+ PopoverTrigger,
8690
+ {
8691
+ render: /* @__PURE__ */ jsx(
8692
+ "button",
8693
+ {
8694
+ type: "button",
8695
+ className: cn(
8696
+ "inline-flex items-center gap-1.5 rounded-full border px-3.5 py-1.5",
8697
+ "text-sm font-ui font-semibold transition-colors",
8698
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8699
+ isActive ? "border-foreground bg-foreground text-background" : "border-border bg-background text-foreground hover:bg-muted"
8700
+ )
8701
+ }
8702
+ ),
8703
+ children: [
8704
+ group.icon && /* @__PURE__ */ jsx(
8705
+ "span",
8706
+ {
8707
+ className: cn(
8708
+ "[&>svg]:h-3.5 [&>svg]:w-3.5",
8709
+ isActive ? "" : "text-muted-foreground"
8710
+ ),
8711
+ children: group.icon
8712
+ }
8713
+ ),
8714
+ group.label,
8715
+ selectedCount > 0 && /* @__PURE__ */ jsx(
8716
+ "span",
8717
+ {
8718
+ className: cn(
8719
+ "inline-flex items-center justify-center rounded-full text-[10px] font-bold px-1.5 min-w-[18px] h-[18px]",
8720
+ isActive ? "bg-background text-foreground" : "bg-foreground text-background"
8721
+ ),
8722
+ children: selectedCount
8723
+ }
8724
+ ),
8725
+ /* @__PURE__ */ jsx(
8726
+ ChevronDownIcon,
8727
+ {
8728
+ className: cn(
8729
+ "h-3.5 w-3.5",
8730
+ isActive ? "text-background/70" : "text-muted-foreground"
8731
+ )
8732
+ }
8733
+ )
8734
+ ]
8735
+ }
8736
+ ),
8737
+ /* @__PURE__ */ jsx(
8738
+ PopoverContent,
8739
+ {
8740
+ align: "start",
8741
+ sideOffset: 6,
8742
+ className: "w-72 max-h-[60vh] overflow-y-auto",
8743
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 p-2", children: [
8744
+ /* @__PURE__ */ jsx("p", { className: "px-1 py-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: group.label }),
8745
+ /* @__PURE__ */ jsx(
8746
+ FilterItemsList,
8747
+ {
8748
+ items: group.items,
8749
+ groupId: group.id,
8750
+ groupSelected: (_b2 = selected[group.id]) != null ? _b2 : [],
8751
+ onToggle: (id) => handleToggle(group.id, id),
8752
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8753
+ idPrefix: "popover-filter",
8754
+ parentAsHeader: true,
8755
+ expandedItems,
8756
+ onToggleExpanded: toggleExpanded
8757
+ }
8758
+ )
8759
+ ] })
8760
+ }
8761
+ )
8762
+ ] }, group.id);
8763
+ }),
8764
+ totalSelected > 0 && /* @__PURE__ */ jsxs(
8765
+ "button",
8766
+ {
8767
+ type: "button",
8768
+ onClick: handleClearAll,
8769
+ className: "inline-flex items-center gap-1 rounded-full px-3 py-1.5 text-xs font-ui font-semibold text-muted-foreground hover:text-foreground transition-colors",
8770
+ children: [
8771
+ /* @__PURE__ */ jsx(XIcon, { className: "h-3 w-3" }),
8772
+ "Clear all (",
8773
+ totalSelected,
8774
+ ")"
8775
+ ]
8776
+ }
8777
+ ),
8778
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
8779
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-ui hidden sm:inline", children: "Sort by" }),
8780
+ /* @__PURE__ */ jsxs(Popover, { children: [
8781
+ /* @__PURE__ */ jsxs(
8782
+ PopoverTrigger,
8783
+ {
8784
+ render: /* @__PURE__ */ jsx(
8785
+ "button",
8786
+ {
8787
+ type: "button",
8788
+ className: cn(
8789
+ "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-3.5 py-1.5",
8790
+ "text-sm font-ui font-semibold text-foreground hover:bg-muted transition-colors",
8791
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8792
+ )
8793
+ }
8794
+ ),
8795
+ children: [
8796
+ (_b = activeSort == null ? void 0 : activeSort.label) != null ? _b : "Default",
8797
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-3.5 w-3.5 text-muted-foreground" })
8798
+ ]
8799
+ }
8800
+ ),
8801
+ /* @__PURE__ */ jsx(PopoverContent, { align: "end", sideOffset: 6, className: "w-52", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 p-0.5", children: sortOptions.map((opt) => /* @__PURE__ */ jsx(
8802
+ "button",
8803
+ {
8804
+ type: "button",
8805
+ onClick: () => onSortChange == null ? void 0 : onSortChange(opt.id),
8806
+ className: cn(
8807
+ "flex items-center px-2 py-1.5 rounded-md text-sm text-left",
8808
+ opt.id === (activeSort == null ? void 0 : activeSort.id) ? "bg-muted text-foreground font-semibold" : "text-foreground/80 hover:bg-muted"
8809
+ ),
8810
+ children: opt.label
8811
+ },
8812
+ opt.id
8813
+ )) }) })
8814
+ ] })
8815
+ ] })
8816
+ ] })
8817
+ ] });
8818
+ }
8318
8819
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), children: [
8319
8820
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8320
8821
  /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-ui", children: title }),
@@ -8325,9 +8826,9 @@ function FilterPanel({
8325
8826
  {
8326
8827
  defaultValue: defaultOpenValues,
8327
8828
  className: "flex flex-col gap-2",
8328
- children: groups.map((group) => {
8329
- var _a;
8330
- const groupSelected = (_a = selected[group.id]) != null ? _a : [];
8829
+ children: resolvedGroups.map((group) => {
8830
+ var _a2;
8831
+ const groupSelected = (_a2 = selected[group.id]) != null ? _a2 : [];
8331
8832
  return /* @__PURE__ */ jsxs(
8332
8833
  AccordionItem,
8333
8834
  {
@@ -8339,34 +8840,19 @@ function FilterPanel({
8339
8840
  /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-foreground font-ui", children: group.label }),
8340
8841
  groupSelected.length > 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[9px] font-bold text-primary-foreground", children: groupSelected.length })
8341
8842
  ] }) }),
8342
- /* @__PURE__ */ jsx(AccordionContent, { className: "px-4 pb-3 pt-1", children: /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-0.5", children: group.items.map((item) => {
8343
- const checked = groupSelected.includes(item.id);
8344
- const checkboxId = `filter-${group.id}-${item.id}`;
8345
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
8346
- "label",
8347
- {
8348
- htmlFor: checkboxId,
8349
- className: "flex cursor-pointer items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50",
8350
- children: [
8351
- /* @__PURE__ */ jsx(
8352
- Checkbox,
8353
- {
8354
- id: checkboxId,
8355
- checked,
8356
- onCheckedChange: () => handleToggle(group.id, item.id),
8357
- className: "shrink-0"
8358
- }
8359
- ),
8360
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-foreground font-ui", children: item.label }),
8361
- item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8362
- "(",
8363
- item.count,
8364
- ")"
8365
- ] })
8366
- ]
8367
- }
8368
- ) }, item.id);
8369
- }) }) })
8843
+ /* @__PURE__ */ jsx(AccordionContent, { className: "px-4 pb-3 pt-1", children: /* @__PURE__ */ jsx(
8844
+ FilterItemsList,
8845
+ {
8846
+ items: group.items,
8847
+ groupId: group.id,
8848
+ groupSelected,
8849
+ onToggle: (id) => handleToggle(group.id, id),
8850
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8851
+ idPrefix: "filter",
8852
+ expandedItems,
8853
+ onToggleExpanded: toggleExpanded
8854
+ }
8855
+ ) })
8370
8856
  ]
8371
8857
  },
8372
8858
  group.id
@@ -8387,70 +8873,182 @@ function FilterPanel({
8387
8873
  var TRUSTPILOT_SCRIPT_SRC = "https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js";
8388
8874
  function TrustpilotEmbed({ config }) {
8389
8875
  var _a, _b, _c, _d, _e, _f;
8390
- const ref = React8.useRef(null);
8391
- React8.useEffect(() => {
8876
+ const ref = React28.useRef(null);
8877
+ const [widgetReady, setWidgetReady] = React28.useState(false);
8878
+ const [delayPassed, setDelayPassed] = React28.useState(false);
8879
+ const showFallback = delayPassed && !widgetReady;
8880
+ React28.useEffect(() => {
8881
+ var _a2;
8392
8882
  if (typeof document === "undefined" || !ref.current) return;
8883
+ const node = ref.current;
8393
8884
  let cancelled = false;
8885
+ const checkRendered = () => {
8886
+ if (!node) return false;
8887
+ if (node.querySelector("iframe")) return true;
8888
+ if (node.innerHTML.length > 200) return true;
8889
+ return false;
8890
+ };
8891
+ const observer = new MutationObserver(() => {
8892
+ if (cancelled) return;
8893
+ if (checkRendered()) setWidgetReady(true);
8894
+ });
8895
+ observer.observe(node, { childList: true, subtree: true });
8896
+ if (checkRendered()) setWidgetReady(true);
8394
8897
  const initWidget = () => {
8395
- if (cancelled || !ref.current) return;
8898
+ if (cancelled || !node) return;
8396
8899
  const tp = window.Trustpilot;
8397
8900
  if (tp == null ? void 0 : tp.loadFromElement) {
8398
- tp.loadFromElement(ref.current, true);
8901
+ tp.loadFromElement(node, true);
8399
8902
  }
8400
8903
  };
8401
8904
  const existing = document.querySelector(
8402
8905
  `script[src="${TRUSTPILOT_SCRIPT_SRC}"]`
8403
8906
  );
8907
+ let cleanupScriptListener;
8404
8908
  if (existing) {
8405
8909
  const tp = window.Trustpilot;
8406
8910
  if (tp == null ? void 0 : tp.loadFromElement) {
8407
8911
  initWidget();
8408
8912
  } else {
8409
8913
  existing.addEventListener("load", initWidget, { once: true });
8914
+ cleanupScriptListener = () => existing.removeEventListener("load", initWidget);
8410
8915
  }
8411
- return () => {
8412
- cancelled = true;
8413
- existing.removeEventListener("load", initWidget);
8414
- };
8916
+ } else {
8917
+ const s = document.createElement("script");
8918
+ s.src = TRUSTPILOT_SCRIPT_SRC;
8919
+ s.async = true;
8920
+ s.addEventListener("load", initWidget, { once: true });
8921
+ document.body.appendChild(s);
8922
+ cleanupScriptListener = () => s.removeEventListener("load", initWidget);
8415
8923
  }
8416
- const s = document.createElement("script");
8417
- s.src = TRUSTPILOT_SCRIPT_SRC;
8418
- s.async = true;
8419
- s.addEventListener("load", initWidget, { once: true });
8420
- document.body.appendChild(s);
8924
+ const delay = (_a2 = config.fallbackDelayMs) != null ? _a2 : 3e3;
8925
+ const timeout = setTimeout(() => {
8926
+ if (!cancelled) setDelayPassed(true);
8927
+ }, delay);
8421
8928
  return () => {
8422
8929
  cancelled = true;
8423
- s.removeEventListener("load", initWidget);
8930
+ clearTimeout(timeout);
8931
+ observer.disconnect();
8932
+ cleanupScriptListener == null ? void 0 : cleanupScriptListener();
8424
8933
  };
8425
8934
  }, [config]);
8426
8935
  const sku = Array.isArray(config.sku) ? config.sku.join(",") : config.sku;
8936
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8937
+ /* @__PURE__ */ jsx(
8938
+ "div",
8939
+ {
8940
+ ref,
8941
+ className: "trustpilot-widget",
8942
+ "data-locale": (_a = config.locale) != null ? _a : "en-US",
8943
+ "data-template-id": (_b = config.templateId) != null ? _b : "5763bccae0a06d08e809ecbb",
8944
+ "data-businessunit-id": config.businessUnitId,
8945
+ "data-style-height": (_c = config.styleHeight) != null ? _c : "700px",
8946
+ "data-style-width": (_d = config.styleWidth) != null ? _d : "100%",
8947
+ "data-sku": sku,
8948
+ "data-no-reviews": (_e = config.noReviews) != null ? _e : "hide",
8949
+ "data-fullwidth": "true",
8950
+ "data-theme": config.theme,
8951
+ "data-token": config.token,
8952
+ "data-scroll-to-list": config.scrollToList ? "true" : void 0,
8953
+ "data-style-alignment": config.styleAlignment,
8954
+ "data-star-color": config.starColor,
8955
+ children: /* @__PURE__ */ jsx(
8956
+ "a",
8957
+ {
8958
+ href: (_f = config.fallbackHref) != null ? _f : "https://www.trustpilot.com/",
8959
+ target: "_blank",
8960
+ rel: "noopener noreferrer",
8961
+ children: "Trustpilot"
8962
+ }
8963
+ )
8964
+ }
8965
+ ),
8966
+ showFallback && /* @__PURE__ */ jsx(TrustpilotFallback, { config })
8967
+ ] });
8968
+ }
8969
+ function FallbackStar({ filled, className }) {
8427
8970
  return /* @__PURE__ */ jsx(
8428
- "div",
8971
+ "span",
8429
8972
  {
8430
- ref,
8431
- className: "trustpilot-widget",
8432
- "data-locale": (_a = config.locale) != null ? _a : "en-US",
8433
- "data-template-id": (_b = config.templateId) != null ? _b : "5763bccae0a06d08e809ecbb",
8434
- "data-businessunit-id": config.businessUnitId,
8435
- "data-style-height": (_c = config.styleHeight) != null ? _c : "700px",
8436
- "data-style-width": (_d = config.styleWidth) != null ? _d : "100%",
8437
- "data-sku": sku,
8438
- "data-no-reviews": (_e = config.noReviews) != null ? _e : "hide",
8439
- "data-fullwidth": "true",
8440
- "data-theme": config.theme,
8441
- "data-token": config.token,
8442
- "data-scroll-to-list": config.scrollToList ? "true" : void 0,
8443
- "data-style-alignment": config.styleAlignment,
8444
- "data-star-color": config.starColor,
8445
- children: /* @__PURE__ */ jsx(
8446
- "a",
8447
- {
8448
- href: (_f = config.fallbackHref) != null ? _f : "https://www.trustpilot.com/",
8449
- target: "_blank",
8450
- rel: "noopener noreferrer",
8451
- children: "Trustpilot"
8452
- }
8453
- )
8973
+ "aria-hidden": true,
8974
+ className: cn(
8975
+ "inline-flex items-center justify-center",
8976
+ filled ? "bg-[#00b67a] text-white" : "bg-muted text-muted-foreground",
8977
+ className
8978
+ ),
8979
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-[60%] w-[60%]", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) })
8980
+ }
8981
+ );
8982
+ }
8983
+ function TrustpilotFallback({ config }) {
8984
+ var _a, _b, _c, _d, _e, _f;
8985
+ const score = (_a = config.fallbackScore) != null ? _a : 4.8;
8986
+ const count = (_b = config.fallbackCount) != null ? _b : 0;
8987
+ const label = (_c = config.fallbackLabel) != null ? _c : "Excellent";
8988
+ const href = (_d = config.fallbackHref) != null ? _d : "https://www.trustpilot.com/";
8989
+ const isDark = config.theme === "dark";
8990
+ const styleHeightPx = parseInt((_e = config.styleHeight) != null ? _e : "", 10);
8991
+ const autoVariant = Number.isFinite(styleHeightPx) && styleHeightPx > 0 && styleHeightPx < 120 ? "mini" : "card";
8992
+ const variant = (_f = config.fallbackVariant) != null ? _f : autoVariant;
8993
+ const filledStars = Math.round(score);
8994
+ if (variant === "mini") {
8995
+ return /* @__PURE__ */ jsxs(
8996
+ "a",
8997
+ {
8998
+ href,
8999
+ target: "_blank",
9000
+ rel: "noopener noreferrer",
9001
+ className: cn(
9002
+ "inline-flex items-center gap-2 text-sm font-ui no-underline hover:opacity-80 transition-opacity",
9003
+ isDark ? "text-white" : "text-foreground"
9004
+ ),
9005
+ children: [
9006
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(FallbackStar, { filled: i < filledStars, className: "h-4 w-4 rounded-[2px]" }, i)) }),
9007
+ /* @__PURE__ */ jsx("span", { className: "font-bold", children: score.toFixed(1) }),
9008
+ count > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
9009
+ /* @__PURE__ */ jsx("span", { className: cn(isDark ? "text-white/60" : "text-muted-foreground"), children: "\xB7" }),
9010
+ /* @__PURE__ */ jsxs("span", { className: cn("text-xs", isDark ? "text-white/80" : "text-muted-foreground"), children: [
9011
+ count.toLocaleString(),
9012
+ " reviews"
9013
+ ] })
9014
+ ] }),
9015
+ /* @__PURE__ */ jsx("span", { className: cn("text-xs", isDark ? "text-white/60" : "text-muted-foreground"), children: "on Trustpilot" })
9016
+ ]
9017
+ }
9018
+ );
9019
+ }
9020
+ return /* @__PURE__ */ jsxs(
9021
+ "a",
9022
+ {
9023
+ href,
9024
+ target: "_blank",
9025
+ rel: "noopener noreferrer",
9026
+ className: "block max-w-md mx-auto rounded-2xl border border-border bg-card p-8 text-center no-underline shadow-sm hover:shadow-md transition-shadow",
9027
+ children: [
9028
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center items-center gap-1 mb-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(FallbackStar, { filled: i < filledStars, className: "h-7 w-7 rounded-[3px]" }, i)) }),
9029
+ /* @__PURE__ */ jsxs("p", { className: "text-2xl font-bold text-foreground font-heading", children: [
9030
+ label,
9031
+ " ",
9032
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground font-normal", children: [
9033
+ "\xB7 ",
9034
+ score.toFixed(1),
9035
+ " / 5"
9036
+ ] })
9037
+ ] }),
9038
+ count > 0 && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-2", children: [
9039
+ "Based on ",
9040
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: count.toLocaleString() }),
9041
+ " reviews"
9042
+ ] }),
9043
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-4", children: "Reviews powered by Trustpilot" }),
9044
+ /* @__PURE__ */ jsxs("span", { className: "mt-5 inline-flex items-center gap-1.5 text-sm font-semibold text-primary border-b border-primary/40 pb-0.5", children: [
9045
+ "Read all reviews on Trustpilot",
9046
+ /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
9047
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
9048
+ /* @__PURE__ */ jsx("polyline", { points: "12 5 19 12 12 19" })
9049
+ ] })
9050
+ ] })
9051
+ ]
8454
9052
  }
8455
9053
  );
8456
9054
  }
@@ -8520,11 +9118,11 @@ function ItineraryModal({
8520
9118
  onNext
8521
9119
  }) {
8522
9120
  var _a, _b, _c;
8523
- const [imgIndex, setImgIndex] = React8.useState(0);
9121
+ const [imgIndex, setImgIndex] = React28.useState(0);
8524
9122
  const images = stop ? [stop.coverImage, ...(_a = stop.images) != null ? _a : []] : [];
8525
9123
  const isFirst = (stop == null ? void 0 : stop.dayNumber) === ((_b = allStops[0]) == null ? void 0 : _b.dayNumber);
8526
9124
  const isLast = (stop == null ? void 0 : stop.dayNumber) === ((_c = allStops[allStops.length - 1]) == null ? void 0 : _c.dayNumber);
8527
- React8.useEffect(() => {
9125
+ React28.useEffect(() => {
8528
9126
  setImgIndex(0);
8529
9127
  }, [stop == null ? void 0 : stop.dayNumber]);
8530
9128
  if (!stop) return null;
@@ -8651,8 +9249,8 @@ function ItineraryModal({
8651
9249
  ) });
8652
9250
  }
8653
9251
  function Itinerary({ title, subtitle, stops, className }) {
8654
- const [activeIndex, setActiveIndex] = React8.useState(null);
8655
- const scrollRef = React8.useRef(null);
9252
+ const [activeIndex, setActiveIndex] = React28.useState(null);
9253
+ const scrollRef = React28.useRef(null);
8656
9254
  const activeStop = activeIndex !== null ? stops[activeIndex] : null;
8657
9255
  const scrollBy = (dir) => {
8658
9256
  if (!scrollRef.current) return;
@@ -8744,18 +9342,18 @@ function Lightbox({
8744
9342
  onClose
8745
9343
  }) {
8746
9344
  var _a;
8747
- const [index, setIndex] = React8.useState(initialIndex);
9345
+ const [index, setIndex] = React28.useState(initialIndex);
8748
9346
  const total = photos.length;
8749
9347
  const photo = photos[index];
8750
- const prev = React8.useCallback(
9348
+ const prev = React28.useCallback(
8751
9349
  () => setIndex((i) => (i - 1 + total) % total),
8752
9350
  [total]
8753
9351
  );
8754
- const next = React8.useCallback(
9352
+ const next = React28.useCallback(
8755
9353
  () => setIndex((i) => (i + 1) % total),
8756
9354
  [total]
8757
9355
  );
8758
- React8.useEffect(() => {
9356
+ React28.useEffect(() => {
8759
9357
  const onKey = (e) => {
8760
9358
  if (e.key === "Escape") onClose();
8761
9359
  if (e.key === "ArrowLeft") prev();
@@ -8921,7 +9519,7 @@ function GridGallery({
8921
9519
  initialVisible,
8922
9520
  onOpen
8923
9521
  }) {
8924
- const [expanded, setExpanded] = React8.useState(false);
9522
+ const [expanded, setExpanded] = React28.useState(false);
8925
9523
  const cols = gridCols(photos.length);
8926
9524
  const hasMore = photos.length > initialVisible;
8927
9525
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
@@ -8946,12 +9544,41 @@ function GridGallery({
8946
9544
  )
8947
9545
  ] });
8948
9546
  }
9547
+ function CompactGridGallery({
9548
+ photos,
9549
+ initialVisible,
9550
+ onOpen
9551
+ }) {
9552
+ const [expanded, setExpanded] = React28.useState(false);
9553
+ const hasMore = photos.length > initialVisible;
9554
+ const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
9555
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9556
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-4", children: visible.map((p, i) => /* @__PURE__ */ jsx(
9557
+ PhotoTile,
9558
+ {
9559
+ photo: p,
9560
+ index: i,
9561
+ className: "aspect-[4/3]",
9562
+ onClick: () => onOpen(i)
9563
+ },
9564
+ i
9565
+ )) }),
9566
+ hasMore && /* @__PURE__ */ jsx(
9567
+ ShowMoreButton,
9568
+ {
9569
+ count: photos.length - initialVisible,
9570
+ expanded,
9571
+ onClick: () => setExpanded((v) => !v)
9572
+ }
9573
+ )
9574
+ ] });
9575
+ }
8949
9576
  function MasonryGallery({
8950
9577
  photos,
8951
9578
  initialVisible,
8952
9579
  onOpen
8953
9580
  }) {
8954
- const [expanded, setExpanded] = React8.useState(false);
9581
+ const [expanded, setExpanded] = React28.useState(false);
8955
9582
  const hasMore = photos.length > initialVisible;
8956
9583
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
8957
9584
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9024,7 +9651,7 @@ function FeaturedGallery({
9024
9651
  photos,
9025
9652
  onOpen
9026
9653
  }) {
9027
- const [expanded, setExpanded] = React8.useState(false);
9654
+ const [expanded, setExpanded] = React28.useState(false);
9028
9655
  const featured = photos.slice(0, 3);
9029
9656
  const extra = photos.slice(3);
9030
9657
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9191,9 +9818,9 @@ function PhotoGallery({
9191
9818
  onPhotoClick,
9192
9819
  className
9193
9820
  }) {
9194
- const [lightboxIndex, setLightboxIndex] = React8.useState(null);
9195
- const [carouselIndex, setCarouselIndex] = React8.useState(0);
9196
- const normalised = React8.useMemo(() => photos.map(normalise), [photos]);
9821
+ const [lightboxIndex, setLightboxIndex] = React28.useState(null);
9822
+ const [carouselIndex, setCarouselIndex] = React28.useState(0);
9823
+ const normalised = React28.useMemo(() => photos.map(normalise), [photos]);
9197
9824
  const handleOpen = (index) => {
9198
9825
  setLightboxIndex(index);
9199
9826
  onPhotoClick == null ? void 0 : onPhotoClick(normalised[index].src, index);
@@ -9235,6 +9862,14 @@ function PhotoGallery({
9235
9862
  onOpen: handleOpen
9236
9863
  }
9237
9864
  ),
9865
+ variant === "gridCompact" && /* @__PURE__ */ jsx(
9866
+ CompactGridGallery,
9867
+ {
9868
+ photos: normalised,
9869
+ initialVisible,
9870
+ onOpen: handleOpen
9871
+ }
9872
+ ),
9238
9873
  variant === "masonry" && /* @__PURE__ */ jsx(
9239
9874
  MasonryGallery,
9240
9875
  {
@@ -9269,7 +9904,7 @@ function ItineraryDay({
9269
9904
  photoLayout = "rounded",
9270
9905
  className
9271
9906
  }) {
9272
- const photoList = React8.useMemo(() => normalisePhotos(photos), [photos]);
9907
+ const photoList = React28.useMemo(() => normalisePhotos(photos), [photos]);
9273
9908
  const isFullBleed = photoLayout === "fullBleed" || photoLayout === "fullBleedBottom";
9274
9909
  const photoPosition = photoLayout === "fullBleedBottom" ? "bottom" : "top";
9275
9910
  const gallery = photoList.length > 0 && /* @__PURE__ */ jsx(
@@ -9288,13 +9923,16 @@ function ItineraryDay({
9288
9923
  specs && specs.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3 sm:gap-2.5", children: specs.map((spec, i) => /* @__PURE__ */ jsxs(
9289
9924
  "li",
9290
9925
  {
9291
- className: "flex flex-col text-base text-foreground font-ui",
9926
+ className: "flex items-start gap-3 text-base text-foreground font-ui",
9292
9927
  children: [
9293
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
9294
- /* @__PURE__ */ jsx("span", { className: "font-semibold", children: spec.label }),
9295
- spec.detail && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: spec.detail })
9296
- ] }),
9297
- spec.subdetail && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: spec.subdetail })
9928
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true, children: spec.icon }),
9929
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
9930
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
9931
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: spec.label }),
9932
+ spec.detail && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: spec.detail })
9933
+ ] }),
9934
+ spec.subdetail && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: spec.subdetail })
9935
+ ] })
9298
9936
  ]
9299
9937
  },
9300
9938
  i
@@ -9321,8 +9959,8 @@ function MenuTrip({
9321
9959
  bold = true,
9322
9960
  className
9323
9961
  }) {
9324
- const scrollRef = React8.useRef(null);
9325
- React8.useEffect(() => {
9962
+ const scrollRef = React28.useRef(null);
9963
+ React28.useEffect(() => {
9326
9964
  if (!scrollRef.current || !activeSection) return;
9327
9965
  const container = scrollRef.current;
9328
9966
  const btn = container.querySelector(
@@ -9513,8 +10151,8 @@ function PricingTrip({
9513
10151
  className
9514
10152
  }) {
9515
10153
  const rOuter = sharp ? "rounded-none" : "rounded-2xl";
9516
- const [showEstimates, setShowEstimates] = React8.useState(false);
9517
- const [showPriceInfo, setShowPriceInfo] = React8.useState(false);
10154
+ const [showEstimates, setShowEstimates] = React28.useState(false);
10155
+ const [showPriceInfo, setShowPriceInfo] = React28.useState(false);
9518
10156
  if (variant === "compact") {
9519
10157
  const showOverlay = showPriceInfo && (!!priceInfo || !!currencyEstimates && currencyEstimates.length > 0);
9520
10158
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
@@ -9798,8 +10436,7 @@ var VARIANT = {
9798
10436
  mobileLink: "text-white hover:text-primary-400 border-b border-white/10",
9799
10437
  mobileSub: "text-white/70 font-bold hover:text-primary-400 border-b border-white/8",
9800
10438
  mobileLangActive: "text-primary-400 font-semibold",
9801
- mobileLangIdle: "text-white/40 hover:text-primary-400",
9802
- logoBlend: "mix-blend-screen"
10439
+ mobileLangIdle: "text-white/40 hover:text-primary-400"
9803
10440
  },
9804
10441
  white: {
9805
10442
  header: "bg-white border-b border-border shadow-sm",
@@ -9815,8 +10452,7 @@ var VARIANT = {
9815
10452
  mobileLink: "text-foreground/80 hover:text-foreground border-b border-border",
9816
10453
  mobileSub: "text-foreground/50 font-bold hover:text-foreground border-b border-border/40",
9817
10454
  mobileLangActive: "text-primary font-semibold",
9818
- mobileLangIdle: "text-muted-foreground hover:text-foreground",
9819
- logoBlend: "invert mix-blend-multiply"
10455
+ mobileLangIdle: "text-muted-foreground hover:text-foreground"
9820
10456
  },
9821
10457
  dark: {
9822
10458
  header: "bg-neutral-950 border-b border-white/10",
@@ -9832,8 +10468,7 @@ var VARIANT = {
9832
10468
  mobileLink: "text-white/80 hover:text-white border-b border-white/8",
9833
10469
  mobileSub: "text-white/45 font-bold hover:text-white border-b border-white/5",
9834
10470
  mobileLangActive: "text-white font-semibold",
9835
- mobileLangIdle: "text-white/35 hover:text-white/60",
9836
- logoBlend: "mix-blend-screen"
10471
+ mobileLangIdle: "text-white/35 hover:text-white/60"
9837
10472
  }
9838
10473
  };
9839
10474
  var DEFAULT_HEADER_LINKS = [
@@ -9943,7 +10578,9 @@ function LangDropdown({
9943
10578
  function SiteHeader({
9944
10579
  variant = "transparent",
9945
10580
  links = DEFAULT_HEADER_LINKS,
9946
- logoSrc = "/logo-planetaexo.png",
10581
+ logoSrcLight = "/logo-planetaexo-white.png",
10582
+ logoSrcDark = "/logo-planetaexo-green.png",
10583
+ logoSrc,
9947
10584
  logoAlt = "Planeta Exo",
9948
10585
  languages = DEFAULT_LANGUAGES,
9949
10586
  currentLanguage = "EN",
@@ -9954,14 +10591,15 @@ function SiteHeader({
9954
10591
  className
9955
10592
  }) {
9956
10593
  const t = VARIANT[variant];
9957
- const [openMenu, setOpenMenu] = React8.useState(null);
9958
- const [langOpen, setLangOpen] = React8.useState(false);
9959
- const [mobileOpen, setMobileOpen] = React8.useState(false);
9960
- const [openMobileSection, setOpenMobileSection] = React8.useState(null);
9961
- const [activeLang, setActiveLang] = React8.useState(currentLanguage);
10594
+ const resolvedLogo = logoSrc != null ? logoSrc : variant === "white" ? logoSrcDark : logoSrcLight;
10595
+ const [openMenu, setOpenMenu] = React28.useState(null);
10596
+ const [langOpen, setLangOpen] = React28.useState(false);
10597
+ const [mobileOpen, setMobileOpen] = React28.useState(false);
10598
+ const [openMobileSection, setOpenMobileSection] = React28.useState(null);
10599
+ const [activeLang, setActiveLang] = React28.useState(currentLanguage);
9962
10600
  const toggleMobileSection = (label) => setOpenMobileSection((prev) => prev === label ? null : label);
9963
- const menuCloseTimer = React8.useRef(void 0);
9964
- const langCloseTimer = React8.useRef(void 0);
10601
+ const menuCloseTimer = React28.useRef(void 0);
10602
+ const langCloseTimer = React28.useRef(void 0);
9965
10603
  const handleMenuEnter = (label) => {
9966
10604
  clearTimeout(menuCloseTimer.current);
9967
10605
  setOpenMenu(label);
@@ -9982,7 +10620,7 @@ function SiteHeader({
9982
10620
  setOpenMenu(null);
9983
10621
  setLangOpen(false);
9984
10622
  };
9985
- React8.useEffect(() => () => {
10623
+ React28.useEffect(() => () => {
9986
10624
  clearTimeout(menuCloseTimer.current);
9987
10625
  clearTimeout(langCloseTimer.current);
9988
10626
  }, []);
@@ -10002,17 +10640,41 @@ function SiteHeader({
10002
10640
  className
10003
10641
  ),
10004
10642
  children: [
10005
- variant === "transparent" && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 top-0 h-52 bg-gradient-to-b from-black/55 via-black/20 to-transparent pointer-events-none" }),
10643
+ variant === "transparent" && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 top-0 h-52 bg-gradient-to-b from-black/70 via-black/30 to-transparent pointer-events-none" }),
10006
10644
  /* @__PURE__ */ jsxs("div", { className: "relative flex items-center gap-2 px-6 sm:px-10 h-[72px]", children: [
10007
- /* @__PURE__ */ jsx("a", { href: "#", className: "shrink-0 flex items-center mr-4", children: /* @__PURE__ */ jsx(
10008
- "img",
10645
+ /* @__PURE__ */ jsx(
10646
+ "button",
10009
10647
  {
10010
- src: logoSrc,
10011
- alt: logoAlt,
10012
- className: cn("h-11 w-auto select-none", t.logoBlend),
10013
- draggable: false
10648
+ type: "button",
10649
+ onClick: () => setMobileOpen(true),
10650
+ "aria-label": "Open menu",
10651
+ className: cn(
10652
+ "flex lg:hidden h-9 w-9 items-center justify-center rounded-full transition-colors -ml-1.5",
10653
+ t.mobileTrigger
10654
+ ),
10655
+ children: /* @__PURE__ */ jsx(MenuIcon, { className: "h-[18px] w-[18px]" })
10014
10656
  }
10015
- ) }),
10657
+ ),
10658
+ /* @__PURE__ */ jsx(
10659
+ "a",
10660
+ {
10661
+ href: "#",
10662
+ className: cn(
10663
+ "shrink-0 flex items-center",
10664
+ "absolute left-1/2 -translate-x-1/2",
10665
+ "lg:static lg:translate-x-0 lg:mr-4"
10666
+ ),
10667
+ children: /* @__PURE__ */ jsx(
10668
+ "img",
10669
+ {
10670
+ src: resolvedLogo,
10671
+ alt: logoAlt,
10672
+ className: "h-14 w-auto select-none",
10673
+ draggable: false
10674
+ }
10675
+ )
10676
+ }
10677
+ ),
10016
10678
  /* @__PURE__ */ jsx("nav", { className: "hidden lg:flex items-center gap-0.5 mx-auto", children: links.map((link) => {
10017
10679
  var _a, _b;
10018
10680
  const hasDropdown = !!((_a = link.items) == null ? void 0 : _a.length);
@@ -10136,19 +10798,6 @@ function SiteHeader({
10136
10798
  ),
10137
10799
  children: /* @__PURE__ */ jsx(UserIcon, { className: "h-[18px] w-[18px]" })
10138
10800
  }
10139
- ),
10140
- /* @__PURE__ */ jsx(
10141
- "button",
10142
- {
10143
- type: "button",
10144
- onClick: () => setMobileOpen(true),
10145
- "aria-label": "Open menu",
10146
- className: cn(
10147
- "flex lg:hidden h-9 w-9 items-center justify-center rounded-full transition-colors ml-0.5",
10148
- t.mobileTrigger
10149
- ),
10150
- children: /* @__PURE__ */ jsx(MenuIcon, { className: "h-[18px] w-[18px]" })
10151
- }
10152
10801
  )
10153
10802
  ] })
10154
10803
  ] }),
@@ -10164,9 +10813,9 @@ function SiteHeader({
10164
10813
  /* @__PURE__ */ jsx("a", { href: "#", className: "shrink-0 flex items-center", onClick: () => setMobileOpen(false), children: /* @__PURE__ */ jsx(
10165
10814
  "img",
10166
10815
  {
10167
- src: logoSrc,
10816
+ src: resolvedLogo,
10168
10817
  alt: logoAlt,
10169
- className: cn("h-11 w-auto select-none", t.logoBlend),
10818
+ className: "h-14 w-auto select-none",
10170
10819
  draggable: false
10171
10820
  }
10172
10821
  ) }),
@@ -10247,7 +10896,7 @@ function SiteHeader({
10247
10896
  ), children: [
10248
10897
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: languages.map((lang, i) => {
10249
10898
  const isActive = lang.code === activeLang;
10250
- return /* @__PURE__ */ jsxs(React8.Fragment, { children: [
10899
+ return /* @__PURE__ */ jsxs(React28.Fragment, { children: [
10251
10900
  i > 0 && /* @__PURE__ */ jsx("span", { className: cn(
10252
10901
  "text-xs select-none",
10253
10902
  variant === "white" ? "text-border" : "text-white/15"
@@ -10309,8 +10958,8 @@ function SiteHeader({
10309
10958
  );
10310
10959
  }
10311
10960
  function ThemeToggle({ className }) {
10312
- const [dark, setDark] = React8.useState(false);
10313
- React8.useEffect(() => {
10961
+ const [dark, setDark] = React28.useState(false);
10962
+ React28.useEffect(() => {
10314
10963
  const saved = localStorage.getItem("theme");
10315
10964
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
10316
10965
  const isDark = saved === "dark" || !saved && prefersDark;
@@ -10339,6 +10988,44 @@ function ThemeToggle({ className }) {
10339
10988
  }
10340
10989
  );
10341
10990
  }
10991
+ var chipVariants = cva(
10992
+ "inline-flex items-center rounded-full font-ui font-medium transition-colors whitespace-nowrap",
10993
+ {
10994
+ variants: {
10995
+ variant: {
10996
+ glass: "border border-white/15 bg-black/30 text-white/85 backdrop-blur-sm hover:bg-white/10 hover:border-white/50 hover:text-white",
10997
+ solid: "bg-muted text-foreground/80 hover:bg-primary hover:text-primary-foreground",
10998
+ outline: "border border-border text-foreground/80 hover:bg-primary hover:border-primary hover:text-primary-foreground"
10999
+ },
11000
+ size: {
11001
+ sm: "px-2.5 py-0.5 text-[11px] leading-5",
11002
+ md: "px-3 py-1 text-xs leading-5",
11003
+ lg: "px-4 py-1.5 text-sm leading-5"
11004
+ }
11005
+ },
11006
+ defaultVariants: {
11007
+ variant: "glass",
11008
+ size: "sm"
11009
+ }
11010
+ }
11011
+ );
11012
+ var Chip = React28.forwardRef(function Chip2(_a, ref) {
11013
+ var _b = _a, { className, variant, size, href, children } = _b, props = __objRest(_b, ["className", "variant", "size", "href", "children"]);
11014
+ const classes = cn(chipVariants({ variant, size }), className);
11015
+ if (href) {
11016
+ return /* @__PURE__ */ jsx(
11017
+ "a",
11018
+ __spreadProps(__spreadValues({
11019
+ ref,
11020
+ href,
11021
+ className: classes
11022
+ }, props), {
11023
+ children
11024
+ })
11025
+ );
11026
+ }
11027
+ return /* @__PURE__ */ jsx("span", __spreadProps(__spreadValues({ ref, className: classes }, props), { children }));
11028
+ });
10342
11029
  function CalendarIcon6() {
10343
11030
  return /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
10344
11031
  /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
@@ -10389,19 +11076,125 @@ var statusConfig = {
10389
11076
  icon: /* @__PURE__ */ jsx(TrendingIcon, {})
10390
11077
  }
10391
11078
  };
10392
- function TripCard({
10393
- image,
10394
- imageAlt = "",
10395
- status,
10396
- nights,
10397
- period,
10398
- title,
10399
- description,
10400
- cta,
10401
- price,
10402
- size = "md",
10403
- className
10404
- }) {
11079
+ function HeartIcon({ filled = false }) {
11080
+ return /* @__PURE__ */ jsx(
11081
+ "svg",
11082
+ {
11083
+ width: "16",
11084
+ height: "16",
11085
+ viewBox: "0 0 24 24",
11086
+ fill: filled ? "currentColor" : "none",
11087
+ stroke: "currentColor",
11088
+ strokeWidth: "2",
11089
+ strokeLinecap: "round",
11090
+ strokeLinejoin: "round",
11091
+ children: /* @__PURE__ */ jsx("path", { d: "M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" })
11092
+ }
11093
+ );
11094
+ }
11095
+ function TripCardEditorial(props) {
11096
+ const {
11097
+ image,
11098
+ imageAlt = "",
11099
+ title,
11100
+ description,
11101
+ nights,
11102
+ price,
11103
+ href,
11104
+ className,
11105
+ favoritable,
11106
+ favorited: favoritedProp,
11107
+ onFavoriteToggle,
11108
+ location,
11109
+ difficulty,
11110
+ tag
11111
+ } = props;
11112
+ const [internalFav, setInternalFav] = React28.useState(false);
11113
+ const favorited = favoritedProp != null ? favoritedProp : internalFav;
11114
+ const handleFav = (e) => {
11115
+ e.preventDefault();
11116
+ e.stopPropagation();
11117
+ const next = !favorited;
11118
+ if (favoritedProp === void 0) setInternalFav(next);
11119
+ onFavoriteToggle == null ? void 0 : onFavoriteToggle(next);
11120
+ };
11121
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
11122
+ /* @__PURE__ */ jsxs("div", { className: "relative aspect-[4/3] overflow-hidden bg-muted", children: [
11123
+ /* @__PURE__ */ jsx(
11124
+ "img",
11125
+ {
11126
+ src: image,
11127
+ alt: imageAlt,
11128
+ loading: "lazy",
11129
+ className: "absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
11130
+ }
11131
+ ),
11132
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/85 via-black/20 to-transparent" }),
11133
+ tag && /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10 max-w-[calc(100%-4.5rem)]", children: /* @__PURE__ */ jsx(Chip, { variant: "glass", size: "sm", children: tag }) }),
11134
+ favoritable && /* @__PURE__ */ jsx(
11135
+ "button",
11136
+ {
11137
+ type: "button",
11138
+ "aria-label": favorited ? "Remove from favorites" : "Add to favorites",
11139
+ "aria-pressed": favorited,
11140
+ onClick: handleFav,
11141
+ className: cn(
11142
+ "absolute top-3 right-3 flex h-9 w-9 items-center justify-center rounded-full",
11143
+ "border border-white/15 bg-black/30 backdrop-blur-sm",
11144
+ "transition-colors hover:bg-white/10 hover:border-white/50",
11145
+ favorited ? "text-white" : "text-white/85 hover:text-white"
11146
+ ),
11147
+ children: /* @__PURE__ */ jsx(HeartIcon, { filled: favorited })
11148
+ }
11149
+ ),
11150
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 bottom-0 p-5 text-white", children: /* @__PURE__ */ jsx("h3", { className: "text-lg sm:text-xl font-bold font-heading leading-tight", children: title }) })
11151
+ ] }),
11152
+ (description || price || nights || location || difficulty) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 bg-card p-6", children: [
11153
+ (location || difficulty) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
11154
+ location ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-foreground/85", children: [
11155
+ /* @__PURE__ */ jsx(MapPinIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
11156
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-ui font-semibold", children: location })
11157
+ ] }) : /* @__PURE__ */ jsx("span", {}),
11158
+ difficulty && /* @__PURE__ */ jsx(Chip, { variant: "outline", size: "sm", className: "capitalize text-muted-foreground", children: difficulty })
11159
+ ] }),
11160
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-3", children: description }),
11161
+ (nights || price) && /* @__PURE__ */ jsxs("div", { className: "mt-auto flex items-center justify-between gap-3", children: [
11162
+ nights ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-foreground/80", children: [
11163
+ /* @__PURE__ */ jsx(MoonIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
11164
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-ui font-semibold", children: [
11165
+ nights,
11166
+ " ",
11167
+ nights === 1 ? "night" : "nights"
11168
+ ] })
11169
+ ] }) : /* @__PURE__ */ jsx("span", {}),
11170
+ price && /* @__PURE__ */ jsx("p", { className: "text-base font-bold text-foreground font-ui", children: price })
11171
+ ] })
11172
+ ] })
11173
+ ] });
11174
+ const baseClasses = cn(
11175
+ "group relative flex flex-col overflow-hidden rounded-2xl bg-card border border-border/50",
11176
+ "shadow-md transition-shadow duration-300 hover:shadow-xl",
11177
+ className
11178
+ );
11179
+ return href ? /* @__PURE__ */ jsx("a", { href, className: baseClasses, "aria-label": title, children: body }) : /* @__PURE__ */ jsx("div", { className: baseClasses, children: body });
11180
+ }
11181
+ function TripCard(props) {
11182
+ if (props.variant === "editorial") {
11183
+ return /* @__PURE__ */ jsx(TripCardEditorial, __spreadValues({}, props));
11184
+ }
11185
+ const {
11186
+ image,
11187
+ imageAlt = "",
11188
+ status,
11189
+ nights,
11190
+ period,
11191
+ title,
11192
+ description,
11193
+ cta,
11194
+ price,
11195
+ size = "md",
11196
+ className
11197
+ } = props;
10405
11198
  const s = sizeConfig[size];
10406
11199
  const statusInfo = status ? statusConfig[status] : null;
10407
11200
  const meta = [
@@ -10461,7 +11254,7 @@ function TripCard({
10461
11254
  );
10462
11255
  }
10463
11256
  function useHlsVideo(videoRef, src) {
10464
- React8.useEffect(() => {
11257
+ React28.useEffect(() => {
10465
11258
  if (!src || !videoRef.current) return;
10466
11259
  const video = videoRef.current;
10467
11260
  if (!src.includes(".m3u8")) return;
@@ -10498,17 +11291,18 @@ function TripHeader({
10498
11291
  destination,
10499
11292
  duration,
10500
11293
  tagline,
11294
+ chips,
10501
11295
  belowMeta,
10502
11296
  siteHeader,
10503
11297
  uiVariant = "v1",
10504
11298
  className
10505
11299
  }) {
10506
11300
  var _a;
10507
- const [heroIndex, setHeroIndex] = React8.useState(0);
10508
- const [videoReady, setVideoReady] = React8.useState(false);
10509
- const videoRef = React8.useRef(null);
11301
+ const [heroIndex, setHeroIndex] = React28.useState(0);
11302
+ const [videoReady, setVideoReady] = React28.useState(false);
11303
+ const videoRef = React28.useRef(null);
10510
11304
  const isHls = !!(videoUrl == null ? void 0 : videoUrl.includes(".m3u8"));
10511
- const validImages = React8.useMemo(
11305
+ const validImages = React28.useMemo(
10512
11306
  () => images.map((u) => u == null ? void 0 : u.trim()).filter(Boolean),
10513
11307
  [images]
10514
11308
  );
@@ -10523,7 +11317,7 @@ function TripHeader({
10523
11317
  const nights = duration ? (_a = duration.nights) != null ? _a : Math.max(duration.days - 1, 1) : null;
10524
11318
  const hasMeta = !!(destination || duration);
10525
11319
  useHlsVideo(videoRef, isHls ? videoUrl : void 0);
10526
- React8.useEffect(() => {
11320
+ React28.useEffect(() => {
10527
11321
  if (!videoUrl) return;
10528
11322
  const el = videoRef.current;
10529
11323
  if (!el) return;
@@ -10657,15 +11451,15 @@ function TripHeader({
10657
11451
  ]
10658
11452
  }
10659
11453
  ),
10660
- /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-5xl px-4 sm:px-6", children: /* @__PURE__ */ jsxs(
11454
+ /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8", children: /* @__PURE__ */ jsxs(
10661
11455
  "div",
10662
11456
  {
10663
11457
  className: cn(
10664
11458
  "relative z-10 pb-10",
10665
- siteHeader ? "-mt-44" : "-mt-36"
11459
+ chips && chips.length > 0 ? siteHeader ? "-mt-[200px] sm:-mt-[214px]" : "-mt-[168px] sm:-mt-[182px]" : siteHeader ? "-mt-44" : "-mt-36"
10666
11460
  ),
10667
11461
  children: [
10668
- breadcrumb && breadcrumb.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 flex items-center gap-1.5 flex-wrap", children: breadcrumb.map((crumb, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
11462
+ breadcrumb && breadcrumb.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 flex items-center gap-1.5 flex-wrap", children: breadcrumb.map((crumb, i) => /* @__PURE__ */ jsxs(React28.Fragment, { children: [
10669
11463
  i > 0 && /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 text-white/50 shrink-0" }),
10670
11464
  /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 font-ui hover:text-white/90 cursor-default", children: crumb.label })
10671
11465
  ] }, i)) }),
@@ -10691,6 +11485,7 @@ function TripHeader({
10691
11485
  ] })
10692
11486
  ] })
10693
11487
  ] }) : tagline ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm sm:text-base text-white/80 font-ui", children: tagline }) : null,
11488
+ chips && chips.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap items-center gap-1.5", children: chips.map((chip, i) => /* @__PURE__ */ jsx(Chip, { href: chip.href, children: chip.label }, i)) }),
10694
11489
  belowMeta && /* @__PURE__ */ jsx("div", { className: "mt-3", children: belowMeta })
10695
11490
  ]
10696
11491
  }
@@ -10699,6 +11494,427 @@ function TripHeader({
10699
11494
  }
10700
11495
  );
10701
11496
  }
11497
+ var VARIANT2 = {
11498
+ light: {
11499
+ footer: "bg-primary-50 text-foreground",
11500
+ heading: "text-foreground",
11501
+ body: "text-foreground/75",
11502
+ muted: "text-foreground/60",
11503
+ link: "text-foreground/85 hover:text-primary-800 underline decoration-foreground/25 underline-offset-4 hover:decoration-primary-800",
11504
+ badgeStroke: "text-foreground/80",
11505
+ /** Inverts white logos so they read on the light background. */
11506
+ badgeFilter: "[filter:invert(1)_brightness(0.2)]",
11507
+ socialBtn: "bg-foreground text-white hover:bg-primary-800",
11508
+ langTrigger: "text-foreground hover:bg-white",
11509
+ langOpen: "text-foreground bg-white",
11510
+ langChevron: "text-foreground/40",
11511
+ bottomBar: "border-t border-foreground/10",
11512
+ bottomText: "text-foreground/60",
11513
+ bottomLink: "text-foreground/80 hover:text-foreground underline decoration-foreground/20 underline-offset-4 hover:decoration-foreground"
11514
+ },
11515
+ dark: {
11516
+ footer: "bg-brand-charcoal text-white",
11517
+ heading: "text-white",
11518
+ body: "text-white/75",
11519
+ muted: "text-white/55",
11520
+ link: "text-white/85 hover:text-primary-400 underline decoration-white/20 underline-offset-4 hover:decoration-primary-400",
11521
+ badgeStroke: "text-white",
11522
+ badgeFilter: "",
11523
+ socialBtn: "bg-white/10 text-white hover:bg-primary-400 hover:text-primary-900",
11524
+ langTrigger: "text-white/85 hover:bg-white/10",
11525
+ langOpen: "text-white bg-white/10",
11526
+ langChevron: "text-white/40",
11527
+ bottomBar: "border-t border-white/10",
11528
+ bottomText: "text-white/55",
11529
+ bottomLink: "text-white/80 hover:text-white underline decoration-white/20 underline-offset-4 hover:decoration-white"
11530
+ }
11531
+ };
11532
+ var DEFAULT_FOOTER_THEMES = [
11533
+ { label: "Roadtrips", href: "#" },
11534
+ { label: "Saf\xE1ri", href: "#" },
11535
+ { label: "Trilhas", href: "#" },
11536
+ { label: "Caiaque & Canoa", href: "#" },
11537
+ { label: "Aurora boreal", href: "#" },
11538
+ { label: "Micro-aventuras", href: "#" },
11539
+ { label: "Packrafting", href: "#" },
11540
+ { label: "Glamping", href: "#" },
11541
+ { label: "Surf", href: "#" },
11542
+ { label: "Viagens em fam\xEDlia", href: "#" }
11543
+ ];
11544
+ var DEFAULT_FOOTER_DESTINATIONS = [
11545
+ { label: "Brasil", href: "#" },
11546
+ { label: "Patag\xF4nia", href: "#" },
11547
+ { label: "Argentina", href: "#" },
11548
+ { label: "Chile", href: "#" },
11549
+ { label: "Bol\xEDvia", href: "#" },
11550
+ { label: "Peru", href: "#" },
11551
+ { label: "Equador", href: "#" },
11552
+ { label: "Col\xF4mbia", href: "#" },
11553
+ { label: "Costa Rica", href: "#" },
11554
+ { label: "Filipinas", href: "#" }
11555
+ ];
11556
+ var DEFAULT_FOOTER_PAGES = [
11557
+ { label: "Contato", href: "#" },
11558
+ { label: "Pol\xEDtica de cookies", href: "#" },
11559
+ { label: "FAQ", href: "#" },
11560
+ { label: "Sobre n\xF3s", href: "#" }
11561
+ ];
11562
+ var DEFAULT_FOOTER_LEGAL = [
11563
+ { label: "Termos e condi\xE7\xF5es", href: "#" },
11564
+ { label: "Mapa do site", href: "#" }
11565
+ ];
11566
+ var DEFAULT_FOOTER_LANGUAGES = [
11567
+ { code: "PT", label: "Portugu\xEAs" },
11568
+ { code: "EN", label: "English" },
11569
+ { code: "NL", label: "Nederlands" },
11570
+ { code: "DE", label: "Deutsch" },
11571
+ { code: "FR", label: "Fran\xE7ais" },
11572
+ { code: "ES", label: "Espa\xF1ol" }
11573
+ ];
11574
+ var DEFAULT_FOOTER_SOCIALS = [
11575
+ { network: "facebook", href: "#" },
11576
+ { network: "instagram", href: "#" },
11577
+ { network: "linkedin", href: "#" }
11578
+ ];
11579
+ var DEFAULT_FOOTER_BADGES = [
11580
+ {
11581
+ src: "https://static.planetaexo.com/trips/wp-content/uploads/2025/04/member_of_TLR-white-1.png",
11582
+ alt: "Member of The Long Run",
11583
+ height: 80
11584
+ },
11585
+ {
11586
+ src: "https://static.planetaexo.com/trips/wp-content/uploads/2025/04/atta-member_white.png",
11587
+ alt: "Member \xB7 Adventure Travel Trade Association",
11588
+ height: 56
11589
+ }
11590
+ ];
11591
+ var SOCIAL_ICON = {
11592
+ facebook: FacebookIcon,
11593
+ instagram: InstagramIcon,
11594
+ linkedin: LinkedinIcon,
11595
+ youtube: YoutubeIcon,
11596
+ twitter: TwitterIcon
11597
+ };
11598
+ var SOCIAL_LABEL = {
11599
+ facebook: "Facebook",
11600
+ instagram: "Instagram",
11601
+ linkedin: "LinkedIn",
11602
+ youtube: "YouTube",
11603
+ twitter: "Twitter"
11604
+ };
11605
+ function ColumnHeading({
11606
+ children,
11607
+ className
11608
+ }) {
11609
+ return /* @__PURE__ */ jsx(
11610
+ "h3",
11611
+ {
11612
+ className: cn(
11613
+ "font-heading font-black text-base mb-5 tracking-tight",
11614
+ className
11615
+ ),
11616
+ children
11617
+ }
11618
+ );
11619
+ }
11620
+ function LanguagePicker({
11621
+ variant,
11622
+ languages,
11623
+ currentLanguage,
11624
+ onChange
11625
+ }) {
11626
+ var _a;
11627
+ const t = VARIANT2[variant];
11628
+ const [open, setOpen] = React28.useState(false);
11629
+ const ref = React28.useRef(null);
11630
+ const active = (_a = languages.find((l) => l.code === currentLanguage)) != null ? _a : languages[0];
11631
+ React28.useEffect(() => {
11632
+ if (!open) return;
11633
+ const onDocClick = (e) => {
11634
+ if (ref.current && !ref.current.contains(e.target)) {
11635
+ setOpen(false);
11636
+ }
11637
+ };
11638
+ document.addEventListener("mousedown", onDocClick);
11639
+ return () => document.removeEventListener("mousedown", onDocClick);
11640
+ }, [open]);
11641
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative inline-block", children: [
11642
+ /* @__PURE__ */ jsxs(
11643
+ "button",
11644
+ {
11645
+ type: "button",
11646
+ onClick: () => setOpen((v) => !v),
11647
+ "aria-haspopup": "listbox",
11648
+ "aria-expanded": open,
11649
+ className: cn(
11650
+ "inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-ui transition-colors",
11651
+ t.langTrigger,
11652
+ open && t.langOpen
11653
+ ),
11654
+ children: [
11655
+ active == null ? void 0 : active.code,
11656
+ /* @__PURE__ */ jsx(
11657
+ ChevronDownIcon,
11658
+ {
11659
+ className: cn(
11660
+ "h-3 w-3 transition-transform duration-150",
11661
+ t.langChevron,
11662
+ open && "rotate-180"
11663
+ )
11664
+ }
11665
+ )
11666
+ ]
11667
+ }
11668
+ ),
11669
+ open && /* @__PURE__ */ jsx(
11670
+ "div",
11671
+ {
11672
+ role: "listbox",
11673
+ className: "absolute left-0 bottom-[calc(100%+8px)] min-w-[180px] rounded-xl bg-white shadow-2xl border border-black/8 py-1.5 z-10",
11674
+ children: languages.map((lang) => {
11675
+ const isActive = lang.code === (active == null ? void 0 : active.code);
11676
+ return /* @__PURE__ */ jsxs(
11677
+ "button",
11678
+ {
11679
+ type: "button",
11680
+ role: "option",
11681
+ "aria-selected": isActive,
11682
+ onClick: () => {
11683
+ onChange == null ? void 0 : onChange(lang.code);
11684
+ setOpen(false);
11685
+ },
11686
+ className: cn(
11687
+ "flex items-center gap-3 w-full px-5 py-2.5 text-sm font-ui text-left transition-colors hover:bg-muted",
11688
+ isActive ? "text-primary font-semibold" : "text-foreground"
11689
+ ),
11690
+ children: [
11691
+ /* @__PURE__ */ jsx("span", { className: "font-semibold w-8 shrink-0", children: lang.code }),
11692
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: lang.label })
11693
+ ]
11694
+ },
11695
+ lang.code
11696
+ );
11697
+ })
11698
+ }
11699
+ )
11700
+ ] });
11701
+ }
11702
+ function SiteFooter({
11703
+ variant = "dark",
11704
+ brandTitle = "PlanetaEXO",
11705
+ logoSrcLight = "/logo-planetaexo-white.png",
11706
+ logoSrcDark = "/logo-planetaexo-green.png",
11707
+ logoSrc,
11708
+ logoAlt = "PlanetaEXO",
11709
+ logoHref = "#",
11710
+ brandDescription = /* @__PURE__ */ jsxs(Fragment, { children: [
11711
+ "A PlanetaEXO \xE9 uma ag\xEAncia brasileira especializada em viagens de ecoturismo e aventura. Operamos com guias locais credenciados e parceiros que respeitam comunidades e ecossistemas.",
11712
+ " ",
11713
+ /* @__PURE__ */ jsx(
11714
+ "a",
11715
+ {
11716
+ href: "#",
11717
+ className: "font-bold underline decoration-current/30 underline-offset-4 hover:decoration-current",
11718
+ children: "Pol\xEDtica de privacidade"
11719
+ }
11720
+ )
11721
+ ] }),
11722
+ badges = DEFAULT_FOOTER_BADGES,
11723
+ languages = DEFAULT_FOOTER_LANGUAGES,
11724
+ currentLanguage = "PT",
11725
+ onLanguageChange,
11726
+ address = {
11727
+ title: "Basecamp S\xE3o Paulo",
11728
+ lines: ["Av. Paulista, 1234", "01310-100 S\xE3o Paulo \xB7 Brasil"]
11729
+ },
11730
+ phone = "+55 11 9999-0000",
11731
+ email = "ola@planetaexo.com",
11732
+ socials = DEFAULT_FOOTER_SOCIALS,
11733
+ themesTitle = "Temas",
11734
+ themes = DEFAULT_FOOTER_THEMES,
11735
+ destinationsTitle = "Destinos",
11736
+ destinations = DEFAULT_FOOTER_DESTINATIONS,
11737
+ destinationsMore = { label: "Ver todos os destinos", href: "#" },
11738
+ pagesTitle = "P\xE1ginas",
11739
+ pages = DEFAULT_FOOTER_PAGES,
11740
+ cta = {
11741
+ title: "Colaborar?",
11742
+ label: "parceiros@planetaexo.com",
11743
+ href: "mailto:parceiros@planetaexo.com"
11744
+ },
11745
+ copyright,
11746
+ legalLinks = DEFAULT_FOOTER_LEGAL,
11747
+ className
11748
+ }) {
11749
+ const t = VARIANT2[variant];
11750
+ const resolvedLogo = logoSrc != null ? logoSrc : variant === "light" ? logoSrcDark : logoSrcLight;
11751
+ const year = (/* @__PURE__ */ new Date()).getFullYear();
11752
+ const copy = copyright != null ? copyright : `\xA9 ${year} ${brandTitle}. Todos os direitos reservados.`;
11753
+ return /* @__PURE__ */ jsxs("footer", { className: cn(t.footer, className), children: [
11754
+ /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto px-6 sm:px-10 pt-16 pb-10", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-x-8 gap-y-12", children: [
11755
+ /* @__PURE__ */ jsxs("div", { className: "lg:col-span-4 space-y-6", children: [
11756
+ /* @__PURE__ */ jsx(
11757
+ "a",
11758
+ {
11759
+ href: logoHref,
11760
+ className: "inline-flex items-center",
11761
+ "aria-label": logoAlt,
11762
+ children: /* @__PURE__ */ jsx(
11763
+ "img",
11764
+ {
11765
+ src: resolvedLogo,
11766
+ alt: logoAlt,
11767
+ className: "h-16 w-auto select-none",
11768
+ draggable: false
11769
+ }
11770
+ )
11771
+ }
11772
+ ),
11773
+ brandDescription && /* @__PURE__ */ jsx("p", { className: cn("font-sans text-sm leading-relaxed", t.body), children: brandDescription }),
11774
+ address && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11775
+ /* @__PURE__ */ jsx("h4", { className: cn("font-heading font-black text-base", t.heading), children: address.title }),
11776
+ /* @__PURE__ */ jsx("address", { className: cn("not-italic text-sm leading-relaxed font-sans", t.body), children: address.lines.map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i)) })
11777
+ ] }),
11778
+ (phone || email) && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 text-sm font-ui font-bold", children: [
11779
+ phone && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("a", { href: `tel:${phone.replace(/\s+/g, "")}`, className: t.link, children: phone }) }),
11780
+ email && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("a", { href: `mailto:${email}`, className: t.link, children: email }) })
11781
+ ] }),
11782
+ socials.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: socials.map((s) => {
11783
+ var _a;
11784
+ const Icon = SOCIAL_ICON[s.network];
11785
+ const label = (_a = s.label) != null ? _a : SOCIAL_LABEL[s.network];
11786
+ return /* @__PURE__ */ jsx(
11787
+ "a",
11788
+ {
11789
+ href: s.href,
11790
+ "aria-label": label,
11791
+ className: cn(
11792
+ "flex h-9 w-9 items-center justify-center rounded-full transition-colors",
11793
+ t.socialBtn
11794
+ ),
11795
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 2.25 })
11796
+ },
11797
+ s.network + s.href
11798
+ );
11799
+ }) }),
11800
+ badges && badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-5 pt-2", children: badges.map((b, i) => {
11801
+ var _a, _b;
11802
+ const content = (_b = b.node) != null ? _b : /* @__PURE__ */ jsx(
11803
+ "img",
11804
+ {
11805
+ src: b.src,
11806
+ alt: b.alt,
11807
+ style: { height: (_a = b.height) != null ? _a : 56 },
11808
+ className: "block w-auto object-contain",
11809
+ draggable: false
11810
+ }
11811
+ );
11812
+ const wrapper = /* @__PURE__ */ jsx(
11813
+ "span",
11814
+ {
11815
+ className: cn(
11816
+ "inline-flex items-center",
11817
+ t.badgeStroke,
11818
+ t.badgeFilter
11819
+ ),
11820
+ children: content
11821
+ }
11822
+ );
11823
+ return b.href ? /* @__PURE__ */ jsx(
11824
+ "a",
11825
+ {
11826
+ href: b.href,
11827
+ "aria-label": b.alt,
11828
+ className: "hover:opacity-80 transition-opacity",
11829
+ children: wrapper
11830
+ },
11831
+ b.alt + i
11832
+ ) : /* @__PURE__ */ jsx(React28.Fragment, { children: wrapper }, b.alt + i);
11833
+ }) })
11834
+ ] }),
11835
+ themes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-3", children: [
11836
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: themesTitle }),
11837
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: themes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11838
+ "a",
11839
+ {
11840
+ href: c.href,
11841
+ className: cn("text-sm font-ui font-bold", t.link),
11842
+ children: c.label
11843
+ }
11844
+ ) }, c.label)) })
11845
+ ] }),
11846
+ destinations.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-3", children: [
11847
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: destinationsTitle }),
11848
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: destinations.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11849
+ "a",
11850
+ {
11851
+ href: c.href,
11852
+ className: cn("text-sm font-ui font-bold", t.link),
11853
+ children: c.label
11854
+ }
11855
+ ) }, c.label)) }),
11856
+ destinationsMore && /* @__PURE__ */ jsxs(
11857
+ "a",
11858
+ {
11859
+ href: destinationsMore.href,
11860
+ className: cn(
11861
+ "inline-flex items-center gap-1.5 mt-5 text-sm font-ui font-bold",
11862
+ t.link
11863
+ ),
11864
+ children: [
11865
+ destinationsMore.label,
11866
+ /* @__PURE__ */ jsx(ArrowRightIcon, { className: "h-3.5 w-3.5 no-underline" })
11867
+ ]
11868
+ }
11869
+ )
11870
+ ] }),
11871
+ /* @__PURE__ */ jsxs("div", { className: "lg:col-span-2 space-y-8", children: [
11872
+ pages.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
11873
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: pagesTitle }),
11874
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: pages.map((p) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11875
+ "a",
11876
+ {
11877
+ href: p.href,
11878
+ className: cn("text-sm font-ui font-bold", t.link),
11879
+ children: p.label
11880
+ }
11881
+ ) }, p.label)) })
11882
+ ] }),
11883
+ cta && /* @__PURE__ */ jsxs("div", { children: [
11884
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: cta.title }),
11885
+ /* @__PURE__ */ jsx(
11886
+ "a",
11887
+ {
11888
+ href: cta.href,
11889
+ className: cn("text-sm font-ui font-bold break-all", t.link),
11890
+ children: cta.label
11891
+ }
11892
+ )
11893
+ ] })
11894
+ ] })
11895
+ ] }) }),
11896
+ /* @__PURE__ */ jsx("div", { className: cn(t.bottomBar), children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto px-6 sm:px-10 py-4 flex flex-wrap items-center gap-x-6 gap-y-3", children: [
11897
+ languages.length > 0 && /* @__PURE__ */ jsx(
11898
+ LanguagePicker,
11899
+ {
11900
+ variant,
11901
+ languages,
11902
+ currentLanguage,
11903
+ onChange: onLanguageChange
11904
+ }
11905
+ ),
11906
+ /* @__PURE__ */ jsx("p", { className: cn("text-xs font-ui", t.bottomText), children: copy }),
11907
+ legalLinks.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap items-center gap-x-6 gap-y-2", children: legalLinks.map((l) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11908
+ "a",
11909
+ {
11910
+ href: l.href,
11911
+ className: cn("text-xs font-ui font-bold", t.bottomLink),
11912
+ children: l.label
11913
+ }
11914
+ ) }, l.label)) })
11915
+ ] }) })
11916
+ ] });
11917
+ }
10702
11918
  function Stars({ count = 5 }) {
10703
11919
  return /* @__PURE__ */ jsx("span", { className: "flex gap-0.5", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(
10704
11920
  StarIcon,
@@ -10742,9 +11958,9 @@ function TripPage({
10742
11958
  images,
10743
11959
  videoUrl,
10744
11960
  breadcrumb,
11961
+ chips,
10745
11962
  highlights,
10746
- infoGroups,
10747
- keyInfo,
11963
+ howToGetThere,
10748
11964
  recommendedFor,
10749
11965
  overview,
10750
11966
  overviewHighlights,
@@ -10762,6 +11978,7 @@ function TripPage({
10762
11978
  meetingPoints,
10763
11979
  meetingPoint,
10764
11980
  faqs,
11981
+ faqInitialCount = 5,
10765
11982
  sectionIcons,
10766
11983
  reviews,
10767
11984
  trustpilot,
@@ -10781,11 +11998,12 @@ function TripPage({
10781
11998
  features,
10782
11999
  className
10783
12000
  }) {
10784
- const [activeSection, setActiveSection] = React8.useState("");
10785
- const [accordionValue, setAccordionValue] = React8.useState([]);
10786
- const accordionSectionIds = React8.useMemo(
12001
+ const [activeSection, setActiveSection] = React28.useState("");
12002
+ const [accordionValue, setAccordionValue] = React28.useState([]);
12003
+ const [faqsExpanded, setFaqsExpanded] = React28.useState(false);
12004
+ const accordionSectionIds = React28.useMemo(
10787
12005
  () => /* @__PURE__ */ new Set([
10788
- "key-info",
12006
+ "how-to-get-there",
10789
12007
  "what-to-bring",
10790
12008
  "weather",
10791
12009
  "optional-extras",
@@ -10796,18 +12014,18 @@ function TripPage({
10796
12014
  ]),
10797
12015
  []
10798
12016
  );
10799
- const [navFloating, setNavFloating] = React8.useState(false);
10800
- const [navHidden, setNavHidden] = React8.useState(false);
10801
- const [isFloating, setIsFloating] = React8.useState(false);
10802
- const [sidebarPos, setSidebarPos] = React8.useState(null);
10803
- const [pricingBarVisible, setPricingBarVisible] = React8.useState(false);
10804
- const navRef = React8.useRef(null);
10805
- const navSentinelRef = React8.useRef(null);
10806
- const sentinelRef = React8.useRef(null);
10807
- const sidebarPlaceholderRef = React8.useRef(null);
10808
- const pricingBarRef = React8.useRef(null);
10809
- const galleryRef = React8.useRef(null);
10810
- const sections = React8.useMemo(
12017
+ const [navFloating, setNavFloating] = React28.useState(false);
12018
+ const [navHidden, setNavHidden] = React28.useState(false);
12019
+ const [isFloating, setIsFloating] = React28.useState(false);
12020
+ const [sidebarPos, setSidebarPos] = React28.useState(null);
12021
+ const [pricingBarVisible, setPricingBarVisible] = React28.useState(false);
12022
+ const navRef = React28.useRef(null);
12023
+ const navSentinelRef = React28.useRef(null);
12024
+ const sentinelRef = React28.useRef(null);
12025
+ const sidebarPlaceholderRef = React28.useRef(null);
12026
+ const pricingBarRef = React28.useRef(null);
12027
+ const galleryRef = React28.useRef(null);
12028
+ const sections = React28.useMemo(
10811
12029
  () => [
10812
12030
  { id: "overview", label: "Overview", show: !!(overview || (overviewHighlights == null ? void 0 : overviewHighlights.length)) },
10813
12031
  {
@@ -10825,7 +12043,7 @@ function TripPage({
10825
12043
  // eslint-disable-next-line react-hooks/exhaustive-deps
10826
12044
  []
10827
12045
  );
10828
- React8.useEffect(() => {
12046
+ React28.useEffect(() => {
10829
12047
  const sentinel = navSentinelRef.current;
10830
12048
  if (!sentinel) return;
10831
12049
  const update = () => setNavFloating(sentinel.getBoundingClientRect().top < 1);
@@ -10833,7 +12051,7 @@ function TripPage({
10833
12051
  update();
10834
12052
  return () => document.removeEventListener("scroll", update, { capture: true });
10835
12053
  }, []);
10836
- React8.useEffect(() => {
12054
+ React28.useEffect(() => {
10837
12055
  const sentinel = sentinelRef.current;
10838
12056
  if (!sentinel) return;
10839
12057
  const update = () => setIsFloating(sentinel.getBoundingClientRect().top < 1);
@@ -10841,7 +12059,7 @@ function TripPage({
10841
12059
  update();
10842
12060
  return () => document.removeEventListener("scroll", update, { capture: true });
10843
12061
  }, []);
10844
- React8.useEffect(() => {
12062
+ React28.useEffect(() => {
10845
12063
  const measure = () => {
10846
12064
  if (!sidebarPlaceholderRef.current) return;
10847
12065
  const rect = sidebarPlaceholderRef.current.getBoundingClientRect();
@@ -10851,7 +12069,7 @@ function TripPage({
10851
12069
  window.addEventListener("resize", measure);
10852
12070
  return () => window.removeEventListener("resize", measure);
10853
12071
  }, [isFloating]);
10854
- React8.useEffect(() => {
12072
+ React28.useEffect(() => {
10855
12073
  const check = () => {
10856
12074
  var _a;
10857
12075
  const target = (_a = galleryRef.current) != null ? _a : pricingBarRef.current;
@@ -10862,7 +12080,7 @@ function TripPage({
10862
12080
  check();
10863
12081
  return () => document.removeEventListener("scroll", check, { capture: true });
10864
12082
  }, []);
10865
- React8.useEffect(() => {
12083
+ React28.useEffect(() => {
10866
12084
  const check = () => {
10867
12085
  if (!pricingBarRef.current) return;
10868
12086
  setNavHidden(pricingBarRef.current.getBoundingClientRect().top < window.innerHeight * 0.92);
@@ -10871,7 +12089,7 @@ function TripPage({
10871
12089
  check();
10872
12090
  return () => document.removeEventListener("scroll", check, { capture: true });
10873
12091
  }, []);
10874
- React8.useEffect(() => {
12092
+ React28.useEffect(() => {
10875
12093
  if (sections.length === 0) return;
10876
12094
  setActiveSection(sections[0].id);
10877
12095
  const update = () => {
@@ -10946,6 +12164,7 @@ function TripPage({
10946
12164
  destination,
10947
12165
  duration,
10948
12166
  tagline,
12167
+ chips,
10949
12168
  siteHeader,
10950
12169
  uiVariant,
10951
12170
  belowMeta: trustpilotHero ? /* @__PURE__ */ jsx(TrustpilotEmbed, { config: trustpilotHero }) : void 0
@@ -10979,10 +12198,7 @@ function TripPage({
10979
12198
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row gap-8 mt-4", children: [
10980
12199
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 space-y-12 pb-12", children: [
10981
12200
  (overview || (overviewHighlights == null ? void 0 : overviewHighlights.length)) && /* @__PURE__ */ jsxs("section", { id: "trip-section-overview", className: "scroll-mt-20", children: [
10982
- /* @__PURE__ */ jsxs("h2", { className: "text-xl font-bold text-foreground font-heading mb-4 flex items-center gap-2", children: [
10983
- (sectionIcons == null ? void 0 : sectionIcons.overview) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.overview }) : /* @__PURE__ */ jsx(InfoIcon, { className: "h-5 w-5 text-primary" }),
10984
- "Overview"
10985
- ] }),
12201
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-4", children: "Overview" }),
10986
12202
  overview && /* @__PURE__ */ jsx("div", { className: "text-lg text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: overview }),
10987
12203
  overviewHighlights && overviewHighlights.length > 0 && /* @__PURE__ */ jsx("ul", { className: cn("flex flex-col gap-5", overview && "mt-8"), children: overviewHighlights.map((h, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-4", children: [
10988
12204
  h.icon && /* @__PURE__ */ jsx("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center text-foreground [&_svg]:h-8 [&_svg]:w-8", children: h.icon }),
@@ -11029,7 +12245,7 @@ function TripPage({
11029
12245
  }
11030
12246
  )
11031
12247
  ] }),
11032
- ((infoGroups == null ? void 0 : infoGroups.length) || keyInfo || (whatToBring == null ? void 0 : whatToBring.length) || weather || optionalExtras || accommodation || food || (meetingPoints == null ? void 0 : meetingPoints.length) || meetingPoint || termsAndConditions) && /* @__PURE__ */ jsxs(
12248
+ (howToGetThere || (whatToBring == null ? void 0 : whatToBring.length) || weather || optionalExtras || accommodation || food || (meetingPoints == null ? void 0 : meetingPoints.length) || meetingPoint || termsAndConditions) && /* @__PURE__ */ jsxs(
11033
12249
  Accordion,
11034
12250
  {
11035
12251
  multiple: false,
@@ -11037,25 +12253,33 @@ function TripPage({
11037
12253
  onValueChange: setAccordionValue,
11038
12254
  className: "border-t border-border",
11039
12255
  children: [
11040
- (keyInfo || infoGroups && infoGroups.length > 0) && /* @__PURE__ */ jsxs(
12256
+ accommodation && /* @__PURE__ */ jsxs(
12257
+ AccordionItem,
12258
+ {
12259
+ value: "accommodation",
12260
+ id: "trip-section-accommodation",
12261
+ className: "scroll-mt-20 border-b border-border",
12262
+ children: [
12263
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
12264
+ (sectionIcons == null ? void 0 : sectionIcons.accommodation) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.accommodation }) : /* @__PURE__ */ jsx(BedDoubleIcon, { className: "h-5 w-5 text-primary" }),
12265
+ "Accommodation"
12266
+ ] }) }),
12267
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: accommodation }) })
12268
+ ]
12269
+ }
12270
+ ),
12271
+ food && /* @__PURE__ */ jsxs(
11041
12272
  AccordionItem,
11042
12273
  {
11043
- value: "key-info",
11044
- id: "trip-section-key-info",
12274
+ value: "food",
12275
+ id: "trip-section-food",
11045
12276
  className: "scroll-mt-20 border-b border-border",
11046
12277
  children: [
11047
12278
  /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11048
- (sectionIcons == null ? void 0 : sectionIcons.keyInfo) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.keyInfo }) : /* @__PURE__ */ jsx(InfoIcon, { className: "h-5 w-5 text-primary" }),
11049
- "Key info"
12279
+ (sectionIcons == null ? void 0 : sectionIcons.food) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.food }) : /* @__PURE__ */ jsx(UtensilsIcon, { className: "h-5 w-5 text-primary" }),
12280
+ "Food"
11050
12281
  ] }) }),
11051
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: keyInfo ? /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: keyInfo }) : /* @__PURE__ */ jsx("div", { className: "space-y-6", children: infoGroups.map((group, i) => /* @__PURE__ */ jsxs("div", { children: [
11052
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
11053
- group.icon && /* @__PURE__ */ jsx("span", { className: "text-primary", children: group.icon }),
11054
- /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-heading", children: group.title })
11055
- ] }),
11056
- /* @__PURE__ */ jsx(Checklist, { items: group.items }),
11057
- i < infoGroups.length - 1 && /* @__PURE__ */ jsx(Separator, { className: "mt-6" })
11058
- ] }, i)) }) })
12282
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: food }) })
11059
12283
  ]
11060
12284
  }
11061
12285
  ),
@@ -11081,78 +12305,63 @@ function TripPage({
11081
12305
  ]
11082
12306
  }
11083
12307
  ),
11084
- optionalExtras && /* @__PURE__ */ jsxs(
12308
+ howToGetThere && /* @__PURE__ */ jsxs(
11085
12309
  AccordionItem,
11086
12310
  {
11087
- value: "optional-extras",
11088
- id: "trip-section-optional-extras",
12311
+ value: "how-to-get-there",
12312
+ id: "trip-section-how-to-get-there",
11089
12313
  className: "scroll-mt-20 border-b border-border",
11090
12314
  children: [
11091
12315
  /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11092
- (sectionIcons == null ? void 0 : sectionIcons.optionalExtras) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.optionalExtras }) : /* @__PURE__ */ jsx(SparklesIcon, { className: "h-5 w-5 text-primary" }),
11093
- "Optional extras"
12316
+ (sectionIcons == null ? void 0 : sectionIcons.howToGetThere) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.howToGetThere }) : /* @__PURE__ */ jsx(CompassIcon, { className: "h-5 w-5 text-primary" }),
12317
+ "How to get there"
11094
12318
  ] }) }),
11095
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: optionalExtras }) })
12319
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: howToGetThere }) })
11096
12320
  ]
11097
12321
  }
11098
12322
  ),
11099
- whatToBring && whatToBring.length > 0 && /* @__PURE__ */ jsxs(
11100
- AccordionItem,
11101
- {
11102
- value: "what-to-bring",
11103
- id: "trip-section-what-to-bring",
11104
- className: "scroll-mt-20 border-b border-border",
11105
- children: [
11106
- /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11107
- (sectionIcons == null ? void 0 : sectionIcons.whatToBring) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.whatToBring }) : /* @__PURE__ */ jsx(BackpackIcon, { className: "h-5 w-5 text-primary" }),
11108
- "What to bring"
11109
- ] }) }),
11110
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx(Checklist, { items: whatToBring, icon: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4" }) }) })
11111
- ]
11112
- }
11113
- ),
11114
- accommodation && /* @__PURE__ */ jsxs(
12323
+ weather && /* @__PURE__ */ jsxs(
11115
12324
  AccordionItem,
11116
12325
  {
11117
- value: "accommodation",
11118
- id: "trip-section-accommodation",
12326
+ value: "weather",
12327
+ id: "trip-section-weather",
11119
12328
  className: "scroll-mt-20 border-b border-border",
11120
12329
  children: [
11121
12330
  /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11122
- (sectionIcons == null ? void 0 : sectionIcons.accommodation) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.accommodation }) : /* @__PURE__ */ jsx(BedDoubleIcon, { className: "h-5 w-5 text-primary" }),
11123
- "Accommodation"
12331
+ (sectionIcons == null ? void 0 : sectionIcons.weather) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.weather }) : /* @__PURE__ */ jsx(SunIcon, { className: "h-5 w-5 text-primary" }),
12332
+ "Weather"
11124
12333
  ] }) }),
11125
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: accommodation }) })
12334
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "flex items-start gap-3 rounded-xl bg-muted/60 border border-border p-5", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-2 [&_strong]:font-semibold", children: weather }) }) })
11126
12335
  ]
11127
12336
  }
11128
12337
  ),
11129
- food && /* @__PURE__ */ jsxs(
12338
+ whatToBring && whatToBring.length > 0 && /* @__PURE__ */ jsxs(
11130
12339
  AccordionItem,
11131
12340
  {
11132
- value: "food",
11133
- id: "trip-section-food",
12341
+ value: "what-to-bring",
12342
+ id: "trip-section-what-to-bring",
11134
12343
  className: "scroll-mt-20 border-b border-border",
11135
12344
  children: [
11136
12345
  /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11137
- (sectionIcons == null ? void 0 : sectionIcons.food) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.food }) : /* @__PURE__ */ jsx(UtensilsIcon, { className: "h-5 w-5 text-primary" }),
11138
- "Food"
12346
+ (sectionIcons == null ? void 0 : sectionIcons.whatToBring) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.whatToBring }) : /* @__PURE__ */ jsx(BackpackIcon, { className: "h-5 w-5 text-primary" }),
12347
+ "What to bring"
11139
12348
  ] }) }),
11140
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: food }) })
12349
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx(Checklist, { items: whatToBring, icon: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4" }) }) })
11141
12350
  ]
11142
12351
  }
11143
12352
  ),
11144
- weather && /* @__PURE__ */ jsxs(
12353
+ optionalExtras && /* @__PURE__ */ jsxs(
11145
12354
  AccordionItem,
11146
12355
  {
11147
- value: "weather",
11148
- id: "trip-section-weather",
12356
+ value: "optional-extras",
12357
+ id: "trip-section-optional-extras",
11149
12358
  className: "scroll-mt-20 border-b border-border",
11150
12359
  children: [
11151
12360
  /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-5 text-xl font-bold text-foreground font-heading hover:no-underline", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
11152
- (sectionIcons == null ? void 0 : sectionIcons.weather) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.weather }) : /* @__PURE__ */ jsx(SunIcon, { className: "h-5 w-5 text-primary" }),
11153
- "Weather"
12361
+ (sectionIcons == null ? void 0 : sectionIcons.optionalExtras) ? /* @__PURE__ */ jsx("span", { className: "text-primary [&>svg]:h-5 [&>svg]:w-5", children: sectionIcons.optionalExtras }) : /* @__PURE__ */ jsx(CherryIcon, { className: "h-5 w-5 text-primary" }),
12362
+ "Optional extras"
11154
12363
  ] }) }),
11155
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "flex items-start gap-3 rounded-xl bg-muted/60 border border-border p-5", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-2 [&_strong]:font-semibold", children: weather }) }) })
12364
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx("div", { className: "text-base text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: optionalExtras }) })
11156
12365
  ]
11157
12366
  }
11158
12367
  ),
@@ -11174,13 +12383,39 @@ function TripPage({
11174
12383
  ]
11175
12384
  }
11176
12385
  ),
11177
- faqs && faqs.length > 0 && /* @__PURE__ */ jsxs("section", { id: "trip-section-faq", className: "scroll-mt-20", children: [
11178
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-6", children: "FAQ" }),
11179
- /* @__PURE__ */ jsx(Accordion, { variant: "faq", children: faqs.map((faq, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `faq-${i}`, children: [
11180
- /* @__PURE__ */ jsx(AccordionTrigger, { children: faq.question }),
11181
- /* @__PURE__ */ jsx(AccordionContent, { children: faq.answer })
11182
- ] }, i)) })
11183
- ] }),
12386
+ faqs && faqs.length > 0 && (() => {
12387
+ const visibleFaqs = faqsExpanded ? faqs : faqs.slice(0, faqInitialCount);
12388
+ const hiddenCount = faqs.length - visibleFaqs.length;
12389
+ return /* @__PURE__ */ jsxs("section", { id: "trip-section-faq", className: "scroll-mt-20", children: [
12390
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-6", children: "FAQ" }),
12391
+ /* @__PURE__ */ jsx(Accordion, { variant: "faq", children: visibleFaqs.map((faq, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `faq-${i}`, children: [
12392
+ /* @__PURE__ */ jsx(AccordionTrigger, { children: faq.question }),
12393
+ /* @__PURE__ */ jsx(AccordionContent, { children: faq.answer })
12394
+ ] }, i)) }),
12395
+ faqs.length > faqInitialCount && /* @__PURE__ */ jsx("div", { className: "mt-5 flex justify-center", children: /* @__PURE__ */ jsx(
12396
+ "button",
12397
+ {
12398
+ type: "button",
12399
+ onClick: () => setFaqsExpanded((v) => !v),
12400
+ className: cn(
12401
+ "inline-flex items-center gap-2 rounded-full border border-border bg-background px-5 py-2.5",
12402
+ "text-sm font-semibold text-foreground shadow-sm",
12403
+ "hover:bg-muted transition-colors duration-150",
12404
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
12405
+ ),
12406
+ children: faqsExpanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
12407
+ /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4 text-muted-foreground" }),
12408
+ "Show less"
12409
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
12410
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" }),
12411
+ "See more (",
12412
+ hiddenCount,
12413
+ ")"
12414
+ ] })
12415
+ }
12416
+ ) })
12417
+ ] });
12418
+ })(),
11184
12419
  trustpilot ? /* @__PURE__ */ jsxs("section", { id: "trip-section-reviews", className: "scroll-mt-20", children: [
11185
12420
  /* @__PURE__ */ jsx(Separator, { className: "mb-10" }),
11186
12421
  /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-5", children: "What our guests think" }),
@@ -11269,8 +12504,8 @@ function TripPage({
11269
12504
  PhotoGallery,
11270
12505
  {
11271
12506
  photos: gallery,
11272
- variant: "grid",
11273
- initialVisible: 6
12507
+ variant: "gridCompact",
12508
+ initialVisible: 8
11274
12509
  }
11275
12510
  ) }),
11276
12511
  gallery && gallery.length > 0 && /* @__PURE__ */ jsx("div", { ref: pricingBarRef, className: "mx-auto w-full max-w-6xl px-6 sm:px-8 py-12", children: /* @__PURE__ */ jsx("div", { id: "trip-booking-form", className: "rounded-2xl border border-border bg-card p-8 shadow-sm", children: /* @__PURE__ */ jsx(BookingForm, { onSubmit: onBook ? (values) => onBook() : void 0 }) }) }),
@@ -11287,7 +12522,8 @@ function TripPage({
11287
12522
  currencyEstimates
11288
12523
  }
11289
12524
  ) }),
11290
- /* @__PURE__ */ jsx("div", { className: "h-20 lg:hidden" })
12525
+ /* @__PURE__ */ jsx("div", { className: "h-20 lg:hidden" }),
12526
+ /* @__PURE__ */ jsx(SiteFooter, {})
11291
12527
  ]
11292
12528
  }
11293
12529
  );
@@ -11393,12 +12629,12 @@ function Toast({
11393
12629
  duration = 6e3,
11394
12630
  className
11395
12631
  }) {
11396
- const [mounted, setMounted] = React8.useState(false);
11397
- const [visible, setVisible] = React8.useState(true);
11398
- React8.useEffect(() => {
12632
+ const [mounted, setMounted] = React28.useState(false);
12633
+ const [visible, setVisible] = React28.useState(true);
12634
+ React28.useEffect(() => {
11399
12635
  setMounted(true);
11400
12636
  }, []);
11401
- React8.useEffect(() => {
12637
+ React28.useEffect(() => {
11402
12638
  if (duration === 0) return;
11403
12639
  const t = setTimeout(() => {
11404
12640
  setVisible(false);