@planetaexo/design-system 0.52.3 → 0.54.1

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 React28 from 'react';
1
+ import * as React29 from 'react';
2
2
  import { useState, useRef, useCallback, useEffect, useId } 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, 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, Info, MailIcon, PhoneIcon, MessageCircleIcon, UserPlusIcon, ExternalLinkIcon, CopyIcon, PencilIcon, Trash2Icon, UserMinusIcon, AlertTriangleIcon, ZoomInIcon, StarIcon, TwitterIcon, YoutubeIcon, LinkedinIcon, InstagramIcon, FacebookIcon, ArrowRightIcon, 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, ArrowRightIcon, Loader2Icon, SendIcon, CheckCircleIcon, ArrowDownIcon, SparkleIcon, Share2Icon, CopyIcon, Info, MailIcon, PhoneIcon, MessageCircleIcon, UserPlusIcon, ExternalLinkIcon, PencilIcon, Trash2Icon, UserMinusIcon, AlertTriangleIcon, ZoomInIcon, StarIcon, TwitterIcon, YoutubeIcon, LinkedinIcon, InstagramIcon, FacebookIcon, 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 = React28.forwardRef(
84
+ var Button = React29.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(
@@ -310,10 +310,10 @@ function DialogDescription(_a) {
310
310
  }, props)
311
311
  );
312
312
  }
