diff --git a/public/crack1.png b/public/crack1.png
new file mode 100644
index 0000000..f366469
Binary files /dev/null and b/public/crack1.png differ
diff --git a/public/crack2.png b/public/crack2.png
new file mode 100644
index 0000000..f6ca3e1
Binary files /dev/null and b/public/crack2.png differ
diff --git a/public/lava.jpg b/public/lava.jpg
new file mode 100644
index 0000000..ea8a87b
Binary files /dev/null and b/public/lava.jpg differ
diff --git a/src/app/globals.css b/src/app/globals.css
index 2ab11b8..5fe3514 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -64,4 +64,167 @@ body {
.icon-link:focus p {
color: #111;
/* or black */
+}
+
+/* ---- LAVA FLOOD OVERLAY ---- */
+.lava-flood-overlay {
+ pointer-events: none;
+ position: fixed;
+ top: -100vh;
+ left: 0;
+ right: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 9999;
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ transition: top 0.9s cubic-bezier(.6, 0, .2, 1);
+}
+
+.lava-flood-overlay.lava-active {
+ top: 0;
+ transition: top 0.33s cubic-bezier(.6, 0, .2, 1);
+}
+
+.lava-flood-overlay img,
+.lava-gradient {
+ width: 100vw;
+ height: 100vh;
+ object-fit: cover;
+ pointer-events: none;
+ user-select: none;
+ filter: brightness(1.15) saturate(1.8) drop-shadow(0 0 80px #ff5500);
+}
+
+/* ---- INSANE SCREEN SHAKE (LinkedIn) ---- */
+@keyframes supershake {
+ 0% {
+ transform: translate(0, 0) rotate(0);
+ }
+
+ 5% {
+ transform: translate(-20px, 5px) rotate(-2deg);
+ }
+
+ 10% {
+ transform: translate(18px, -8px) rotate(2deg);
+ }
+
+ 15% {
+ transform: translate(-22px, 8px) rotate(-4deg);
+ }
+
+ 20% {
+ transform: translate(22px, -2px) rotate(4deg);
+ }
+
+ 25% {
+ transform: translate(-18px, 12px) rotate(-2deg);
+ }
+
+ 30% {
+ transform: translate(18px, -10px) rotate(2deg);
+ }
+
+ 35% {
+ transform: translate(-22px, 14px) rotate(-4deg);
+ }
+
+ 40% {
+ transform: translate(22px, -12px) rotate(4deg);
+ }
+
+ 45% {
+ transform: translate(-18px, 8px) rotate(-2deg);
+ }
+
+ 50% {
+ transform: translate(18px, -14px) rotate(4deg);
+ }
+
+ 55% {
+ transform: translate(-22px, 12px) rotate(-4deg);
+ }
+
+ 60% {
+ transform: translate(22px, -8px) rotate(2deg);
+ }
+
+ 65% {
+ transform: translate(-18px, 10px) rotate(-2deg);
+ }
+
+ 70% {
+ transform: translate(18px, -12px) rotate(2deg);
+ }
+
+ 75% {
+ transform: translate(-22px, 14px) rotate(-4deg);
+ }
+
+ 80% {
+ transform: translate(22px, -10px) rotate(4deg);
+ }
+
+ 85% {
+ transform: translate(-18px, 8px) rotate(-2deg);
+ }
+
+ 90% {
+ transform: translate(18px, -14px) rotate(2deg);
+ }
+
+ 95% {
+ transform: translate(-20px, 5px) rotate(-2deg);
+ }
+
+ 100% {
+ transform: translate(0, 0) rotate(0);
+ }
+}
+
+.shake-screen {
+ animation: supershake 1s cubic-bezier(.36, .07, .19, .97) both;
+}
+
+/* ---- CRACK + COLLAPSE OVERLAY (X icon) ---- */
+.crack-overlay {
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 9999;
+ transition: transform 1.1s cubic-bezier(.65, .05, .45, 1), opacity 0.5s;
+ will-change: transform, opacity;
+}
+
+.crack {
+ position: absolute;
+ pointer-events: none;
+}
+
+.crack1 {
+ width: 35vw;
+ left: 10vw;
+ top: 22vh;
+ opacity: 0.8;
+}
+
+.crack2 {
+ width: 32vw;
+ right: 12vw;
+ top: 42vh;
+ opacity: 0.7;
+ transform: rotate(-8deg);
+}
+
+/* Add more .crackN classes if using more cracks */
+
+/* Collapse falling effect */
+.crack-collapse {
+ transform: perspective(900px) rotateX(75deg) translateY(80vh) scale(0.9);
+ opacity: 0;
+ transition: transform 1.1s cubic-bezier(.65, .05, .45, 1), opacity 0.6s;
}
\ No newline at end of file
diff --git a/src/app/learn/page.tsx b/src/app/learn/page.tsx
index ad0542f..b11f775 100644
--- a/src/app/learn/page.tsx
+++ b/src/app/learn/page.tsx
@@ -55,7 +55,7 @@ export default function LearnPage() {
First aid kit and emergency medication
Food (non-perishable)
Bottled water
- Torch (flashlight)
+ Torch
Satellite phone
Warm clothing and blankets
diff --git a/src/app/observatories/page.tsx b/src/app/observatories/page.tsx
index 6409fac..d1a919e 100644
--- a/src/app/observatories/page.tsx
+++ b/src/app/observatories/page.tsx
@@ -22,18 +22,17 @@ export default function Observatories() {
const observatoryEvents = useMemo(
() =>
data && data.observatories
- ? data.observatories
- .map(
- (x: Observatory): GeologicalEvent => ({
- id: x.id.toString(),
- title: `New Observatory - ${x.name}`,
- longitude: x.longitude,
- latitude: x.latitude,
- text1: "",
- text2: getRelativeDate(x.dateEstablished),
- date: x.dateEstablished,
- })
- )
+ ? data.observatories
+ .map((x: Observatory): GeologicalEvent & { isFunctional: boolean } => ({
+ id: x.id.toString(),
+ title: ` ${x.name}`,
+ longitude: x.longitude,
+ latitude: x.latitude,
+ isFunctional: x.isFunctional, // <-- include this!
+ text1: "",
+ text2: getRelativeDate(x.dateEstablished),
+ date: x.dateEstablished,
+ }))
.sort(
(a: GeologicalEvent, b: GeologicalEvent) =>
new Date(b.date).getTime() - new Date(a.date).getTime()
diff --git a/src/components/BottomFooter.tsx b/src/components/BottomFooter.tsx
index 80f133c..39339fd 100644
--- a/src/components/BottomFooter.tsx
+++ b/src/components/BottomFooter.tsx
@@ -1,74 +1,170 @@
-// components/Footer.tsx
+import React, { useCallback, useRef, useState } from "react";
import Link from "next/link";
-import { FaFacebook, FaLinkedin, FaTwitter, FaYoutube } from "react-icons/fa";
-export default function Footer() {
- return (
-
- );
-}
+export default function BottomFooter() {
+ // Lava flood state & timer
+ const [lavaActive, setLavaActive] = useState(false);
+ const lavaTimeout = useRef(null);
+
+ // LinkedIn shake state & timer
+ const [shaking, setShaking] = useState(false);
+ const shakeTimeout = useRef(null);
+
+ // Crack+collapse states for the X logo
+ const [showCracks, setShowCracks] = useState(false);
+ const [collapse, setCollapse] = useState(false);
+ const crackTimeout = useRef(null);
+
+ // Lava flood handler (top-down flood)
+ const handleInstagramClick = useCallback((e: React.MouseEvent) => {
+ e.preventDefault();
+ setLavaActive(true);
+ clearTimeout(lavaTimeout.current);
+ lavaTimeout.current = setTimeout(() => setLavaActive(false), 2000);
+ }, []);
+
+ // LinkedIn shake handler
+ const handleLinkedInClick = useCallback((e: React.MouseEvent) => {
+ e.preventDefault();
+ if (shaking) return; // prevent stacking
+ setShaking(true);
+ const body = document.body;
+ body.classList.remove("shake-screen");
+ void body.offsetWidth;
+ body.classList.add("shake-screen");
+ shakeTimeout.current = setTimeout(() => {
+ setShaking(false);
+ body.classList.remove("shake-screen");
+ }, 1000);
+ }, [shaking]);
+
+ // X (crack and collapse) handler
+ const handleXClick = useCallback((e: React.MouseEvent) => {
+ e.preventDefault();
+ setShowCracks(true);
+ crackTimeout.current = setTimeout(() => {
+ setCollapse(true);
+ setTimeout(() => {
+ setShowCracks(false);
+ setCollapse(false);
+ }, 1500);
+ }, 1000);
+ }, []);
+
+ React.useEffect(() => {
+ return () => {
+ clearTimeout(lavaTimeout.current);
+ clearTimeout(shakeTimeout.current);
+ clearTimeout(crackTimeout.current);
+ document.body.classList.remove("shake-screen");
+ };
+ }, []);
+
+ return (
+ <>
+ {/* Lava Flood Overlay */}
+ {lavaActive && (
+
+

+
+ )}
+
+ {/* Crack & Collapse Overlay */}
+ {(showCracks || collapse) && (
+
+

+

+ {/* Add more cracks for extra effect if you wish */}
+
+ )}
+
+ {/* Footer */}
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/components/Map.tsx b/src/components/Map.tsx
index 2a4094a..9472d62 100644
--- a/src/components/Map.tsx
+++ b/src/components/Map.tsx
@@ -111,8 +111,12 @@ function MapComponent({
}
const observatoryElement = document.createElement("div");
- const root = createRoot(observatoryElement);
- root.render();
+ const root = createRoot(observatoryElement);
+ root.render(
+
+ );
quakeElement.appendChild(pulseElement);
quakeElement.appendChild(dotElement);