@prosophia/lab-classic 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,12 +30,53 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AnimatedCard: () => AnimatedCard,
34
+ AnimatedGalleryGrid: () => AnimatedGalleryGrid,
35
+ AnimatedGalleryHeader: () => AnimatedGalleryHeader,
36
+ AnimatedGrid: () => AnimatedGrid,
37
+ AnimatedHeader: () => AnimatedHeader,
33
38
  AnimatedHero: () => AnimatedHero,
39
+ AnimatedHeroContent: () => AnimatedHeroContent,
40
+ AnimatedImage: () => AnimatedImage,
41
+ AnimatedItem: () => AnimatedItem,
42
+ AnimatedList: () => AnimatedList,
43
+ AnimatedMain: () => AnimatedMain,
44
+ AnimatedPage: () => AnimatedPage,
45
+ AnimatedSection: () => AnimatedSection,
46
+ AnimatedSectionHeader: () => AnimatedSectionHeader,
47
+ AnimatedStats: () => AnimatedStats,
34
48
  ClientLayout: () => ClientLayout,
35
49
  ContactCTA: () => ContactCTA,
36
50
  Footer: () => Footer,
37
51
  Header: () => Header,
38
- ThemeToggle: () => ThemeToggle
52
+ HomePage: () => HomePage,
53
+ ScrollRevealSection: () => ScrollRevealSection,
54
+ StaggeredGrid: () => StaggeredGrid,
55
+ ThemeToggle: () => ThemeToggle,
56
+ cardHover: () => cardHover,
57
+ client: () => client,
58
+ defineConfig: () => defineConfig,
59
+ escapeHtml: () => escapeHtml,
60
+ fadeIn: () => fadeIn,
61
+ fadeInUp: () => fadeInUp,
62
+ fadeInUpShort: () => fadeInUpShort,
63
+ getClient: () => getClient,
64
+ imageZoom: () => imageZoom,
65
+ isValidEmail: () => isValidEmail,
66
+ isValidExternalUrl: () => isValidExternalUrl,
67
+ isValidGoogleMapsEmbedUrl: () => isValidGoogleMapsEmbedUrl,
68
+ isValidSlug: () => isValidSlug,
69
+ pageTransition: () => pageTransition,
70
+ reducedMotion: () => reducedMotion,
71
+ sanitizeUrl: () => sanitizeUrl,
72
+ scaleIn: () => scaleIn,
73
+ scrollReveal: () => scrollReveal,
74
+ slideInLeft: () => slideInLeft,
75
+ slideInRight: () => slideInRight,
76
+ staggerContainer: () => staggerContainer,
77
+ staggerItem: () => staggerItem,
78
+ urlFor: () => urlFor,
79
+ viewportSettings: () => viewportSettings
39
80
  });
40
81
  module.exports = __toCommonJS(index_exports);
41
82
 
@@ -43,6 +84,16 @@ module.exports = __toCommonJS(index_exports);
43
84
  var import_framer_motion = require("framer-motion");
44
85
 
45
86
  // src/lib/animations.ts
87
+ var fadeIn = {
88
+ hidden: { opacity: 0 },
89
+ visible: {
90
+ opacity: 1,
91
+ transition: {
92
+ duration: 0.6,
93
+ ease: [0.65, 0, 0.35, 1]
94
+ }
95
+ }
96
+ };
46
97
  var fadeInUp = {
47
98
  hidden: { opacity: 0, y: 30 },
48
99
  visible: {
@@ -54,6 +105,17 @@ var fadeInUp = {
54
105
  }
55
106
  }
56
107
  };
108
+ var fadeInUpShort = {
109
+ hidden: { opacity: 0, y: 20 },
110
+ visible: {
111
+ opacity: 1,
112
+ y: 0,
113
+ transition: {
114
+ duration: 0.6,
115
+ ease: [0.4, 0, 0.2, 1]
116
+ }
117
+ }
118
+ };
57
119
  var scaleIn = {
58
120
  hidden: { opacity: 0, scale: 0.9 },
59
121
  visible: {
@@ -65,113 +127,660 @@ var scaleIn = {
65
127
  }
66
128
  }
67
129
  };
130
+ var slideInRight = {
131
+ hidden: { opacity: 0, x: 20 },
132
+ visible: {
133
+ opacity: 1,
134
+ x: 0,
135
+ transition: {
136
+ duration: 0.6,
137
+ ease: [0.4, 0, 0.2, 1]
138
+ }
139
+ }
140
+ };
141
+ var slideInLeft = {
142
+ hidden: { opacity: 0, x: -20 },
143
+ visible: {
144
+ opacity: 1,
145
+ x: 0,
146
+ transition: {
147
+ duration: 0.6,
148
+ ease: [0.4, 0, 0.2, 1]
149
+ }
150
+ }
151
+ };
152
+ var staggerContainer = {
153
+ hidden: { opacity: 0 },
154
+ visible: {
155
+ opacity: 1,
156
+ transition: {
157
+ staggerChildren: 0.1,
158
+ delayChildren: 0.2
159
+ }
160
+ }
161
+ };
162
+ var staggerItem = {
163
+ hidden: { opacity: 0, y: 20 },
164
+ visible: {
165
+ opacity: 1,
166
+ y: 0,
167
+ transition: {
168
+ duration: 0.5,
169
+ ease: [0.4, 0, 0.2, 1]
170
+ }
171
+ }
172
+ };
173
+ var cardHover = {
174
+ hover: {
175
+ y: -8,
176
+ transition: {
177
+ duration: 0.3,
178
+ ease: [0.4, 0, 0.2, 1]
179
+ }
180
+ }
181
+ };
182
+ var imageZoom = {
183
+ hover: {
184
+ scale: 1.08,
185
+ transition: {
186
+ duration: 0.5,
187
+ ease: [0.65, 0, 0.35, 1]
188
+ }
189
+ }
190
+ };
191
+ var pageTransition = {
192
+ hidden: { opacity: 0, y: 20 },
193
+ visible: {
194
+ opacity: 1,
195
+ y: 0,
196
+ transition: {
197
+ duration: 0.6,
198
+ ease: [0.4, 0, 0.2, 1]
199
+ }
200
+ },
201
+ exit: {
202
+ opacity: 0,
203
+ y: -20,
204
+ transition: {
205
+ duration: 0.4,
206
+ ease: [0.4, 0, 0.2, 1]
207
+ }
208
+ }
209
+ };
210
+ var viewportSettings = {
211
+ once: true,
212
+ amount: 0.3,
213
+ margin: "0px 0px -100px 0px"
214
+ };
215
+ var scrollReveal = {
216
+ hidden: { opacity: 0, y: 50 },
217
+ visible: {
218
+ opacity: 1,
219
+ y: 0,
220
+ transition: {
221
+ duration: 0.8,
222
+ ease: [0.65, 0, 0.35, 1]
223
+ }
224
+ }
225
+ };
226
+ var reducedMotion = {
227
+ hidden: { opacity: 0 },
228
+ visible: {
229
+ opacity: 1,
230
+ transition: {
231
+ duration: 0.01
232
+ }
233
+ }
234
+ };
68
235
 
