@planetaexo/design-system 0.37.2 → 0.37.4

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));
@@ -2258,13 +2262,16 @@ function Offer({
2258
2262
  labels,
2259
2263
  confirmedState,
2260
2264
  interactionsDisabled,
2265
+ internalDemoCheckout = false,
2261
2266
  className
2262
2267
  }) {
2263
2268
  var _a, _b, _c;
2264
- const [showBooking, setShowBooking] = React8.useState(false);
2265
- const isShowingCheckout = !confirmedState && (!!checkoutSlot || showBooking);
2269
+ const [showBooking, setShowBooking] = React28.useState(false);
2270
+ const isShowingCheckout = !confirmedState && (!!checkoutSlot || internalDemoCheckout && showBooking);
2266
2271
  const handleBook = () => {
2267
- if (!checkoutSlot && !externalBookingFlow) setShowBooking(true);
2272
+ if (!checkoutSlot && !externalBookingFlow && internalDemoCheckout) {
2273
+ setShowBooking(true);
2274
+ }
2268
2275
  onContinue == null ? void 0 : onContinue();
2269
2276
  };
2270
2277
  return /* @__PURE__ */ jsxs("div", { className: cn("w-full max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col gap-6 pb-20 lg:pb-12", className), children: [
@@ -2309,7 +2316,7 @@ function Offer({
2309
2316
  labels
2310
2317
  }
2311
2318
  ),
2312
- isShowingCheckout && (checkoutSlot != null ? checkoutSlot : /* @__PURE__ */ jsx(
2319
+ isShowingCheckout && (checkoutSlot != null ? checkoutSlot : internalDemoCheckout ? /* @__PURE__ */ jsx(
2313
2320
  BookingWizard,
2314
2321
  {
2315
2322
  adventures,
@@ -2318,7 +2325,7 @@ function Offer({
2318
2325
  onCancel: () => setShowBooking(false),
2319
2326
  labels
2320
2327
  }
2321
- ))
2328
+ ) : null)
2322
2329
  ] }) }),
2323
2330
  /* @__PURE__ */ jsx("div", { className: "lg:sticky lg:top-8", children: /* @__PURE__ */ jsx(
2324
2331
  OfferSidebar,
@@ -2626,7 +2633,7 @@ function AdventureSection({
2626
2633
  labels
2627
2634
  }) {
2628
2635
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
2629
- const [detailsOpen, setDetailsOpen] = React8.useState(false);
2636
+ const [detailsOpen, setDetailsOpen] = React28.useState(false);
2630
2637
  const handleCopyUrl = (url) => {
2631
2638
  if (onCopyFormLink) {
2632
2639
  onCopyFormLink(url);
@@ -3138,8 +3145,8 @@ function AddTravellerDialog({
3138
3145
  errorMessage
3139
3146
  }) {
3140
3147
  var _a, _b, _c, _d, _e;
3141
- const [form, setForm] = React8.useState(() => createInitialAddFormData(config));
3142
- React8.useEffect(() => {
3148
+ const [form, setForm] = React28.useState(() => createInitialAddFormData(config));
3149
+ React28.useEffect(() => {
3143
3150
  if (open) {
3144
3151
  setForm(createInitialAddFormData(config));
3145
3152
  }
@@ -3199,7 +3206,7 @@ function EditTravellerDialog({
3199
3206
  errorMessage
3200
3207
  }) {
3201
3208
  var _a, _b, _c, _d, _e;
3202
- const [form, setForm] = React8.useState(() => ({
3209
+ const [form, setForm] = React28.useState(() => ({
3203
3210
  firstName: "",
3204
3211
  lastName: "",
3205
3212
  email: "",
@@ -3208,7 +3215,7 @@ function EditTravellerDialog({
3208
3215
  birthDate: "",
3209
3216
  personType: "ADULT"
3210
3217
  }));
3211
- React8.useEffect(() => {
3218
+ React28.useEffect(() => {
3212
3219
  var _a2, _b2, _c2, _d2, _e2, _f;
3213
3220
  if (open && traveller) {
3214
3221
  setForm({
@@ -3543,48 +3550,48 @@ function BookingDetails({
3543
3550
  const hasSubmitAddTraveller = !!onSubmitAddTraveller;
3544
3551
  const hasSubmitEditTraveller = !!onSubmitEditTraveller;
3545
3552
  const hasConfirmRemoveTraveller = !!onConfirmRemoveTraveller;
3546
- const [addModalState, setAddModalState] = React8.useState({
3553
+ const [addModalState, setAddModalState] = React28.useState({
3547
3554
  open: false,
3548
3555
  adventureId: null
3549
3556
  });
3550
- const [editModalState, setEditModalState] = React8.useState({ open: false, adventureId: null, traveller: null });
3551
- const [deleteModalState, setDeleteModalState] = React8.useState({ open: false, adventureId: null, traveller: null });
3552
- const [resendInviteDialogState, setResendInviteDialogState] = React8.useState({ open: false, traveller: null });
3553
- 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) => {
3554
3561
  setAddModalState({ open: true, adventureId });
3555
3562
  }, []);
3556
- const handleRequestOpenEditModal = React8.useCallback(
3563
+ const handleRequestOpenEditModal = React28.useCallback(
3557
3564
  (adventureId, traveller) => {
3558
3565
  setEditModalState({ open: true, adventureId, traveller });
3559
3566
  },
3560
3567
  []
3561
3568
  );
3562
- const handleRequestOpenDeleteModal = React8.useCallback(
3569
+ const handleRequestOpenDeleteModal = React28.useCallback(
3563
3570
  (adventureId, traveller) => {
3564
3571
  setDeleteModalState({ open: true, adventureId, traveller });
3565
3572
  },
3566
3573
  []
3567
3574
  );
3568
- const handleRequestOpenResendInviteDialog = React8.useCallback(
3575
+ const handleRequestOpenResendInviteDialog = React28.useCallback(
3569
3576
  (traveller) => {
3570
3577
  setResendInviteDialogState({ open: true, traveller });
3571
3578
  },
3572
3579
  []
3573
3580
  );
3574
- const closeAddModal = React8.useCallback(() => {
3581
+ const closeAddModal = React28.useCallback(() => {
3575
3582
  setAddModalState({ open: false, adventureId: null });
3576
3583
  }, []);
3577
- const closeEditModal = React8.useCallback(() => {
3584
+ const closeEditModal = React28.useCallback(() => {
3578
3585
  setEditModalState({ open: false, adventureId: null, traveller: null });
3579
3586
  }, []);
3580
- const closeDeleteModal = React8.useCallback(() => {
3587
+ const closeDeleteModal = React28.useCallback(() => {
3581
3588
  setDeleteModalState({ open: false, adventureId: null, traveller: null });
3582
3589
  }, []);
3583
- const closeResendInviteDialog = React8.useCallback(() => {
3590
+ const closeResendInviteDialog = React28.useCallback(() => {
3584
3591
  setResendInviteDialogState({ open: false, traveller: null });
3585
3592
  }, []);
3586
- const submitInFlightRef = React8.useRef(false);
3587
- const handleAddSubmit = React8.useCallback(
3593
+ const submitInFlightRef = React28.useRef(false);
3594
+ const handleAddSubmit = React28.useCallback(
3588
3595
  async (adventureId, data) => {
3589
3596
  if (!onSubmitAddTraveller) return;
3590
3597
  if (submitInFlightRef.current) return;
@@ -3599,7 +3606,7 @@ function BookingDetails({
3599
3606
  },
3600
3607
  [onSubmitAddTraveller, closeAddModal]
3601
3608
  );
3602
- const handleEditSubmit = React8.useCallback(
3609
+ const handleEditSubmit = React28.useCallback(
3603
3610
  async (adventureId, travellerId, data) => {
3604
3611
  if (!onSubmitEditTraveller) return;
3605
3612
  if (submitInFlightRef.current) return;
@@ -3614,7 +3621,7 @@ function BookingDetails({
3614
3621
  },
3615
3622
  [onSubmitEditTraveller, closeEditModal]
3616
3623
  );
3617
- const handleDeleteConfirm = React8.useCallback(
3624
+ const handleDeleteConfirm = React28.useCallback(
3618
3625
  async (adventureId, travellerId) => {
3619
3626
  if (!onConfirmRemoveTraveller) return;
3620
3627
  if (submitInFlightRef.current) return;
@@ -5088,7 +5095,7 @@ function BookingCreatedEmail({
5088
5095
  }, children: i + 1 }) }),
5089
5096
  /* @__PURE__ */ jsx("td", { style: { verticalAlign: "top" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "14px", color: emailTokens.bodyText, lineHeight: "1.6", margin: 0 }, children: step }) })
5090
5097
  ] }) }) }, i)) }),
5091
- 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: [
5098
+ 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: [
5092
5099
  idx === 0 ? /* @__PURE__ */ jsx("strong", { children: line }) : line,
5093
5100
  idx < arr.length - 1 ? /* @__PURE__ */ jsx("br", {}) : null
5094
5101
  ] }, idx)) })
@@ -6457,11 +6464,11 @@ function DatePickerField({
6457
6464
  fromDate,
6458
6465
  className
6459
6466
  }) {
6460
- const [open, setOpen] = React8.useState(false);
6461
- const containerRef = React8.useRef(null);
6462
- const [calendarWidth, setCalendarWidth] = React8.useState();
6467
+ const [open, setOpen] = React28.useState(false);
6468
+ const containerRef = React28.useRef(null);
6469
+ const [calendarWidth, setCalendarWidth] = React28.useState();
6463
6470
  const hasValue = !!value;
6464
- React8.useEffect(() => {
6471
+ React28.useEffect(() => {
6465
6472
  if (!containerRef.current) return;
6466
6473
  const observer = new ResizeObserver(([entry]) => {
6467
6474
  setCalendarWidth(entry.contentRect.width);
@@ -6570,7 +6577,7 @@ function BookingForm({
6570
6577
  subtitle = "Free enquiry \u2013 no commitment",
6571
6578
  className
6572
6579
  }) {
6573
- const [values, setValues] = React8.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
6580
+ const [values, setValues] = React28.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
6574
6581
  const set = (key, value) => setValues((prev) => __spreadProps(__spreadValues({}, prev), { [key]: value }));
6575
6582
  const handleSubmit = (e) => {
6576
6583
  e.preventDefault();
@@ -7107,11 +7114,11 @@ function FloatingTextarea({
7107
7114
  }
7108
7115
  function SelectField({ field, value, onChange, error, disabled }) {
7109
7116
  var _a, _b, _c;
7110
- const [open, setOpen] = React8.useState(false);
7111
- const containerRef = React8.useRef(null);
7117
+ const [open, setOpen] = React28.useState(false);
7118
+ const containerRef = React28.useRef(null);
7112
7119
  const options = (_a = field.options) != null ? _a : [];
7113
7120
  const selectedOpt = (_b = options.find((o) => o.value === value)) != null ? _b : null;
7114
- React8.useEffect(() => {
7121
+ React28.useEffect(() => {
7115
7122
  if (!open) return;
7116
7123
  const handleOutside = (e) => {
7117
7124
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -7500,11 +7507,11 @@ function RegistrationForm({
7500
7507
  readOnly = false
7501
7508
  }) {
7502
7509
  var _a;
7503
- const L = React8.useMemo(
7510
+ const L = React28.useMemo(
7504
7511
  () => __spreadValues(__spreadValues({}, DEFAULT_LABELS9), labels != null ? labels : {}),
7505
7512
  [labels]
7506
7513
  );
7507
- const sortedFields = React8.useMemo(
7514
+ const sortedFields = React28.useMemo(
7508
7515
  () => [...fields].sort((a, b) => {
7509
7516
  var _a2, _b;
7510
7517
  return ((_a2 = a.order) != null ? _a2 : 0) - ((_b = b.order) != null ? _b : 0);
@@ -7512,7 +7519,7 @@ function RegistrationForm({
7512
7519
  [fields]
7513
7520
  );
7514
7521
  const isControlled = values !== void 0;
7515
- const [internal, setInternal] = React8.useState(
7522
+ const [internal, setInternal] = React28.useState(
7516
7523
  () => initializeValues(
7517
7524
  sortedFields,
7518
7525
  defaultValues != null ? defaultValues : {},
@@ -7520,9 +7527,9 @@ function RegistrationForm({
7520
7527
  includeTerms
7521
7528
  )
7522
7529
  );
7523
- const [submitAttempted, setSubmitAttempted] = React8.useState(false);
7524
- const [validationErrors, setValidationErrors] = React8.useState({});
7525
- React8.useEffect(() => {
7530
+ const [submitAttempted, setSubmitAttempted] = React28.useState(false);
7531
+ const [validationErrors, setValidationErrors] = React28.useState({});
7532
+ React28.useEffect(() => {
7526
7533
  if (isControlled) return;
7527
7534
  setInternal((prev) => {
7528
7535
  const next = initializeValues(
@@ -7579,7 +7586,7 @@ function RegistrationForm({
7579
7586
  const termsError = submitAttempted && termsEnabled && !termsAccepted;
7580
7587
  const firstErrorFieldId = Object.keys(fieldErrors)[0];
7581
7588
  const scrollTargetId = firstErrorFieldId ? `rf-${firstErrorFieldId}` : termsError ? "rf-terms" : null;
7582
- React8.useEffect(() => {
7589
+ React28.useEffect(() => {
7583
7590
  if (!submitAttempted || !scrollTargetId) return;
7584
7591
  const timer = setTimeout(() => {
7585
7592
  const elem = document.getElementById(scrollTargetId);
@@ -8041,10 +8048,10 @@ var OTPCodeInput = ({
8041
8048
  id,
8042
8049
  required
8043
8050
  }) => {
8044
- const baseId = id != null ? id : React8.useId();
8045
- const inputRef = React8.useRef(null);
8046
- const [focused, setFocused] = React8.useState(false);
8047
- const digits = React8.useMemo(() => {
8051
+ const baseId = id != null ? id : React28.useId();
8052
+ const inputRef = React28.useRef(null);
8053
+ const [focused, setFocused] = React28.useState(false);
8054
+ const digits = React28.useMemo(() => {
8048
8055
  const arr = value.split("").slice(0, length);
8049
8056
  while (arr.length < length) arr.push("");
8050
8057
  return arr;
@@ -8142,7 +8149,7 @@ function Checkbox(_a) {
8142
8149
  __spreadProps(__spreadValues({
8143
8150
  "data-slot": "checkbox",
8144
8151
  className: cn(
8145
- "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",
8152
+ "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",
8146
8153
  className
8147
8154
  )
8148
8155
  }, props), {
@@ -8151,16 +8158,13 @@ function Checkbox(_a) {
8151
8158
  {
8152
8159
  "data-slot": "checkbox-indicator",
8153
8160
  className: "grid place-content-center text-current transition-none [&>svg]:size-3.5",
8154
- children: /* @__PURE__ */ jsx(
8155
- CheckIcon,
8156
- {}
8157
- )
8161
+ children: props.indeterminate ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {})
8158
8162
  }
8159
8163
  )
8160
8164
  })
8161
8165
  );
8162
8166
  }
8163
- var AccordionVariantContext = React8.createContext("default");
8167
+ var AccordionVariantContext = React28.createContext("default");
8164
8168
  function Accordion(_a) {
8165
8169
  var _b = _a, { className, variant = "default" } = _b, props = __objRest(_b, ["className", "variant"]);
8166
8170
  return /* @__PURE__ */ jsx(AccordionVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsx(
@@ -8178,7 +8182,7 @@ function Accordion(_a) {
8178
8182
  }
8179
8183
  function AccordionItem(_a) {
8180
8184
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
8181
- const variant = React8.useContext(AccordionVariantContext);
8185
+ const variant = React28.useContext(AccordionVariantContext);
8182
8186
  return /* @__PURE__ */ jsx(
8183
8187
  Accordion$1.Item,
8184
8188
  __spreadValues({
@@ -8199,7 +8203,7 @@ function AccordionTrigger(_a) {
8199
8203
  "className",
8200
8204
  "children"
8201
8205
  ]);
8202
- const variant = React8.useContext(AccordionVariantContext);
8206
+ const variant = React28.useContext(AccordionVariantContext);
8203
8207
  return /* @__PURE__ */ jsx(Accordion$1.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
8204
8208
  Accordion$1.Trigger,
8205
8209
  __spreadProps(__spreadValues({
@@ -8253,7 +8257,7 @@ function AccordionContent(_a) {
8253
8257
  "className",
8254
8258
  "children"
8255
8259
  ]);
8256
- const variant = React8.useContext(AccordionVariantContext);
8260
+ const variant = React28.useContext(AccordionVariantContext);
8257
8261
  return /* @__PURE__ */ jsx(
8258
8262
  Accordion$1.Panel,
8259
8263
  __spreadProps(__spreadValues({
@@ -8276,6 +8280,187 @@ function AccordionContent(_a) {
8276
8280
  })
8277
8281
  );
8278
8282
  }
8283
+ function getLeafIds(item) {
8284
+ var _a;
8285
+ if (!((_a = item.children) == null ? void 0 : _a.length)) return [item.id];
8286
+ return item.children.flatMap(getLeafIds);
8287
+ }
8288
+ function getDefaultExpandedIds(items) {
8289
+ const out = [];
8290
+ const walk = (list) => {
8291
+ var _a;
8292
+ for (const i of list) {
8293
+ if ((_a = i.children) == null ? void 0 : _a.length) {
8294
+ if (i.defaultExpanded) out.push(i.id);
8295
+ walk(i.children);
8296
+ }
8297
+ }
8298
+ };
8299
+ walk(items);
8300
+ return out;
8301
+ }
8302
+ function getAllItemIds(items) {
8303
+ return items.flatMap(
8304
+ (i) => {
8305
+ var _a;
8306
+ return ((_a = i.children) == null ? void 0 : _a.length) ? [i.id, ...getAllItemIds(i.children)] : [i.id];
8307
+ }
8308
+ );
8309
+ }
8310
+ function findItemById(items, id) {
8311
+ var _a;
8312
+ for (const item of items) {
8313
+ if (item.id === id) return item;
8314
+ if ((_a = item.children) == null ? void 0 : _a.length) {
8315
+ const found = findItemById(item.children, id);
8316
+ if (found) return found;
8317
+ }
8318
+ }
8319
+ return void 0;
8320
+ }
8321
+ function resolveGroups(groups) {
8322
+ return groups.map((g) => {
8323
+ var _a;
8324
+ if (!g.scopeItemId) return g;
8325
+ const node = findItemById(g.items, g.scopeItemId);
8326
+ return __spreadProps(__spreadValues({}, g), { items: (_a = node == null ? void 0 : node.children) != null ? _a : [] });
8327
+ }).filter((g) => g.items.length > 0);
8328
+ }
8329
+ function FilterItemsList({
8330
+ items,
8331
+ groupId,
8332
+ groupSelected,
8333
+ onToggle,
8334
+ onBulkToggle,
8335
+ idPrefix,
8336
+ depth = 0,
8337
+ parentAsHeader = false,
8338
+ expandedItems,
8339
+ onToggleExpanded
8340
+ }) {
8341
+ return /* @__PURE__ */ jsx(
8342
+ "ul",
8343
+ {
8344
+ className: cn(
8345
+ "flex flex-col gap-0.5",
8346
+ !parentAsHeader && depth > 0 && "mt-0.5 ml-6 border-l border-border pl-3"
8347
+ ),
8348
+ children: items.map((item) => {
8349
+ var _a, _b;
8350
+ const isParent = !!((_a = item.children) == null ? void 0 : _a.length);
8351
+ const checkboxId = `${idPrefix}-${groupId}-${item.id}`;
8352
+ if (!isParent) {
8353
+ const checked = groupSelected.includes(item.id);
8354
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
8355
+ "label",
8356
+ {
8357
+ htmlFor: checkboxId,
8358
+ className: "flex cursor-pointer items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50",
8359
+ children: [
8360
+ /* @__PURE__ */ jsx(
8361
+ Checkbox,
8362
+ {
8363
+ id: checkboxId,
8364
+ checked,
8365
+ onCheckedChange: () => onToggle(item.id),
8366
+ className: "shrink-0"
8367
+ }
8368
+ ),
8369
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-foreground font-ui", children: item.label }),
8370
+ item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8371
+ "(",
8372
+ item.count,
8373
+ ")"
8374
+ ] })
8375
+ ]
8376
+ }
8377
+ ) }, item.id);
8378
+ }
8379
+ if (parentAsHeader) {
8380
+ return /* @__PURE__ */ jsxs("li", { className: cn(depth > 0 && "mt-1"), children: [
8381
+ /* @__PURE__ */ jsx("p", { className: "px-1 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: item.label }),
8382
+ /* @__PURE__ */ jsx(
8383
+ FilterItemsList,
8384
+ {
8385
+ items: item.children,
8386
+ groupId,
8387
+ groupSelected,
8388
+ onToggle,
8389
+ onBulkToggle,
8390
+ idPrefix,
8391
+ depth: depth + 1,
8392
+ parentAsHeader: true,
8393
+ expandedItems,
8394
+ onToggleExpanded
8395
+ }
8396
+ )
8397
+ ] }, item.id);
8398
+ }
8399
+ const leafIds = item.children.flatMap(getLeafIds);
8400
+ const selectedLeaves = leafIds.filter((id) => groupSelected.includes(id));
8401
+ const allSelected = leafIds.length > 0 && selectedLeaves.length === leafIds.length;
8402
+ const someSelected = selectedLeaves.length > 0 && !allSelected;
8403
+ const isExpanded = (_b = expandedItems == null ? void 0 : expandedItems.has(item.id)) != null ? _b : false;
8404
+ const panelId = `${checkboxId}-children`;
8405
+ return /* @__PURE__ */ jsxs("li", { children: [
8406
+ /* @__PURE__ */ jsxs("div", { className: "group/parent flex items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50", children: [
8407
+ /* @__PURE__ */ jsx(
8408
+ Checkbox,
8409
+ {
8410
+ id: checkboxId,
8411
+ checked: allSelected,
8412
+ indeterminate: someSelected,
8413
+ onCheckedChange: () => onBulkToggle(leafIds, !allSelected),
8414
+ className: "shrink-0"
8415
+ }
8416
+ ),
8417
+ /* @__PURE__ */ jsxs(
8418
+ "button",
8419
+ {
8420
+ type: "button",
8421
+ onClick: () => onToggleExpanded == null ? void 0 : onToggleExpanded(item.id),
8422
+ "aria-expanded": isExpanded,
8423
+ "aria-controls": panelId,
8424
+ 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",
8425
+ children: [
8426
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-bold text-foreground font-ui", children: item.label }),
8427
+ item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8428
+ "(",
8429
+ item.count,
8430
+ ")"
8431
+ ] }),
8432
+ /* @__PURE__ */ jsx(
8433
+ ChevronDownIcon,
8434
+ {
8435
+ className: cn(
8436
+ "h-4 w-4 text-muted-foreground transition-transform",
8437
+ isExpanded && "rotate-180"
8438
+ )
8439
+ }
8440
+ )
8441
+ ]
8442
+ }
8443
+ )
8444
+ ] }),
8445
+ isExpanded && /* @__PURE__ */ jsx("div", { id: panelId, children: /* @__PURE__ */ jsx(
8446
+ FilterItemsList,
8447
+ {
8448
+ items: item.children,
8449
+ groupId,
8450
+ groupSelected,
8451
+ onToggle,
8452
+ onBulkToggle,
8453
+ idPrefix,
8454
+ depth: depth + 1,
8455
+ expandedItems,
8456
+ onToggleExpanded
8457
+ }
8458
+ ) })
8459
+ ] }, item.id);
8460
+ })
8461
+ }
8462
+ );
8463
+ }
8279
8464
  function FilterPanel({
8280
8465
  groups,
8281
8466
  value,
@@ -8283,15 +8468,32 @@ function FilterPanel({
8283
8468
  onClearAll,
8284
8469
  alwaysShowClear = false,
8285
8470
  title = "Filters",
8286
- className
8471
+ className,
8472
+ variant = "sidebar",
8473
+ sortOptions,
8474
+ sort,
8475
+ onSortChange
8287
8476
  }) {
8288
- const [internalValue, setInternalValue] = React8.useState(
8477
+ var _a, _b;
8478
+ const resolvedGroups = React28.useMemo(() => resolveGroups(groups), [groups]);
8479
+ const [internalValue, setInternalValue] = React28.useState(
8289
8480
  () => Object.fromEntries(groups.map((g) => [g.id, []]))
8290
8481
  );
8291
8482
  const selected = value != null ? value : internalValue;
8483
+ const [expandedItems, setExpandedItems] = React28.useState(
8484
+ () => new Set(groups.flatMap((g) => getDefaultExpandedIds(g.items)))
8485
+ );
8486
+ const toggleExpanded = React28.useCallback((id) => {
8487
+ setExpandedItems((prev) => {
8488
+ const next = new Set(prev);
8489
+ if (next.has(id)) next.delete(id);
8490
+ else next.add(id);
8491
+ return next;
8492
+ });
8493
+ }, []);
8292
8494
  const handleToggle = (groupId, itemId) => {
8293
- var _a;
8294
- const current = (_a = selected[groupId]) != null ? _a : [];
8495
+ var _a2;
8496
+ const current = (_a2 = selected[groupId]) != null ? _a2 : [];
8295
8497
  const next = current.includes(itemId) ? current.filter((id) => id !== itemId) : [...current, itemId];
8296
8498
  const nextValue = __spreadProps(__spreadValues({}, selected), { [groupId]: next });
8297
8499
  if (onChange) {
@@ -8300,8 +8502,24 @@ function FilterPanel({
8300
8502
  setInternalValue(nextValue);
8301
8503
  }
8302
8504
  };
8505
+ const handleBulkToggle = (groupId, itemIds, select) => {
8506
+ var _a2;
8507
+ const current = (_a2 = selected[groupId]) != null ? _a2 : [];
8508
+ const next = select ? Array.from(/* @__PURE__ */ new Set([...current, ...itemIds])) : current.filter((id) => !itemIds.includes(id));
8509
+ const nextValue = __spreadProps(__spreadValues({}, selected), { [groupId]: next });
8510
+ if (onChange) {
8511
+ onChange(nextValue);
8512
+ } else {
8513
+ setInternalValue(nextValue);
8514
+ }
8515
+ };
8303
8516
  const handleClearAll = () => {
8304
- const cleared = Object.fromEntries(groups.map((g) => [g.id, []]));
8517
+ var _a2;
8518
+ const cleared = __spreadValues({}, selected);
8519
+ for (const g of resolvedGroups) {
8520
+ const visible = new Set(getAllItemIds(g.items));
8521
+ cleared[g.id] = ((_a2 = selected[g.id]) != null ? _a2 : []).filter((id) => !visible.has(id));
8522
+ }
8305
8523
  if (onChange) {
8306
8524
  onChange(cleared);
8307
8525
  } else {
@@ -8309,9 +8527,289 @@ function FilterPanel({
8309
8527
  }
8310
8528
  onClearAll == null ? void 0 : onClearAll();
8311
8529
  };
8312
- const totalSelected = Object.values(selected).flat().length;
8530
+ const totalSelected = resolvedGroups.reduce((sum, g) => {
8531
+ var _a2;
8532
+ const visible = new Set(getAllItemIds(g.items));
8533
+ return sum + ((_a2 = selected[g.id]) != null ? _a2 : []).filter((id) => visible.has(id)).length;
8534
+ }, 0);
8313
8535
  const showClear = alwaysShowClear || totalSelected > 0;
8314
- const defaultOpenValues = groups.filter((g) => g.defaultOpen).map((g) => g.id);
8536
+ const defaultOpenValues = resolvedGroups.filter((g) => g.defaultOpen).map((g) => g.id);
8537
+ if (resolvedGroups.length === 0) return null;
8538
+ if (variant === "horizontal") {
8539
+ const activeSort = (_a = sortOptions == null ? void 0 : sortOptions.find((o) => o.id === sort)) != null ? _a : sortOptions == null ? void 0 : sortOptions[0];
8540
+ const drawerGroups = /* @__PURE__ */ jsx(Accordion, { defaultValue: defaultOpenValues, className: "flex flex-col gap-2", children: resolvedGroups.map((group) => {
8541
+ var _a2;
8542
+ const groupSelected = (_a2 = selected[group.id]) != null ? _a2 : [];
8543
+ return /* @__PURE__ */ jsxs(
8544
+ AccordionItem,
8545
+ {
8546
+ value: group.id,
8547
+ className: "border-0 border-b border-border last:border-b-0",
8548
+ children: [
8549
+ /* @__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: [
8550
+ group.icon && /* @__PURE__ */ jsx("span", { className: "text-primary shrink-0", children: group.icon }),
8551
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-foreground font-ui", children: group.label }),
8552
+ 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 })
8553
+ ] }) }),
8554
+ /* @__PURE__ */ jsx(AccordionContent, { className: "px-4 pb-3 pt-1", children: /* @__PURE__ */ jsx(
8555
+ FilterItemsList,
8556
+ {
8557
+ items: group.items,
8558
+ groupId: group.id,
8559
+ groupSelected,
8560
+ onToggle: (id) => handleToggle(group.id, id),
8561
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8562
+ idPrefix: "mobile-filter",
8563
+ expandedItems,
8564
+ onToggleExpanded: toggleExpanded
8565
+ }
8566
+ ) })
8567
+ ]
8568
+ },
8569
+ group.id
8570
+ );
8571
+ }) });
8572
+ return /* @__PURE__ */ jsxs("div", { className: cn("contents", className), children: [
8573
+ /* @__PURE__ */ jsxs("div", { className: "flex sm:hidden items-center gap-2", children: [
8574
+ /* @__PURE__ */ jsxs(Dialog, { children: [
8575
+ /* @__PURE__ */ jsxs(
8576
+ DialogTrigger,
8577
+ {
8578
+ render: /* @__PURE__ */ jsx(
8579
+ "button",
8580
+ {
8581
+ type: "button",
8582
+ className: cn(
8583
+ "flex-1 inline-flex items-center justify-between gap-2 rounded-xl border-2 border-foreground bg-background px-4 py-3",
8584
+ "text-sm font-ui font-bold text-foreground transition-colors hover:bg-muted",
8585
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8586
+ )
8587
+ }
8588
+ ),
8589
+ children: [
8590
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
8591
+ title,
8592
+ 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 })
8593
+ ] }),
8594
+ /* @__PURE__ */ jsx(SlidersHorizontalIcon, { className: "h-4 w-4 text-foreground" })
8595
+ ]
8596
+ }
8597
+ ),
8598
+ /* @__PURE__ */ jsx(
8599
+ DialogContent,
8600
+ {
8601
+ className: cn(
8602
+ "p-0 sm:max-w-md",
8603
+ "max-w-none w-screen h-screen sm:h-auto sm:max-h-[90vh] rounded-none sm:rounded-2xl"
8604
+ ),
8605
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full max-h-[90vh]", children: [
8606
+ /* @__PURE__ */ jsx(DialogTitle, { className: "px-5 py-4 text-lg font-bold font-heading border-b border-border", children: title }),
8607
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-5 py-3", children: drawerGroups }),
8608
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 px-5 py-4 border-t border-border", children: [
8609
+ /* @__PURE__ */ jsx(
8610
+ "button",
8611
+ {
8612
+ type: "button",
8613
+ onClick: handleClearAll,
8614
+ className: "text-sm font-ui font-semibold text-muted-foreground underline underline-offset-2 hover:text-foreground",
8615
+ children: "Clear all"
8616
+ }
8617
+ ),
8618
+ /* @__PURE__ */ jsxs(
8619
+ DialogClose,
8620
+ {
8621
+ render: /* @__PURE__ */ jsx(
8622
+ "button",
8623
+ {
8624
+ type: "button",
8625
+ 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"
8626
+ }
8627
+ ),
8628
+ children: [
8629
+ "Show ",
8630
+ totalSelected > 0 ? `(${totalSelected})` : "",
8631
+ " results"
8632
+ ]
8633
+ }
8634
+ )
8635
+ ] })
8636
+ ] })
8637
+ }
8638
+ )
8639
+ ] }),
8640
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
8641
+ /* @__PURE__ */ jsxs(
8642
+ PopoverTrigger,
8643
+ {
8644
+ render: /* @__PURE__ */ jsx(
8645
+ "button",
8646
+ {
8647
+ type: "button",
8648
+ className: cn(
8649
+ "inline-flex items-center gap-1.5 rounded-xl border border-border bg-background px-4 py-3",
8650
+ "text-sm font-ui font-bold text-foreground transition-colors hover:bg-muted",
8651
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8652
+ )
8653
+ }
8654
+ ),
8655
+ children: [
8656
+ "Sort",
8657
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" })
8658
+ ]
8659
+ }
8660
+ ),
8661
+ /* @__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(
8662
+ "button",
8663
+ {
8664
+ type: "button",
8665
+ onClick: () => onSortChange == null ? void 0 : onSortChange(opt.id),
8666
+ className: cn(
8667
+ "flex items-center px-2 py-1.5 rounded-md text-sm text-left",
8668
+ opt.id === (activeSort == null ? void 0 : activeSort.id) ? "bg-muted text-foreground font-semibold" : "text-foreground/80 hover:bg-muted"
8669
+ ),
8670
+ children: opt.label
8671
+ },
8672
+ opt.id
8673
+ )) }) })
8674
+ ] })
8675
+ ] }),
8676
+ /* @__PURE__ */ jsxs("div", { className: "hidden sm:flex items-center gap-2 flex-wrap", children: [
8677
+ resolvedGroups.map((group) => {
8678
+ var _a2, _b2;
8679
+ const selectedCount = ((_a2 = selected[group.id]) != null ? _a2 : []).length;
8680
+ const isActive = selectedCount > 0;
8681
+ return /* @__PURE__ */ jsxs(Popover, { children: [
8682
+ /* @__PURE__ */ jsxs(
8683
+ PopoverTrigger,
8684
+ {
8685
+ render: /* @__PURE__ */ jsx(
8686
+ "button",
8687
+ {
8688
+ type: "button",
8689
+ className: cn(
8690
+ "inline-flex items-center gap-1.5 rounded-full border px-3.5 py-1.5",
8691
+ "text-sm font-ui font-semibold transition-colors",
8692
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8693
+ isActive ? "border-foreground bg-foreground text-background" : "border-border bg-background text-foreground hover:bg-muted"
8694
+ )
8695
+ }
8696
+ ),
8697
+ children: [
8698
+ group.icon && /* @__PURE__ */ jsx(
8699
+ "span",
8700
+ {
8701
+ className: cn(
8702
+ "[&>svg]:h-3.5 [&>svg]:w-3.5",
8703
+ isActive ? "" : "text-muted-foreground"
8704
+ ),
8705
+ children: group.icon
8706
+ }
8707
+ ),
8708
+ group.label,
8709
+ selectedCount > 0 && /* @__PURE__ */ jsx(
8710
+ "span",
8711
+ {
8712
+ className: cn(
8713
+ "inline-flex items-center justify-center rounded-full text-[10px] font-bold px-1.5 min-w-[18px] h-[18px]",
8714
+ isActive ? "bg-background text-foreground" : "bg-foreground text-background"
8715
+ ),
8716
+ children: selectedCount
8717
+ }
8718
+ ),
8719
+ /* @__PURE__ */ jsx(
8720
+ ChevronDownIcon,
8721
+ {
8722
+ className: cn(
8723
+ "h-3.5 w-3.5",
8724
+ isActive ? "text-background/70" : "text-muted-foreground"
8725
+ )
8726
+ }
8727
+ )
8728
+ ]
8729
+ }
8730
+ ),
8731
+ /* @__PURE__ */ jsx(
8732
+ PopoverContent,
8733
+ {
8734
+ align: "start",
8735
+ sideOffset: 6,
8736
+ className: "w-72 max-h-[60vh] overflow-y-auto",
8737
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 p-2", children: [
8738
+ /* @__PURE__ */ jsx("p", { className: "px-1 py-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: group.label }),
8739
+ /* @__PURE__ */ jsx(
8740
+ FilterItemsList,
8741
+ {
8742
+ items: group.items,
8743
+ groupId: group.id,
8744
+ groupSelected: (_b2 = selected[group.id]) != null ? _b2 : [],
8745
+ onToggle: (id) => handleToggle(group.id, id),
8746
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8747
+ idPrefix: "popover-filter",
8748
+ parentAsHeader: true,
8749
+ expandedItems,
8750
+ onToggleExpanded: toggleExpanded
8751
+ }
8752
+ )
8753
+ ] })
8754
+ }
8755
+ )
8756
+ ] }, group.id);
8757
+ }),
8758
+ totalSelected > 0 && /* @__PURE__ */ jsxs(
8759
+ "button",
8760
+ {
8761
+ type: "button",
8762
+ onClick: handleClearAll,
8763
+ 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",
8764
+ children: [
8765
+ /* @__PURE__ */ jsx(XIcon, { className: "h-3 w-3" }),
8766
+ "Clear all (",
8767
+ totalSelected,
8768
+ ")"
8769
+ ]
8770
+ }
8771
+ ),
8772
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
8773
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-ui hidden sm:inline", children: "Sort by" }),
8774
+ /* @__PURE__ */ jsxs(Popover, { children: [
8775
+ /* @__PURE__ */ jsxs(
8776
+ PopoverTrigger,
8777
+ {
8778
+ render: /* @__PURE__ */ jsx(
8779
+ "button",
8780
+ {
8781
+ type: "button",
8782
+ className: cn(
8783
+ "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-3.5 py-1.5",
8784
+ "text-sm font-ui font-semibold text-foreground hover:bg-muted transition-colors",
8785
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8786
+ )
8787
+ }
8788
+ ),
8789
+ children: [
8790
+ (_b = activeSort == null ? void 0 : activeSort.label) != null ? _b : "Default",
8791
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-3.5 w-3.5 text-muted-foreground" })
8792
+ ]
8793
+ }
8794
+ ),
8795
+ /* @__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(
8796
+ "button",
8797
+ {
8798
+ type: "button",
8799
+ onClick: () => onSortChange == null ? void 0 : onSortChange(opt.id),
8800
+ className: cn(
8801
+ "flex items-center px-2 py-1.5 rounded-md text-sm text-left",
8802
+ opt.id === (activeSort == null ? void 0 : activeSort.id) ? "bg-muted text-foreground font-semibold" : "text-foreground/80 hover:bg-muted"
8803
+ ),
8804
+ children: opt.label
8805
+ },
8806
+ opt.id
8807
+ )) }) })
8808
+ ] })
8809
+ ] })
8810
+ ] })
8811
+ ] });
8812
+ }
8315
8813
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), children: [
8316
8814
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8317
8815
  /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-ui", children: title }),
@@ -8322,9 +8820,9 @@ function FilterPanel({
8322
8820
  {
8323
8821
  defaultValue: defaultOpenValues,
8324
8822
  className: "flex flex-col gap-2",
8325
- children: groups.map((group) => {
8326
- var _a;
8327
- const groupSelected = (_a = selected[group.id]) != null ? _a : [];
8823
+ children: resolvedGroups.map((group) => {
8824
+ var _a2;
8825
+ const groupSelected = (_a2 = selected[group.id]) != null ? _a2 : [];
8328
8826
  return /* @__PURE__ */ jsxs(
8329
8827
  AccordionItem,
8330
8828
  {
@@ -8336,34 +8834,19 @@ function FilterPanel({
8336
8834
  /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-foreground font-ui", children: group.label }),
8337
8835
  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 })
8338
8836
  ] }) }),
8339
- /* @__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) => {
8340
- const checked = groupSelected.includes(item.id);
8341
- const checkboxId = `filter-${group.id}-${item.id}`;
8342
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
8343
- "label",
8344
- {
8345
- htmlFor: checkboxId,
8346
- className: "flex cursor-pointer items-center gap-3 rounded-md px-1 py-2 transition-colors hover:bg-muted/50",
8347
- children: [
8348
- /* @__PURE__ */ jsx(
8349
- Checkbox,
8350
- {
8351
- id: checkboxId,
8352
- checked,
8353
- onCheckedChange: () => handleToggle(group.id, item.id),
8354
- className: "shrink-0"
8355
- }
8356
- ),
8357
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-foreground font-ui", children: item.label }),
8358
- item.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-primary font-ui", children: [
8359
- "(",
8360
- item.count,
8361
- ")"
8362
- ] })
8363
- ]
8364
- }
8365
- ) }, item.id);
8366
- }) }) })
8837
+ /* @__PURE__ */ jsx(AccordionContent, { className: "px-4 pb-3 pt-1", children: /* @__PURE__ */ jsx(
8838
+ FilterItemsList,
8839
+ {
8840
+ items: group.items,
8841
+ groupId: group.id,
8842
+ groupSelected,
8843
+ onToggle: (id) => handleToggle(group.id, id),
8844
+ onBulkToggle: (ids, select) => handleBulkToggle(group.id, ids, select),
8845
+ idPrefix: "filter",
8846
+ expandedItems,
8847
+ onToggleExpanded: toggleExpanded
8848
+ }
8849
+ ) })
8367
8850
  ]
8368
8851
  },
8369
8852
  group.id
@@ -8384,70 +8867,182 @@ function FilterPanel({
8384
8867
  var TRUSTPILOT_SCRIPT_SRC = "https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js";
8385
8868
  function TrustpilotEmbed({ config }) {
8386
8869
  var _a, _b, _c, _d, _e, _f;
8387
- const ref = React8.useRef(null);
8388
- React8.useEffect(() => {
8870
+ const ref = React28.useRef(null);
8871
+ const [widgetReady, setWidgetReady] = React28.useState(false);
8872
+ const [delayPassed, setDelayPassed] = React28.useState(false);
8873
+ const showFallback = delayPassed && !widgetReady;
8874
+ React28.useEffect(() => {
8875
+ var _a2;
8389
8876
  if (typeof document === "undefined" || !ref.current) return;
8877
+ const node = ref.current;
8390
8878
  let cancelled = false;
8879
+ const checkRendered = () => {
8880
+ if (!node) return false;
8881
+ if (node.querySelector("iframe")) return true;
8882
+ if (node.innerHTML.length > 200) return true;
8883
+ return false;
8884
+ };
8885
+ const observer = new MutationObserver(() => {
8886
+ if (cancelled) return;
8887
+ if (checkRendered()) setWidgetReady(true);
8888
+ });
8889
+ observer.observe(node, { childList: true, subtree: true });
8890
+ if (checkRendered()) setWidgetReady(true);
8391
8891
  const initWidget = () => {
8392
- if (cancelled || !ref.current) return;
8892
+ if (cancelled || !node) return;
8393
8893
  const tp = window.Trustpilot;
8394
8894
  if (tp == null ? void 0 : tp.loadFromElement) {
8395
- tp.loadFromElement(ref.current, true);
8895
+ tp.loadFromElement(node, true);
8396
8896
  }
8397
8897
  };
8398
8898
  const existing = document.querySelector(
8399
8899
  `script[src="${TRUSTPILOT_SCRIPT_SRC}"]`
8400
8900
  );
8901
+ let cleanupScriptListener;
8401
8902
  if (existing) {
8402
8903
  const tp = window.Trustpilot;
8403
8904
  if (tp == null ? void 0 : tp.loadFromElement) {
8404
8905
  initWidget();
8405
8906
  } else {
8406
8907
  existing.addEventListener("load", initWidget, { once: true });
8908
+ cleanupScriptListener = () => existing.removeEventListener("load", initWidget);
8407
8909
  }
8408
- return () => {
8409
- cancelled = true;
8410
- existing.removeEventListener("load", initWidget);
8411
- };
8910
+ } else {
8911
+ const s = document.createElement("script");
8912
+ s.src = TRUSTPILOT_SCRIPT_SRC;
8913
+ s.async = true;
8914
+ s.addEventListener("load", initWidget, { once: true });
8915
+ document.body.appendChild(s);
8916
+ cleanupScriptListener = () => s.removeEventListener("load", initWidget);
8412
8917
  }
8413
- const s = document.createElement("script");
8414
- s.src = TRUSTPILOT_SCRIPT_SRC;
8415
- s.async = true;
8416
- s.addEventListener("load", initWidget, { once: true });
8417
- document.body.appendChild(s);
8918
+ const delay = (_a2 = config.fallbackDelayMs) != null ? _a2 : 3e3;
8919
+ const timeout = setTimeout(() => {
8920
+ if (!cancelled) setDelayPassed(true);
8921
+ }, delay);
8418
8922
  return () => {
8419
8923
  cancelled = true;
8420
- s.removeEventListener("load", initWidget);
8924
+ clearTimeout(timeout);
8925
+ observer.disconnect();
8926
+ cleanupScriptListener == null ? void 0 : cleanupScriptListener();
8421
8927
  };
8422
8928
  }, [config]);
8423
8929
  const sku = Array.isArray(config.sku) ? config.sku.join(",") : config.sku;
8930
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8931
+ /* @__PURE__ */ jsx(
8932
+ "div",
8933
+ {
8934
+ ref,
8935
+ className: "trustpilot-widget",
8936
+ "data-locale": (_a = config.locale) != null ? _a : "en-US",
8937
+ "data-template-id": (_b = config.templateId) != null ? _b : "5763bccae0a06d08e809ecbb",
8938
+ "data-businessunit-id": config.businessUnitId,
8939
+ "data-style-height": (_c = config.styleHeight) != null ? _c : "700px",
8940
+ "data-style-width": (_d = config.styleWidth) != null ? _d : "100%",
8941
+ "data-sku": sku,
8942
+ "data-no-reviews": (_e = config.noReviews) != null ? _e : "hide",
8943
+ "data-fullwidth": "true",
8944
+ "data-theme": config.theme,
8945
+ "data-token": config.token,
8946
+ "data-scroll-to-list": config.scrollToList ? "true" : void 0,
8947
+ "data-style-alignment": config.styleAlignment,
8948
+ "data-star-color": config.starColor,
8949
+ children: /* @__PURE__ */ jsx(
8950
+ "a",
8951
+ {
8952
+ href: (_f = config.fallbackHref) != null ? _f : "https://www.trustpilot.com/",
8953
+ target: "_blank",
8954
+ rel: "noopener noreferrer",
8955
+ children: "Trustpilot"
8956
+ }
8957
+ )
8958
+ }
8959
+ ),
8960
+ showFallback && /* @__PURE__ */ jsx(TrustpilotFallback, { config })
8961
+ ] });
8962
+ }
8963
+ function FallbackStar({ filled, className }) {
8424
8964
  return /* @__PURE__ */ jsx(
8425
- "div",
8965
+ "span",
8426
8966
  {
8427
- ref,
8428
- className: "trustpilot-widget",
8429
- "data-locale": (_a = config.locale) != null ? _a : "en-US",
8430
- "data-template-id": (_b = config.templateId) != null ? _b : "5763bccae0a06d08e809ecbb",
8431
- "data-businessunit-id": config.businessUnitId,
8432
- "data-style-height": (_c = config.styleHeight) != null ? _c : "700px",
8433
- "data-style-width": (_d = config.styleWidth) != null ? _d : "100%",
8434
- "data-sku": sku,
8435
- "data-no-reviews": (_e = config.noReviews) != null ? _e : "hide",
8436
- "data-fullwidth": "true",
8437
- "data-theme": config.theme,
8438
- "data-token": config.token,
8439
- "data-scroll-to-list": config.scrollToList ? "true" : void 0,
8440
- "data-style-alignment": config.styleAlignment,
8441
- "data-star-color": config.starColor,
8442
- children: /* @__PURE__ */ jsx(
8443
- "a",
8444
- {
8445
- href: (_f = config.fallbackHref) != null ? _f : "https://www.trustpilot.com/",
8446
- target: "_blank",
8447
- rel: "noopener noreferrer",
8448
- children: "Trustpilot"
8449
- }
8450
- )
8967
+ "aria-hidden": true,
8968
+ className: cn(
8969
+ "inline-flex items-center justify-center",
8970
+ filled ? "bg-[#00b67a] text-white" : "bg-muted text-muted-foreground",
8971
+ className
8972
+ ),
8973
+ 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" }) })
8974
+ }
8975
+ );
8976
+ }
8977
+ function TrustpilotFallback({ config }) {
8978
+ var _a, _b, _c, _d, _e, _f;
8979
+ const score = (_a = config.fallbackScore) != null ? _a : 4.8;
8980
+ const count = (_b = config.fallbackCount) != null ? _b : 0;
8981
+ const label = (_c = config.fallbackLabel) != null ? _c : "Excellent";
8982
+ const href = (_d = config.fallbackHref) != null ? _d : "https://www.trustpilot.com/";
8983
+ const isDark = config.theme === "dark";
8984
+ const styleHeightPx = parseInt((_e = config.styleHeight) != null ? _e : "", 10);
8985
+ const autoVariant = Number.isFinite(styleHeightPx) && styleHeightPx > 0 && styleHeightPx < 120 ? "mini" : "card";
8986
+ const variant = (_f = config.fallbackVariant) != null ? _f : autoVariant;
8987
+ const filledStars = Math.round(score);
8988
+ if (variant === "mini") {
8989
+ return /* @__PURE__ */ jsxs(
8990
+ "a",
8991
+ {
8992
+ href,
8993
+ target: "_blank",
8994
+ rel: "noopener noreferrer",
8995
+ className: cn(
8996
+ "inline-flex items-center gap-2 text-sm font-ui no-underline hover:opacity-80 transition-opacity",
8997
+ isDark ? "text-white" : "text-foreground"
8998
+ ),
8999
+ children: [
9000
+ /* @__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)) }),
9001
+ /* @__PURE__ */ jsx("span", { className: "font-bold", children: score.toFixed(1) }),
9002
+ count > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
9003
+ /* @__PURE__ */ jsx("span", { className: cn(isDark ? "text-white/60" : "text-muted-foreground"), children: "\xB7" }),
9004
+ /* @__PURE__ */ jsxs("span", { className: cn("text-xs", isDark ? "text-white/80" : "text-muted-foreground"), children: [
9005
+ count.toLocaleString(),
9006
+ " reviews"
9007
+ ] })
9008
+ ] }),
9009
+ /* @__PURE__ */ jsx("span", { className: cn("text-xs", isDark ? "text-white/60" : "text-muted-foreground"), children: "on Trustpilot" })
9010
+ ]
9011
+ }
9012
+ );
9013
+ }
9014
+ return /* @__PURE__ */ jsxs(
9015
+ "a",
9016
+ {
9017
+ href,
9018
+ target: "_blank",
9019
+ rel: "noopener noreferrer",
9020
+ 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",
9021
+ children: [
9022
+ /* @__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)) }),
9023
+ /* @__PURE__ */ jsxs("p", { className: "text-2xl font-bold text-foreground font-heading", children: [
9024
+ label,
9025
+ " ",
9026
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground font-normal", children: [
9027
+ "\xB7 ",
9028
+ score.toFixed(1),
9029
+ " / 5"
9030
+ ] })
9031
+ ] }),
9032
+ count > 0 && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-2", children: [
9033
+ "Based on ",
9034
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: count.toLocaleString() }),
9035
+ " reviews"
9036
+ ] }),
9037
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-4", children: "Reviews powered by Trustpilot" }),
9038
+ /* @__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: [
9039
+ "Read all reviews on Trustpilot",
9040
+ /* @__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: [
9041
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
9042
+ /* @__PURE__ */ jsx("polyline", { points: "12 5 19 12 12 19" })
9043
+ ] })
9044
+ ] })
9045
+ ]
8451
9046
  }
8452
9047
  );
8453
9048
  }
@@ -8517,11 +9112,11 @@ function ItineraryModal({
8517
9112
  onNext
8518
9113
  }) {
8519
9114
  var _a, _b, _c;
8520
- const [imgIndex, setImgIndex] = React8.useState(0);
9115
+ const [imgIndex, setImgIndex] = React28.useState(0);
8521
9116
  const images = stop ? [stop.coverImage, ...(_a = stop.images) != null ? _a : []] : [];
8522
9117
  const isFirst = (stop == null ? void 0 : stop.dayNumber) === ((_b = allStops[0]) == null ? void 0 : _b.dayNumber);
8523
9118
  const isLast = (stop == null ? void 0 : stop.dayNumber) === ((_c = allStops[allStops.length - 1]) == null ? void 0 : _c.dayNumber);
8524
- React8.useEffect(() => {
9119
+ React28.useEffect(() => {
8525
9120
  setImgIndex(0);
8526
9121
  }, [stop == null ? void 0 : stop.dayNumber]);
8527
9122
  if (!stop) return null;
@@ -8648,8 +9243,8 @@ function ItineraryModal({
8648
9243
  ) });
8649
9244
  }
8650
9245
  function Itinerary({ title, subtitle, stops, className }) {
8651
- const [activeIndex, setActiveIndex] = React8.useState(null);
8652
- const scrollRef = React8.useRef(null);
9246
+ const [activeIndex, setActiveIndex] = React28.useState(null);
9247
+ const scrollRef = React28.useRef(null);
8653
9248
  const activeStop = activeIndex !== null ? stops[activeIndex] : null;
8654
9249
  const scrollBy = (dir) => {
8655
9250
  if (!scrollRef.current) return;
@@ -8741,18 +9336,18 @@ function Lightbox({
8741
9336
  onClose
8742
9337
  }) {
8743
9338
  var _a;
8744
- const [index, setIndex] = React8.useState(initialIndex);
9339
+ const [index, setIndex] = React28.useState(initialIndex);
8745
9340
  const total = photos.length;
8746
9341
  const photo = photos[index];
8747
- const prev = React8.useCallback(
9342
+ const prev = React28.useCallback(
8748
9343
  () => setIndex((i) => (i - 1 + total) % total),
8749
9344
  [total]
8750
9345
  );
8751
- const next = React8.useCallback(
9346
+ const next = React28.useCallback(
8752
9347
  () => setIndex((i) => (i + 1) % total),
8753
9348
  [total]
8754
9349
  );
8755
- React8.useEffect(() => {
9350
+ React28.useEffect(() => {
8756
9351
  const onKey = (e) => {
8757
9352
  if (e.key === "Escape") onClose();
8758
9353
  if (e.key === "ArrowLeft") prev();
@@ -8918,7 +9513,7 @@ function GridGallery({
8918
9513
  initialVisible,
8919
9514
  onOpen
8920
9515
  }) {
8921
- const [expanded, setExpanded] = React8.useState(false);
9516
+ const [expanded, setExpanded] = React28.useState(false);
8922
9517
  const cols = gridCols(photos.length);
8923
9518
  const hasMore = photos.length > initialVisible;
8924
9519
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
@@ -8943,12 +9538,41 @@ function GridGallery({
8943
9538
  )
8944
9539
  ] });
8945
9540
  }
9541
+ function CompactGridGallery({
9542
+ photos,
9543
+ initialVisible,
9544
+ onOpen
9545
+ }) {
9546
+ const [expanded, setExpanded] = React28.useState(false);
9547
+ const hasMore = photos.length > initialVisible;
9548
+ const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
9549
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9550
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-4", children: visible.map((p, i) => /* @__PURE__ */ jsx(
9551
+ PhotoTile,
9552
+ {
9553
+ photo: p,
9554
+ index: i,
9555
+ className: "aspect-[4/3]",
9556
+ onClick: () => onOpen(i)
9557
+ },
9558
+ i
9559
+ )) }),
9560
+ hasMore && /* @__PURE__ */ jsx(
9561
+ ShowMoreButton,
9562
+ {
9563
+ count: photos.length - initialVisible,
9564
+ expanded,
9565
+ onClick: () => setExpanded((v) => !v)
9566
+ }
9567
+ )
9568
+ ] });
9569
+ }
8946
9570
  function MasonryGallery({
8947
9571
  photos,
8948
9572
  initialVisible,
8949
9573
  onOpen
8950
9574
  }) {
8951
- const [expanded, setExpanded] = React8.useState(false);
9575
+ const [expanded, setExpanded] = React28.useState(false);
8952
9576
  const hasMore = photos.length > initialVisible;
8953
9577
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
8954
9578
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9021,7 +9645,7 @@ function FeaturedGallery({
9021
9645
  photos,
9022
9646
  onOpen
9023
9647
  }) {
9024
- const [expanded, setExpanded] = React8.useState(false);
9648
+ const [expanded, setExpanded] = React28.useState(false);
9025
9649
  const featured = photos.slice(0, 3);
9026
9650
  const extra = photos.slice(3);
9027
9651
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9188,9 +9812,9 @@ function PhotoGallery({
9188
9812
  onPhotoClick,
9189
9813
  className
9190
9814
  }) {
9191
- const [lightboxIndex, setLightboxIndex] = React8.useState(null);
9192
- const [carouselIndex, setCarouselIndex] = React8.useState(0);
9193
- const normalised = React8.useMemo(() => photos.map(normalise), [photos]);
9815
+ const [lightboxIndex, setLightboxIndex] = React28.useState(null);
9816
+ const [carouselIndex, setCarouselIndex] = React28.useState(0);
9817
+ const normalised = React28.useMemo(() => photos.map(normalise), [photos]);
9194
9818
  const handleOpen = (index) => {
9195
9819
  setLightboxIndex(index);
9196
9820
  onPhotoClick == null ? void 0 : onPhotoClick(normalised[index].src, index);
@@ -9232,6 +9856,14 @@ function PhotoGallery({
9232
9856
  onOpen: handleOpen
9233
9857
  }
9234
9858
  ),
9859
+ variant === "gridCompact" && /* @__PURE__ */ jsx(
9860
+ CompactGridGallery,
9861
+ {
9862
+ photos: normalised,
9863
+ initialVisible,
9864
+ onOpen: handleOpen
9865
+ }
9866
+ ),
9235
9867
  variant === "masonry" && /* @__PURE__ */ jsx(
9236
9868
  MasonryGallery,
9237
9869
  {
@@ -9266,7 +9898,7 @@ function ItineraryDay({
9266
9898
  photoLayout = "rounded",
9267
9899
  className
9268
9900
  }) {
9269
- const photoList = React8.useMemo(() => normalisePhotos(photos), [photos]);
9901
+ const photoList = React28.useMemo(() => normalisePhotos(photos), [photos]);
9270
9902
  const isFullBleed = photoLayout === "fullBleed" || photoLayout === "fullBleedBottom";
9271
9903
  const photoPosition = photoLayout === "fullBleedBottom" ? "bottom" : "top";
9272
9904
  const gallery = photoList.length > 0 && /* @__PURE__ */ jsx(
@@ -9285,13 +9917,16 @@ function ItineraryDay({
9285
9917
  specs && specs.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3 sm:gap-2.5", children: specs.map((spec, i) => /* @__PURE__ */ jsxs(
9286
9918
  "li",
9287
9919
  {
9288
- className: "flex flex-col text-base text-foreground font-ui",
9920
+ className: "flex items-start gap-3 text-base text-foreground font-ui",
9289
9921
  children: [
9290
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
9291
- /* @__PURE__ */ jsx("span", { className: "font-semibold", children: spec.label }),
9292
- spec.detail && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: spec.detail })
9293
- ] }),
9294
- spec.subdetail && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: spec.subdetail })
9922
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true, children: spec.icon }),
9923
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
9924
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
9925
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: spec.label }),
9926
+ spec.detail && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: spec.detail })
9927
+ ] }),
9928
+ spec.subdetail && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: spec.subdetail })
9929
+ ] })
9295
9930
  ]
9296
9931
  },
9297
9932
  i
@@ -9318,8 +9953,8 @@ function MenuTrip({
9318
9953
  bold = true,
9319
9954
  className
9320
9955
  }) {
9321
- const scrollRef = React8.useRef(null);
9322
- React8.useEffect(() => {
9956
+ const scrollRef = React28.useRef(null);
9957
+ React28.useEffect(() => {
9323
9958
  if (!scrollRef.current || !activeSection) return;
9324
9959
  const container = scrollRef.current;
9325
9960
  const btn = container.querySelector(
@@ -9510,8 +10145,8 @@ function PricingTrip({
9510
10145
  className
9511
10146
  }) {
9512
10147
  const rOuter = sharp ? "rounded-none" : "rounded-2xl";
9513
- const [showEstimates, setShowEstimates] = React8.useState(false);
9514
- const [showPriceInfo, setShowPriceInfo] = React8.useState(false);
10148
+ const [showEstimates, setShowEstimates] = React28.useState(false);
10149
+ const [showPriceInfo, setShowPriceInfo] = React28.useState(false);
9515
10150
  if (variant === "compact") {
9516
10151
  const showOverlay = showPriceInfo && (!!priceInfo || !!currencyEstimates && currencyEstimates.length > 0);
9517
10152
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
@@ -9795,8 +10430,7 @@ var VARIANT = {
9795
10430
  mobileLink: "text-white hover:text-primary-400 border-b border-white/10",
9796
10431
  mobileSub: "text-white/70 font-bold hover:text-primary-400 border-b border-white/8",
9797
10432
  mobileLangActive: "text-primary-400 font-semibold",
9798
- mobileLangIdle: "text-white/40 hover:text-primary-400",
9799
- logoBlend: "mix-blend-screen"
10433
+ mobileLangIdle: "text-white/40 hover:text-primary-400"
9800
10434
  },
9801
10435
  white: {
9802
10436
  header: "bg-white border-b border-border shadow-sm",
@@ -9812,8 +10446,7 @@ var VARIANT = {
9812
10446
  mobileLink: "text-foreground/80 hover:text-foreground border-b border-border",
9813
10447
  mobileSub: "text-foreground/50 font-bold hover:text-foreground border-b border-border/40",
9814
10448
  mobileLangActive: "text-primary font-semibold",
9815
- mobileLangIdle: "text-muted-foreground hover:text-foreground",
9816
- logoBlend: "invert mix-blend-multiply"
10449
+ mobileLangIdle: "text-muted-foreground hover:text-foreground"
9817
10450
  },
9818
10451
  dark: {
9819
10452
  header: "bg-neutral-950 border-b border-white/10",
@@ -9829,8 +10462,7 @@ var VARIANT = {
9829
10462
  mobileLink: "text-white/80 hover:text-white border-b border-white/8",
9830
10463
  mobileSub: "text-white/45 font-bold hover:text-white border-b border-white/5",
9831
10464
  mobileLangActive: "text-white font-semibold",
9832
- mobileLangIdle: "text-white/35 hover:text-white/60",
9833
- logoBlend: "mix-blend-screen"
10465
+ mobileLangIdle: "text-white/35 hover:text-white/60"
9834
10466
  }
9835
10467
  };
9836
10468
  var DEFAULT_HEADER_LINKS = [
@@ -9940,7 +10572,9 @@ function LangDropdown({
9940
10572
  function SiteHeader({
9941
10573
  variant = "transparent",
9942
10574
  links = DEFAULT_HEADER_LINKS,
9943
- logoSrc = "/logo-planetaexo.png",
10575
+ logoSrcLight = "/logo-planetaexo-white.png",
10576
+ logoSrcDark = "/logo-planetaexo-green.png",
10577
+ logoSrc,
9944
10578
  logoAlt = "Planeta Exo",
9945
10579
  languages = DEFAULT_LANGUAGES,
9946
10580
  currentLanguage = "EN",
@@ -9951,14 +10585,15 @@ function SiteHeader({
9951
10585
  className
9952
10586
  }) {
9953
10587
  const t = VARIANT[variant];
9954
- const [openMenu, setOpenMenu] = React8.useState(null);
9955
- const [langOpen, setLangOpen] = React8.useState(false);
9956
- const [mobileOpen, setMobileOpen] = React8.useState(false);
9957
- const [openMobileSection, setOpenMobileSection] = React8.useState(null);
9958
- const [activeLang, setActiveLang] = React8.useState(currentLanguage);
10588
+ const resolvedLogo = logoSrc != null ? logoSrc : variant === "white" ? logoSrcDark : logoSrcLight;
10589
+ const [openMenu, setOpenMenu] = React28.useState(null);
10590
+ const [langOpen, setLangOpen] = React28.useState(false);
10591
+ const [mobileOpen, setMobileOpen] = React28.useState(false);
10592
+ const [openMobileSection, setOpenMobileSection] = React28.useState(null);
10593
+ const [activeLang, setActiveLang] = React28.useState(currentLanguage);
9959
10594
  const toggleMobileSection = (label) => setOpenMobileSection((prev) => prev === label ? null : label);
9960
- const menuCloseTimer = React8.useRef(void 0);
9961
- const langCloseTimer = React8.useRef(void 0);
10595
+ const menuCloseTimer = React28.useRef(void 0);
10596
+ const langCloseTimer = React28.useRef(void 0);
9962
10597
  const handleMenuEnter = (label) => {
9963
10598
  clearTimeout(menuCloseTimer.current);
9964
10599
  setOpenMenu(label);
@@ -9979,7 +10614,7 @@ function SiteHeader({
9979
10614
  setOpenMenu(null);
9980
10615
  setLangOpen(false);
9981
10616
  };
9982
- React8.useEffect(() => () => {
10617
+ React28.useEffect(() => () => {
9983
10618
  clearTimeout(menuCloseTimer.current);
9984
10619
  clearTimeout(langCloseTimer.current);
9985
10620
  }, []);
@@ -9999,17 +10634,41 @@ function SiteHeader({
9999
10634
  className
10000
10635
  ),
10001
10636
  children: [
10002
- 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" }),
10637
+ 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" }),
10003
10638
  /* @__PURE__ */ jsxs("div", { className: "relative flex items-center gap-2 px-6 sm:px-10 h-[72px]", children: [
10004
- /* @__PURE__ */ jsx("a", { href: "#", className: "shrink-0 flex items-center mr-4", children: /* @__PURE__ */ jsx(
10005
- "img",
10639
+ /* @__PURE__ */ jsx(
10640
+ "button",
10006
10641
  {
10007
- src: logoSrc,
10008
- alt: logoAlt,
10009
- className: cn("h-11 w-auto select-none", t.logoBlend),
10010
- draggable: false
10642
+ type: "button",
10643
+ onClick: () => setMobileOpen(true),
10644
+ "aria-label": "Open menu",
10645
+ className: cn(
10646
+ "flex lg:hidden h-9 w-9 items-center justify-center rounded-full transition-colors -ml-1.5",
10647
+ t.mobileTrigger
10648
+ ),
10649
+ children: /* @__PURE__ */ jsx(MenuIcon, { className: "h-[18px] w-[18px]" })
10011
10650
  }
10012
- ) }),
10651
+ ),
10652
+ /* @__PURE__ */ jsx(
10653
+ "a",
10654
+ {
10655
+ href: "#",
10656
+ className: cn(
10657
+ "shrink-0 flex items-center",
10658
+ "absolute left-1/2 -translate-x-1/2",
10659
+ "lg:static lg:translate-x-0 lg:mr-4"
10660
+ ),
10661
+ children: /* @__PURE__ */ jsx(
10662
+ "img",
10663
+ {
10664
+ src: resolvedLogo,
10665
+ alt: logoAlt,
10666
+ className: "h-14 w-auto select-none",
10667
+ draggable: false
10668
+ }
10669
+ )
10670
+ }
10671
+ ),
10013
10672
  /* @__PURE__ */ jsx("nav", { className: "hidden lg:flex items-center gap-0.5 mx-auto", children: links.map((link) => {
10014
10673
  var _a, _b;
10015
10674
  const hasDropdown = !!((_a = link.items) == null ? void 0 : _a.length);
@@ -10133,19 +10792,6 @@ function SiteHeader({
10133
10792
  ),
10134
10793
  children: /* @__PURE__ */ jsx(UserIcon, { className: "h-[18px] w-[18px]" })
10135
10794
  }
10136
- ),
10137
- /* @__PURE__ */ jsx(
10138
- "button",
10139
- {
10140
- type: "button",
10141
- onClick: () => setMobileOpen(true),
10142
- "aria-label": "Open menu",
10143
- className: cn(
10144
- "flex lg:hidden h-9 w-9 items-center justify-center rounded-full transition-colors ml-0.5",
10145
- t.mobileTrigger
10146
- ),
10147
- children: /* @__PURE__ */ jsx(MenuIcon, { className: "h-[18px] w-[18px]" })
10148
- }
10149
10795
  )
10150
10796
  ] })
10151
10797
  ] }),
@@ -10161,9 +10807,9 @@ function SiteHeader({
10161
10807
  /* @__PURE__ */ jsx("a", { href: "#", className: "shrink-0 flex items-center", onClick: () => setMobileOpen(false), children: /* @__PURE__ */ jsx(
10162
10808
  "img",
10163
10809
  {
10164
- src: logoSrc,
10810
+ src: resolvedLogo,
10165
10811
  alt: logoAlt,
10166
- className: cn("h-11 w-auto select-none", t.logoBlend),
10812
+ className: "h-14 w-auto select-none",
10167
10813
  draggable: false
10168
10814
  }
10169
10815
  ) }),
@@ -10244,7 +10890,7 @@ function SiteHeader({
10244
10890
  ), children: [
10245
10891
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: languages.map((lang, i) => {
10246
10892
  const isActive = lang.code === activeLang;
10247
- return /* @__PURE__ */ jsxs(React8.Fragment, { children: [
10893
+ return /* @__PURE__ */ jsxs(React28.Fragment, { children: [
10248
10894
  i > 0 && /* @__PURE__ */ jsx("span", { className: cn(
10249
10895
  "text-xs select-none",
10250
10896
  variant === "white" ? "text-border" : "text-white/15"
@@ -10306,8 +10952,8 @@ function SiteHeader({
10306
10952
  );
10307
10953
  }
10308
10954
  function ThemeToggle({ className }) {
10309
- const [dark, setDark] = React8.useState(false);
10310
- React8.useEffect(() => {
10955
+ const [dark, setDark] = React28.useState(false);
10956
+ React28.useEffect(() => {
10311
10957
  const saved = localStorage.getItem("theme");
10312
10958
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
10313
10959
  const isDark = saved === "dark" || !saved && prefersDark;
@@ -10336,6 +10982,44 @@ function ThemeToggle({ className }) {
10336
10982
  }
10337
10983
  );
10338
10984
  }
10985
+ var chipVariants = cva(
10986
+ "inline-flex items-center rounded-full font-ui font-medium transition-colors whitespace-nowrap",
10987
+ {
10988
+ variants: {
10989
+ variant: {
10990
+ 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",
10991
+ solid: "bg-muted text-foreground/80 hover:bg-primary hover:text-primary-foreground",
10992
+ outline: "border border-border text-foreground/80 hover:bg-primary hover:border-primary hover:text-primary-foreground"
10993
+ },
10994
+ size: {
10995
+ sm: "px-2.5 py-0.5 text-[11px] leading-5",
10996
+ md: "px-3 py-1 text-xs leading-5",
10997
+ lg: "px-4 py-1.5 text-sm leading-5"
10998
+ }
10999
+ },
11000
+ defaultVariants: {
11001
+ variant: "glass",
11002
+ size: "sm"
11003
+ }
11004
+ }
11005
+ );
11006
+ var Chip = React28.forwardRef(function Chip2(_a, ref) {
11007
+ var _b = _a, { className, variant, size, href, children } = _b, props = __objRest(_b, ["className", "variant", "size", "href", "children"]);
11008
+ const classes = cn(chipVariants({ variant, size }), className);
11009
+ if (href) {
11010
+ return /* @__PURE__ */ jsx(
11011
+ "a",
11012
+ __spreadProps(__spreadValues({
11013
+ ref,
11014
+ href,
11015
+ className: classes
11016
+ }, props), {
11017
+ children
11018
+ })
11019
+ );
11020
+ }
11021
+ return /* @__PURE__ */ jsx("span", __spreadProps(__spreadValues({ ref, className: classes }, props), { children }));
11022
+ });
10339
11023
  function CalendarIcon6() {
10340
11024
  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: [
10341
11025
  /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
@@ -10386,19 +11070,125 @@ var statusConfig = {
10386
11070
  icon: /* @__PURE__ */ jsx(TrendingIcon, {})
10387
11071
  }
10388
11072
  };
10389
- function TripCard({
10390
- image,
10391
- imageAlt = "",
10392
- status,
10393
- nights,
10394
- period,
10395
- title,
10396
- description,
10397
- cta,
10398
- price,
10399
- size = "md",
10400
- className
10401
- }) {
11073
+ function HeartIcon({ filled = false }) {
11074
+ return /* @__PURE__ */ jsx(
11075
+ "svg",
11076
+ {
11077
+ width: "16",
11078
+ height: "16",
11079
+ viewBox: "0 0 24 24",
11080
+ fill: filled ? "currentColor" : "none",
11081
+ stroke: "currentColor",
11082
+ strokeWidth: "2",
11083
+ strokeLinecap: "round",
11084
+ strokeLinejoin: "round",
11085
+ 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" })
11086
+ }
11087
+ );
11088
+ }
11089
+ function TripCardEditorial(props) {
11090
+ const {
11091
+ image,
11092
+ imageAlt = "",
11093
+ title,
11094
+ description,
11095
+ nights,
11096
+ price,
11097
+ href,
11098
+ className,
11099
+ favoritable,
11100
+ favorited: favoritedProp,
11101
+ onFavoriteToggle,
11102
+ location,
11103
+ difficulty,
11104
+ tag
11105
+ } = props;
11106
+ const [internalFav, setInternalFav] = React28.useState(false);
11107
+ const favorited = favoritedProp != null ? favoritedProp : internalFav;
11108
+ const handleFav = (e) => {
11109
+ e.preventDefault();
11110
+ e.stopPropagation();
11111
+ const next = !favorited;
11112
+ if (favoritedProp === void 0) setInternalFav(next);
11113
+ onFavoriteToggle == null ? void 0 : onFavoriteToggle(next);
11114
+ };
11115
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
11116
+ /* @__PURE__ */ jsxs("div", { className: "relative aspect-[4/3] overflow-hidden bg-muted", children: [
11117
+ /* @__PURE__ */ jsx(
11118
+ "img",
11119
+ {
11120
+ src: image,
11121
+ alt: imageAlt,
11122
+ loading: "lazy",
11123
+ className: "absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
11124
+ }
11125
+ ),
11126
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/85 via-black/20 to-transparent" }),
11127
+ 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 }) }),
11128
+ favoritable && /* @__PURE__ */ jsx(
11129
+ "button",
11130
+ {
11131
+ type: "button",
11132
+ "aria-label": favorited ? "Remove from favorites" : "Add to favorites",
11133
+ "aria-pressed": favorited,
11134
+ onClick: handleFav,
11135
+ className: cn(
11136
+ "absolute top-3 right-3 flex h-9 w-9 items-center justify-center rounded-full",
11137
+ "border border-white/15 bg-black/30 backdrop-blur-sm",
11138
+ "transition-colors hover:bg-white/10 hover:border-white/50",
11139
+ favorited ? "text-white" : "text-white/85 hover:text-white"
11140
+ ),
11141
+ children: /* @__PURE__ */ jsx(HeartIcon, { filled: favorited })
11142
+ }
11143
+ ),
11144
+ /* @__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 }) })
11145
+ ] }),
11146
+ (description || price || nights || location || difficulty) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 bg-card p-6", children: [
11147
+ (location || difficulty) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
11148
+ location ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-foreground/85", children: [
11149
+ /* @__PURE__ */ jsx(MapPinIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
11150
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-ui font-semibold", children: location })
11151
+ ] }) : /* @__PURE__ */ jsx("span", {}),
11152
+ difficulty && /* @__PURE__ */ jsx(Chip, { variant: "outline", size: "sm", className: "capitalize text-muted-foreground", children: difficulty })
11153
+ ] }),
11154
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-3", children: description }),
11155
+ (nights || price) && /* @__PURE__ */ jsxs("div", { className: "mt-auto flex items-center justify-between gap-3", children: [
11156
+ nights ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-foreground/80", children: [
11157
+ /* @__PURE__ */ jsx(MoonIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
11158
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-ui font-semibold", children: [
11159
+ nights,
11160
+ " ",
11161
+ nights === 1 ? "night" : "nights"
11162
+ ] })
11163
+ ] }) : /* @__PURE__ */ jsx("span", {}),
11164
+ price && /* @__PURE__ */ jsx("p", { className: "text-base font-bold text-foreground font-ui", children: price })
11165
+ ] })
11166
+ ] })
11167
+ ] });
11168
+ const baseClasses = cn(
11169
+ "group relative flex flex-col overflow-hidden rounded-2xl bg-card border border-border/50",
11170
+ "shadow-md transition-shadow duration-300 hover:shadow-xl",
11171
+ className
11172
+ );
11173
+ return href ? /* @__PURE__ */ jsx("a", { href, className: baseClasses, "aria-label": title, children: body }) : /* @__PURE__ */ jsx("div", { className: baseClasses, children: body });
11174
+ }
11175
+ function TripCard(props) {
11176
+ if (props.variant === "editorial") {
11177
+ return /* @__PURE__ */ jsx(TripCardEditorial, __spreadValues({}, props));
11178
+ }
11179
+ const {
11180
+ image,
11181
+ imageAlt = "",
11182
+ status,
11183
+ nights,
11184
+ period,
11185
+ title,
11186
+ description,
11187
+ cta,
11188
+ price,
11189
+ size = "md",
11190
+ className
11191
+ } = props;
10402
11192
  const s = sizeConfig[size];
10403
11193
  const statusInfo = status ? statusConfig[status] : null;
10404
11194
  const meta = [
@@ -10458,7 +11248,7 @@ function TripCard({
10458
11248
  );
10459
11249
  }
10460
11250
  function useHlsVideo(videoRef, src) {
10461
- React8.useEffect(() => {
11251
+ React28.useEffect(() => {
10462
11252
  if (!src || !videoRef.current) return;
10463
11253
  const video = videoRef.current;
10464
11254
  if (!src.includes(".m3u8")) return;
@@ -10495,17 +11285,18 @@ function TripHeader({
10495
11285
  destination,
10496
11286
  duration,
10497
11287
  tagline,
11288
+ chips,
10498
11289
  belowMeta,
10499
11290
  siteHeader,
10500
11291
  uiVariant = "v1",
10501
11292
  className
10502
11293
  }) {
10503
11294
  var _a;
10504
- const [heroIndex, setHeroIndex] = React8.useState(0);
10505
- const [videoReady, setVideoReady] = React8.useState(false);
10506
- const videoRef = React8.useRef(null);
11295
+ const [heroIndex, setHeroIndex] = React28.useState(0);
11296
+ const [videoReady, setVideoReady] = React28.useState(false);
11297
+ const videoRef = React28.useRef(null);
10507
11298
  const isHls = !!(videoUrl == null ? void 0 : videoUrl.includes(".m3u8"));
10508
- const validImages = React8.useMemo(
11299
+ const validImages = React28.useMemo(
10509
11300
  () => images.map((u) => u == null ? void 0 : u.trim()).filter(Boolean),
10510
11301
  [images]
10511
11302
  );
@@ -10520,7 +11311,7 @@ function TripHeader({
10520
11311
  const nights = duration ? (_a = duration.nights) != null ? _a : Math.max(duration.days - 1, 1) : null;
10521
11312
  const hasMeta = !!(destination || duration);
10522
11313
  useHlsVideo(videoRef, isHls ? videoUrl : void 0);
10523
- React8.useEffect(() => {
11314
+ React28.useEffect(() => {
10524
11315
  if (!videoUrl) return;
10525
11316
  const el = videoRef.current;
10526
11317
  if (!el) return;
@@ -10654,15 +11445,15 @@ function TripHeader({
10654
11445
  ]
10655
11446
  }
10656
11447
  ),
10657
- /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-5xl px-4 sm:px-6", children: /* @__PURE__ */ jsxs(
11448
+ /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8", children: /* @__PURE__ */ jsxs(
10658
11449
  "div",
10659
11450
  {
10660
11451
  className: cn(
10661
11452
  "relative z-10 pb-10",
10662
- siteHeader ? "-mt-44" : "-mt-36"
11453
+ chips && chips.length > 0 ? siteHeader ? "-mt-[200px] sm:-mt-[214px]" : "-mt-[168px] sm:-mt-[182px]" : siteHeader ? "-mt-44" : "-mt-36"
10663
11454
  ),
10664
11455
  children: [
10665
- 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: [
11456
+ 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: [
10666
11457
  i > 0 && /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 text-white/50 shrink-0" }),
10667
11458
  /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 font-ui hover:text-white/90 cursor-default", children: crumb.label })
10668
11459
  ] }, i)) }),
@@ -10688,6 +11479,7 @@ function TripHeader({
10688
11479
  ] })
10689
11480
  ] })
10690
11481
  ] }) : tagline ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm sm:text-base text-white/80 font-ui", children: tagline }) : null,
11482
+ 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)) }),
10691
11483
  belowMeta && /* @__PURE__ */ jsx("div", { className: "mt-3", children: belowMeta })
10692
11484
  ]
10693
11485
  }
@@ -10696,6 +11488,427 @@ function TripHeader({
10696
11488
  }
10697
11489
  );
10698
11490
  }
11491
+ var VARIANT2 = {
11492
+ light: {
11493
+ footer: "bg-primary-50 text-foreground",
11494
+ heading: "text-foreground",
11495
+ body: "text-foreground/75",
11496
+ muted: "text-foreground/60",
11497
+ link: "text-foreground/85 hover:text-primary-800 underline decoration-foreground/25 underline-offset-4 hover:decoration-primary-800",
11498
+ badgeStroke: "text-foreground/80",
11499
+ /** Inverts white logos so they read on the light background. */
11500
+ badgeFilter: "[filter:invert(1)_brightness(0.2)]",
11501
+ socialBtn: "bg-foreground text-white hover:bg-primary-800",
11502
+ langTrigger: "text-foreground hover:bg-white",
11503
+ langOpen: "text-foreground bg-white",
11504
+ langChevron: "text-foreground/40",
11505
+ bottomBar: "border-t border-foreground/10",
11506
+ bottomText: "text-foreground/60",
11507
+ bottomLink: "text-foreground/80 hover:text-foreground underline decoration-foreground/20 underline-offset-4 hover:decoration-foreground"
11508
+ },
11509
+ dark: {
11510
+ footer: "bg-brand-charcoal text-white",
11511
+ heading: "text-white",
11512
+ body: "text-white/75",
11513
+ muted: "text-white/55",
11514
+ link: "text-white/85 hover:text-primary-400 underline decoration-white/20 underline-offset-4 hover:decoration-primary-400",
11515
+ badgeStroke: "text-white",
11516
+ badgeFilter: "",
11517
+ socialBtn: "bg-white/10 text-white hover:bg-primary-400 hover:text-primary-900",
11518
+ langTrigger: "text-white/85 hover:bg-white/10",
11519
+ langOpen: "text-white bg-white/10",
11520
+ langChevron: "text-white/40",
11521
+ bottomBar: "border-t border-white/10",
11522
+ bottomText: "text-white/55",
11523
+ bottomLink: "text-white/80 hover:text-white underline decoration-white/20 underline-offset-4 hover:decoration-white"
11524
+ }
11525
+ };
11526
+ var DEFAULT_FOOTER_THEMES = [
11527
+ { label: "Roadtrips", href: "#" },
11528
+ { label: "Saf\xE1ri", href: "#" },
11529
+ { label: "Trilhas", href: "#" },
11530
+ { label: "Caiaque & Canoa", href: "#" },
11531
+ { label: "Aurora boreal", href: "#" },
11532
+ { label: "Micro-aventuras", href: "#" },
11533
+ { label: "Packrafting", href: "#" },
11534
+ { label: "Glamping", href: "#" },
11535
+ { label: "Surf", href: "#" },
11536
+ { label: "Viagens em fam\xEDlia", href: "#" }
11537
+ ];
11538
+ var DEFAULT_FOOTER_DESTINATIONS = [
11539
+ { label: "Brasil", href: "#" },
11540
+ { label: "Patag\xF4nia", href: "#" },
11541
+ { label: "Argentina", href: "#" },
11542
+ { label: "Chile", href: "#" },
11543
+ { label: "Bol\xEDvia", href: "#" },
11544
+ { label: "Peru", href: "#" },
11545
+ { label: "Equador", href: "#" },
11546
+ { label: "Col\xF4mbia", href: "#" },
11547
+ { label: "Costa Rica", href: "#" },
11548
+ { label: "Filipinas", href: "#" }
11549
+ ];
11550
+ var DEFAULT_FOOTER_PAGES = [
11551
+ { label: "Contato", href: "#" },
11552
+ { label: "Pol\xEDtica de cookies", href: "#" },
11553
+ { label: "FAQ", href: "#" },
11554
+ { label: "Sobre n\xF3s", href: "#" }
11555
+ ];
11556
+ var DEFAULT_FOOTER_LEGAL = [
11557
+ { label: "Termos e condi\xE7\xF5es", href: "#" },
11558
+ { label: "Mapa do site", href: "#" }
11559
+ ];
11560
+ var DEFAULT_FOOTER_LANGUAGES = [
11561
+ { code: "PT", label: "Portugu\xEAs" },
11562
+ { code: "EN", label: "English" },
11563
+ { code: "NL", label: "Nederlands" },
11564
+ { code: "DE", label: "Deutsch" },
11565
+ { code: "FR", label: "Fran\xE7ais" },
11566
+ { code: "ES", label: "Espa\xF1ol" }
11567
+ ];
11568
+ var DEFAULT_FOOTER_SOCIALS = [
11569
+ { network: "facebook", href: "#" },
11570
+ { network: "instagram", href: "#" },
11571
+ { network: "linkedin", href: "#" }
11572
+ ];
11573
+ var DEFAULT_FOOTER_BADGES = [
11574
+ {
11575
+ src: "https://static.planetaexo.com/trips/wp-content/uploads/2025/04/member_of_TLR-white-1.png",
11576
+ alt: "Member of The Long Run",
11577
+ height: 80
11578
+ },
11579
+ {
11580
+ src: "https://static.planetaexo.com/trips/wp-content/uploads/2025/04/atta-member_white.png",
11581
+ alt: "Member \xB7 Adventure Travel Trade Association",
11582
+ height: 56
11583
+ }
11584
+ ];
11585
+ var SOCIAL_ICON = {
11586
+ facebook: FacebookIcon,
11587
+ instagram: InstagramIcon,
11588
+ linkedin: LinkedinIcon,
11589
+ youtube: YoutubeIcon,
11590
+ twitter: TwitterIcon
11591
+ };
11592
+ var SOCIAL_LABEL = {
11593
+ facebook: "Facebook",
11594
+ instagram: "Instagram",
11595
+ linkedin: "LinkedIn",
11596
+ youtube: "YouTube",
11597
+ twitter: "Twitter"
11598
+ };
11599
+ function ColumnHeading({
11600
+ children,
11601
+ className
11602
+ }) {
11603
+ return /* @__PURE__ */ jsx(
11604
+ "h3",
11605
+ {
11606
+ className: cn(
11607
+ "font-heading font-black text-base mb-5 tracking-tight",
11608
+ className
11609
+ ),
11610
+ children
11611
+ }
11612
+ );
11613
+ }
11614
+ function LanguagePicker({
11615
+ variant,
11616
+ languages,
11617
+ currentLanguage,
11618
+ onChange
11619
+ }) {
11620
+ var _a;
11621
+ const t = VARIANT2[variant];
11622
+ const [open, setOpen] = React28.useState(false);
11623
+ const ref = React28.useRef(null);
11624
+ const active = (_a = languages.find((l) => l.code === currentLanguage)) != null ? _a : languages[0];
11625
+ React28.useEffect(() => {
11626
+ if (!open) return;
11627
+ const onDocClick = (e) => {
11628
+ if (ref.current && !ref.current.contains(e.target)) {
11629
+ setOpen(false);
11630
+ }
11631
+ };
11632
+ document.addEventListener("mousedown", onDocClick);
11633
+ return () => document.removeEventListener("mousedown", onDocClick);
11634
+ }, [open]);
11635
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative inline-block", children: [
11636
+ /* @__PURE__ */ jsxs(
11637
+ "button",
11638
+ {
11639
+ type: "button",
11640
+ onClick: () => setOpen((v) => !v),
11641
+ "aria-haspopup": "listbox",
11642
+ "aria-expanded": open,
11643
+ className: cn(
11644
+ "inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-ui transition-colors",
11645
+ t.langTrigger,
11646
+ open && t.langOpen
11647
+ ),
11648
+ children: [
11649
+ active == null ? void 0 : active.code,
11650
+ /* @__PURE__ */ jsx(
11651
+ ChevronDownIcon,
11652
+ {
11653
+ className: cn(
11654
+ "h-3 w-3 transition-transform duration-150",
11655
+ t.langChevron,
11656
+ open && "rotate-180"
11657
+ )
11658
+ }
11659
+ )
11660
+ ]
11661
+ }
11662
+ ),
11663
+ open && /* @__PURE__ */ jsx(
11664
+ "div",
11665
+ {
11666
+ role: "listbox",
11667
+ 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",
11668
+ children: languages.map((lang) => {
11669
+ const isActive = lang.code === (active == null ? void 0 : active.code);
11670
+ return /* @__PURE__ */ jsxs(
11671
+ "button",
11672
+ {
11673
+ type: "button",
11674
+ role: "option",
11675
+ "aria-selected": isActive,
11676
+ onClick: () => {
11677
+ onChange == null ? void 0 : onChange(lang.code);
11678
+ setOpen(false);
11679
+ },
11680
+ className: cn(
11681
+ "flex items-center gap-3 w-full px-5 py-2.5 text-sm font-ui text-left transition-colors hover:bg-muted",
11682
+ isActive ? "text-primary font-semibold" : "text-foreground"
11683
+ ),
11684
+ children: [
11685
+ /* @__PURE__ */ jsx("span", { className: "font-semibold w-8 shrink-0", children: lang.code }),
11686
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: lang.label })
11687
+ ]
11688
+ },
11689
+ lang.code
11690
+ );
11691
+ })
11692
+ }
11693
+ )
11694
+ ] });
11695
+ }
11696
+ function SiteFooter({
11697
+ variant = "dark",
11698
+ brandTitle = "PlanetaEXO",
11699
+ logoSrcLight = "/logo-planetaexo-white.png",
11700
+ logoSrcDark = "/logo-planetaexo-green.png",
11701
+ logoSrc,
11702
+ logoAlt = "PlanetaEXO",
11703
+ logoHref = "#",
11704
+ brandDescription = /* @__PURE__ */ jsxs(Fragment, { children: [
11705
+ "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.",
11706
+ " ",
11707
+ /* @__PURE__ */ jsx(
11708
+ "a",
11709
+ {
11710
+ href: "#",
11711
+ className: "font-bold underline decoration-current/30 underline-offset-4 hover:decoration-current",
11712
+ children: "Pol\xEDtica de privacidade"
11713
+ }
11714
+ )
11715
+ ] }),
11716
+ badges = DEFAULT_FOOTER_BADGES,
11717
+ languages = DEFAULT_FOOTER_LANGUAGES,
11718
+ currentLanguage = "PT",
11719
+ onLanguageChange,
11720
+ address = {
11721
+ title: "Basecamp S\xE3o Paulo",
11722
+ lines: ["Av. Paulista, 1234", "01310-100 S\xE3o Paulo \xB7 Brasil"]
11723
+ },
11724
+ phone = "+55 11 9999-0000",
11725
+ email = "ola@planetaexo.com",
11726
+ socials = DEFAULT_FOOTER_SOCIALS,
11727
+ themesTitle = "Temas",
11728
+ themes = DEFAULT_FOOTER_THEMES,
11729
+ destinationsTitle = "Destinos",
11730
+ destinations = DEFAULT_FOOTER_DESTINATIONS,
11731
+ destinationsMore = { label: "Ver todos os destinos", href: "#" },
11732
+ pagesTitle = "P\xE1ginas",
11733
+ pages = DEFAULT_FOOTER_PAGES,
11734
+ cta = {
11735
+ title: "Colaborar?",
11736
+ label: "parceiros@planetaexo.com",
11737
+ href: "mailto:parceiros@planetaexo.com"
11738
+ },
11739
+ copyright,
11740
+ legalLinks = DEFAULT_FOOTER_LEGAL,
11741
+ className
11742
+ }) {
11743
+ const t = VARIANT2[variant];
11744
+ const resolvedLogo = logoSrc != null ? logoSrc : variant === "light" ? logoSrcDark : logoSrcLight;
11745
+ const year = (/* @__PURE__ */ new Date()).getFullYear();
11746
+ const copy = copyright != null ? copyright : `\xA9 ${year} ${brandTitle}. Todos os direitos reservados.`;
11747
+ return /* @__PURE__ */ jsxs("footer", { className: cn(t.footer, className), children: [
11748
+ /* @__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: [
11749
+ /* @__PURE__ */ jsxs("div", { className: "lg:col-span-4 space-y-6", children: [
11750
+ /* @__PURE__ */ jsx(
11751
+ "a",
11752
+ {
11753
+ href: logoHref,
11754
+ className: "inline-flex items-center",
11755
+ "aria-label": logoAlt,
11756
+ children: /* @__PURE__ */ jsx(
11757
+ "img",
11758
+ {
11759
+ src: resolvedLogo,
11760
+ alt: logoAlt,
11761
+ className: "h-16 w-auto select-none",
11762
+ draggable: false
11763
+ }
11764
+ )
11765
+ }
11766
+ ),
11767
+ brandDescription && /* @__PURE__ */ jsx("p", { className: cn("font-sans text-sm leading-relaxed", t.body), children: brandDescription }),
11768
+ address && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11769
+ /* @__PURE__ */ jsx("h4", { className: cn("font-heading font-black text-base", t.heading), children: address.title }),
11770
+ /* @__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)) })
11771
+ ] }),
11772
+ (phone || email) && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 text-sm font-ui font-bold", children: [
11773
+ phone && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("a", { href: `tel:${phone.replace(/\s+/g, "")}`, className: t.link, children: phone }) }),
11774
+ email && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("a", { href: `mailto:${email}`, className: t.link, children: email }) })
11775
+ ] }),
11776
+ socials.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: socials.map((s) => {
11777
+ var _a;
11778
+ const Icon = SOCIAL_ICON[s.network];
11779
+ const label = (_a = s.label) != null ? _a : SOCIAL_LABEL[s.network];
11780
+ return /* @__PURE__ */ jsx(
11781
+ "a",
11782
+ {
11783
+ href: s.href,
11784
+ "aria-label": label,
11785
+ className: cn(
11786
+ "flex h-9 w-9 items-center justify-center rounded-full transition-colors",
11787
+ t.socialBtn
11788
+ ),
11789
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 2.25 })
11790
+ },
11791
+ s.network + s.href
11792
+ );
11793
+ }) }),
11794
+ badges && badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-5 pt-2", children: badges.map((b, i) => {
11795
+ var _a, _b;
11796
+ const content = (_b = b.node) != null ? _b : /* @__PURE__ */ jsx(
11797
+ "img",
11798
+ {
11799
+ src: b.src,
11800
+ alt: b.alt,
11801
+ style: { height: (_a = b.height) != null ? _a : 56 },
11802
+ className: "block w-auto object-contain",
11803
+ draggable: false
11804
+ }
11805
+ );
11806
+ const wrapper = /* @__PURE__ */ jsx(
11807
+ "span",
11808
+ {
11809
+ className: cn(
11810
+ "inline-flex items-center",
11811
+ t.badgeStroke,
11812
+ t.badgeFilter
11813
+ ),
11814
+ children: content
11815
+ }
11816
+ );
11817
+ return b.href ? /* @__PURE__ */ jsx(
11818
+ "a",
11819
+ {
11820
+ href: b.href,
11821
+ "aria-label": b.alt,
11822
+ className: "hover:opacity-80 transition-opacity",
11823
+ children: wrapper
11824
+ },
11825
+ b.alt + i
11826
+ ) : /* @__PURE__ */ jsx(React28.Fragment, { children: wrapper }, b.alt + i);
11827
+ }) })
11828
+ ] }),
11829
+ themes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-3", children: [
11830
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: themesTitle }),
11831
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: themes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11832
+ "a",
11833
+ {
11834
+ href: c.href,
11835
+ className: cn("text-sm font-ui font-bold", t.link),
11836
+ children: c.label
11837
+ }
11838
+ ) }, c.label)) })
11839
+ ] }),
11840
+ destinations.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-3", children: [
11841
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: destinationsTitle }),
11842
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: destinations.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11843
+ "a",
11844
+ {
11845
+ href: c.href,
11846
+ className: cn("text-sm font-ui font-bold", t.link),
11847
+ children: c.label
11848
+ }
11849
+ ) }, c.label)) }),
11850
+ destinationsMore && /* @__PURE__ */ jsxs(
11851
+ "a",
11852
+ {
11853
+ href: destinationsMore.href,
11854
+ className: cn(
11855
+ "inline-flex items-center gap-1.5 mt-5 text-sm font-ui font-bold",
11856
+ t.link
11857
+ ),
11858
+ children: [
11859
+ destinationsMore.label,
11860
+ /* @__PURE__ */ jsx(ArrowRightIcon, { className: "h-3.5 w-3.5 no-underline" })
11861
+ ]
11862
+ }
11863
+ )
11864
+ ] }),
11865
+ /* @__PURE__ */ jsxs("div", { className: "lg:col-span-2 space-y-8", children: [
11866
+ pages.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
11867
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: pagesTitle }),
11868
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: pages.map((p) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11869
+ "a",
11870
+ {
11871
+ href: p.href,
11872
+ className: cn("text-sm font-ui font-bold", t.link),
11873
+ children: p.label
11874
+ }
11875
+ ) }, p.label)) })
11876
+ ] }),
11877
+ cta && /* @__PURE__ */ jsxs("div", { children: [
11878
+ /* @__PURE__ */ jsx(ColumnHeading, { className: t.heading, children: cta.title }),
11879
+ /* @__PURE__ */ jsx(
11880
+ "a",
11881
+ {
11882
+ href: cta.href,
11883
+ className: cn("text-sm font-ui font-bold break-all", t.link),
11884
+ children: cta.label
11885
+ }
11886
+ )
11887
+ ] })
11888
+ ] })
11889
+ ] }) }),
11890
+ /* @__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: [
11891
+ languages.length > 0 && /* @__PURE__ */ jsx(
11892
+ LanguagePicker,
11893
+ {
11894
+ variant,
11895
+ languages,
11896
+ currentLanguage,
11897
+ onChange: onLanguageChange
11898
+ }
11899
+ ),
11900
+ /* @__PURE__ */ jsx("p", { className: cn("text-xs font-ui", t.bottomText), children: copy }),
11901
+ 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(
11902
+ "a",
11903
+ {
11904
+ href: l.href,
11905
+ className: cn("text-xs font-ui font-bold", t.bottomLink),
11906
+ children: l.label
11907
+ }
11908
+ ) }, l.label)) })
11909
+ ] }) })
11910
+ ] });
11911
+ }
10699
11912
  function Stars({ count = 5 }) {
10700
11913
  return /* @__PURE__ */ jsx("span", { className: "flex gap-0.5", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(
10701
11914
  StarIcon,
@@ -10739,9 +11952,9 @@ function TripPage({
10739
11952
  images,
10740
11953
  videoUrl,
10741
11954
  breadcrumb,
11955
+ chips,
10742
11956
  highlights,
10743
- infoGroups,
10744
- keyInfo,
11957
+ howToGetThere,
10745
11958
  recommendedFor,
10746
11959
  overview,
10747
11960
  overviewHighlights,
@@ -10759,6 +11972,7 @@ function TripPage({
10759
11972
  meetingPoints,
10760
11973
  meetingPoint,
10761
11974
  faqs,
11975
+ faqInitialCount = 5,
10762
11976
  sectionIcons,
10763
11977
  reviews,
10764
11978
  trustpilot,
@@ -10778,11 +11992,12 @@ function TripPage({
10778
11992
  features,
10779
11993
  className
10780
11994
  }) {
10781
- const [activeSection, setActiveSection] = React8.useState("");
10782
- const [accordionValue, setAccordionValue] = React8.useState([]);
10783
- const accordionSectionIds = React8.useMemo(
11995
+ const [activeSection, setActiveSection] = React28.useState("");
11996
+ const [accordionValue, setAccordionValue] = React28.useState([]);
11997
+ const [faqsExpanded, setFaqsExpanded] = React28.useState(false);
11998
+ const accordionSectionIds = React28.useMemo(
10784
11999
  () => /* @__PURE__ */ new Set([
10785
- "key-info",
12000
+ "how-to-get-there",
10786
12001
  "what-to-bring",
10787
12002
  "weather",
10788
12003
  "optional-extras",
@@ -10793,18 +12008,18 @@ function TripPage({
10793
12008
  ]),
10794
12009
  []
10795
12010
  );
10796
- const [navFloating, setNavFloating] = React8.useState(false);
10797
- const [navHidden, setNavHidden] = React8.useState(false);
10798
- const [isFloating, setIsFloating] = React8.useState(false);
10799
- const [sidebarPos, setSidebarPos] = React8.useState(null);
10800
- const [pricingBarVisible, setPricingBarVisible] = React8.useState(false);
10801
- const navRef = React8.useRef(null);
10802
- const navSentinelRef = React8.useRef(null);
10803
- const sentinelRef = React8.useRef(null);
10804
- const sidebarPlaceholderRef = React8.useRef(null);
10805
- const pricingBarRef = React8.useRef(null);
10806
- const galleryRef = React8.useRef(null);
10807
- const sections = React8.useMemo(
12011
+ const [navFloating, setNavFloating] = React28.useState(false);
12012
+ const [navHidden, setNavHidden] = React28.useState(false);
12013
+ const [isFloating, setIsFloating] = React28.useState(false);
12014
+ const [sidebarPos, setSidebarPos] = React28.useState(null);
12015
+ const [pricingBarVisible, setPricingBarVisible] = React28.useState(false);
12016
+ const navRef = React28.useRef(null);
12017
+ const navSentinelRef = React28.useRef(null);
12018
+ const sentinelRef = React28.useRef(null);
12019
+ const sidebarPlaceholderRef = React28.useRef(null);
12020
+ const pricingBarRef = React28.useRef(null);
12021
+ const galleryRef = React28.useRef(null);
12022
+ const sections = React28.useMemo(
10808
12023
  () => [
10809
12024
  { id: "overview", label: "Overview", show: !!(overview || (overviewHighlights == null ? void 0 : overviewHighlights.length)) },
10810
12025
  {
@@ -10822,7 +12037,7 @@ function TripPage({
10822
12037
  // eslint-disable-next-line react-hooks/exhaustive-deps
10823
12038
  []
10824
12039
  );
10825
- React8.useEffect(() => {
12040
+ React28.useEffect(() => {
10826
12041
  const sentinel = navSentinelRef.current;
10827
12042
  if (!sentinel) return;
10828
12043
  const update = () => setNavFloating(sentinel.getBoundingClientRect().top < 1);
@@ -10830,7 +12045,7 @@ function TripPage({
10830
12045
  update();
10831
12046
  return () => document.removeEventListener("scroll", update, { capture: true });
10832
12047
  }, []);
10833
- React8.useEffect(() => {
12048
+ React28.useEffect(() => {
10834
12049
  const sentinel = sentinelRef.current;
10835
12050
  if (!sentinel) return;
10836
12051
  const update = () => setIsFloating(sentinel.getBoundingClientRect().top < 1);
@@ -10838,7 +12053,7 @@ function TripPage({
10838
12053
  update();
10839
12054
  return () => document.removeEventListener("scroll", update, { capture: true });
10840
12055
  }, []);
10841
- React8.useEffect(() => {
12056
+ React28.useEffect(() => {
10842
12057
  const measure = () => {
10843
12058
  if (!sidebarPlaceholderRef.current) return;
10844
12059
  const rect = sidebarPlaceholderRef.current.getBoundingClientRect();
@@ -10848,7 +12063,7 @@ function TripPage({
10848
12063
  window.addEventListener("resize", measure);
10849
12064
  return () => window.removeEventListener("resize", measure);
10850
12065
  }, [isFloating]);
10851
- React8.useEffect(() => {
12066
+ React28.useEffect(() => {
10852
12067
  const check = () => {
10853
12068
  var _a;
10854
12069
  const target = (_a = galleryRef.current) != null ? _a : pricingBarRef.current;
@@ -10859,7 +12074,7 @@ function TripPage({
10859
12074
  check();
10860
12075
  return () => document.removeEventListener("scroll", check, { capture: true });
10861
12076
  }, []);
10862
- React8.useEffect(() => {
12077
+ React28.useEffect(() => {
10863
12078
  const check = () => {
10864
12079
  if (!pricingBarRef.current) return;
10865
12080
  setNavHidden(pricingBarRef.current.getBoundingClientRect().top < window.innerHeight * 0.92);
@@ -10868,7 +12083,7 @@ function TripPage({
10868
12083
  check();
10869
12084
  return () => document.removeEventListener("scroll", check, { capture: true });
10870
12085
  }, []);
10871
- React8.useEffect(() => {
12086
+ React28.useEffect(() => {
10872
12087
  if (sections.length === 0) return;
10873
12088
  setActiveSection(sections[0].id);
10874
12089
  const update = () => {
@@ -10943,6 +12158,7 @@ function TripPage({
10943
12158
  destination,
10944
12159
  duration,
10945
12160
  tagline,
12161
+ chips,
10946
12162
  siteHeader,
10947
12163
  uiVariant,
10948
12164
  belowMeta: trustpilotHero ? /* @__PURE__ */ jsx(TrustpilotEmbed, { config: trustpilotHero }) : void 0
@@ -10976,10 +12192,7 @@ function TripPage({
10976
12192
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row gap-8 mt-4", children: [
10977
12193
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 space-y-12 pb-12", children: [
10978
12194
  (overview || (overviewHighlights == null ? void 0 : overviewHighlights.length)) && /* @__PURE__ */ jsxs("section", { id: "trip-section-overview", className: "scroll-mt-20", children: [
10979
- /* @__PURE__ */ jsxs("h2", { className: "text-xl font-bold text-foreground font-heading mb-4 flex items-center gap-2", children: [
10980
- (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" }),
10981
- "Overview"
10982
- ] }),
12195
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-4", children: "Overview" }),
10983
12196
  overview && /* @__PURE__ */ jsx("div", { className: "text-lg text-foreground leading-relaxed space-y-3 [&_strong]:font-semibold [&_a]:text-primary [&_a]:underline", children: overview }),
10984
12197
  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: [
10985
12198
  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 }),
@@ -11026,7 +12239,7 @@ function TripPage({
11026
12239
  }
11027
12240
  )
11028
12241
  ] }),
11029
- ((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(
12242
+ (howToGetThere || (whatToBring == null ? void 0 : whatToBring.length) || weather || optionalExtras || accommodation || food || (meetingPoints == null ? void 0 : meetingPoints.length) || meetingPoint || termsAndConditions) && /* @__PURE__ */ jsxs(
11030
12243
  Accordion,
11031
12244
  {
11032
12245
  multiple: false,
@@ -11034,25 +12247,33 @@ function TripPage({
11034
12247
  onValueChange: setAccordionValue,
11035
12248
  className: "border-t border-border",
11036
12249
  children: [
11037
- (keyInfo || infoGroups && infoGroups.length > 0) && /* @__PURE__ */ jsxs(
12250
+ accommodation && /* @__PURE__ */ jsxs(
12251
+ AccordionItem,
12252
+ {
12253
+ value: "accommodation",
12254
+ id: "trip-section-accommodation",
12255
+ className: "scroll-mt-20 border-b border-border",
12256
+ children: [
12257
+ /* @__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: [
12258
+ (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" }),
12259
+ "Accommodation"
12260
+ ] }) }),
12261
+ /* @__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 }) })
12262
+ ]
12263
+ }
12264
+ ),
12265
+ food && /* @__PURE__ */ jsxs(
11038
12266
  AccordionItem,
11039
12267
  {
11040
- value: "key-info",
11041
- id: "trip-section-key-info",
12268
+ value: "food",
12269
+ id: "trip-section-food",
11042
12270
  className: "scroll-mt-20 border-b border-border",
11043
12271
  children: [
11044
12272
  /* @__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: [
11045
- (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" }),
11046
- "Key info"
12273
+ (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" }),
12274
+ "Food"
11047
12275
  ] }) }),
11048
- /* @__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: [
11049
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
11050
- group.icon && /* @__PURE__ */ jsx("span", { className: "text-primary", children: group.icon }),
11051
- /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-heading", children: group.title })
11052
- ] }),
11053
- /* @__PURE__ */ jsx(Checklist, { items: group.items }),
11054
- i < infoGroups.length - 1 && /* @__PURE__ */ jsx(Separator, { className: "mt-6" })
11055
- ] }, i)) }) })
12276
+ /* @__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 }) })
11056
12277
  ]
11057
12278
  }
11058
12279
  ),
@@ -11078,78 +12299,63 @@ function TripPage({
11078
12299
  ]
11079
12300
  }
11080
12301
  ),
11081
- optionalExtras && /* @__PURE__ */ jsxs(
12302
+ howToGetThere && /* @__PURE__ */ jsxs(
11082
12303
  AccordionItem,
11083
12304
  {
11084
- value: "optional-extras",
11085
- id: "trip-section-optional-extras",
12305
+ value: "how-to-get-there",
12306
+ id: "trip-section-how-to-get-there",
11086
12307
  className: "scroll-mt-20 border-b border-border",
11087
12308
  children: [
11088
12309
  /* @__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: [
11089
- (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" }),
11090
- "Optional extras"
12310
+ (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" }),
12311
+ "How to get there"
11091
12312
  ] }) }),
11092
- /* @__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 }) })
12313
+ /* @__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 }) })
11093
12314
  ]
11094
12315
  }
11095
12316
  ),
11096
- whatToBring && whatToBring.length > 0 && /* @__PURE__ */ jsxs(
11097
- AccordionItem,
11098
- {
11099
- value: "what-to-bring",
11100
- id: "trip-section-what-to-bring",
11101
- className: "scroll-mt-20 border-b border-border",
11102
- children: [
11103
- /* @__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: [
11104
- (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" }),
11105
- "What to bring"
11106
- ] }) }),
11107
- /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx(Checklist, { items: whatToBring, icon: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4" }) }) })
11108
- ]
11109
- }
11110
- ),
11111
- accommodation && /* @__PURE__ */ jsxs(
12317
+ weather && /* @__PURE__ */ jsxs(
11112
12318
  AccordionItem,
11113
12319
  {
11114
- value: "accommodation",
11115
- id: "trip-section-accommodation",
12320
+ value: "weather",
12321
+ id: "trip-section-weather",
11116
12322
  className: "scroll-mt-20 border-b border-border",
11117
12323
  children: [
11118
12324
  /* @__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: [
11119
- (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" }),
11120
- "Accommodation"
12325
+ (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" }),
12326
+ "Weather"
11121
12327
  ] }) }),
11122
- /* @__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 }) })
12328
+ /* @__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 }) }) })
11123
12329
  ]
11124
12330
  }
11125
12331
  ),
11126
- food && /* @__PURE__ */ jsxs(
12332
+ whatToBring && whatToBring.length > 0 && /* @__PURE__ */ jsxs(
11127
12333
  AccordionItem,
11128
12334
  {
11129
- value: "food",
11130
- id: "trip-section-food",
12335
+ value: "what-to-bring",
12336
+ id: "trip-section-what-to-bring",
11131
12337
  className: "scroll-mt-20 border-b border-border",
11132
12338
  children: [
11133
12339
  /* @__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: [
11134
- (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" }),
11135
- "Food"
12340
+ (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" }),
12341
+ "What to bring"
11136
12342
  ] }) }),
11137
- /* @__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 }) })
12343
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-6", children: /* @__PURE__ */ jsx(Checklist, { items: whatToBring, icon: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4" }) }) })
11138
12344
  ]
11139
12345
  }
11140
12346
  ),
11141
- weather && /* @__PURE__ */ jsxs(
12347
+ optionalExtras && /* @__PURE__ */ jsxs(
11142
12348
  AccordionItem,
11143
12349
  {
11144
- value: "weather",
11145
- id: "trip-section-weather",
12350
+ value: "optional-extras",
12351
+ id: "trip-section-optional-extras",
11146
12352
  className: "scroll-mt-20 border-b border-border",
11147
12353
  children: [
11148
12354
  /* @__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: [
11149
- (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" }),
11150
- "Weather"
12355
+ (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" }),
12356
+ "Optional extras"
11151
12357
  ] }) }),
11152
- /* @__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 }) }) })
12358
+ /* @__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 }) })
11153
12359
  ]
11154
12360
  }
11155
12361
  ),
@@ -11171,13 +12377,39 @@ function TripPage({
11171
12377
  ]
11172
12378
  }
11173
12379
  ),
11174
- faqs && faqs.length > 0 && /* @__PURE__ */ jsxs("section", { id: "trip-section-faq", className: "scroll-mt-20", children: [
11175
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-6", children: "FAQ" }),
11176
- /* @__PURE__ */ jsx(Accordion, { variant: "faq", children: faqs.map((faq, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `faq-${i}`, children: [
11177
- /* @__PURE__ */ jsx(AccordionTrigger, { children: faq.question }),
11178
- /* @__PURE__ */ jsx(AccordionContent, { children: faq.answer })
11179
- ] }, i)) })
11180
- ] }),
12380
+ faqs && faqs.length > 0 && (() => {
12381
+ const visibleFaqs = faqsExpanded ? faqs : faqs.slice(0, faqInitialCount);
12382
+ const hiddenCount = faqs.length - visibleFaqs.length;
12383
+ return /* @__PURE__ */ jsxs("section", { id: "trip-section-faq", className: "scroll-mt-20", children: [
12384
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-6", children: "FAQ" }),
12385
+ /* @__PURE__ */ jsx(Accordion, { variant: "faq", children: visibleFaqs.map((faq, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `faq-${i}`, children: [
12386
+ /* @__PURE__ */ jsx(AccordionTrigger, { children: faq.question }),
12387
+ /* @__PURE__ */ jsx(AccordionContent, { children: faq.answer })
12388
+ ] }, i)) }),
12389
+ faqs.length > faqInitialCount && /* @__PURE__ */ jsx("div", { className: "mt-5 flex justify-center", children: /* @__PURE__ */ jsx(
12390
+ "button",
12391
+ {
12392
+ type: "button",
12393
+ onClick: () => setFaqsExpanded((v) => !v),
12394
+ className: cn(
12395
+ "inline-flex items-center gap-2 rounded-full border border-border bg-background px-5 py-2.5",
12396
+ "text-sm font-semibold text-foreground shadow-sm",
12397
+ "hover:bg-muted transition-colors duration-150",
12398
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
12399
+ ),
12400
+ children: faqsExpanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
12401
+ /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4 text-muted-foreground" }),
12402
+ "Show less"
12403
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
12404
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" }),
12405
+ "See more (",
12406
+ hiddenCount,
12407
+ ")"
12408
+ ] })
12409
+ }
12410
+ ) })
12411
+ ] });
12412
+ })(),
11181
12413
  trustpilot ? /* @__PURE__ */ jsxs("section", { id: "trip-section-reviews", className: "scroll-mt-20", children: [
11182
12414
  /* @__PURE__ */ jsx(Separator, { className: "mb-10" }),
11183
12415
  /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-foreground font-heading mb-5", children: "What our guests think" }),
@@ -11266,8 +12498,8 @@ function TripPage({
11266
12498
  PhotoGallery,
11267
12499
  {
11268
12500
  photos: gallery,
11269
- variant: "grid",
11270
- initialVisible: 6
12501
+ variant: "gridCompact",
12502
+ initialVisible: 8
11271
12503
  }
11272
12504
  ) }),
11273
12505
  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 }) }) }),
@@ -11284,7 +12516,8 @@ function TripPage({
11284
12516
  currencyEstimates
11285
12517
  }
11286
12518
  ) }),
11287
- /* @__PURE__ */ jsx("div", { className: "h-20 lg:hidden" })
12519
+ /* @__PURE__ */ jsx("div", { className: "h-20 lg:hidden" }),
12520
+ /* @__PURE__ */ jsx(SiteFooter, {})
11288
12521
  ]
11289
12522
  }
11290
12523
  );
@@ -11390,12 +12623,12 @@ function Toast({
11390
12623
  duration = 6e3,
11391
12624
  className
11392
12625
  }) {
11393
- const [mounted, setMounted] = React8.useState(false);
11394
- const [visible, setVisible] = React8.useState(true);
11395
- React8.useEffect(() => {
12626
+ const [mounted, setMounted] = React28.useState(false);
12627
+ const [visible, setVisible] = React28.useState(true);
12628
+ React28.useEffect(() => {
11396
12629
  setMounted(true);
11397
12630
  }, []);
11398
- React8.useEffect(() => {
12631
+ React28.useEffect(() => {
11399
12632
  if (duration === 0) return;
11400
12633
  const t = setTimeout(() => {
11401
12634
  setVisible(false);