313
- var FloatingInput = React28.forwardRef(
313
+ var FloatingInput = React29.forwardRef(
314
314
  (_a, ref) => {
315
315
  var _b = _a, { label, error, id, className, required } = _b, props = __objRest(_b, ["label", "error", "id", "className", "required"]);
316
- const inputId = id != null ? id : React28.useId();
316
+ const inputId = id != null ? id : React29.useId();
317
317
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
318
318
  /* @__PURE__ */ jsx(
319
319
  "input",
@@ -353,10 +353,10 @@ var FloatingInput = React28.forwardRef(
353
353
  }
354
354
  );
355
355
  FloatingInput.displayName = "FloatingInput";
356
- var FloatingSelect = React28.forwardRef(
356
+ var FloatingSelect = React29.forwardRef(
357
357
  (_a, ref) => {
358
358
  var _b = _a, { label, error, id, className, required, children, value } = _b, props = __objRest(_b, ["label", "error", "id", "className", "required", "children", "value"]);
359
- const inputId = id != null ? id : React28.useId();
359
+ const inputId = id != null ? id : React29.useId();
360
360
  const hasValue = typeof value === "string" ? value !== "" : value !== void 0 && value !== null;
361
361
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
362
362
  /* @__PURE__ */ jsx(
@@ -620,11 +620,11 @@ function PhoneCountrySelect({
620
620
  disabled
621
621
  }) {
622
622
  var _a;
623
- const [open, setOpen] = React28.useState(false);
624
- const containerRef = React28.useRef(null);
625
- const listRef = React28.useRef(null);
623
+ const [open, setOpen] = React29.useState(false);
624
+ const containerRef = React29.useRef(null);
625
+ const listRef = React29.useRef(null);
626
626
  const selected = (_a = PHONE_COUNTRIES.find((c) => c.code === value)) != null ? _a : PHONE_COUNTRIES[0];
627
- React28.useEffect(() => {
627
+ React29.useEffect(() => {
628
628
  if (!open) return;
629
629
  const handler = (e) => {
630
630
  var _a2;
@@ -635,7 +635,7 @@ function PhoneCountrySelect({
635
635
  document.addEventListener("mousedown", handler);
636
636
  return () => document.removeEventListener("mousedown", handler);
637
637
  }, [open]);
638
- React28.useEffect(() => {
638
+ React29.useEffect(() => {
639
639
  if (!open || !listRef.current) return;
640
640
  const activeEl = listRef.current.querySelector("[data-selected=true]");
641
641
  activeEl == null ? void 0 : activeEl.scrollIntoView({ block: "nearest" });
@@ -905,8 +905,8 @@ function CalendarDayButton(_a) {
905
905
  "locale"
906
906
  ]);
907
907
  const defaultClassNames = getDefaultClassNames();
908
- const ref = React28.useRef(null);
909
- React28.useEffect(() => {
908
+ const ref = React29.useRef(null);
909
+ React29.useEffect(() => {
910
910
  var _a2;
911
911
  if (modifiers.focused) (_a2 = ref.current) == null ? void 0 : _a2.focus();
912
912
  }, [modifiers.focused]);
@@ -937,16 +937,16 @@ function BirthDateField({
937
937
  className,
938
938
  disabled
939
939
  }) {
940
- const [open, setOpen] = React28.useState(false);
941
- const [text, setText] = React28.useState(
940
+ const [open, setOpen] = React29.useState(false);
941
+ const [text, setText] = React29.useState(
942
942
  value ? format(value, "dd/MM/yyyy") : ""
943
943
  );
944
- const containerRef = React28.useRef(null);
945
- const inputId = React28.useId();
946
- React28.useEffect(() => {
944
+ const containerRef = React29.useRef(null);
945
+ const inputId = React29.useId();
946
+ React29.useEffect(() => {
947
947
  setText(value ? format(value, "dd/MM/yyyy") : "");
948
948
  }, [value]);
949
- React28.useEffect(() => {
949
+ React29.useEffect(() => {
950
950
  if (!open) return;
951
951
  const handler = (e) => {
952
952
  var _a;
@@ -1155,14 +1155,14 @@ function CountrySearchField({
1155
1155
  }) {
1156
1156
  var _a;
1157
1157
  const list = countries != null ? countries : COUNTRIES;
1158
- const [query, setQuery] = React28.useState("");
1159
- const [open, setOpen] = React28.useState(false);
1160
- const containerRef = React28.useRef(null);
1161
- const searchRef = React28.useRef(null);
1158
+ const [query, setQuery] = React29.useState("");
1159
+ const [open, setOpen] = React29.useState(false);
1160
+ const containerRef = React29.useRef(null);
1161
+ const searchRef = React29.useRef(null);
1162
1162
  const selected = list.find((c) => c.code === value);
1163
1163
  const isFloated = open || !!selected;
1164
1164
  const filtered = query.trim() ? list.filter((c) => c.name.toLowerCase().includes(query.toLowerCase())) : list;
1165
- React28.useEffect(() => {
1165
+ React29.useEffect(() => {
1166
1166
  if (!open) return;
1167
1167
  const handler = (e) => {
1168
1168
  var _a2;
@@ -1256,16 +1256,47 @@ var VARIANT_STYLES = {
1256
1256
  success: "text-primary border-primary/30 bg-primary/10",
1257
1257
  info: "text-muted-foreground border-primary/25 bg-primary/5"
1258
1258
  };
1259
- function Alert({ variant = "info", children, className }) {
1260
- return /* @__PURE__ */ jsx(
1259
+ function Alert({
1260
+ variant = "info",
1261
+ title,
1262
+ icon,
1263
+ action,
1264
+ role = "status",
1265
+ children,
1266
+ className
1267
+ }) {
1268
+ const isBanner = Boolean(title || icon || action);
1269
+ if (!isBanner) {
1270
+ return /* @__PURE__ */ jsx(
1271
+ "div",
1272
+ {
1273
+ role,
1274
+ className: cn(
1275
+ "rounded-lg border px-3 py-2 text-sm font-sans leading-snug",
1276
+ VARIANT_STYLES[variant],
1277
+ className
1278
+ ),
1279
+ children
1280
+ }
1281
+ );
1282
+ }
1283
+ return /* @__PURE__ */ jsxs(
1261
1284
  "div",
1262
1285
  {
1286
+ role,
1263
1287
  className: cn(
1264
- "rounded-lg border px-3 py-2 text-sm font-sans leading-snug",
1288
+ "flex items-start gap-3 rounded-lg border px-4 py-3 text-sm font-sans leading-snug",
1265
1289
  VARIANT_STYLES[variant],
1266
1290
  className
1267
1291
  ),
1268
- children
1292
+ children: [
1293
+ icon && /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 [&>svg]:size-4", "aria-hidden": "true", children: icon }),
1294
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1295
+ title && /* @__PURE__ */ jsx("p", { className: "font-ui font-bold text-current leading-snug", children: title }),
1296
+ children && /* @__PURE__ */ jsx("div", { className: cn(title && "mt-0.5", "text-current/90"), children })
1297
+ ] }),
1298
+ action && /* @__PURE__ */ jsx("div", { className: "shrink-0 self-center", children: action })
1299
+ ]
1269
1300
  }
1270
1301
  );
1271
1302
  }
@@ -1276,10 +1307,10 @@ function AdventureCard({
1276
1307
  }) {
1277
1308
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
1278
1309
  const isControlled = (_b = (_a = adventure.optionals) == null ? void 0 : _a.some((o) => o.onCheckedChange !== void 0)) != null ? _b : false;
1279
- const [checkedInternal, setCheckedInternal] = React28.useState(
1310
+ const [checkedInternal, setCheckedInternal] = React29.useState(
1280
1311
  new Set((_d = (_c = adventure.optionals) == null ? void 0 : _c.filter((o) => o.defaultChecked).map((o) => o.id)) != null ? _d : [])
1281
1312
  );
1282
- const [openDescriptionId, setOpenDescriptionId] = React28.useState(null);
1313
+ const [openDescriptionId, setOpenDescriptionId] = React29.useState(null);
1283
1314
  const openDescriptionOptional = openDescriptionId ? (_e = adventure.optionals) == null ? void 0 : _e.find((o) => o.id === openDescriptionId) : void 0;
1284
1315
  const isChecked = (opt) => {
1285
1316
  var _a2;
@@ -1709,7 +1740,7 @@ function BookingShell({
1709
1740
  return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-border bg-card overflow-hidden", children: [
1710
1741
  /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-5 py-4 bg-muted/20", children: [
1711
1742
  /* @__PURE__ */ jsx("h3", { className: "text-base font-bold text-foreground font-heading mb-2", children: title }),
1712
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: steps.map((label, i) => /* @__PURE__ */ jsxs(React28.Fragment, { children: [
1743
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: steps.map((label, i) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
1713
1744
  /* @__PURE__ */ jsx(
1714
1745
  "span",
1715
1746
  {
@@ -1908,7 +1939,7 @@ function TermsSection({
1908
1939
  termsContent
1909
1940
  }) {
1910
1941
  var _a;
1911
- const [modalOpen, setModalOpen] = React28.useState(false);
1942
+ const [modalOpen, setModalOpen] = React29.useState(false);
1912
1943
  const i18n = (_a = TERMS_I18N[locale]) != null ? _a : TERMS_I18N.en;
1913
1944
  return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border p-4 flex flex-col gap-3", children: [
1914
1945
  /* @__PURE__ */ jsx("p", { className: "text-xs font-bold text-muted-foreground font-heading uppercase tracking-widest", children: title }),
@@ -2046,9 +2077,9 @@ function BookingWizard({
2046
2077
  }) {
2047
2078
  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;
2048
2079
  const wizardSteps = WIZARD_STEPS_FN(labels);
2049
- const [step, setStep] = React28.useState("responsible");
2050
- const [error, setError] = React28.useState(null);
2051
- const [responsible, setResponsible] = React28.useState({
2080
+ const [step, setStep] = React29.useState("responsible");
2081
+ const [error, setError] = React29.useState(null);
2082
+ const [responsible, setResponsible] = React29.useState({
2052
2083
  firstName: "",
2053
2084
  lastName: "",
2054
2085
  email: "",
@@ -2067,7 +2098,7 @@ function BookingWizard({
2067
2098
  return s + ((_b2 = (_a2 = a.slots) == null ? void 0 : _a2.children) != null ? _b2 : 0);
2068
2099
  }, 0);
2069
2100
  const totalPax = totalAdults + totalChildren;
2070
- const [travellers, setTravellers] = React28.useState(
2101
+ const [travellers, setTravellers] = React29.useState(
2071
2102
  Array.from({ length: Math.max(totalPax, 1) }, () => ({
2072
2103
  firstName: "",
2073
2104
  lastName: "",
@@ -2075,9 +2106,9 @@ function BookingWizard({
2075
2106
  email: ""
2076
2107
  }))
2077
2108
  );
2078
- const [payAmount, setPayAmount] = React28.useState("full");
2079
- const [payMethod, setPayMethod] = React28.useState("stripe");
2080
- const [termsAccepted, setTermsAccepted] = React28.useState(false);
2109
+ const [payAmount, setPayAmount] = React29.useState("full");
2110
+ const [payMethod, setPayMethod] = React29.useState("stripe");
2111
+ const [termsAccepted, setTermsAccepted] = React29.useState(false);
2081
2112
  const setR = (k, v) => setResponsible((p) => __spreadProps(__spreadValues({}, p), { [k]: v }));
2082
2113
  const setT = (i, k, v) => setTravellers((prev) => prev.map((t, idx) => idx === i ? __spreadProps(__spreadValues({}, t), { [k]: v }) : t));
2083
2114
  const setTDob = (i, v) => setTravellers((prev) => prev.map((t, idx) => idx === i ? __spreadProps(__spreadValues({}, t), { dateOfBirth: v }) : t));
@@ -2305,7 +2336,7 @@ function Offer({
2305
2336
  className
2306
2337
  }) {
2307
2338
  var _a, _b, _c;
2308
- const [showBooking, setShowBooking] = React28.useState(false);
2339
+ const [showBooking, setShowBooking] = React29.useState(false);
2309
2340
  const isShowingCheckout = !confirmedState && (!!checkoutSlot || internalDemoCheckout && showBooking);
2310
2341
  const handleBook = () => {
2311
2342
  if (!checkoutSlot && !externalBookingFlow && internalDemoCheckout) {
@@ -2672,7 +2703,7 @@ function AdventureSection({
2672
2703
  labels
2673
2704
  }) {
2674
2705
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
2675
- const [detailsOpen, setDetailsOpen] = React28.useState(false);
2706
+ const [detailsOpen, setDetailsOpen] = React29.useState(false);
2676
2707
  const handleCopyUrl = (url) => {
2677
2708
  if (onCopyFormLink) {
2678
2709
  onCopyFormLink(url);
@@ -3185,8 +3216,8 @@ function AddTravellerDialog({
3185
3216
  errorMessage
3186
3217
  }) {
3187
3218
  var _a, _b, _c, _d, _e;
3188
- const [form, setForm] = React28.useState(() => createInitialAddFormData(config));
3189
- React28.useEffect(() => {
3219
+ const [form, setForm] = React29.useState(() => createInitialAddFormData(config));
3220
+ React29.useEffect(() => {
3190
3221
  if (open) {
3191
3222
  setForm(createInitialAddFormData(config));
3192
3223
  }
@@ -3246,7 +3277,7 @@ function EditTravellerDialog({
3246
3277
  errorMessage
3247
3278
  }) {
3248
3279
  var _a, _b, _c, _d, _e;
3249
- const [form, setForm] = React28.useState(() => ({
3280
+ const [form, setForm] = React29.useState(() => ({
3250
3281
  firstName: "",
3251
3282
  lastName: "",
3252
3283
  email: "",
@@ -3255,7 +3286,7 @@ function EditTravellerDialog({
3255
3286
  birthDate: "",
3256
3287
  personType: "ADULT"
3257
3288
  }));
3258
- React28.useEffect(() => {
3289
+ React29.useEffect(() => {
3259
3290
  var _a2, _b2, _c2, _d2, _e2, _f;
3260
3291
  if (open && traveller) {
3261
3292
  setForm({
@@ -3591,48 +3622,48 @@ function BookingDetails({
3591
3622
  const hasSubmitAddTraveller = !!onSubmitAddTraveller;
3592
3623
  const hasSubmitEditTraveller = !!onSubmitEditTraveller;
3593
3624
  const hasConfirmRemoveTraveller = !!onConfirmRemoveTraveller;
3594
- const [addModalState, setAddModalState] = React28.useState({
3625
+ const [addModalState, setAddModalState] = React29.useState({
3595
3626
  open: false,
3596
3627
  adventureId: null
3597
3628
  });
3598
- const [editModalState, setEditModalState] = React28.useState({ open: false, adventureId: null, traveller: null });
3599
- const [deleteModalState, setDeleteModalState] = React28.useState({ open: false, adventureId: null, traveller: null });
3600
- const [resendInviteDialogState, setResendInviteDialogState] = React28.useState({ open: false, traveller: null });
3601
- const handleRequestOpenAddModal = React28.useCallback((adventureId) => {
3629
+ const [editModalState, setEditModalState] = React29.useState({ open: false, adventureId: null, traveller: null });
3630
+ const [deleteModalState, setDeleteModalState] = React29.useState({ open: false, adventureId: null, traveller: null });
3631
+ const [resendInviteDialogState, setResendInviteDialogState] = React29.useState({ open: false, traveller: null });
3632
+ const handleRequestOpenAddModal = React29.useCallback((adventureId) => {
3602
3633
  setAddModalState({ open: true, adventureId });
3603
3634
  }, []);
3604
- const handleRequestOpenEditModal = React28.useCallback(
3635
+ const handleRequestOpenEditModal = React29.useCallback(
3605
3636
  (adventureId, traveller) => {
3606
3637
  setEditModalState({ open: true, adventureId, traveller });
3607
3638
  },
3608
3639
  []
3609
3640
  );
3610
- const handleRequestOpenDeleteModal = React28.useCallback(
3641
+ const handleRequestOpenDeleteModal = React29.useCallback(
3611
3642
  (adventureId, traveller) => {
3612
3643
  setDeleteModalState({ open: true, adventureId, traveller });
3613
3644
  },
3614
3645
  []
3615
3646
  );
3616
- const handleRequestOpenResendInviteDialog = React28.useCallback(
3647
+ const handleRequestOpenResendInviteDialog = React29.useCallback(
3617
3648
  (traveller) => {
3618
3649
  setResendInviteDialogState({ open: true, traveller });
3619
3650
  },
3620
3651
  []
3621
3652
  );
3622
- const closeAddModal = React28.useCallback(() => {
3653
+ const closeAddModal = React29.useCallback(() => {
3623
3654
  setAddModalState({ open: false, adventureId: null });
3624
3655
  }, []);
3625
- const closeEditModal = React28.useCallback(() => {
3656
+ const closeEditModal = React29.useCallback(() => {
3626
3657
  setEditModalState({ open: false, adventureId: null, traveller: null });
3627
3658
  }, []);
3628
- const closeDeleteModal = React28.useCallback(() => {
3659
+ const closeDeleteModal = React29.useCallback(() => {
3629
3660
  setDeleteModalState({ open: false, adventureId: null, traveller: null });
3630
3661
  }, []);
3631
- const closeResendInviteDialog = React28.useCallback(() => {
3662
+ const closeResendInviteDialog = React29.useCallback(() => {
3632
3663
  setResendInviteDialogState({ open: false, traveller: null });
3633
3664
  }, []);
3634
- const submitInFlightRef = React28.useRef(false);
3635
- const handleAddSubmit = React28.useCallback(
3665
+ const submitInFlightRef = React29.useRef(false);
3666
+ const handleAddSubmit = React29.useCallback(
3636
3667
  async (adventureId, data) => {
3637
3668
  if (!onSubmitAddTraveller) return;
3638
3669
  if (submitInFlightRef.current) return;
@@ -3647,7 +3678,7 @@ function BookingDetails({
3647
3678
  },
3648
3679
  [onSubmitAddTraveller, closeAddModal]
3649
3680
  );
3650
- const handleEditSubmit = React28.useCallback(
3681
+ const handleEditSubmit = React29.useCallback(
3651
3682
  async (adventureId, travellerId, data) => {
3652
3683
  if (!onSubmitEditTraveller) return;
3653
3684
  if (submitInFlightRef.current) return;
@@ -3662,7 +3693,7 @@ function BookingDetails({
3662
3693
  },
3663
3694
  [onSubmitEditTraveller, closeEditModal]
3664
3695
  );
3665
- const handleDeleteConfirm = React28.useCallback(
3696
+ const handleDeleteConfirm = React29.useCallback(
3666
3697
  async (adventureId, travellerId) => {
3667
3698
  if (!onConfirmRemoveTraveller) return;
3668
3699
  if (submitInFlightRef.current) return;
@@ -5238,7 +5269,7 @@ function BookingCreatedEmail({
5238
5269
  }, children: i + 1 }) }),
5239
5270
  /* @__PURE__ */ jsx("td", { style: { verticalAlign: "top" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "14px", color: emailTokens.bodyText, lineHeight: "1.6", margin: 0 }, children: step }) })
5240
5271
  ] }) }) }, i)) }),
5241
- 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: [
5272
+ 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(React29.Fragment, { children: [
5242
5273
  idx === 0 ? /* @__PURE__ */ jsx("strong", { children: line }) : line,
5243
5274
  idx < arr.length - 1 ? /* @__PURE__ */ jsx("br", {}) : null
5244
5275
  ] }, idx)) })
@@ -7258,11 +7289,11 @@ function DatePickerField({
7258
7289
  fromDate,
7259
7290
  className
7260
7291
  }) {
7261
- const [open, setOpen] = React28.useState(false);
7262
- const containerRef = React28.useRef(null);
7263
- const [calendarWidth, setCalendarWidth] = React28.useState();
7292
+ const [open, setOpen] = React29.useState(false);
7293
+ const containerRef = React29.useRef(null);
7294
+ const [calendarWidth, setCalendarWidth] = React29.useState();
7264
7295
  const hasValue = !!value;
7265
- React28.useEffect(() => {
7296
+ React29.useEffect(() => {
7266
7297
  if (!containerRef.current) return;
7267
7298
  const observer = new ResizeObserver(([entry]) => {
7268
7299
  setCalendarWidth(entry.contentRect.width);
@@ -7371,7 +7402,7 @@ function BookingForm({
7371
7402
  subtitle = "Free enquiry \u2013 no commitment",
7372
7403
  className
7373
7404
  }) {
7374
- const [values, setValues] = React28.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
7405
+ const [values, setValues] = React29.useState(__spreadValues(__spreadValues({}, defaultInitial), defaultValues));
7375
7406
  const set = (key, value) => setValues((prev) => __spreadProps(__spreadValues({}, prev), { [key]: value }));
7376
7407
  const handleSubmit = (e) => {
7377
7408
  e.preventDefault();
@@ -7939,11 +7970,11 @@ function FloatingTextarea({
7939
7970
  }
7940
7971
  function SelectField({ field, value, onChange, error, disabled }) {
7941
7972
  var _a, _b, _c;
7942
- const [open, setOpen] = React28.useState(false);
7943
- const containerRef = React28.useRef(null);
7973
+ const [open, setOpen] = React29.useState(false);
7974
+ const containerRef = React29.useRef(null);
7944
7975
  const options = (_a = field.options) != null ? _a : [];
7945
7976
  const selectedOpt = (_b = options.find((o) => o.value === value)) != null ? _b : null;
7946
- React28.useEffect(() => {
7977
+ React29.useEffect(() => {
7947
7978
  if (!open) return;
7948
7979
  const handleOutside = (e) => {
7949
7980
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -8408,11 +8439,11 @@ function RegistrationForm({
8408
8439
  readOnly = false
8409
8440
  }) {
8410
8441
  var _a;
8411
- const L = React28.useMemo(
8442
+ const L = React29.useMemo(
8412
8443
  () => __spreadValues(__spreadValues({}, DEFAULT_LABELS12), labels != null ? labels : {}),
8413
8444
  [labels]
8414
8445
  );
8415
- const sortedFields = React28.useMemo(
8446
+ const sortedFields = React29.useMemo(
8416
8447
  () => [...fields].sort((a, b) => {
8417
8448
  var _a2, _b;
8418
8449
  return ((_a2 = a.order) != null ? _a2 : 0) - ((_b = b.order) != null ? _b : 0);
@@ -8420,7 +8451,7 @@ function RegistrationForm({
8420
8451
  [fields]
8421
8452
  );
8422
8453
  const isControlled = values !== void 0;
8423
- const [internal, setInternal] = React28.useState(
8454
+ const [internal, setInternal] = React29.useState(
8424
8455
  () => initializeValues(
8425
8456
  sortedFields,
8426
8457
  defaultValues != null ? defaultValues : {},
@@ -8428,9 +8459,9 @@ function RegistrationForm({
8428
8459
  includeTerms
8429
8460
  )
8430
8461
  );
8431
- const [submitAttempted, setSubmitAttempted] = React28.useState(false);
8432
- const [validationErrors, setValidationErrors] = React28.useState({});
8433
- React28.useEffect(() => {
8462
+ const [submitAttempted, setSubmitAttempted] = React29.useState(false);
8463
+ const [validationErrors, setValidationErrors] = React29.useState({});
8464
+ React29.useEffect(() => {
8434
8465
  if (isControlled) return;
8435
8466
  setInternal((prev) => {
8436
8467
  const next = initializeValues(
@@ -8487,7 +8518,7 @@ function RegistrationForm({
8487
8518
  const termsError = submitAttempted && termsEnabled && !termsAccepted;
8488
8519
  const firstErrorFieldId = Object.keys(fieldErrors)[0];
8489
8520
  const scrollTargetId = firstErrorFieldId ? `rf-${firstErrorFieldId}` : termsError ? "rf-terms" : null;
8490
- React28.useEffect(() => {
8521
+ React29.useEffect(() => {
8491
8522
  if (!submitAttempted || !scrollTargetId) return;
8492
8523
  const timer = setTimeout(() => {
8493
8524
  const elem = document.getElementById(scrollTargetId);
@@ -8949,10 +8980,10 @@ var OTPCodeInput = ({
8949
8980
  id,
8950
8981
  required
8951
8982
  }) => {
8952
- const baseId = id != null ? id : React28.useId();
8953
- const inputRef = React28.useRef(null);
8954
- const [focused, setFocused] = React28.useState(false);
8955
- const digits = React28.useMemo(() => {
8983
+ const baseId = id != null ? id : React29.useId();
8984
+ const inputRef = React29.useRef(null);
8985
+ const [focused, setFocused] = React29.useState(false);
8986
+ const digits = React29.useMemo(() => {
8956
8987
  const arr = value.split("").slice(0, length);
8957
8988
  while (arr.length < length) arr.push("");
8958
8989
  return arr;
@@ -9065,7 +9096,7 @@ function Checkbox(_a) {
9065
9096
  })
9066
9097
  );
9067
9098
  }
9068
- var AccordionVariantContext = React28.createContext("default");
9099
+ var AccordionVariantContext = React29.createContext("default");
9069
9100
  function Accordion(_a) {
9070
9101
  var _b = _a, { className, variant = "default" } = _b, props = __objRest(_b, ["className", "variant"]);
9071
9102
  return /* @__PURE__ */ jsx(AccordionVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsx(
@@ -9083,7 +9114,7 @@ function Accordion(_a) {
9083
9114
  }
9084
9115
  function AccordionItem(_a) {
9085
9116
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
9086
- const variant = React28.useContext(AccordionVariantContext);
9117
+ const variant = React29.useContext(AccordionVariantContext);
9087
9118
  return /* @__PURE__ */ jsx(
9088
9119
  Accordion$1.Item,
9089
9120
  __spreadValues({
@@ -9104,7 +9135,7 @@ function AccordionTrigger(_a) {
9104
9135
  "className",
9105
9136
  "children"
9106
9137
  ]);
9107
- const variant = React28.useContext(AccordionVariantContext);
9138
+ const variant = React29.useContext(AccordionVariantContext);
9108
9139
  return /* @__PURE__ */ jsx(Accordion$1.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
9109
9140
  Accordion$1.Trigger,
9110
9141
  __spreadProps(__spreadValues({
@@ -9158,7 +9189,7 @@ function AccordionContent(_a) {
9158
9189
  "className",
9159
9190
  "children"
9160
9191
  ]);
9161
- const variant = React28.useContext(AccordionVariantContext);
9192
+ const variant = React29.useContext(AccordionVariantContext);
9162
9193
  return /* @__PURE__ */ jsx(
9163
9194
  Accordion$1.Panel,
9164
9195
  __spreadProps(__spreadValues({
@@ -9376,15 +9407,15 @@ function FilterPanel({
9376
9407
  onSortChange
9377
9408
  }) {
9378
9409
  var _a, _b;
9379
- const resolvedGroups = React28.useMemo(() => resolveGroups(groups), [groups]);
9380
- const [internalValue, setInternalValue] = React28.useState(
9410
+ const resolvedGroups = React29.useMemo(() => resolveGroups(groups), [groups]);
9411
+ const [internalValue, setInternalValue] = React29.useState(
9381
9412
  () => Object.fromEntries(groups.map((g) => [g.id, []]))
9382
9413
  );
9383
9414
  const selected = value != null ? value : internalValue;
9384
- const [expandedItems, setExpandedItems] = React28.useState(
9415
+ const [expandedItems, setExpandedItems] = React29.useState(
9385
9416
  () => new Set(groups.flatMap((g) => getDefaultExpandedIds(g.items)))
9386
9417
  );
9387
- const toggleExpanded = React28.useCallback((id) => {
9418
+ const toggleExpanded = React29.useCallback((id) => {
9388
9419
  setExpandedItems((prev) => {
9389
9420
  const next = new Set(prev);
9390
9421
  if (next.has(id)) next.delete(id);
@@ -9768,11 +9799,11 @@ function FilterPanel({
9768
9799
  var TRUSTPILOT_SCRIPT_SRC = "https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js";
9769
9800
  function TrustpilotEmbed({ config }) {
9770
9801
  var _a, _b, _c, _d, _e, _f;
9771
- const ref = React28.useRef(null);
9772
- const [widgetReady, setWidgetReady] = React28.useState(false);
9773
- const [delayPassed, setDelayPassed] = React28.useState(false);
9802
+ const ref = React29.useRef(null);
9803
+ const [widgetReady, setWidgetReady] = React29.useState(false);
9804
+ const [delayPassed, setDelayPassed] = React29.useState(false);
9774
9805
  const showFallback = delayPassed && !widgetReady;
9775
- React28.useEffect(() => {
9806
+ React29.useEffect(() => {
9776
9807
  var _a2;
9777
9808
  if (typeof document === "undefined" || !ref.current) return;
9778
9809
  const node = ref.current;
@@ -9959,16 +9990,73 @@ function webpVariantUrl(src) {
9959
9990
  const withoutQuery = query ? src.slice(0, -query.length) : src;
9960
9991
  return `${withoutQuery}.webp${query}`;
9961
9992
  }
9993
+ var PLACEHOLDER_SRC = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
9962
9994
  function Picture(_a) {
9963
- var _b = _a, { src, extraSources } = _b, imgProps = __objRest(_b, ["src", "extraSources"]);
9995
+ var _b = _a, {
9996
+ src,
9997
+ extraSources,
9998
+ eager = false,
9999
+ rootMargin = "200px",
10000
+ decoding,
10001
+ loading
10002
+ } = _b, imgProps = __objRest(_b, [
10003
+ "src",
10004
+ "extraSources",
10005
+ "eager",
10006
+ "rootMargin",
10007
+ "decoding",
10008
+ "loading"
10009
+ ]);
10010
+ const ref = React29.useRef(null);
10011
+ const [visible, setVisible] = React29.useState(eager);
10012
+ React29.useEffect(() => {
10013
+ if (eager || visible) return;
10014
+ const el = ref.current;
10015
+ if (!el || typeof IntersectionObserver === "undefined") {
10016
+ setVisible(true);
10017
+ return;
10018
+ }
10019
+ const io = new IntersectionObserver(
10020
+ (entries) => {
10021
+ if (entries.some((e) => e.isIntersecting)) {
10022
+ setVisible(true);
10023
+ io.disconnect();
10024
+ }
10025
+ },
10026
+ { rootMargin }
10027
+ );
10028
+ io.observe(el);
10029
+ return () => io.disconnect();
10030
+ }, [eager, visible, rootMargin]);
9964
10031
  const webp = webpVariantUrl(src);
10032
+ const realSrc = visible ? src : PLACEHOLDER_SRC;
10033
+ const decodingResolved = decoding != null ? decoding : eager ? void 0 : "async";
9965
10034
  if (!webp) {
9966
- return /* @__PURE__ */ jsx("img", __spreadValues({ src }, imgProps));
10035
+ return /* @__PURE__ */ jsx(
10036
+ "img",
10037
+ __spreadValues({
10038
+ ref,
10039
+ src: realSrc,
10040
+ "data-src": visible ? void 0 : src,
10041
+ decoding: decodingResolved,
10042
+ loading: loading != null ? loading : eager ? void 0 : "lazy"
10043
+ }, imgProps)
10044
+ );
9967
10045
  }
9968
10046
  return /* @__PURE__ */ jsxs("picture", { style: { display: "contents" }, children: [
9969
- /* @__PURE__ */ jsx("source", { srcSet: webp, type: "image/webp" }),
10047
+ visible && /* @__PURE__ */ jsx("source", { srcSet: webp, type: "image/webp" }),
9970
10048
  extraSources,
9971
- /* @__PURE__ */ jsx("img", __spreadValues({ src }, imgProps))
10049
+ /* @__PURE__ */ jsx(
10050
+ "img",
10051
+ __spreadValues({
10052
+ ref,
10053
+ src: realSrc,
10054
+ "data-src": visible ? void 0 : src,
10055
+ "data-srcset-webp": visible ? void 0 : webp,
10056
+ decoding: decodingResolved,
10057
+ loading: loading != null ? loading : eager ? void 0 : "lazy"
10058
+ }, imgProps)
10059
+ )
9972
10060
  ] });
9973
10061
  }
9974
10062
  function ItineraryDayCard({
@@ -10037,11 +10125,11 @@ function ItineraryModal({
10037
10125
  onNext
10038
10126
  }) {
10039
10127
  var _a, _b, _c;
10040
- const [imgIndex, setImgIndex] = React28.useState(0);
10128
+ const [imgIndex, setImgIndex] = React29.useState(0);
10041
10129
  const images = stop ? [stop.coverImage, ...(_a = stop.images) != null ? _a : []] : [];
10042
10130
  const isFirst = (stop == null ? void 0 : stop.dayNumber) === ((_b = allStops[0]) == null ? void 0 : _b.dayNumber);
10043
10131
  const isLast = (stop == null ? void 0 : stop.dayNumber) === ((_c = allStops[allStops.length - 1]) == null ? void 0 : _c.dayNumber);
10044
- React28.useEffect(() => {
10132
+ React29.useEffect(() => {
10045
10133
  setImgIndex(0);
10046
10134
  }, [stop == null ? void 0 : stop.dayNumber]);
10047
10135
  if (!stop) return null;
@@ -10168,8 +10256,8 @@ function ItineraryModal({
10168
10256
  ) });
10169
10257
  }
10170
10258
  function Itinerary({ title, subtitle, stops, className }) {
10171
- const [activeIndex, setActiveIndex] = React28.useState(null);
10172
- const scrollRef = React28.useRef(null);
10259
+ const [activeIndex, setActiveIndex] = React29.useState(null);
10260
+ const scrollRef = React29.useRef(null);
10173
10261
  const activeStop = activeIndex !== null ? stops[activeIndex] : null;
10174
10262
  const scrollBy = (dir) => {
10175
10263
  if (!scrollRef.current) return;
@@ -10261,18 +10349,18 @@ function Lightbox({
10261
10349
  onClose
10262
10350
  }) {
10263
10351
  var _a;
10264
- const [index, setIndex] = React28.useState(initialIndex);
10352
+ const [index, setIndex] = React29.useState(initialIndex);
10265
10353
  const total = photos.length;
10266
10354
  const photo = photos[index];
10267
- const prev = React28.useCallback(
10355
+ const prev = React29.useCallback(
10268
10356
  () => setIndex((i) => (i - 1 + total) % total),
10269
10357
  [total]
10270
10358
  );
10271
- const next = React28.useCallback(
10359
+ const next = React29.useCallback(
10272
10360
  () => setIndex((i) => (i + 1) % total),
10273
10361
  [total]
10274
10362
  );
10275
- React28.useEffect(() => {
10363
+ React29.useEffect(() => {
10276
10364
  const onKey = (e) => {
10277
10365
  if (e.key === "Escape") onClose();
10278
10366
  if (e.key === "ArrowLeft") prev();
@@ -10438,7 +10526,7 @@ function GridGallery({
10438
10526
  initialVisible,
10439
10527
  onOpen
10440
10528
  }) {
10441
- const [expanded, setExpanded] = React28.useState(false);
10529
+ const [expanded, setExpanded] = React29.useState(false);
10442
10530
  const cols = gridCols(photos.length);
10443
10531
  const hasMore = photos.length > initialVisible;
10444
10532
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
@@ -10468,7 +10556,7 @@ function CompactGridGallery({
10468
10556
  initialVisible,
10469
10557
  onOpen
10470
10558
  }) {
10471
- const [expanded, setExpanded] = React28.useState(false);
10559
+ const [expanded, setExpanded] = React29.useState(false);
10472
10560
  const hasMore = photos.length > initialVisible;
10473
10561
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
10474
10562
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10497,7 +10585,7 @@ function MasonryGallery({
10497
10585
  initialVisible,
10498
10586
  onOpen
10499
10587
  }) {
10500
- const [expanded, setExpanded] = React28.useState(false);
10588
+ const [expanded, setExpanded] = React29.useState(false);
10501
10589
  const hasMore = photos.length > initialVisible;
10502
10590
  const visible = expanded || !hasMore ? photos : photos.slice(0, initialVisible);
10503
10591
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10570,7 +10658,7 @@ function FeaturedGallery({
10570
10658
  photos,
10571
10659
  onOpen
10572
10660
  }) {
10573
- const [expanded, setExpanded] = React28.useState(false);
10661
+ const [expanded, setExpanded] = React29.useState(false);
10574
10662
  const featured = photos.slice(0, 3);
10575
10663
  const extra = photos.slice(3);
10576
10664
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10737,9 +10825,9 @@ function PhotoGallery({
10737
10825
  onPhotoClick,
10738
10826
  className
10739
10827
  }) {
10740
- const [lightboxIndex, setLightboxIndex] = React28.useState(null);
10741
- const [carouselIndex, setCarouselIndex] = React28.useState(0);
10742
- const normalised = React28.useMemo(() => photos.map(normalise), [photos]);
10828
+ const [lightboxIndex, setLightboxIndex] = React29.useState(null);
10829
+ const [carouselIndex, setCarouselIndex] = React29.useState(0);
10830
+ const normalised = React29.useMemo(() => photos.map(normalise), [photos]);
10743
10831
  const handleOpen = (index) => {
10744
10832
  setLightboxIndex(index);
10745
10833
  onPhotoClick == null ? void 0 : onPhotoClick(normalised[index].src, index);
@@ -10823,7 +10911,7 @@ function ItineraryDay({
10823
10911
  photoLayout = "rounded",
10824
10912
  className
10825
10913
  }) {
10826
- const photoList = React28.useMemo(() => normalisePhotos(photos), [photos]);
10914
+ const photoList = React29.useMemo(() => normalisePhotos(photos), [photos]);
10827
10915
  const isFullBleed = photoLayout === "fullBleed" || photoLayout === "fullBleedBottom";
10828
10916
  const photoPosition = photoLayout === "fullBleedBottom" ? "bottom" : "top";
10829
10917
  const gallery = photoList.length > 0 && /* @__PURE__ */ jsx(
@@ -10878,8 +10966,8 @@ function MenuTrip({
10878
10966
  bold = true,
10879
10967
  className
10880
10968
  }) {
10881
- const scrollRef = React28.useRef(null);
10882
- React28.useEffect(() => {
10969
+ const scrollRef = React29.useRef(null);
10970
+ React29.useEffect(() => {
10883
10971
  if (!scrollRef.current || !activeSection) return;
10884
10972
  const container = scrollRef.current;
10885
10973
  const btn = container.querySelector(
@@ -11021,7 +11109,12 @@ var badgeVariants = cva(
11021
11109
  destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
11022
11110
  outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
11023
11111
  ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
11024
- link: "text-primary underline-offset-4 hover:underline"
11112
+ link: "text-primary underline-offset-4 hover:underline",
11113
+ // ── Semantic soft tones (added for status surfaces) ────────────────
11114
+ success: "bg-success/10 text-success border-success/20 [a]:hover:bg-success/20",
11115
+ warning: "bg-warning/15 text-warning-foreground border-warning/30 dark:bg-warning/20 dark:text-warning [a]:hover:bg-warning/25",
11116
+ info: "bg-info/10 text-info border-info/20 [a]:hover:bg-info/20",
11117
+ neutral: "bg-muted text-muted-foreground border-border [a]:hover:bg-muted/70"
11025
11118
  }
11026
11119
  },
11027
11120
  defaultVariants: {
@@ -11070,8 +11163,8 @@ function PricingTrip({
11070
11163
  className
11071
11164
  }) {
11072
11165
  const rOuter = sharp ? "rounded-none" : "rounded-2xl";
11073
- const [showEstimates, setShowEstimates] = React28.useState(false);
11074
- const [showPriceInfo, setShowPriceInfo] = React28.useState(false);
11166
+ const [showEstimates, setShowEstimates] = React29.useState(false);
11167
+ const [showPriceInfo, setShowPriceInfo] = React29.useState(false);
11075
11168
  if (variant === "compact") {
11076
11169
  const showOverlay = showPriceInfo && (!!priceInfo || !!currencyEstimates && currencyEstimates.length > 0);
11077
11170
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
@@ -11511,14 +11604,14 @@ function SiteHeader({
11511
11604
  }) {
11512
11605
  const t = VARIANT[variant];
11513
11606
  const resolvedLogo = logoSrc != null ? logoSrc : variant === "white" ? logoSrcDark : logoSrcLight;
11514
- const [openMenu, setOpenMenu] = React28.useState(null);
11515
- const [langOpen, setLangOpen] = React28.useState(false);
11516
- const [mobileOpen, setMobileOpen] = React28.useState(false);
11517
- const [openMobileSection, setOpenMobileSection] = React28.useState(null);
11518
- const [activeLang, setActiveLang] = React28.useState(currentLanguage);
11607
+ const [openMenu, setOpenMenu] = React29.useState(null);
11608
+ const [langOpen, setLangOpen] = React29.useState(false);
11609
+ const [mobileOpen, setMobileOpen] = React29.useState(false);
11610
+ const [openMobileSection, setOpenMobileSection] = React29.useState(null);
11611
+ const [activeLang, setActiveLang] = React29.useState(currentLanguage);
11519
11612
  const toggleMobileSection = (label) => setOpenMobileSection((prev) => prev === label ? null : label);
11520
- const menuCloseTimer = React28.useRef(void 0);
11521
- const langCloseTimer = React28.useRef(void 0);
11613
+ const menuCloseTimer = React29.useRef(void 0);
11614
+ const langCloseTimer = React29.useRef(void 0);
11522
11615
  const handleMenuEnter = (label) => {
11523
11616
  clearTimeout(menuCloseTimer.current);
11524
11617
  setOpenMenu(label);
@@ -11539,7 +11632,7 @@ function SiteHeader({
11539
11632
  setOpenMenu(null);
11540
11633
  setLangOpen(false);
11541
11634
  };
11542
- React28.useEffect(() => () => {
11635
+ React29.useEffect(() => () => {
11543
11636
  clearTimeout(menuCloseTimer.current);
11544
11637
  clearTimeout(langCloseTimer.current);
11545
11638
  }, []);
@@ -11815,7 +11908,7 @@ function SiteHeader({
11815
11908
  ), children: [
11816
11909
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: languages.map((lang, i) => {
11817
11910
  const isActive = lang.code === activeLang;
11818
- return /* @__PURE__ */ jsxs(React28.Fragment, { children: [
11911
+ return /* @__PURE__ */ jsxs(React29.Fragment, { children: [
11819
11912
  i > 0 && /* @__PURE__ */ jsx("span", { className: cn(
11820
11913
  "text-xs select-none",
11821
11914
  variant === "white" ? "text-border" : "text-white/15"
@@ -11877,8 +11970,8 @@ function SiteHeader({
11877
11970
  );
11878
11971
  }
11879
11972
  function ThemeToggle({ className }) {
11880
- const [dark, setDark] = React28.useState(false);
11881
- React28.useEffect(() => {
11973
+ const [dark, setDark] = React29.useState(false);
11974
+ React29.useEffect(() => {
11882
11975
  const saved = localStorage.getItem("theme");
11883
11976
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
11884
11977
  const isDark = saved === "dark" || !saved && prefersDark;
@@ -11928,7 +12021,7 @@ var chipVariants = cva(
11928
12021
  }
11929
12022
  }
11930
12023
  );
11931
- var Chip = React28.forwardRef(function Chip2(_a, ref) {
12024
+ var Chip = React29.forwardRef(function Chip2(_a, ref) {
11932
12025
  var _b = _a, { className, variant, size, href, children } = _b, props = __objRest(_b, ["className", "variant", "size", "href", "children"]);
11933
12026
  const classes = cn(chipVariants({ variant, size }), className);
11934
12027
  if (href) {
@@ -12028,7 +12121,7 @@ function TripCardEditorial(props) {
12028
12121
  difficulty,
12029
12122
  tag
12030
12123
  } = props;
12031
- const [internalFav, setInternalFav] = React28.useState(false);
12124
+ const [internalFav, setInternalFav] = React29.useState(false);
12032
12125
  const favorited = favoritedProp != null ? favoritedProp : internalFav;
12033
12126
  const handleFav = (e) => {
12034
12127
  e.preventDefault();
@@ -12173,7 +12266,7 @@ function TripCard(props) {
12173
12266
  );
12174
12267
  }
12175
12268
  function useHlsVideo(videoRef, src) {
12176
- React28.useEffect(() => {
12269
+ React29.useEffect(() => {
12177
12270
  if (!src || !videoRef.current) return;
12178
12271
  const video = videoRef.current;
12179
12272
  if (!src.includes(".m3u8")) return;
@@ -12217,11 +12310,11 @@ function TripHeader({
12217
12310
  className
12218
12311
  }) {
12219
12312
  var _a;
12220
- const [heroIndex, setHeroIndex] = React28.useState(0);
12221
- const [videoReady, setVideoReady] = React28.useState(false);
12222
- const videoRef = React28.useRef(null);
12313
+ const [heroIndex, setHeroIndex] = React29.useState(0);
12314
+ const [videoReady, setVideoReady] = React29.useState(false);
12315
+ const videoRef = React29.useRef(null);
12223
12316
  const isHls = !!(videoUrl == null ? void 0 : videoUrl.includes(".m3u8"));
12224
- const validImages = React28.useMemo(
12317
+ const validImages = React29.useMemo(
12225
12318
  () => images.map((u) => u == null ? void 0 : u.trim()).filter(Boolean),
12226
12319
  [images]
12227
12320
  );
@@ -12236,7 +12329,7 @@ function TripHeader({
12236
12329
  const nights = duration ? (_a = duration.nights) != null ? _a : Math.max(duration.days - 1, 1) : null;
12237
12330
  const hasMeta = !!(destination || duration);
12238
12331
  useHlsVideo(videoRef, isHls ? videoUrl : void 0);
12239
- React28.useEffect(() => {
12332
+ React29.useEffect(() => {
12240
12333
  if (!videoUrl) return;
12241
12334
  const el = videoRef.current;
12242
12335
  if (!el) return;
@@ -12284,6 +12377,7 @@ function TripHeader({
12284
12377
  alt: "",
12285
12378
  "aria-hidden": true,
12286
12379
  fetchPriority: "high",
12380
+ eager: true,
12287
12381
  className: cn(
12288
12382
  "absolute inset-0 h-full w-full object-cover transition-opacity duration-700",
12289
12383
  videoReady ? "opacity-0 pointer-events-none" : "opacity-100"
@@ -12320,6 +12414,7 @@ function TripHeader({
12320
12414
  src: currentSrc,
12321
12415
  alt: title,
12322
12416
  fetchPriority: safeIndex === 0 ? "high" : "auto",
12417
+ eager: safeIndex === 0,
12323
12418
  className: "absolute inset-0 h-full w-full object-cover transition-opacity duration-700"
12324
12419
  }
12325
12420
  ) : null,
@@ -12377,7 +12472,7 @@ function TripHeader({
12377
12472
  chips && chips.length > 0 ? siteHeader ? "-mt-[200px] sm:-mt-[214px]" : "-mt-[168px] sm:-mt-[182px]" : siteHeader ? "-mt-44" : "-mt-36"
12378
12473
  ),
12379
12474
  children: [
12380
- 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: [
12475
+ 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(React29.Fragment, { children: [
12381
12476
  i > 0 && /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 text-white/50 shrink-0" }),
12382
12477
  /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 font-ui hover:text-white/90 cursor-default", children: crumb.label })
12383
12478
  ] }, i)) }),
@@ -12543,10 +12638,10 @@ function LanguagePicker({
12543
12638
  }) {
12544
12639
  var _a;
12545
12640
  const t = VARIANT2[variant];
12546
- const [open, setOpen] = React28.useState(false);
12547
- const ref = React28.useRef(null);
12641
+ const [open, setOpen] = React29.useState(false);
12642
+ const ref = React29.useRef(null);
12548
12643
  const active = (_a = languages.find((l) => l.code === currentLanguage)) != null ? _a : languages[0];
12549
- React28.useEffect(() => {
12644
+ React29.useEffect(() => {
12550
12645
  if (!open) return;
12551
12646
  const onDocClick = (e) => {
12552
12647
  if (ref.current && !ref.current.contains(e.target)) {
@@ -12747,7 +12842,7 @@ function SiteFooter({
12747
12842
  children: wrapper
12748
12843
  },
12749
12844
  b.alt + i
12750
- ) : /* @__PURE__ */ jsx(React28.Fragment, { children: wrapper }, b.alt + i);
12845
+ ) : /* @__PURE__ */ jsx(React29.Fragment, { children: wrapper }, b.alt + i);
12751
12846
  }) })
12752
12847
  ] }),
12753
12848
  themes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-3", children: [
@@ -12922,10 +13017,10 @@ function TripPage({
12922
13017
  className
12923
13018
  }) {
12924
13019
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
12925
- const [activeSection, setActiveSection] = React28.useState("");
12926
- const [accordionValue, setAccordionValue] = React28.useState([]);
12927
- const [faqsExpanded, setFaqsExpanded] = React28.useState(false);
12928
- const accordionSectionIds = React28.useMemo(
13020
+ const [activeSection, setActiveSection] = React29.useState("");
13021
+ const [accordionValue, setAccordionValue] = React29.useState([]);
13022
+ const [faqsExpanded, setFaqsExpanded] = React29.useState(false);
13023
+ const accordionSectionIds = React29.useMemo(
12929
13024
  () => /* @__PURE__ */ new Set([
12930
13025
  "when-it-operates",
12931
13026
  "how-to-get-there",
@@ -12939,18 +13034,18 @@ function TripPage({
12939
13034
  ]),
12940
13035
  []
12941
13036
  );
12942
- const [navFloating, setNavFloating] = React28.useState(false);
12943
- const [navHidden, setNavHidden] = React28.useState(false);
12944
- const [isFloating, setIsFloating] = React28.useState(false);
12945
- const [sidebarPos, setSidebarPos] = React28.useState(null);
12946
- const [pricingBarVisible, setPricingBarVisible] = React28.useState(false);
12947
- const navRef = React28.useRef(null);
12948
- const navSentinelRef = React28.useRef(null);
12949
- const sentinelRef = React28.useRef(null);
12950
- const sidebarPlaceholderRef = React28.useRef(null);
12951
- const pricingBarRef = React28.useRef(null);
12952
- const galleryRef = React28.useRef(null);
12953
- const sections = React28.useMemo(
13037
+ const [navFloating, setNavFloating] = React29.useState(false);
13038
+ const [navHidden, setNavHidden] = React29.useState(false);
13039
+ const [isFloating, setIsFloating] = React29.useState(false);
13040
+ const [sidebarPos, setSidebarPos] = React29.useState(null);
13041
+ const [pricingBarVisible, setPricingBarVisible] = React29.useState(false);
13042
+ const navRef = React29.useRef(null);
13043
+ const navSentinelRef = React29.useRef(null);
13044
+ const sentinelRef = React29.useRef(null);
13045
+ const sidebarPlaceholderRef = React29.useRef(null);
13046
+ const pricingBarRef = React29.useRef(null);
13047
+ const galleryRef = React29.useRef(null);
13048
+ const sections = React29.useMemo(
12954
13049
  () => {
12955
13050
  var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2;
12956
13051
  return [
@@ -12972,7 +13067,7 @@ function TripPage({
12972
13067
  // eslint-disable-next-line react-hooks/exhaustive-deps
12973
13068
  []
12974
13069
  );
12975
- React28.useEffect(() => {
13070
+ React29.useEffect(() => {
12976
13071
  const sentinel = navSentinelRef.current;
12977
13072
  if (!sentinel) return;
12978
13073
  const update = () => setNavFloating(sentinel.getBoundingClientRect().top < 1);
@@ -12980,7 +13075,7 @@ function TripPage({
12980
13075
  update();
12981
13076
  return () => document.removeEventListener("scroll", update, { capture: true });
12982
13077
  }, []);
12983
- React28.useEffect(() => {
13078
+ React29.useEffect(() => {
12984
13079
  const sentinel = sentinelRef.current;
12985
13080
  if (!sentinel) return;
12986
13081
  const update = () => setIsFloating(sentinel.getBoundingClientRect().top < 1);
@@ -12988,7 +13083,7 @@ function TripPage({
12988
13083
  update();
12989
13084
  return () => document.removeEventListener("scroll", update, { capture: true });
12990
13085
  }, []);
12991
- React28.useEffect(() => {
13086
+ React29.useEffect(() => {
12992
13087
  const measure = () => {
12993
13088
  if (!sidebarPlaceholderRef.current) return;
12994
13089
  const rect = sidebarPlaceholderRef.current.getBoundingClientRect();
@@ -12998,7 +13093,7 @@ function TripPage({
12998
13093
  window.addEventListener("resize", measure);
12999
13094
  return () => window.removeEventListener("resize", measure);
13000
13095
  }, [isFloating]);
13001
- React28.useEffect(() => {
13096
+ React29.useEffect(() => {
13002
13097
  const check = () => {
13003
13098
  var _a2;
13004
13099
  const target = (_a2 = galleryRef.current) != null ? _a2 : pricingBarRef.current;
@@ -13009,7 +13104,7 @@ function TripPage({
13009
13104
  check();
13010
13105
  return () => document.removeEventListener("scroll", check, { capture: true });
13011
13106
  }, []);
13012
- React28.useEffect(() => {
13107
+ React29.useEffect(() => {
13013
13108
  const check = () => {
13014
13109
  if (!pricingBarRef.current) return;
13015
13110
  setNavHidden(pricingBarRef.current.getBoundingClientRect().top < window.innerHeight * 0.92);
@@ -13018,7 +13113,7 @@ function TripPage({
13018
13113
  check();
13019
13114
  return () => document.removeEventListener("scroll", check, { capture: true });
13020
13115
  }, []);
13021
- React28.useEffect(() => {
13116
+ React29.useEffect(() => {
13022
13117
  if (sections.length === 0) return;
13023
13118
  setActiveSection(sections[0].id);
13024
13119
  const update = () => {
@@ -13493,7 +13588,385 @@ function TripPage({
13493
13588
  }
13494
13589
  );
13495
13590
  }
13591
+ function ArrowIcon2() {
13592
+ return /* @__PURE__ */ jsxs(
13593
+ "svg",
13594
+ {
13595
+ width: "13",
13596
+ height: "13",
13597
+ viewBox: "0 0 24 24",
13598
+ fill: "none",
13599
+ stroke: "currentColor",
13600
+ strokeWidth: "2.2",
13601
+ strokeLinecap: "round",
13602
+ strokeLinejoin: "round",
13603
+ children: [
13604
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
13605
+ /* @__PURE__ */ jsx("polyline", { points: "12 5 19 12 12 19" })
13606
+ ]
13607
+ }
13608
+ );
13609
+ }
13496
13610
  var sizeConfig2 = {
13611
+ sm: {
13612
+ card: "h-72 w-56",
13613
+ title: "text-lg font-bold",
13614
+ meta: "text-xs",
13615
+ excerpt: "text-xs"
13616
+ },
13617
+ md: {
13618
+ card: "h-96 w-72",
13619
+ title: "text-xl font-bold",
13620
+ meta: "text-xs",
13621
+ excerpt: "text-sm"
13622
+ },
13623
+ lg: {
13624
+ card: "h-[28rem] w-96",
13625
+ title: "text-2xl font-bold",
13626
+ meta: "text-sm",
13627
+ excerpt: "text-sm"
13628
+ }
13629
+ };
13630
+ function BlogCard({
13631
+ image,
13632
+ imageAlt = "",
13633
+ category,
13634
+ readingTime,
13635
+ date,
13636
+ title,
13637
+ excerpt,
13638
+ href,
13639
+ cta,
13640
+ size = "md",
13641
+ className
13642
+ }) {
13643
+ var _a;
13644
+ const s = sizeConfig2[size];
13645
+ const meta = [date != null ? date : null, readingTime != null ? readingTime : null].filter(Boolean).join(" | ");
13646
+ const ctaLabel = (_a = cta == null ? void 0 : cta.label) != null ? _a : "Read more";
13647
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
13648
+ /* @__PURE__ */ jsx(
13649
+ "img",
13650
+ {
13651
+ src: image,
13652
+ alt: imageAlt,
13653
+ loading: "lazy",
13654
+ className: "absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
13655
+ }
13656
+ ),
13657
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/90 via-black/40 to-black/10" }),
13658
+ category ? /* @__PURE__ */ jsx("div", { className: "relative z-10 p-3", children: /* @__PURE__ */ jsx(Chip, { variant: "glass", children: category }) }) : /* @__PURE__ */ jsx("div", { className: "relative z-10" }),
13659
+ /* @__PURE__ */ jsxs("div", { className: "relative z-10 flex flex-col gap-1.5 p-5", children: [
13660
+ meta && /* @__PURE__ */ jsx("p", { className: cn("text-white/70 font-medium font-ui", s.meta), children: meta }),
13661
+ /* @__PURE__ */ jsx("h3", { className: cn("text-white leading-snug", s.title), children: title }),
13662
+ excerpt && /* @__PURE__ */ jsx(
13663
+ "p",
13664
+ {
13665
+ className: cn(
13666
+ "text-white/80 leading-relaxed -mt-1 line-clamp-2",
13667
+ s.excerpt
13668
+ ),
13669
+ children: excerpt
13670
+ }
13671
+ ),
13672
+ /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center justify-between gap-4", children: /* @__PURE__ */ jsxs(
13673
+ "span",
13674
+ {
13675
+ className: cn(
13676
+ "group/cta inline-flex items-center gap-1.5 border-b border-white/70 pb-0.5",
13677
+ "text-sm font-semibold text-white transition-colors hover:border-white hover:text-white",
13678
+ "font-ui"
13679
+ ),
13680
+ children: [
13681
+ ctaLabel,
13682
+ /* @__PURE__ */ jsx("span", { className: "transition-transform duration-150 group-hover/cta:translate-x-0.5", children: /* @__PURE__ */ jsx(ArrowIcon2, {}) })
13683
+ ]
13684
+ }
13685
+ ) })
13686
+ ] })
13687
+ ] });
13688
+ const baseClasses = cn(
13689
+ "group relative flex flex-col justify-between overflow-hidden rounded-2xl",
13690
+ "shadow-md transition-shadow duration-300 hover:shadow-xl",
13691
+ s.card,
13692
+ className
13693
+ );
13694
+ return href ? /* @__PURE__ */ jsx(
13695
+ "a",
13696
+ {
13697
+ href,
13698
+ onClick: cta == null ? void 0 : cta.onClick,
13699
+ className: baseClasses,
13700
+ "aria-label": title,
13701
+ children: inner
13702
+ }
13703
+ ) : /* @__PURE__ */ jsx("div", { className: baseClasses, children: inner });
13704
+ }
13705
+ function SectionHeading({
13706
+ eyebrow,
13707
+ title,
13708
+ rightSlot
13709
+ }) {
13710
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-4 flex-wrap mb-6", children: [
13711
+ /* @__PURE__ */ jsxs("div", { children: [
13712
+ eyebrow && /* @__PURE__ */ jsx("p", { className: "text-xs font-mono font-semibold text-primary uppercase tracking-widest mb-1", children: eyebrow }),
13713
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-foreground font-heading leading-tight", children: title })
13714
+ ] }),
13715
+ rightSlot
13716
+ ] });
13717
+ }
13718
+ function CategoryPage2({
13719
+ title,
13720
+ intro,
13721
+ heroImage,
13722
+ trustpilotMini,
13723
+ breadcrumb,
13724
+ siteHeader,
13725
+ popularTours,
13726
+ popularToursTitle = "More adventures calling your name",
13727
+ popularToursEyebrow = "Popular tours",
13728
+ trips,
13729
+ tripsTitle,
13730
+ tripsEyebrow,
13731
+ filterGroups,
13732
+ sortOptions,
13733
+ defaultSort,
13734
+ tripsInitialCount = 15,
13735
+ trustpilot,
13736
+ reviewsTitle = "Don't just take our word for it",
13737
+ reviewsSubtitle,
13738
+ blogPosts,
13739
+ aboutTitle,
13740
+ aboutContent,
13741
+ blogIntro,
13742
+ travelGuideHref,
13743
+ travelGuideLabel = "Read our Travel Guide",
13744
+ blogPostsTitle,
13745
+ blogPostsViewAllHref,
13746
+ faqs,
13747
+ faqsTitle = "Frequently asked questions",
13748
+ faqInitialCount = 5,
13749
+ gallery,
13750
+ galleryTitle,
13751
+ className
13752
+ }) {
13753
+ var _a;
13754
+ const [faqsExpanded, setFaqsExpanded] = React29.useState(false);
13755
+ const [tripsExpanded, setTripsExpanded] = React29.useState(false);
13756
+ const [filterValue, setFilterValue] = React29.useState({});
13757
+ const [sort, setSort] = React29.useState(
13758
+ defaultSort != null ? defaultSort : (_a = sortOptions == null ? void 0 : sortOptions[0]) == null ? void 0 : _a.id
13759
+ );
13760
+ const sortedTrips = React29.useMemo(
13761
+ () => [...trips].sort((a, b) => {
13762
+ const af = a.featured ? 1 : 0;
13763
+ const bf = b.featured ? 1 : 0;
13764
+ return bf - af;
13765
+ }),
13766
+ [trips]
13767
+ );
13768
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
13769
+ /* @__PURE__ */ jsxs(
13770
+ "section",
13771
+ {
13772
+ className: cn(
13773
+ "relative w-full",
13774
+ siteHeader ? "min-h-[420px] pt-[140px]" : "min-h-[300px] pt-16",
13775
+ "pb-12 text-white",
13776
+ !heroImage && "bg-gradient-to-br from-primary-900 via-primary-800 to-primary-950"
13777
+ ),
13778
+ children: [
13779
+ heroImage && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 overflow-hidden", children: [
13780
+ /* @__PURE__ */ jsx(
13781
+ "img",
13782
+ {
13783
+ src: heroImage,
13784
+ alt: "",
13785
+ "aria-hidden": true,
13786
+ fetchPriority: "high",
13787
+ className: "absolute inset-0 h-full w-full object-cover"
13788
+ }
13789
+ ),
13790
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-b from-black/55 via-black/40 to-black/65" })
13791
+ ] }),
13792
+ siteHeader && /* @__PURE__ */ jsx(
13793
+ SiteHeader,
13794
+ {
13795
+ links: Array.isArray(siteHeader) ? siteHeader : void 0,
13796
+ position: "overlay"
13797
+ }
13798
+ ),
13799
+ /* @__PURE__ */ jsxs("div", { className: "relative mx-auto w-full max-w-6xl px-6 sm:px-8", children: [
13800
+ 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(React29.Fragment, { children: [
13801
+ i > 0 && /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 text-white/50 shrink-0" }),
13802
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 font-ui", children: crumb.label })
13803
+ ] }, i)) }),
13804
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl sm:text-5xl font-bold text-white font-heading leading-tight max-w-3xl", children: title }),
13805
+ intro && /* @__PURE__ */ jsx("div", { className: "mt-4 text-base sm:text-lg text-white/90 leading-relaxed max-w-2xl [&_strong]:font-semibold [&_a]:underline", children: intro }),
13806
+ trustpilotMini && /* @__PURE__ */ jsx("div", { className: "mt-5 max-w-sm", children: /* @__PURE__ */ jsx(TrustpilotEmbed, { config: trustpilotMini }) })
13807
+ ] })
13808
+ ]
13809
+ }
13810
+ ),
13811
+ popularTours && popularTours.length > 0 && /* @__PURE__ */ jsxs("section", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 py-12", children: [
13812
+ /* @__PURE__ */ jsx(
13813
+ SectionHeading,
13814
+ {
13815
+ eyebrow: popularToursEyebrow,
13816
+ title: popularToursTitle
13817
+ }
13818
+ ),
13819
+ /* @__PURE__ */ jsx("div", { className: "-mx-6 sm:-mx-8 px-6 sm:px-8 overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: /* @__PURE__ */ jsx("div", { className: "inline-flex gap-5 min-w-max pb-2", children: popularTours.map((trip, i) => {
13820
+ var _b;
13821
+ const _a2 = trip, { featured: _featured, variant: _variant } = _a2, cardProps = __objRest(_a2, ["featured", "variant"]);
13822
+ return /* @__PURE__ */ jsx(
13823
+ TripCard,
13824
+ __spreadProps(__spreadValues({}, cardProps), {
13825
+ variant: "overlay",
13826
+ size: (_b = cardProps.size) != null ? _b : "md"
13827
+ }),
13828
+ i
13829
+ );
13830
+ }) }) })
13831
+ ] }),
13832
+ /* @__PURE__ */ jsxs("section", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 pt-6 sm:pt-8 pb-12", children: [
13833
+ (tripsTitle || tripsEyebrow) && /* @__PURE__ */ jsx(SectionHeading, { eyebrow: tripsEyebrow, title: tripsTitle != null ? tripsTitle : "" }),
13834
+ filterGroups && filterGroups.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsx(
13835
+ FilterPanel,
13836
+ {
13837
+ variant: "horizontal",
13838
+ groups: filterGroups,
13839
+ value: filterValue,
13840
+ onChange: setFilterValue,
13841
+ onClearAll: () => setFilterValue({}),
13842
+ sortOptions,
13843
+ sort,
13844
+ onSortChange: setSort
13845
+ }
13846
+ ) }),
13847
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground font-ui mb-5", children: [
13848
+ trips.length,
13849
+ " ",
13850
+ trips.length === 1 ? "trip" : "trips",
13851
+ " found"
13852
+ ] }),
13853
+ (() => {
13854
+ const visibleTrips = tripsExpanded ? sortedTrips : sortedTrips.slice(0, tripsInitialCount);
13855
+ const hiddenCount = sortedTrips.length - visibleTrips.length;
13856
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
13857
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-6 gap-y-8 lg:gap-x-[35px] lg:gap-y-[38px]", children: visibleTrips.map((trip, i) => {
13858
+ const _a2 = trip, { featured: _featured } = _a2, cardProps = __objRest(_a2, ["featured"]);
13859
+ return /* @__PURE__ */ jsx(
13860
+ TripCard,
13861
+ __spreadProps(__spreadValues({}, cardProps), {
13862
+ className: cn("w-full h-auto", cardProps.className)
13863
+ }),
13864
+ i
13865
+ );
13866
+ }) }),
13867
+ sortedTrips.length > tripsInitialCount && /* @__PURE__ */ jsx("div", { className: "mt-8 flex justify-center", children: /* @__PURE__ */ jsx(
13868
+ "button",
13869
+ {
13870
+ type: "button",
13871
+ onClick: () => setTripsExpanded((v) => !v),
13872
+ className: cn(
13873
+ "inline-flex items-center gap-2 rounded-full border border-border bg-background px-5 py-2.5",
13874
+ "text-sm font-semibold text-foreground shadow-sm",
13875
+ "hover:bg-muted transition-colors duration-150",
13876
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
13877
+ ),
13878
+ children: tripsExpanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
13879
+ /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4 text-muted-foreground" }),
13880
+ "Show less"
13881
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
13882
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" }),
13883
+ "Load more (",
13884
+ hiddenCount,
13885
+ ")"
13886
+ ] })
13887
+ }
13888
+ ) })
13889
+ ] });
13890
+ })()
13891
+ ] }),
13892
+ trustpilot && /* @__PURE__ */ jsxs("section", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 py-12 border-t border-border", children: [
13893
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-foreground font-heading mb-2", children: reviewsTitle }),
13894
+ reviewsSubtitle && /* @__PURE__ */ jsx("p", { className: "text-base text-muted-foreground leading-relaxed max-w-3xl mb-6 [&_a]:text-primary [&_a]:underline", children: reviewsSubtitle }),
13895
+ /* @__PURE__ */ jsx("div", { className: "min-h-[400px]", children: /* @__PURE__ */ jsx(TrustpilotEmbed, { config: trustpilot }) })
13896
+ ] }),
13897
+ gallery && gallery.length > 0 && /* @__PURE__ */ jsxs("section", { className: "pt-4", children: [
13898
+ galleryTitle && /* @__PURE__ */ jsx("h2", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 mb-6 text-2xl sm:text-3xl font-bold text-foreground font-heading", children: galleryTitle }),
13899
+ /* @__PURE__ */ jsx(PhotoGallery, { photos: gallery, variant: "gridCompact", initialVisible: 8 })
13900
+ ] }),
13901
+ (aboutTitle || aboutContent || blogPostsTitle || blogPosts && blogPosts.length > 0) && /* @__PURE__ */ jsx("section", { className: "w-full bg-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 py-14", children: [
13902
+ (aboutTitle || blogPostsTitle) && /* @__PURE__ */ jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-foreground font-heading mb-5", children: aboutTitle != null ? aboutTitle : blogPostsTitle }),
13903
+ aboutContent && /* @__PURE__ */ jsx("div", { className: "text-base text-foreground/85 leading-relaxed space-y-3 max-w-3xl mb-10 [&_strong]:font-semibold [&_a]:text-primary [&_a]:font-bold [&_a]:underline", children: aboutContent }),
13904
+ blogPosts && blogPosts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
13905
+ blogIntro && /* @__PURE__ */ jsx("p", { className: "mb-6 text-base sm:text-lg font-semibold text-foreground font-heading", children: blogIntro }),
13906
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5", children: blogPosts.map((post, i) => /* @__PURE__ */ jsx(
13907
+ BlogCard,
13908
+ {
13909
+ href: post.href,
13910
+ image: post.image,
13911
+ imageAlt: post.imageAlt,
13912
+ title: post.title,
13913
+ excerpt: post.excerpt,
13914
+ category: post.category,
13915
+ readingTime: post.readingTime,
13916
+ className: "w-full"
13917
+ },
13918
+ i
13919
+ )) }),
13920
+ (travelGuideHref || blogPostsViewAllHref) && /* @__PURE__ */ jsx("div", { className: "mt-6 flex justify-end", children: /* @__PURE__ */ jsxs(
13921
+ "a",
13922
+ {
13923
+ href: travelGuideHref != null ? travelGuideHref : blogPostsViewAllHref,
13924
+ className: "inline-flex items-center gap-1.5 text-sm font-semibold text-primary hover:underline",
13925
+ children: [
13926
+ travelGuideHref ? travelGuideLabel : "View all posts",
13927
+ /* @__PURE__ */ jsx(ArrowRightIcon, { className: "h-4 w-4" })
13928
+ ]
13929
+ }
13930
+ ) })
13931
+ ] })
13932
+ ] }) }),
13933
+ faqs && faqs.length > 0 && (() => {
13934
+ const visibleFaqs = faqsExpanded ? faqs : faqs.slice(0, faqInitialCount);
13935
+ const hiddenCount = faqs.length - visibleFaqs.length;
13936
+ return /* @__PURE__ */ jsxs("section", { className: "mx-auto w-full max-w-6xl px-6 sm:px-8 py-12", children: [
13937
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-foreground font-heading mb-6", children: faqsTitle }),
13938
+ /* @__PURE__ */ jsx(Accordion, { variant: "faq", children: visibleFaqs.map((faq, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `faq-${i}`, children: [
13939
+ /* @__PURE__ */ jsx(AccordionTrigger, { children: faq.question }),
13940
+ /* @__PURE__ */ jsx(AccordionContent, { children: faq.answer })
13941
+ ] }, i)) }),
13942
+ faqs.length > faqInitialCount && /* @__PURE__ */ jsx("div", { className: "mt-5 flex justify-center", children: /* @__PURE__ */ jsx(
13943
+ "button",
13944
+ {
13945
+ type: "button",
13946
+ onClick: () => setFaqsExpanded((v) => !v),
13947
+ className: cn(
13948
+ "inline-flex items-center gap-2 rounded-full border border-border bg-background px-5 py-2.5",
13949
+ "text-sm font-semibold text-foreground shadow-sm",
13950
+ "hover:bg-muted transition-colors duration-150",
13951
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
13952
+ ),
13953
+ children: faqsExpanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
13954
+ /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4 text-muted-foreground" }),
13955
+ "Show less"
13956
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
13957
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" }),
13958
+ "See more (",
13959
+ hiddenCount,
13960
+ ")"
13961
+ ] })
13962
+ }
13963
+ ) })
13964
+ ] });
13965
+ })(),
13966
+ /* @__PURE__ */ jsx(SiteFooter, {})
13967
+ ] });
13968
+ }
13969
+ var sizeConfig3 = {
13497
13970
  sm: {
13498
13971
  card: "w-56",
13499
13972
  image: "h-36",
@@ -13528,7 +14001,7 @@ function ActivityCard({
13528
14001
  size = "md",
13529
14002
  className
13530
14003
  }) {
13531
- const s = sizeConfig2[size];
14004
+ const s = sizeConfig3[size];
13532
14005
  return /* @__PURE__ */ jsxs(
13533
14006
  "div",
13534
14007
  {
@@ -13594,12 +14067,12 @@ function Toast({
13594
14067
  duration = 6e3,
13595
14068
  className
13596
14069
  }) {
13597
- const [mounted, setMounted] = React28.useState(false);
13598
- const [visible, setVisible] = React28.useState(true);
13599
- React28.useEffect(() => {
14070
+ const [mounted, setMounted] = React29.useState(false);
14071
+ const [visible, setVisible] = React29.useState(true);
14072
+ React29.useEffect(() => {
13600
14073
  setMounted(true);
13601
14074
  }, []);
13602
- React28.useEffect(() => {
14075
+ React29.useEffect(() => {
13603
14076
  if (duration === 0) return;
13604
14077
  const t = setTimeout(() => {
13605
14078
  setVisible(false);
@@ -14741,7 +15214,517 @@ function AskExo({
14741
15214
  )
14742
15215
  ] });
14743
15216
  }
15217
+ var STATUS_MAP = {
15218
+ "draft": { label: "Draft", variant: "neutral", dot: "bg-muted-foreground" },
15219
+ "pending-approval": { label: "Pending approval", variant: "warning", dot: "bg-warning" },
15220
+ "pending-group": { label: "Pending group", variant: "info", dot: "bg-info" },
15221
+ "confirmed": { label: "Confirmed", variant: "success", dot: "bg-success" },
15222
+ "payment-pending": { label: "Payment pending", variant: "warning", dot: "bg-warning" },
15223
+ "payment-reconciliation": { label: "Reconciliation", variant: "info", dot: "bg-info" },
15224
+ "fully-paid": { label: "Fully paid", variant: "default", dot: "bg-primary-foreground" },
15225
+ "full": { label: "Full", variant: "secondary", dot: "bg-secondary-foreground" },
15226
+ "waiting-list": { label: "Waiting list", variant: "info", dot: "bg-info" },
15227
+ "operating": { label: "Operating", variant: "default", dot: "bg-primary-foreground" },
15228
+ "cancelled": { label: "Cancelled", variant: "destructive", dot: "bg-destructive" }
15229
+ };
15230
+ function StatusBadge2({ status, dot = true, label, className }) {
15231
+ const config = STATUS_MAP[status];
15232
+ return /* @__PURE__ */ jsxs(Badge, { variant: config.variant, className: cn("gap-1.5", className), children: [
15233
+ dot && /* @__PURE__ */ jsx(
15234
+ "span",
15235
+ {
15236
+ "aria-hidden": "true",
15237
+ className: cn("size-1.5 shrink-0 rounded-full", config.dot)
15238
+ }
15239
+ ),
15240
+ label != null ? label : config.label
15241
+ ] });
15242
+ }
15243
+ function GroupStatusBanner({
15244
+ variant = "info",
15245
+ title,
15246
+ icon,
15247
+ action,
15248
+ urgent = false,
15249
+ children,
15250
+ className
15251
+ }) {
15252
+ return /* @__PURE__ */ jsx(
15253
+ Alert,
15254
+ {
15255
+ variant,
15256
+ title,
15257
+ icon,
15258
+ action,
15259
+ role: urgent ? "alert" : "status",
15260
+ className,
15261
+ children
15262
+ }
15263
+ );
15264
+ }
15265
+ function ParticipantCounter({
15266
+ current,
15267
+ max,
15268
+ label = "Travelers",
15269
+ hideIcon = false,
15270
+ className
15271
+ }) {
15272
+ return /* @__PURE__ */ jsxs(
15273
+ "span",
15274
+ {
15275
+ className: cn(
15276
+ "inline-flex items-center gap-1.5 font-ui text-sm text-foreground",
15277
+ className
15278
+ ),
15279
+ children: [
15280
+ !hideIcon && /* @__PURE__ */ jsx(UsersIcon, { className: "size-4 text-primary", "aria-hidden": "true" }),
15281
+ /* @__PURE__ */ jsxs("span", { className: "font-bold tabular-nums", children: [
15282
+ current,
15283
+ " / ",
15284
+ max
15285
+ ] }),
15286
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label })
15287
+ ]
15288
+ }
15289
+ );
15290
+ }
15291
+ function GroupProgressBar({
15292
+ current,
15293
+ min,
15294
+ max,
15295
+ hideLabels = false,
15296
+ className
15297
+ }) {
15298
+ const pct = Math.max(0, Math.min(100, current / max * 100));
15299
+ const minPct = Math.max(0, Math.min(100, min / max * 100));
15300
+ const quorumMet = current >= min;
15301
+ const isFull = current >= max;
15302
+ const fillTone = isFull ? "bg-success" : quorumMet ? "bg-primary" : "bg-warning";
15303
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
15304
+ /* @__PURE__ */ jsxs(
15305
+ "div",
15306
+ {
15307
+ className: "relative h-3 w-full overflow-visible rounded-full bg-muted",
15308
+ role: "progressbar",
15309
+ "aria-valuenow": current,
15310
+ "aria-valuemin": 0,
15311
+ "aria-valuemax": max,
15312
+ "aria-label": `${current} of ${max} travelers, minimum ${min}${quorumMet ? " met" : " not yet met"}`,
15313
+ children: [
15314
+ /* @__PURE__ */ jsx(
15315
+ "div",
15316
+ {
15317
+ className: cn(
15318
+ "h-full rounded-full transition-[width,background-color] duration-500",
15319
+ fillTone
15320
+ ),
15321
+ style: { width: `${pct}%` }
15322
+ }
15323
+ ),
15324
+ /* @__PURE__ */ jsx(
15325
+ "span",
15326
+ {
15327
+ "aria-hidden": "true",
15328
+ className: "absolute top-1/2 z-10 h-5 w-0.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-foreground/60",
15329
+ style: { left: `${minPct}%` }
15330
+ }
15331
+ )
15332
+ ]
15333
+ }
15334
+ ),
15335
+ !hideLabels && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between font-ui text-[11px] text-muted-foreground", children: [
15336
+ /* @__PURE__ */ jsx("span", { className: cn(quorumMet && "text-success font-semibold"), children: quorumMet ? "Quorum reached" : `Min ${min} to confirm` }),
15337
+ /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
15338
+ max,
15339
+ " max"
15340
+ ] })
15341
+ ] })
15342
+ ] });
15343
+ }
15344
+ function Card(_a) {
15345
+ var _b = _a, {
15346
+ className,
15347
+ size = "default"
15348
+ } = _b, props = __objRest(_b, [
15349
+ "className",
15350
+ "size"
15351
+ ]);
15352
+ return /* @__PURE__ */ jsx(
15353
+ "div",
15354
+ __spreadValues({
15355
+ "data-slot": "card",
15356
+ "data-size": size,
15357
+ className: cn(
15358
+ "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
15359
+ className
15360
+ )
15361
+ }, props)
15362
+ );
15363
+ }
15364
+ function CardHeader(_a) {
15365
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
15366
+ return /* @__PURE__ */ jsx(
15367
+ "div",
15368
+ __spreadValues({
15369
+ "data-slot": "card-header",
15370
+ className: cn(
15371
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
15372
+ className
15373
+ )
15374
+ }, props)
15375
+ );
15376
+ }
15377
+ function CardTitle(_a) {
15378
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
15379
+ return /* @__PURE__ */ jsx(
15380
+ "div",
15381
+ __spreadValues({
15382
+ "data-slot": "card-title",
15383
+ className: cn(
15384
+ "text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
15385
+ className
15386
+ )
15387
+ }, props)
15388
+ );
15389
+ }
15390
+ function CardContent(_a) {
15391
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
15392
+ return /* @__PURE__ */ jsx(
15393
+ "div",
15394
+ __spreadValues({
15395
+ "data-slot": "card-content",
15396
+ className: cn("px-4 group-data-[size=sm]/card:px-3", className)
15397
+ }, props)
15398
+ );
15399
+ }
15400
+ function PricingMatrixCard({
15401
+ tiers,
15402
+ currentTravelers,
15403
+ title = "Group pricing",
15404
+ locked = false,
15405
+ className
15406
+ }) {
15407
+ const activeIndex = tiers.reduce(
15408
+ (acc, t, i) => currentTravelers >= t.threshold ? i : acc,
15409
+ -1
15410
+ );
15411
+ const bestIndex = tiers.length - 1;
15412
+ return /* @__PURE__ */ jsxs(Card, { className, children: [
15413
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "font-heading", children: title }) }),
15414
+ /* @__PURE__ */ jsx(CardContent, { className: "px-0", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
15415
+ /* @__PURE__ */ jsx("caption", { className: "sr-only", children: "Price per person by number of travelers" }),
15416
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-y border-border text-left font-ui text-[11px] uppercase tracking-wide text-muted-foreground", children: [
15417
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 font-semibold", children: "Travelers" }),
15418
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-right font-semibold", children: "Price / person" })
15419
+ ] }) }),
15420
+ /* @__PURE__ */ jsx("tbody", { children: tiers.map((tier, i) => {
15421
+ const isActive = !locked && i === activeIndex;
15422
+ const isBest = i === bestIndex;
15423
+ return /* @__PURE__ */ jsxs(
15424
+ "tr",
15425
+ {
15426
+ className: cn(
15427
+ "border-b border-border last:border-0 transition-colors",
15428
+ isActive && "bg-accent",
15429
+ locked && "opacity-60"
15430
+ ),
15431
+ "aria-current": isActive ? "true" : void 0,
15432
+ children: [
15433
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
15434
+ /* @__PURE__ */ jsx("span", { className: "font-ui font-semibold text-foreground", children: tier.travelers }),
15435
+ isActive && /* @__PURE__ */ jsx(Badge, { variant: "success", className: "h-4 px-1.5 text-[10px]", children: "You are here" }),
15436
+ isBest && !isActive && /* @__PURE__ */ jsx(Badge, { variant: "info", className: "h-4 px-1.5 text-[10px]", children: "Best price" })
15437
+ ] }) }),
15438
+ /* @__PURE__ */ jsx(
15439
+ "td",
15440
+ {
15441
+ className: cn(
15442
+ "px-4 py-2.5 text-right font-ui tabular-nums",
15443
+ isActive ? "font-bold text-foreground" : "text-muted-foreground",
15444
+ isBest && "text-primary"
15445
+ ),
15446
+ children: tier.price
15447
+ }
15448
+ )
15449
+ ]
15450
+ },
15451
+ tier.travelers
15452
+ );
15453
+ }) })
15454
+ ] }) })
15455
+ ] });
15456
+ }
15457
+ function PriceProgress({
15458
+ currentPrice,
15459
+ lowestPrice,
15460
+ travelersToLowest,
15461
+ pct,
15462
+ className
15463
+ }) {
15464
+ const reached = travelersToLowest <= 0;
15465
+ const safePct = reached ? 100 : Math.max(0, Math.min(100, pct));
15466
+ return /* @__PURE__ */ jsxs(
15467
+ "div",
15468
+ {
15469
+ className: cn(
15470
+ "flex flex-col gap-3 rounded-xl border border-border bg-card p-4",
15471
+ className
15472
+ ),
15473
+ "aria-live": "polite",
15474
+ children: [
15475
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-4", children: [
15476
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
15477
+ /* @__PURE__ */ jsx("span", { className: "font-ui text-[11px] uppercase tracking-wide text-muted-foreground", children: "Current" }),
15478
+ /* @__PURE__ */ jsx("span", { className: "font-heading text-xl font-bold text-foreground tabular-nums", children: currentPrice })
15479
+ ] }),
15480
+ /* @__PURE__ */ jsx(ArrowDownIcon, { className: "mb-1 size-4 shrink-0 text-success", "aria-hidden": "true" }),
15481
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col text-right", children: [
15482
+ /* @__PURE__ */ jsx("span", { className: "font-ui text-[11px] uppercase tracking-wide text-muted-foreground", children: "Potential" }),
15483
+ /* @__PURE__ */ jsx("span", { className: "font-heading text-xl font-bold text-primary tabular-nums", children: lowestPrice })
15484
+ ] })
15485
+ ] }),
15486
+ /* @__PURE__ */ jsx("div", { className: "h-2 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx(
15487
+ "div",
15488
+ {
15489
+ className: cn(
15490
+ "h-full rounded-full transition-[width] duration-500",
15491
+ reached ? "bg-success" : "bg-primary"
15492
+ ),
15493
+ style: { width: `${safePct}%` }
15494
+ }
15495
+ ) }),
15496
+ /* @__PURE__ */ jsx(
15497
+ "p",
15498
+ {
15499
+ className: cn(
15500
+ "flex items-center gap-1.5 font-ui text-sm font-semibold",
15501
+ reached ? "text-success" : "text-foreground"
15502
+ ),
15503
+ children: reached ? /* @__PURE__ */ jsxs(Fragment, { children: [
15504
+ /* @__PURE__ */ jsx(SparkleIcon, { className: "size-4", "aria-hidden": "true" }),
15505
+ "Best possible price unlocked"
15506
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
15507
+ travelersToLowest,
15508
+ " more ",
15509
+ travelersToLowest === 1 ? "traveler" : "travelers",
15510
+ " for the lowest price"
15511
+ ] })
15512
+ }
15513
+ )
15514
+ ]
15515
+ }
15516
+ );
15517
+ }
15518
+ function ParticipantList({
15519
+ participants,
15520
+ emptySlots = 0,
15521
+ title = "Travelers",
15522
+ leaderLabel = "Leader",
15523
+ emptyMessage = "Be the first to join this adventure.",
15524
+ className
15525
+ }) {
15526
+ if (participants.length === 0 && emptySlots === 0) {
15527
+ return /* @__PURE__ */ jsx("p", { className: cn("font-sans text-sm text-muted-foreground", className), children: emptyMessage });
15528
+ }
15529
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
15530
+ title && /* @__PURE__ */ jsx("h3", { className: "font-heading text-sm font-bold text-foreground", children: title }),
15531
+ /* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-2", children: [
15532
+ participants.map((p, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3", children: [
15533
+ /* @__PURE__ */ jsx(
15534
+ "span",
15535
+ {
15536
+ className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary/10 text-primary",
15537
+ "aria-hidden": "true",
15538
+ children: p.avatarUrl ? (
15539
+ // eslint-disable-next-line @next/next/no-img-element
15540
+ /* @__PURE__ */ jsx("img", { src: p.avatarUrl, alt: "", className: "size-full object-cover" })
15541
+ ) : /* @__PURE__ */ jsx(UserIcon, { className: "size-4.5" })
15542
+ }
15543
+ ),
15544
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
15545
+ /* @__PURE__ */ jsx("span", { className: "truncate font-ui text-sm font-medium text-foreground", children: p.firstName }),
15546
+ p.flag && /* @__PURE__ */ jsx("span", { "aria-label": p.country, role: "img", className: "text-base leading-none", children: p.flag }),
15547
+ p.isLeader && /* @__PURE__ */ jsx(Badge, { variant: "info", className: "h-4 px-1.5 text-[10px]", children: leaderLabel })
15548
+ ] })
15549
+ ] }, `${p.firstName}-${i}`)),
15550
+ Array.from({ length: emptySlots }).map((_, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3 opacity-60", children: [
15551
+ /* @__PURE__ */ jsx(
15552
+ "span",
15553
+ {
15554
+ "aria-hidden": "true",
15555
+ className: "flex size-9 shrink-0 items-center justify-center rounded-full border border-dashed border-border text-muted-foreground",
15556
+ children: "+"
15557
+ }
15558
+ ),
15559
+ /* @__PURE__ */ jsx("span", { className: "font-sans text-sm text-muted-foreground", children: "Open spot" })
15560
+ ] }, `empty-${i}`))
15561
+ ] })
15562
+ ] });
15563
+ }
15564
+ function BrandIcon({ path }) {
15565
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "size-4", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: path }) });
15566
+ }
15567
+ var WHATSAPP = "M.057 24l1.687-6.163a11.867 11.867 0 01-1.587-5.945C.16 5.335 5.495 0 12.05 0a11.82 11.82 0 018.413 3.488 11.82 11.82 0 013.48 8.414c-.003 6.557-5.338 11.892-11.893 11.892a11.9 11.9 0 01-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.82 9.82 0 001.51 5.26l-.999 3.648 3.978-1.945zm5.473-6.231c-.074-.124-.272-.198-.57-.347-.297-.149-1.758-.868-2.031-.967-.272-.099-.47-.149-.669.149-.198.297-.768.967-.941 1.165-.173.198-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.372-.025-.521-.075-.148-.669-1.611-.916-2.206-.242-.579-.487-.501-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.096 3.2 5.077 4.487.709.306 1.263.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.719 2.006-1.413.248-.695.248-1.29.173-1.414z";
15568
+ var FACEBOOK = "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z";
15569
+ var X = "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z";
15570
+ function ShareWidget({
15571
+ url,
15572
+ message = "Join my adventure and let's unlock a lower price together!",
15573
+ layout = "row",
15574
+ title = "Invite friends & lower the price",
15575
+ className
15576
+ }) {
15577
+ const [copied, setCopied] = React29.useState(false);
15578
+ const [showToast, setShowToast] = React29.useState(false);
15579
+ const encodedUrl = encodeURIComponent(url);
15580
+ const encodedMsg = encodeURIComponent(`${message} ${url}`);
15581
+ const channels = [
15582
+ {
15583
+ key: "whatsapp",
15584
+ label: "WhatsApp",
15585
+ href: `https://wa.me/?text=${encodedMsg}`,
15586
+ path: WHATSAPP,
15587
+ color: "hover:text-[#25D366] hover:border-[#25D366]"
15588
+ },
15589
+ {
15590
+ key: "facebook",
15591
+ label: "Facebook",
15592
+ href: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
15593
+ path: FACEBOOK,
15594
+ color: "hover:text-[#1877F2] hover:border-[#1877F2]"
15595
+ },
15596
+ {
15597
+ key: "x",
15598
+ label: "X",
15599
+ href: `https://twitter.com/intent/tweet?text=${encodeURIComponent(message)}&url=${encodedUrl}`,
15600
+ path: X,
15601
+ color: "hover:text-foreground hover:border-foreground"
15602
+ }
15603
+ ];
15604
+ const copyLink = async () => {
15605
+ try {
15606
+ await navigator.clipboard.writeText(url);
15607
+ } catch (e) {
15608
+ }
15609
+ setCopied(true);
15610
+ setShowToast(true);
15611
+ setTimeout(() => setCopied(false), 2e3);
15612
+ };
15613
+ const isIcons = layout === "icons";
15614
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
15615
+ title && /* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-1.5 font-heading text-sm font-bold text-foreground", children: [
15616
+ /* @__PURE__ */ jsx(Share2Icon, { className: "size-4 text-primary", "aria-hidden": "true" }),
15617
+ title
15618
+ ] }),
15619
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
15620
+ channels.map((c) => /* @__PURE__ */ jsxs(
15621
+ "a",
15622
+ {
15623
+ href: c.href,
15624
+ target: "_blank",
15625
+ rel: "noopener noreferrer",
15626
+ "aria-label": `Share on ${c.label}`,
15627
+ className: cn(
15628
+ "inline-flex items-center gap-2 rounded-full border border-border px-3 py-2 font-ui text-sm text-foreground transition-colors",
15629
+ c.color
15630
+ ),
15631
+ children: [
15632
+ /* @__PURE__ */ jsx(BrandIcon, { path: c.path }),
15633
+ !isIcons && /* @__PURE__ */ jsx("span", { children: c.label })
15634
+ ]
15635
+ },
15636
+ c.key
15637
+ )),
15638
+ /* @__PURE__ */ jsxs(
15639
+ "button",
15640
+ {
15641
+ type: "button",
15642
+ onClick: copyLink,
15643
+ "aria-label": "Copy link",
15644
+ className: cn(
15645
+ "inline-flex items-center gap-2 rounded-full border border-border px-3 py-2 font-ui text-sm text-foreground transition-colors hover:border-primary hover:text-primary",
15646
+ copied && "border-success text-success"
15647
+ ),
15648
+ children: [
15649
+ copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "size-4" }),
15650
+ !isIcons && /* @__PURE__ */ jsx("span", { children: copied ? "Copied!" : "Copy link" })
15651
+ ]
15652
+ }
15653
+ )
15654
+ ] }),
15655
+ showToast && /* @__PURE__ */ jsx(
15656
+ Toast,
15657
+ {
15658
+ message: "Link copied to clipboard",
15659
+ variant: "success",
15660
+ onClose: () => setShowToast(false),
15661
+ duration: 2500
15662
+ }
15663
+ )
15664
+ ] });
15665
+ }
15666
+ var MODE_COPY = {
15667
+ joinable: { cta: "Join this adventure", disabled: false },
15668
+ full: { cta: "Join waiting list", disabled: false },
15669
+ closed: { cta: "Booking closed", disabled: true },
15670
+ owner: { cta: "Share your departure", disabled: false }
15671
+ };
15672
+ function StickyBookingCard({
15673
+ currentPrice,
15674
+ deposit,
15675
+ spotsRemaining,
15676
+ mode = "joinable",
15677
+ onPrimary,
15678
+ note,
15679
+ className
15680
+ }) {
15681
+ const { cta, disabled } = MODE_COPY[mode];
15682
+ return /* @__PURE__ */ jsxs(
15683
+ "div",
15684
+ {
15685
+ className: cn(
15686
+ "flex flex-col gap-4 rounded-2xl border border-border bg-card p-5 ring-1 ring-foreground/5",
15687
+ className
15688
+ ),
15689
+ children: [
15690
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
15691
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
15692
+ /* @__PURE__ */ jsx("span", { className: "font-ui text-[11px] uppercase tracking-wide text-muted-foreground", children: "Current price" }),
15693
+ /* @__PURE__ */ jsx("span", { className: "font-heading text-2xl font-bold text-foreground tabular-nums", children: currentPrice }),
15694
+ /* @__PURE__ */ jsx("span", { className: "font-sans text-xs text-muted-foreground", children: "per person" })
15695
+ ] }),
15696
+ mode !== "owner" && /* @__PURE__ */ jsx(
15697
+ "span",
15698
+ {
15699
+ className: cn(
15700
+ "font-ui text-xs font-semibold",
15701
+ spotsRemaining <= 2 && spotsRemaining > 0 ? "text-warning" : "text-muted-foreground"
15702
+ ),
15703
+ children: spotsRemaining > 0 ? `${spotsRemaining} spots left` : "Full"
15704
+ }
15705
+ )
15706
+ ] }),
15707
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-lg bg-muted/60 px-3 py-2", children: [
15708
+ /* @__PURE__ */ jsx("span", { className: "font-sans text-sm text-muted-foreground", children: "Deposit today" }),
15709
+ /* @__PURE__ */ jsx("span", { className: "font-ui text-sm font-bold text-foreground tabular-nums", children: deposit })
15710
+ ] }),
15711
+ /* @__PURE__ */ jsx(
15712
+ Button,
15713
+ {
15714
+ variant: "primary",
15715
+ size: "lg",
15716
+ className: "w-full",
15717
+ disabled,
15718
+ onClick: onPrimary,
15719
+ children: cta
15720
+ }
15721
+ ),
15722
+ /* @__PURE__ */ jsx("p", { className: "text-center font-sans text-xs text-muted-foreground", children: note != null ? note : "A hold is placed on your card \u2014 no charge until approved." })
15723
+ ]
15724
+ }
15725
+ );
15726
+ }
14744
15727
 
14745
- export { ActivityCard, AgentContactCard, Alert, AskExo, BirthDateField, BookingAdventureCard, BookingCancellationEmail, BookingConfirmedCard, BookingCreatedEmail, BookingDetails, BookingForm, BookingOtpEmail, BookingPaymentConfirmationEmail, BookingShell, BookingSummary, Button, COUNTRIES, CounterField, CountrySearchField, DEFAULT_HEADER_LINKS, DEFAULT_LANGUAGES, DatePickerField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, ExoOrb, FilterPanel, FloatingInput, FloatingSelect, Itinerary, ItineraryDay, LOGO_PLANETAEXO_DATA_URI, LeadCapturePopup, MenuTrip, OTPCodeInput, Offer, OfferAdventureCard, PartnerBookingCreatedEmail, PartnerRegistrationCompleteEmail, PaymentAmountSelector, PaymentDetailsBlock, PaymentMethodSelector, PaymentModalShell, PaymentReceiptEmail, PaymentReminderEmail, PhoneCountrySelect, PhotoGallery, Picture, PricingTrip, RegistrationForm, RegistrationProgressBar, RegistrationReminderEmail, RegistrationReminderIndividualEmail, RegistrationSuccessCard, SiteHeader, TERMS_ACCEPT_KEY, TermsSection, ThemeToggle, Toast, TransferDetailsBlock, TravellerFormInviteEmail, TripCard, TripHeader, TripPage, TrustpilotEmbed, buttonVariants, cn, emailTokens, formatCpf, getStripeAppearance, itineraryDaySpecIcons, stripeAppearance, validateCpf, webpVariantUrl, wrapEmailHtml };
15728
+ export { ActivityCard, AgentContactCard, Alert, AskExo, BirthDateField, BookingAdventureCard, BookingCancellationEmail, BookingConfirmedCard, BookingCreatedEmail, BookingDetails, BookingForm, BookingOtpEmail, BookingPaymentConfirmationEmail, BookingShell, BookingSummary, Button, COUNTRIES, CategoryPage2, CounterField, CountrySearchField, DEFAULT_HEADER_LINKS, DEFAULT_LANGUAGES, STATUS_MAP as DEPARTURE_STATUS_MAP, DatePickerField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, ExoOrb, FilterPanel, FloatingInput, FloatingSelect, GroupProgressBar, GroupStatusBanner, Itinerary, ItineraryDay, LOGO_PLANETAEXO_DATA_URI, LeadCapturePopup, MenuTrip, OTPCodeInput, Offer, OfferAdventureCard, ParticipantCounter, ParticipantList, PartnerBookingCreatedEmail, PartnerRegistrationCompleteEmail, PaymentAmountSelector, PaymentDetailsBlock, PaymentMethodSelector, PaymentModalShell, PaymentReceiptEmail, PaymentReminderEmail, PhoneCountrySelect, PhotoGallery, Picture, PriceProgress, PricingMatrixCard, PricingTrip, RegistrationForm, RegistrationProgressBar, RegistrationReminderEmail, RegistrationReminderIndividualEmail, RegistrationSuccessCard, ShareWidget, SiteHeader, StatusBadge2 as StatusBadge, StickyBookingCard, TERMS_ACCEPT_KEY, TermsSection, ThemeToggle, Toast, TransferDetailsBlock, TravellerFormInviteEmail, TripCard, TripHeader, TripPage, TrustpilotEmbed, buttonVariants, cn, emailTokens, formatCpf, getStripeAppearance, itineraryDaySpecIcons, stripeAppearance, validateCpf, webpVariantUrl, wrapEmailHtml };
14746
15729
  //# sourceMappingURL=index.js.map
14747
15730
  //# sourceMappingURL=index.js.map