69
236
  // src/components/AnimatedCard.tsx
70
237
  var import_jsx_runtime = require("react/jsx-runtime");
238
+ function AnimatedCard({ children, className, delay = 0 }) {
239
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
240
+ import_framer_motion.motion.div,
241
+ {
242
+ className,
243
+ initial: "hidden",
244
+ whileInView: "visible",
245
+ viewport: viewportSettings,
246
+ variants: {
247
+ hidden: { opacity: 0, y: 30 },
248
+ visible: {
249
+ opacity: 1,
250
+ y: 0,
251
+ transition: {
252
+ duration: 0.6,
253
+ delay,
254
+ ease: [0.4, 0, 0.2, 1]
255
+ }
256
+ }
257
+ },
258
+ whileHover: "hover",
259
+ children
260
+ }
261
+ );
262
+ }
263
+ function AnimatedImage({ children, className }) {
264
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.motion.div, { className, variants: imageZoom, children });
265
+ }
266
+ function AnimatedSection({ children, className }) {
267
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
268
+ import_framer_motion.motion.section,
269
+ {
270
+ className,
271
+ initial: "hidden",
272
+ whileInView: "visible",
273
+ viewport: viewportSettings,
274
+ variants: fadeInUpShort,
275
+ children
276
+ }
277
+ );
278
+ }
71
279
 
72
280
  // src/components/AnimatedGallery.tsx
73
281
  var import_framer_motion2 = require("framer-motion");
74
282
  var import_image = __toESM(require("next/image"));
75
283
  var import_react = require("react");
76
- var import_PicturesPage = __toESM(require("./PicturesPage.module.css"));
284
+
285
+ // src/components/PicturesPage.module.css
286
+ var PicturesPage_default = {};
287
+
288
+ // src/components/AnimatedGallery.tsx
77
289
  var import_jsx_runtime2 = require("react/jsx-runtime");
290
+ function useMounted() {
291
+ const [mounted, setMounted] = (0, import_react.useState)(false);
292
+ (0, import_react.useEffect)(() => {
293
+ setMounted(true);
294
+ }, []);
295
+ return mounted;
296
+ }
297
+ function AnimatedGalleryHeader({ children, className }) {
298
+ const mounted = useMounted();
299
+ if (!mounted) {
300
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("header", { className, children });
301
+ }
302
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
303
+ import_framer_motion2.motion.header,
304
+ {
305
+ className,
306
+ initial: { opacity: 0, y: 30 },
307
+ animate: { opacity: 1, y: 0 },
308
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] },
309
+ children
310
+ }
311
+ );
312
+ }
313
+ function AnimatedGalleryGrid({ images }) {
314
+ const mounted = useMounted();
315
+ if (!mounted) {
316
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: PicturesPage_default.photosGrid, children: images.map((pic) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: PicturesPage_default.photoCard, children: [
317
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: PicturesPage_default.photoImageWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
318
+ import_image.default,
319
+ {
320
+ src: pic.imageUrl,
321
+ alt: pic.altText,
322
+ width: pic.width,
323
+ height: pic.height,
324
+ sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw",
325
+ className: PicturesPage_default.photoImage
326
+ }
327
+ ) }),
328
+ pic.caption && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: PicturesPage_default.photoCaption, children: pic.caption })
329
+ ] }, pic._id)) });
330
+ }
331
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
332
+ import_framer_motion2.motion.div,
333
+ {
334
+ className: PicturesPage_default.photosGrid,
335
+ initial: "hidden",
336
+ animate: "visible",
337
+ variants: {
338
+ hidden: { opacity: 0 },
339
+ visible: {
340
+ opacity: 1,
341
+ transition: {
342
+ staggerChildren: 0.08,
343
+ delayChildren: 0.2
344
+ }
345
+ }
346
+ },
347
+ children: images.map((pic) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
348
+ import_framer_motion2.motion.div,
349
+ {
350
+ className: PicturesPage_default.photoCard,
351
+ variants: {
352
+ hidden: { opacity: 0, y: 40, scale: 0.95 },
353
+ visible: {
354
+ opacity: 1,
355
+ y: 0,
356
+ scale: 1,
357
+ transition: {
358
+ duration: 0.6,
359
+ ease: [0.4, 0, 0.2, 1]
360
+ }
361
+ }
362
+ },
363
+ whileHover: {
364
+ scale: 1.05,
365
+ transition: { duration: 0.3 }
366
+ },
367
+ children: [
368
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: PicturesPage_default.photoImageWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
369
+ import_image.default,
370
+ {
371
+ src: pic.imageUrl,
372
+ alt: pic.altText,
373
+ width: pic.width,
374
+ height: pic.height,
375
+ sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw",
376
+ className: PicturesPage_default.photoImage
377
+ }
378
+ ) }),
379
+ pic.caption && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: PicturesPage_default.photoCaption, children: pic.caption })
380
+ ]
381
+ },
382
+ pic._id
383
+ ))
384
+ }
385
+ );
386
+ }
78
387
 
79
- // src/components/AnimatedHero.tsx
388
+ // src/components/AnimatedPage.tsx
80
389
  var import_framer_motion3 = require("framer-motion");
81
390
  var import_react2 = require("react");
391
+ var import_jsx_runtime3 = require("react/jsx-runtime");
392
+ function useMounted2() {
393
+ const [mounted, setMounted] = (0, import_react2.useState)(false);
394
+ (0, import_react2.useEffect)(() => {
395
+ setMounted(true);
396
+ }, []);
397
+ return mounted;
398
+ }
399
+ function AnimatedPage({ children, className }) {
400
+ const mounted = useMounted2();
401
+ if (!mounted) {
402
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children });
403
+ }
404
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
405
+ import_framer_motion3.motion.div,
406
+ {
407
+ className,
408
+ initial: { opacity: 0 },
409
+ animate: { opacity: 1 },
410
+ transition: { duration: 0.6, ease: [0.4, 0, 0.2, 1] },
411
+ children
412
+ }
413
+ );
414
+ }
415
+ function AnimatedHeader({ children, className }) {
416
+ const mounted = useMounted2();
417
+ if (!mounted) {
418
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("header", { className, children });
419
+ }
420
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
421
+ import_framer_motion3.motion.header,
422
+ {
423
+ className,
424
+ initial: { opacity: 0, y: 30 },
425
+ animate: { opacity: 1, y: 0 },
426
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] },
427
+ children
428
+ }
429
+ );
430
+ }
431
+ function AnimatedMain({ children, className }) {
432
+ const mounted = useMounted2();
433
+ if (!mounted) {
434
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("main", { className, children });
435
+ }
436
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
437
+ import_framer_motion3.motion.main,
438
+ {
439
+ className,
440
+ initial: { opacity: 0, y: 20 },
441
+ animate: { opacity: 1, y: 0 },
442
+ transition: { duration: 0.6, delay: 0.2, ease: [0.4, 0, 0.2, 1] },
443
+ children
444
+ }
445
+ );
446
+ }
447
+ function StaggeredGrid({ children, className }) {
448
+ const mounted = useMounted2();
449
+ const childArray = Array.isArray(children) ? children : [children];
450
+ if (!mounted) {
451
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children });
452
+ }
453
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
454
+ import_framer_motion3.motion.div,
455
+ {
456
+ className,
457
+ initial: "hidden",
458
+ whileInView: "visible",
459
+ viewport: { once: true, amount: 0.1 },
460
+ variants: {
461
+ hidden: { opacity: 0 },
462
+ visible: {
463
+ opacity: 1,
464
+ transition: {
465
+ staggerChildren: 0.1,
466
+ delayChildren: 0.1
467
+ }
468
+ }
469
+ },
470
+ children: childArray.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
471
+ import_framer_motion3.motion.div,
472
+ {
473
+ variants: {
474
+ hidden: { opacity: 0, y: 30 },
475
+ visible: {
476
+ opacity: 1,
477
+ y: 0,
478
+ transition: {
479
+ duration: 0.6,
480
+ ease: [0.4, 0, 0.2, 1]
481
+ }
482
+ }
483
+ },
484
+ children: child
485
+ },
486
+ index
487
+ ))
488
+ }
489
+ );
490
+ }
491
+ function AnimatedItem({ children, className, delay = 0, index = 0 }) {
492
+ const mounted = useMounted2();
493
+ if (!mounted) {
494
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children });
495
+ }
496
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
497
+ import_framer_motion3.motion.div,
498
+ {
499
+ className,
500
+ initial: { opacity: 0, y: 30 },
501
+ whileInView: { opacity: 1, y: 0 },
502
+ viewport: { once: true, amount: 0.3 },
503
+ transition: {
504
+ duration: 0.6,
505
+ delay: delay || index * 0.1,
506
+ ease: [0.4, 0, 0.2, 1]
507
+ },
508
+ children
509
+ }
510
+ );
511
+ }
512
+ function ScrollRevealSection({ children, className }) {
513
+ const mounted = useMounted2();
514
+ if (!mounted) {
515
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("section", { className, children });
516
+ }
517
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
518
+ import_framer_motion3.motion.section,
519
+ {
520
+ className,
521
+ initial: { opacity: 0, y: 40 },
522
+ whileInView: { opacity: 1, y: 0 },
523
+ viewport: { once: true, amount: 0.2 },
524
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] },
525
+ children
526
+ }
527
+ );
528
+ }
529
+ function AnimatedHeroContent({ children, className }) {
530
+ const mounted = useMounted2();
531
+ const childArray = Array.isArray(children) ? children : [children];
532
+ if (!mounted) {
533
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children });
534
+ }
535
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
536
+ import_framer_motion3.motion.div,
537
+ {
538
+ className,
539
+ initial: "hidden",
540
+ animate: "visible",
541
+ variants: {
542
+ hidden: { opacity: 0 },
543
+ visible: {
544
+ opacity: 1,
545
+ transition: {
546
+ staggerChildren: 0.15,
547
+ delayChildren: 0.1
548
+ }
549
+ }
550
+ },
551
+ children: childArray.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
552
+ import_framer_motion3.motion.div,
553
+ {
554
+ variants: {
555
+ hidden: { opacity: 0, y: 20 },
556
+ visible: {
557
+ opacity: 1,
558
+ y: 0,
559
+ transition: {
560
+ duration: 0.6,
561
+ ease: [0.4, 0, 0.2, 1]
562
+ }
563
+ }
564
+ },
565
+ children: child
566
+ },
567
+ index
568
+ ))
569
+ }
570
+ );
571
+ }
572
+
573
+ // src/components/AnimatedSections.tsx
574
+ var import_framer_motion4 = require("framer-motion");
575
+ var import_jsx_runtime4 = require("react/jsx-runtime");
576
+ function AnimatedGrid({ children, className }) {
577
+ const childArray = Array.isArray(children) ? children : [children];
578
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
579
+ import_framer_motion4.motion.div,
580
+ {
581
+ className,
582
+ initial: "hidden",
583
+ whileInView: "visible",
584
+ viewport: viewportSettings,
585
+ variants: staggerContainer,
586
+ children: childArray.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_framer_motion4.motion.div, { variants: staggerItem, children: child }, index))
587
+ }
588
+ );
589
+ }
590
+ function AnimatedStats({ children, className }) {
591
+ const childArray = Array.isArray(children) ? children : [children];
592
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
593
+ import_framer_motion4.motion.div,
594
+ {
595
+ className,
596
+ initial: "hidden",
597
+ whileInView: "visible",
598
+ viewport: { once: true, amount: 0.3 },
599
+ variants: {
600
+ hidden: { opacity: 0 },
601
+ visible: {
602
+ opacity: 1,
603
+ transition: {
604
+ staggerChildren: 0.15,
605
+ delayChildren: 0.1
606
+ }
607
+ }
608
+ },
609
+ children: childArray.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
610
+ import_framer_motion4.motion.div,
611
+ {
612
+ variants: {
613
+ hidden: { opacity: 0, scale: 0.8 },
614
+ visible: {
615
+ opacity: 1,
616
+ scale: 1,
617
+ transition: {
618
+ duration: 0.5,
619
+ ease: [0.4, 0, 0.2, 1]
620
+ }
621
+ }
622
+ },
623
+ children: child
624
+ },
625
+ index
626
+ ))
627
+ }
628
+ );
629
+ }
630
+ function AnimatedSectionHeader({ children, className }) {
631
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
632
+ import_framer_motion4.motion.header,
633
+ {
634
+ className,
635
+ initial: "hidden",
636
+ whileInView: "visible",
637
+ viewport: viewportSettings,
638
+ variants: fadeInUpShort,
639
+ children
640
+ }
641
+ );
642
+ }
643
+ function AnimatedList({ children, className }) {
644
+ const childArray = Array.isArray(children) ? children : [children];
645
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
646
+ import_framer_motion4.motion.div,
647
+ {
648
+ className,
649
+ initial: "hidden",
650
+ whileInView: "visible",
651
+ viewport: viewportSettings,
652
+ variants: {
653
+ hidden: { opacity: 0 },
654
+ visible: {
655
+ opacity: 1,
656
+ transition: {
657
+ staggerChildren: 0.08,
658
+ delayChildren: 0.1
659
+ }
660
+ }
661
+ },
662
+ children: childArray.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
663
+ import_framer_motion4.motion.div,
664
+ {
665
+ variants: {
666
+ hidden: { opacity: 0, x: -20 },
667
+ visible: {
668
+ opacity: 1,
669
+ x: 0,
670
+ transition: {
671
+ duration: 0.5,
672
+ ease: [0.4, 0, 0.2, 1]
673
+ }
674
+ }
675
+ },
676
+ children: child
677
+ },
678
+ index
679
+ ))
680
+ }
681
+ );
682
+ }
683
+
684
+ // src/components/AnimatedHero.tsx
685
+ var import_framer_motion5 = require("framer-motion");
686
+ var import_react3 = require("react");
82
687
  var import_image2 = __toESM(require("next/image"));
83
688
  var import_link = __toESM(require("next/link"));
84
- var import_HomePage = __toESM(require("./HomePage.module.css"));
85
- var import_jsx_runtime3 = require("react/jsx-runtime");
689
+
690
+ // src/components/HomePage.module.css
691
+ var HomePage_default = {};
692
+
693
+ // src/components/AnimatedHero.tsx
694
+ var import_jsx_runtime5 = require("react/jsx-runtime");
86
695
  function AnimatedHero({ heroData, ArrowRightIcon }) {
87
- const ref = (0, import_react2.useRef)(null);
88
- const { scrollY } = (0, import_framer_motion3.useScroll)();
89
- const y = (0, import_framer_motion3.useTransform)(scrollY, [0, 500], [0, 150]);
90
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("section", { className: import_HomePage.default.heroSection, ref, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_HomePage.default.heroContainer, children: [
91
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
92
- import_framer_motion3.motion.div,
696
+ const ref = (0, import_react3.useRef)(null);
697
+ const { scrollY } = (0, import_framer_motion5.useScroll)();
698
+ const y = (0, import_framer_motion5.useTransform)(scrollY, [0, 500], [0, 150]);
699
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("section", { className: HomePage_default.heroSection, ref, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: HomePage_default.heroContainer, children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
701
+ import_framer_motion5.motion.div,
93
702
  {
94
- className: import_HomePage.default.heroContent,
703
+ className: HomePage_default.heroContent,
95
704
  initial: "hidden",
96
705
  animate: "visible",
97
706
  variants: fadeInUp,
98
707
  children: [
99
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
100
- import_framer_motion3.motion.span,
708
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
709
+ import_framer_motion5.motion.span,
101
710
  {
102
- className: import_HomePage.default.heroTagline,
711
+ className: HomePage_default.heroTagline,
103
712
  initial: { opacity: 0 },
104
713
  animate: { opacity: 1 },
105
714
  transition: { duration: 0.6, delay: 0.2 },
106
715
  children: heroData.tagline
107
716
  }
108
717
  ),
109
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
110
- import_framer_motion3.motion.h1,
718
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
719
+ import_framer_motion5.motion.h1,
111
720
  {
112
- className: import_HomePage.default.heroHeading,
721
+ className: HomePage_default.heroHeading,
113
722
  initial: { opacity: 0, y: 20 },
114
723
  animate: { opacity: 1, y: 0 },
115
724
  transition: { duration: 0.8, delay: 0.3 },
116
725
  children: [
117
726
  heroData.heading,
118
727
  " ",
119
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: import_HomePage.default.heroHeadingAccent, children: heroData.headingAccent })
728
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: HomePage_default.heroHeadingAccent, children: heroData.headingAccent })
120
729
  ]
121
730
  }
122
731
  ),
123
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
124
- import_framer_motion3.motion.p,
732
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
733
+ import_framer_motion5.motion.p,
125
734
  {
126
- className: import_HomePage.default.heroDescription,
735
+ className: HomePage_default.heroDescription,
127
736
  initial: { opacity: 0, y: 20 },
128
737
  animate: { opacity: 1, y: 0 },
129
738
  transition: { duration: 0.8, delay: 0.4 },
130
739
  children: heroData.description
131
740
  }
132
741
  ),
133
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
134
- import_framer_motion3.motion.div,
742
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
743
+ import_framer_motion5.motion.div,
135
744
  {
136
- className: import_HomePage.default.heroCtas,
745
+ className: HomePage_default.heroCtas,
137
746
  initial: { opacity: 0, y: 20 },
138
747
  animate: { opacity: 1, y: 0 },
139
748
  transition: { duration: 0.8, delay: 0.5 },
140
749
  children: [
141
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_link.default, { href: heroData.ctaLink, className: import_HomePage.default.heroPrimaryCta, children: [
750
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_link.default, { href: heroData.ctaLink, className: HomePage_default.heroPrimaryCta, children: [
142
751
  heroData.ctaText,
143
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowRightIcon, {})
752
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArrowRightIcon, {})
144
753
  ] }),
145
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link.default, { href: "/publications", className: import_HomePage.default.heroSecondaryCta, children: "View Publications" })
754
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_link.default, { href: "/publications", className: HomePage_default.heroSecondaryCta, children: "View Publications" })
146
755
  ]
147
756
  }
148
757
  )
149
758
  ]
150
759
  }
151
760
  ),
152
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
153
- import_framer_motion3.motion.div,
761
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
762
+ import_framer_motion5.motion.div,
154
763
  {
155
- className: import_HomePage.default.heroImageWrapper,
764
+ className: HomePage_default.heroImageWrapper,
156
765
  style: { y },
157
766
  initial: "hidden",
158
767
  animate: "visible",
159
768
  variants: scaleIn,
160
769
  transition: { duration: 0.8, delay: 0.6 },
161
- children: heroData.image ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
162
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
770
+ children: heroData.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
771
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
163
772
  import_image2.default,
164
773
  {
165
774
  src: heroData.image,
166
775
  alt: "Research lab",
167
776
  width: 800,
168
777
  height: 600,
169
- className: import_HomePage.default.heroImage,
778
+ className: HomePage_default.heroImage,
170
779
  priority: true
171
780
  }
172
781
  ),
173
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_HomePage.default.heroImageOverlay })
174
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: import_HomePage.default.heroImagePlaceholder, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: HomePage_default.heroImageOverlay })
783
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: HomePage_default.heroImagePlaceholder, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
175
784
  "svg",
176
785
  {
177
786
  width: "120",
@@ -181,9 +790,9 @@ function AnimatedHero({ heroData, ArrowRightIcon }) {
181
790
  stroke: "currentColor",
182
791
  strokeWidth: "1",
183
792
  children: [
184
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
185
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
186
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 15l-5-5L5 21" })
793
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
795
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 15l-5-5L5 21" })
187
796
  ]
188
797
  }
189
798
  ) })
@@ -192,15 +801,6 @@ function AnimatedHero({ heroData, ArrowRightIcon }) {
192
801
  ] }) });
193
802
  }
194
803
 
195
- // src/components/AnimatedPage.tsx
196
- var import_framer_motion4 = require("framer-motion");
197
- var import_react3 = require("react");
198
- var import_jsx_runtime4 = require("react/jsx-runtime");
199
-
200
- // src/components/AnimatedSections.tsx
201
- var import_framer_motion5 = require("framer-motion");
202
- var import_jsx_runtime5 = require("react/jsx-runtime");
203
-
204
804
  // src/components/ClientLayout.tsx
205
805
  var import_react6 = require("react");
206
806
  var import_next_themes2 = require("next-themes");
@@ -209,13 +809,19 @@ var import_next_themes2 = require("next-themes");
209
809
  var import_link2 = __toESM(require("next/link"));
210
810
  var import_react5 = require("react");
211
811
  var import_navigation = require("next/navigation");
212
- var import_Layout = __toESM(require("./Layout.module.css"));
812
+
813
+ // src/components/Layout.module.css
814
+ var Layout_default = {};
213
815
 
214
816
  // src/components/ThemeToggle.tsx
215
817
  var import_next_themes = require("next-themes");
216
818
  var import_react4 = require("react");
217
819
  var import_framer_motion6 = require("framer-motion");
218
- var import_ThemeToggle = __toESM(require("./ThemeToggle.module.css"));
820
+
821
+ // src/components/ThemeToggle.module.css
822
+ var ThemeToggle_default = {};
823
+
824
+ // src/components/ThemeToggle.tsx
219
825
  var import_jsx_runtime6 = require("react/jsx-runtime");
220
826
  function ThemeToggle() {
221
827
  const { theme, setTheme, resolvedTheme } = (0, import_next_themes.useTheme)();
@@ -224,7 +830,7 @@ function ThemeToggle() {
224
830
  setMounted(true);
225
831
  }, []);
226
832
  if (!mounted) {
227
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: import_ThemeToggle.default.togglePlaceholder });
833
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: ThemeToggle_default.togglePlaceholder });
228
834
  }
229
835
  const isDark = resolvedTheme === "dark";
230
836
  const toggleTheme = () => {
@@ -233,12 +839,12 @@ function ThemeToggle() {
233
839
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
234
840
  import_framer_motion6.motion.button,
235
841
  {
236
- className: import_ThemeToggle.default.toggle,
842
+ className: ThemeToggle_default.toggle,
237
843
  onClick: toggleTheme,
238
844
  "aria-label": `Switch to ${isDark ? "light" : "dark"} mode`,
239
845
  whileTap: { scale: 0.95 },
240
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: import_ThemeToggle.default.track, children: [
241
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `${import_ThemeToggle.default.icon} ${import_ThemeToggle.default.sunIcon} ${!isDark ? import_ThemeToggle.default.iconActive : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
846
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: ThemeToggle_default.track, children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `${ThemeToggle_default.icon} ${ThemeToggle_default.sunIcon} ${!isDark ? ThemeToggle_default.iconActive : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
242
848
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "5" }),
243
849
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
244
850
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
@@ -252,12 +858,12 @@ function ThemeToggle() {
252
858
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
253
859
  import_framer_motion6.motion.span,
254
860
  {
255
- className: import_ThemeToggle.default.thumb,
861
+ className: ThemeToggle_default.thumb,
256
862
  animate: { x: isDark ? 26 : 0 },
257
863
  transition: { type: "spring", stiffness: 500, damping: 30 }
258
864
  }
259
865
  ),
260
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `${import_ThemeToggle.default.icon} ${import_ThemeToggle.default.moonIcon} ${isDark ? import_ThemeToggle.default.iconActive : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }) })
866
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `${ThemeToggle_default.icon} ${ThemeToggle_default.moonIcon} ${isDark ? ThemeToggle_default.iconActive : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }) })
261
867
  ] })
262
868
  }
263
869
  );
@@ -309,8 +915,8 @@ function Header({ settings }) {
309
915
  if (href === "/") return pathname === "/";
310
916
  return pathname.startsWith(href);
311
917
  };
312
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("header", { className: `${import_Layout.default.header} ${scrolled ? import_Layout.default.headerScrolled : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: import_Layout.default.navContainer, children: [
313
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_link2.default, { href: "/", className: import_Layout.default.navLogo, "aria-label": "Go to homepage", children: [
918
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("header", { className: `${Layout_default.header} ${scrolled ? Layout_default.headerScrolled : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: Layout_default.navContainer, children: [
919
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_link2.default, { href: "/", className: Layout_default.navLogo, "aria-label": "Go to homepage", children: [
314
920
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
315
921
  "svg",
316
922
  {
@@ -356,37 +962,37 @@ function Header({ settings }) {
356
962
  ),
357
963
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
358
964
  settings.labName || "Research",
359
- settings.labNameAccent && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: import_Layout.default.navLogoAccent, children: [
965
+ settings.labNameAccent && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: Layout_default.navLogoAccent, children: [
360
966
  " ",
361
967
  settings.labNameAccent
362
968
  ] })
363
969
  ] })
364
970
  ] }),
365
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("nav", { className: import_Layout.default.desktopNav, "aria-label": "Main navigation", children: navLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
971
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("nav", { className: Layout_default.desktopNav, "aria-label": "Main navigation", children: navLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
366
972
  import_link2.default,
367
973
  {
368
974
  href: link.href,
369
- className: `${import_Layout.default.navLink} ${isActive(link.href) ? import_Layout.default.navLinkActive : ""}`,
975
+ className: `${Layout_default.navLink} ${isActive(link.href) ? Layout_default.navLinkActive : ""}`,
370
976
  children: link.label
371
977
  },
372
978
  link.href
373
979
  )) }),
374
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: import_Layout.default.navActions, children: [
980
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: Layout_default.navActions, children: [
375
981
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ThemeToggle, {}),
376
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_link2.default, { href: "/contact", className: import_Layout.default.navCta, children: "Contact Us" })
982
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_link2.default, { href: "/contact", className: Layout_default.navCta, children: "Contact Us" })
377
983
  ] }),
378
984
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
379
985
  "button",
380
986
  {
381
- className: import_Layout.default.menuButton,
987
+ className: Layout_default.menuButton,
382
988
  onClick: () => setMenuOpen(!menuOpen),
383
989
  "aria-label": menuOpen ? "Close menu" : "Open menu",
384
990
  "aria-expanded": menuOpen,
385
991
  "aria-controls": "mobile-menu",
386
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: import_Layout.default.menuButtonLines, children: [
387
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${import_Layout.default.menuLine} ${menuOpen ? import_Layout.default.menuLineOpen1 : ""}` }),
388
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${import_Layout.default.menuLine} ${menuOpen ? import_Layout.default.menuLineOpen2 : ""}` }),
389
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${import_Layout.default.menuLine} ${menuOpen ? import_Layout.default.menuLineOpen3 : ""}` })
992
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: Layout_default.menuButtonLines, children: [
993
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${Layout_default.menuLine} ${menuOpen ? Layout_default.menuLineOpen1 : ""}` }),
994
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${Layout_default.menuLine} ${menuOpen ? Layout_default.menuLineOpen2 : ""}` }),
995
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `${Layout_default.menuLine} ${menuOpen ? Layout_default.menuLineOpen3 : ""}` })
390
996
  ] })
391
997
  }
392
998
  ),
@@ -394,13 +1000,13 @@ function Header({ settings }) {
394
1000
  "div",
395
1001
  {
396
1002
  id: "mobile-menu",
397
- className: `${import_Layout.default.mobileMenu} ${menuOpen ? import_Layout.default.mobileMenuOpen : ""}`,
1003
+ className: `${Layout_default.mobileMenu} ${menuOpen ? Layout_default.mobileMenuOpen : ""}`,
398
1004
  "aria-hidden": !menuOpen,
399
1005
  children: [
400
1006
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
401
1007
  "div",
402
1008
  {
403
- className: import_Layout.default.mobileMenuOverlay,
1009
+ className: Layout_default.mobileMenuOverlay,
404
1010
  onClick: () => setMenuOpen(false),
405
1011
  "aria-hidden": "true"
406
1012
  }
@@ -408,14 +1014,14 @@ function Header({ settings }) {
408
1014
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
409
1015
  "nav",
410
1016
  {
411
- className: import_Layout.default.mobileMenuContent,
1017
+ className: Layout_default.mobileMenuContent,
412
1018
  "aria-label": "Mobile navigation",
413
1019
  children: [
414
1020
  navLinks.map((link, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
415
1021
  import_link2.default,
416
1022
  {
417
1023
  href: link.href,
418
- className: `${import_Layout.default.mobileNavLink} ${isActive(link.href) ? import_Layout.default.mobileNavLinkActive : ""}`,
1024
+ className: `${Layout_default.mobileNavLink} ${isActive(link.href) ? Layout_default.mobileNavLinkActive : ""}`,
419
1025
  style: { animationDelay: `${index * 50}ms` },
420
1026
  tabIndex: menuOpen ? 0 : -1,
421
1027
  children: link.label
@@ -426,7 +1032,7 @@ function Header({ settings }) {
426
1032
  import_link2.default,
427
1033
  {
428
1034
  href: "/contact",
429
- className: import_Layout.default.mobileNavCta,
1035
+ className: Layout_default.mobileNavCta,
430
1036
  style: { animationDelay: `${navLinks.length * 50}ms` },
431
1037
  tabIndex: menuOpen ? 0 : -1,
432
1038
  children: "Contact Us"
@@ -443,7 +1049,9 @@ function Header({ settings }) {
443
1049
 
444
1050
  // src/components/Footer.tsx
445
1051
  var import_link3 = __toESM(require("next/link"));
446
- var import_Footer = __toESM(require("./Footer.module.css"));
1052
+
1053
+ // src/components/Footer.module.css
1054
+ var Footer_default = {};
447
1055
 
448
1056
  // src/lib/utils.ts
449
1057
  function isValidExternalUrl(url) {
@@ -455,52 +1063,92 @@ function isValidExternalUrl(url) {
455
1063
  return false;
456
1064
  }
457
1065
  }
1066
+ function isValidGoogleMapsEmbedUrl(url) {
1067
+ if (!url || typeof url !== "string") return false;
1068
+ try {
1069
+ const parsed = new URL(url);
1070
+ const allowedHosts = [
1071
+ "www.google.com",
1072
+ "google.com",
1073
+ "maps.google.com"
1074
+ ];
1075
+ return parsed.protocol === "https:" && allowedHosts.includes(parsed.hostname) && parsed.pathname.startsWith("/maps/embed");
1076
+ } catch {
1077
+ return false;
1078
+ }
1079
+ }
1080
+ function sanitizeUrl(url) {
1081
+ if (isValidExternalUrl(url)) {
1082
+ return url;
1083
+ }
1084
+ return void 0;
1085
+ }
1086
+ function isValidEmail(email) {
1087
+ if (!email || typeof email !== "string") return false;
1088
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1089
+ return emailPattern.test(email) && email.length <= 254;
1090
+ }
1091
+ function escapeHtml(text) {
1092
+ const htmlEntities = {
1093
+ "&": "&amp;",
1094
+ "<": "&lt;",
1095
+ ">": "&gt;",
1096
+ '"': "&quot;",
1097
+ "'": "&#39;"
1098
+ };
1099
+ return text.replace(/[&<>"']/g, (char) => htmlEntities[char]);
1100
+ }
1101
+ function isValidSlug(slug) {
1102
+ if (!slug || typeof slug !== "string") return false;
1103
+ const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1104
+ return slugPattern.test(slug) && slug.length <= 200;
1105
+ }
458
1106
 
459
1107
  // src/components/Footer.tsx
460
1108
  var import_jsx_runtime8 = require("react/jsx-runtime");
461
- var SocialIcon = ({ href, children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: import_Footer.default.socialIcon, children });
1109
+ var SocialIcon = ({ href, children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: Footer_default.socialIcon, children });
462
1110
  function Footer({ settings }) {
463
1111
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
464
1112
  const showPrivacy = settings?.showPrivacyPolicy !== false;
465
1113
  const showTerms = settings?.showTerms !== false;
466
1114
  const hasLegalLinks = showPrivacy || showTerms;
467
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("footer", { className: import_Footer.default.footerWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerContainer, children: [
468
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.mainFooter, children: [
469
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerAbout, children: [
470
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_link3.default, { href: "/", className: import_Footer.default.footerLogo, children: [
1115
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("footer", { className: Footer_default.footerWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerContainer, children: [
1116
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.mainFooter, children: [
1117
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerAbout, children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_link3.default, { href: "/", className: Footer_default.footerLogo, children: [
471
1119
  settings?.labName || "Cavendish",
472
1120
  " ",
473
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: import_Footer.default.logoAccent, children: settings?.labNameAccent || "Lab" })
1121
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: Footer_default.logoAccent, children: settings?.labNameAccent || "Lab" })
474
1122
  ] }),
475
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: import_Footer.default.footerDescription, children: settings?.labNameDescription || "Advancing the frontiers of physics and our understanding of the universe." }),
476
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.socials, children: [
1123
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: Footer_default.footerDescription, children: settings?.labNameDescription || "Advancing the frontiers of physics and our understanding of the universe." }),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.socials, children: [
477
1125
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SocialIcon, { href: "#", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" }) }) }),
478
1126
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SocialIcon, { href: "#", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24h-6.617l-5.21-6.817-6.044 6.817h-3.308l7.73-8.835-7.73-10.668h6.78l4.522 6.312 5.59-6.312z" }) }) })
479
1127
  ] })
480
1128
  ] }),
481
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerLinksGrid, children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerColumn, children: [
1129
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerLinksGrid, children: [
1130
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerColumn, children: [
483
1131
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Quick Links" }),
484
1132
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/research", children: "Research" }),
485
1133
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/publications", children: "Publications" }),
486
1134
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/pictures", children: "Gallery" })
487
1135
  ] }),
488
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerColumn, children: [
1136
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerColumn, children: [
489
1137
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "About" }),
490
1138
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/news", children: "News" }),
491
1139
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/people", children: "Our Team" }),
492
1140
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/contact", children: "Contact" })
493
1141
  ] }),
494
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerColumn, children: [
1142
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerColumn, children: [
495
1143
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Resources" }),
496
1144
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "https://www.cam.ac.uk/", children: "University" }),
497
1145
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "#", children: "Careers" })
498
1146
  ] })
499
1147
  ] })
500
1148
  ] }),
501
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.footerBottomBar, children: [
1149
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.footerBottomBar, children: [
502
1150
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: settings?.footerText || `\xA9 ${currentYear} The Research Group. All Rights Reserved.` }),
503
- hasLegalLinks && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: import_Footer.default.legalLinks, children: [
1151
+ hasLegalLinks && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: Footer_default.legalLinks, children: [
504
1152
  showPrivacy && (settings?.privacyPolicyUrl && isValidExternalUrl(settings.privacyPolicyUrl) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { href: settings.privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/privacy", children: "Privacy Policy" })),
505
1153
  showTerms && (settings?.termsUrl && isValidExternalUrl(settings.termsUrl) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { href: settings.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms & Conditions" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_link3.default, { href: "/terms", children: "Terms & Conditions" }))
506
1154
  ] })
@@ -536,21 +1184,133 @@ function ClientLayout({ children, settings }) {
536
1184
 
537
1185
  // src/components/ContactCTA.tsx
538
1186
  var import_link4 = __toESM(require("next/link"));
539
- var import_ContactCTA = __toESM(require("./ContactCTA.module.css"));
1187
+
1188
+ // src/components/ContactCTA.module.css
1189
+ var ContactCTA_default = {};
1190
+
1191
+ // src/components/ContactCTA.tsx
540
1192
  var import_jsx_runtime10 = require("react/jsx-runtime");
541
1193
  function ContactCTA() {
542
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("section", { className: import_ContactCTA.default.ctaContainer, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: import_ContactCTA.default.ctaContent, children: [
543
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: import_ContactCTA.default.ctaHeading, children: "Interested in Our Research?" }),
544
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: import_ContactCTA.default.ctaText, children: "Follow our work, explore our publications, or get in touch to discuss potential collaborations." }),
545
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_link4.default, { href: "/contact", className: import_ContactCTA.default.ctaButton, children: "Contact Us" })
1194
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("section", { className: ContactCTA_default.ctaContainer, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: ContactCTA_default.ctaContent, children: [
1195
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: ContactCTA_default.ctaHeading, children: "Interested in Our Research?" }),
1196
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: ContactCTA_default.ctaText, children: "Follow our work, explore our publications, or get in touch to discuss potential collaborations." }),
1197
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_link4.default, { href: "/contact", className: ContactCTA_default.ctaButton, children: "Contact Us" })
546
1198
  ] }) });
547
1199
  }
1200
+
1201
+ // src/components/HomePage.tsx
1202
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1203
+ function HomePage({
1204
+ children,
1205
+ settings = null,
1206
+ header,
1207
+ footer
1208
+ }) {
1209
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1210
+ header ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Header, { settings: settings || {} }),
1211
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("main", { children }),
1212
+ footer ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Footer, { settings: settings || {} })
1213
+ ] });
1214
+ }
1215
+
1216
+ // src/config.ts
1217
+ function defineConfig(config) {
1218
+ return config;
1219
+ }
1220
+
1221
+ // src/lib/sanity.ts
1222
+ var import_next_sanity = require("next-sanity");
1223
+ var import_image_url = __toESM(require("@sanity/image-url"));
1224
+ var projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
1225
+ var dataset = process.env.NEXT_PUBLIC_SANITY_DATASET || "production";
1226
+ var apiVersion = "2023-05-03";
1227
+ var _client = null;
1228
+ function getClient() {
1229
+ if (!_client) {
1230
+ if (!projectId) {
1231
+ throw new Error(
1232
+ "Sanity Project ID is not defined. Please set NEXT_PUBLIC_SANITY_PROJECT_ID in your environment."
1233
+ );
1234
+ }
1235
+ _client = (0, import_next_sanity.createClient)({
1236
+ projectId,
1237
+ dataset,
1238
+ apiVersion,
1239
+ useCdn: process.env.NODE_ENV === "production"
1240
+ });
1241
+ }
1242
+ return _client;
1243
+ }
1244
+ var client = {
1245
+ get projectId() {
1246
+ return projectId;
1247
+ },
1248
+ get dataset() {
1249
+ return dataset;
1250
+ },
1251
+ fetch: (...args) => getClient().fetch(...args)
1252
+ };
1253
+ var _builder = null;
1254
+ function urlFor(source) {
1255
+ if (!_builder) {
1256
+ if (!projectId) {
1257
+ return {
1258
+ width: () => ({ height: () => ({ url: () => "" }), url: () => "" }),
1259
+ height: () => ({ width: () => ({ url: () => "" }), url: () => "" }),
1260
+ url: () => ""
1261
+ };
1262
+ }
1263
+ _builder = (0, import_image_url.default)({ projectId, dataset });
1264
+ }
1265
+ return _builder.image(source);
1266
+ }
548
1267
  // Annotate the CommonJS export names for ESM import in node:
549
1268
  0 && (module.exports = {
1269
+ AnimatedCard,
1270
+ AnimatedGalleryGrid,
1271
+ AnimatedGalleryHeader,
1272
+ AnimatedGrid,
1273
+ AnimatedHeader,
550
1274
  AnimatedHero,
1275
+ AnimatedHeroContent,
1276
+ AnimatedImage,
1277
+ AnimatedItem,
1278
+ AnimatedList,
1279
+ AnimatedMain,
1280
+ AnimatedPage,
1281
+ AnimatedSection,
1282
+ AnimatedSectionHeader,
1283
+ AnimatedStats,
551
1284
  ClientLayout,
552
1285
  ContactCTA,
553
1286
  Footer,
554
1287
  Header,
555
- ThemeToggle
1288
+ HomePage,
1289
+ ScrollRevealSection,
1290
+ StaggeredGrid,
1291
+ ThemeToggle,
1292
+ cardHover,
1293
+ client,
1294
+ defineConfig,
1295
+ escapeHtml,
1296
+ fadeIn,
1297
+ fadeInUp,
1298
+ fadeInUpShort,
1299
+ getClient,
1300
+ imageZoom,
1301
+ isValidEmail,
1302
+ isValidExternalUrl,
1303
+ isValidGoogleMapsEmbedUrl,
1304
+ isValidSlug,
1305
+ pageTransition,
1306
+ reducedMotion,
1307
+ sanitizeUrl,
1308
+ scaleIn,
1309
+ scrollReveal,
1310
+ slideInLeft,
1311
+ slideInRight,
1312
+ staggerContainer,
1313
+ staggerItem,
1314
+ urlFor,
1315
+ viewportSettings
556
1316
  });