← back to Epstein Card

app/page.tsx

724 lines

"use client";

import VaporizeTextCycle, { Tag } from "@/components/ui/vapour-text-effect";
import { EnhancedDropdown } from "@/components/ui/enhanced-dropdown";
import { MainDropdown } from "@/components/ui/main-dropdown";
import { useState, useEffect, FormEvent } from "react";

export default function Home() {
  const [isMobile, setIsMobile] = useState(false);
  const [showDocument, setShowDocument] = useState(false);
  const [slideToDropdowns, setSlideToDropdowns] = useState(false);
  const [bgColor, setBgColor] = useState("black");
  const [selectedCategory, setSelectedCategory] = useState("");
  const [selectedDocument, setSelectedDocument] = useState("");
  const [documentContent, setDocumentContent] = useState("");
  const [interactionCount, setInteractionCount] = useState(0);
  const [showStopSign, setShowStopSign] = useState(false);
  const [showPoliceAlert, setShowPoliceAlert] = useState(false);
  const [userIP, setUserIP] = useState("███.███.███.███");
  const [userLocation, setUserLocation] = useState({
    city: "████████",
    state: "██",
    country: "███",
    police: "████████ Police Department"
  });
  const [redactedSelections, setRedactedSelections] = useState<Record<string, string>>({});

  // Detect mobile device on mount
  useEffect(() => {
    setIsMobile(/iPhone|iPad|iPod|Android/i.test(navigator.userAgent));
  }, []);

  // Fetch user IP and location on mount
  useEffect(() => {
    // Auto-fetch IP and location
    fetch('https://ipapi.co/json/')
      .then(res => res.json())
      .then(data => {
        setUserIP(data.ip || "███.███.███.███");
        setUserLocation({
          city: data.city || "████████",
          state: data.region_code || "██",
          country: data.country_code || "███",
          police: `${data.city || "████████"} Police Department`
        });
      })
      .catch(() => {
        // Fallback to redacted values if API fails
      });
  }, []);

  // Remove duplicate showDocument timer since it's now handled in flash effect

  // Flash red then slide to dropdowns
  useEffect(() => {
    const flashTimer = setTimeout(() => {
      setBgColor("red");
      setTimeout(() => {
        setBgColor("black");
        setShowDocument(true);
        // Wait 1 second then auto-scroll to document section
        setTimeout(() => {
          setSlideToDropdowns(true);
          const documentSection = document.getElementById('document-section');
          if (documentSection) {
            // Use instant scroll on mobile to avoid performance issues
            documentSection.scrollIntoView({
              behavior: isMobile ? 'instant' : 'smooth',
              block: 'center'
            });
          }
        }, 1000);
      }, 500);
    }, isMobile ? 2000 : 3000); // Shorter delay on mobile

    return () => clearTimeout(flashTimer);
  }, []);

  // Track user interactions and show warnings
  useEffect(() => {
    if (interactionCount === 3) {
      // Show stop sign after 3 interactions
      setShowStopSign(true);
      setTimeout(() => {
        setShowStopSign(false);
        setTimeout(() => {
          setShowPoliceAlert(true);
          setTimeout(() => {
            setShowPoliceAlert(false);
          }, 2000);
        }, 500);
      }, 500);
    }
  }, [interactionCount]);

  const redactedOptions = {
    "names": ["Prince Andrew", "Bill Clinton", "Donald Trump", "Bill Gates", "Alan Dershowitz", "Kevin Spacey", "Chris Tucker", "Stephen Hawking"],
    "locations": ["Little St. James", "Palm Beach Estate", "Manhattan Mansion", "New Mexico Ranch", "Paris Apartment"],
    "ages": ["14", "15", "16", "17", "barely 18"],
    "amounts": ["$500,000", "$2 million", "$50 million", "$100,000", "$1 billion"],
    "activities": ["massage", "entertainment", "modeling", "companionship", "tutoring"],
    "organizations": ["MIT", "Clinton Foundation", "Victoria's Secret", "Harvard", "Mar-a-Lago", "Mossad", "CIA"],
    "years": ["2002", "2005", "2018", "1999", "2001", "2004", "2019"],
    "counts": ["26", "47", "over 100", "7", "12"]
  };

  const documentCategories = {
    "Flight Logs (Released 2024)": [
      "Lolita Express Log - Page 73 of 118",
      "Passenger Manifest - Clinton Africa Trip 2002"
    ],
    "Maxwell Trial Exhibits": [
      "Government Exhibit 52 - Little Black Book",
      "Exhibit 358 - Palm Beach Message Pads"
    ],
    "Court Unsealed Jan 2024": [
      "Doe v. Epstein - Deposition Pages 117-145",
      "Jane Doe #3 Sworn Statement"
    ],
    "FBI Vault Release": [
      "Part 22 of 40 - Celebrity Names",
      "Part 31 - Financial Transfers"
    ]
  };

  const generateFilledDocument = (template: string) => {
    let filled = template;
    filled = filled.replace(/████████ Express/g, redactedSelections.aircraft || "████████ Express");
    filled = filled.replace(/Private Island ████████/g, `Private Island ${redactedSelections.destination || "████████"}`);
    filled = filled.replace(/Ms\. ████████/g, `Ms. ${redactedSelections.person || "████████"}`);
    filled = filled.replace(/Age ██/g, `Age ${redactedSelections.age || "██"}`);
    filled = filled.replace(/██ cases/g, `${redactedSelections.timeframe || "██"} cases`);
    filled = filled.replace(/████████ champagne/g, `${redactedSelections.substance || "████████"} champagne`);
    filled = filled.replace(/████████ Communications/g, `${redactedSelections.company || "████████"} Communications`);
    filled = filled.replace(/Multiple ████████/g, `Multiple ${redactedSelections.activity || "████████"}`);
    filled = filled.replace(/████████ favors/g, `${redactedSelections.payment || "████████"} favors`);
    filled = filled.replace(/Same day ████████/g, `Same day ${redactedSelections.service || "████████"}`);
    return filled;
  };

  const documentContents = {
    "Lolita Express Log - Page 73 of 118": `
DEPOSITION - JANE DOE #3
Case No: 18-cv-████████

Q: Who else was present during these visits?
A: I saw ████████ [TECH CEO], ████████ [POLITICIAN],
   and ████████ [CELEBRITY] on different occasions.

Q: What services were you asked to provide?
A: ████████ massages and other ████████ activities.

EXHIBIT A: Flight manifest showing ██ trips
EXHIBIT B: Photos with ████████ individuals

IP: ${userIP} | Location: ${userLocation.city}
`,
    "N908JE Tail Number - Caribbean Routes 2001-2005": `
FBI INTERVIEW SUMMARY - VIRGINIA GIUFFRE
Date: ██/██/2018
File #: ████████-302

SUBJECT stated she was recruited at age ██ while working
at ████████ Resort by Ghislaine Maxwell.

VICTIM identified the following individuals at
Epstein properties:
• Prince ████████ of UK - ██ encounters
• ████████ [Former President] - Seen on island
• ████████ [Law Professor] - Legal adviser
• ████████ [Modeling Agent] - Supplied girls

SUBJECT provided massage services to ████████
individuals between ages ██ and ██.

Payments received: $████████ total via ████████ accounts

Locations: NYC mansion, Palm Beach, ████████ Island,
New Mexico ranch, ████████ [FOREIGN LOCATION]

[ONGOING INVESTIGATION - DETAILS SEALED]
Access logged: ${userIP}
`,
    "Passenger Manifest - Clinton Africa Trip 2002": `
PALM BEACH REPORT #████████

EVIDENCE COLLECTED:
• Message pads with ████████ girls' numbers
• Photos of ████████ minors
• School uniforms from ████████ Academy

SUSPECT'S ASSOCIATES PRESENT:
• ████████ Maxwell - Recruiter
• ████████ [POLITICIAN] - Witnessed at property
• ████████ [CELEBRITY] - Regular visitor

[CASE FORWARDED TO FBI]
`,
    "Government Exhibit 52 - Little Black Book": `
BLACK BOOK ENTRY - PAGE ██

████████ [TECH BILLIONAIRE]
Island Visits: ██ confirmed

████████ [ROYAL FAMILY MEMBER]
Special Requests: Girls from ████████

████████ [FORMER PRESIDENT]
Flight Count: ██ trips on tail #████████

████████ [HOLLYWOOD DIRECTOR]
Girls supplied: ██ "actresses" aged ██-██

Total contacts in book: ████ individuals
[FBI EVIDENCE TAG #████████]
`,
    "Exhibit 670 - Victim Photos (Sealed)": `
SEALED COURT DOCUMENT - CASE ██-████
Released: January 2024

DEPOSITION OF PILOT ████████

Q: Who did you fly to Epstein's properties?
A: I flew ████████ [PRESIDENT #42] at least ██ times.
   ████████ [BRITISH ROYAL] approximately ██ times.
   ████████ [ISRAELI PM] on ██ occasions.
   ████████ [SENATOR] regularly to ████████.

Q: Were minors present on flights?
A: Girls who appeared to be ages ██ to ██ were
   frequently onboard to ████████ destinations.

Q: What did you observe?
A: ████████ activities in the cabin. Mr. Epstein
   would go to the bedroom with ████████ girls.

Q: Did anyone try to stop this?
A: ████████ [SECRET SERVICE] were told to ████████.

Flight logs subpoenaed showing ████ total flights
between 1997-████.

[GRAND JURY MATERIAL - RESTRICTED]
`,
    "Exhibit 358 - Palm Beach Message Pads": `
MESSAGE PAD FROM PALM BEACH ESTATE

10:30am - ████████ called, needs "massage"
           Girl: ████████, Age ██

11:15am - ████████ [PRINCE] arriving
           Wants ████████ type, ██ years

3:30pm  - Maxwell says ████████ [PRESIDENT] needs
           "Young looking" for fundraiser

7:30pm  - ██ new girls from ████████ High School
           recruited. Pay $████ each.

[EVIDENCE TAG #05-████████]
`
  };

  // Add new document content for the new categories
  documentContents["Doe v. Epstein - Deposition Pages 117-145"] = `
DEPOSITION - SEALED UNTIL 2024

Q: Were you asked to recruit other girls?
A: Yes. I was paid $████ for each girl.
   They had to be between ██ and ██ years old.

Q: Can you identify who participated?
A: ████████ [TECH CEO] - At least ██ times
   ████████ [PRINCE] - London and NYC
   ████████ [PRIME MINISTER] - ████████ Embassy

[CONTINUED ON SEALED PAGES]
`;

  documentContents["Giuffre v. Maxwell - Settlement Details"] = `
SETTLEMENT AGREEMENT - PARTIALLY UNSEALED
Giuffre v. Maxwell, 15-cv-████████

CONFIDENTIAL SETTLEMENT TERMS:

1. Defendant ████████ Maxwell agrees to pay
   $████████ to Virginia Giuffre.

2. Plaintiff identifies the following co-conspirators:
   • ████████ [RETAILER CEO] - ██ incidents
   • ████████ [GOVERNOR] - ████████ Island visits
   • ████████ [AMBASSADOR] - Supplied ████████
   • ████████ [HOLLYWOOD MOGUL] - Casting parties

3. Sealed photographs showing:
   • ████████ [ROYAL] with minor at ████████
   • ████████ [PRESIDENT] at Epstein mansion with ██
   • ████████ [BILLIONAIRE] on island with girls aged ██-██

4. NDA covers ████████ individuals listed in Exhibit A
   including but not limited to ████████ [JUSTICE],
   ████████ [SENATOR], and ████████ [CEO].

5. Maxwell admits facilitating meetings between Epstein
   and ██ underage girls for ████████ purposes.

[FINANCIAL DETAILS REMAIN UNDER SEAL]
`;

  documentContents["Jane Doe #3 Sworn Statement"] = `
SWORN AFFIDAVIT - JANE DOE #3

"I swear the following is true:

1. I was trafficked by Jeffrey Epstein from age ██ to ██.

2. I was forced to have relations with:
   • ████████ [POLITICIAN] - DC and Florida
   • ████████ [FOREIGN LEADER] - ████████ Embassy

3. I personally witnessed:
   • ████████ [PRESIDENT] at NYC townhouse
   • ████████ [PRINCE] with minors aged ██

4. Epstein recorded everything.

[SWORN BEFORE NOTARY]"
`;

  documentContents["Part 22 of 40 - Celebrity Names"] = `
FBI VAULT - EPSTEIN FILE PART 22

CELEBRITY VISITORS:

████████ [A-LIST ACTOR] - ██ visits
- With girls aged ██-██ years

████████ [DIRECTOR] - ██ visits
- "Audition parties" for ████████

████████ [MUSICIAN] - ██ visits
- Private concerts for minors

[SURVEILLANCE PHOTOS CLASSIFIED]
`;

  documentContents["Part 7 - Politicians & Royalty"] = `
FBI VAULT - EPSTEIN FILE PART 7 OF 40
CLASSIFIED/NOFORN

POLITICAL FIGURES UNDER INVESTIGATION:

████████ [SENATOR - D]
- ██ flights on Epstein aircraft
- Present during ████████ with minors
- Received ████████ in campaign donations

████████ [SENATOR - R]
- Island visits: ██ confirmed
- Photographed with ████████, age ██
- ████████ payments through shell company

████████ [CABINET MEMBER]
- Introduced Epstein to ████████ [WORLD LEADER]
- Facilitated visa for ████████ victims
- Received ████████ artwork as payment

████████ [ROYAL FAMILY]
- ██ documented visits to properties
- Used alias "████████" on flight logs
- Diplomatic immunity invoked ██ times

████████ [PRIME MINISTER]
- Secret meeting at ████████ Embassy
- Discussed ████████ age of consent laws
- Transferred $████████ to Epstein account

[ONGOING INVESTIGATION - NO FURTHER DISCLOSURE]
`;

  documentContents["Part 31 - Financial Transfers"] = `
FBI VAULT - EPSTEIN FILE PART 31

SUSPICIOUS TRANSFERS:

$████████ from ████████ [HEDGE FUND]
Actual: Payment for ██ minors

$████████ to ████████ [MODELING AGENCY]
Actual: Recruiting girls aged ██-██

$████████ from ████████ [FOUNDATION]
Actual: Hush money for victims

TOTAL: $████████████

[TREASURY DEPT COORDINATING]
`;

  const handleCategoryChange = (category: string) => {
    setSelectedCategory(category);
    setSelectedDocument("");
    setDocumentContent("");
    setInteractionCount(prev => prev + 1);
  };

  const handleDocumentChange = (doc: string) => {
    setSelectedDocument(doc);
    const content = documentContents[doc as keyof typeof documentContents] || "CLASSIFIED - ACCESS DENIED";
    setDocumentContent(content);
    setInteractionCount(prev => prev + 1);
  };

  const handleRedactedChange = (field: string, value: string) => {
    setRedactedSelections(prev => ({ ...prev, [field]: value }));
    if (selectedDocument) {
      const updatedContent = generateFilledDocument(documentContents[selectedDocument as keyof typeof documentContents] || "");
      setDocumentContent(updatedContent);
    }
  };

  const handleGoClick = (field: string) => {
    setInteractionCount(prev => prev + 1);
    // Each GO button can trigger specific actions
    console.log(`GO clicked for field: ${field}`);
  };

  const handleFormSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setInteractionCount(prev => prev + 1);

    const formData = new FormData(e.currentTarget);

    try {
      const response = await fetch('/api/submit', {
        method: 'POST',
        body: formData
      });

      const result = await response.json();
      console.log('Form submitted:', result);

      // Flash success
      setBgColor("green");
      setTimeout(() => setBgColor("black"), 500);
    } catch (error) {
      console.error('Submit error:', error);
      setBgColor("red");
      setTimeout(() => setBgColor("black"), 500);
    }
  };

  const benefits = [
    "Access to █████ Island",
    "Private jet miles",
    "VIP access to ██████ parties",
    "██% off all purchases"
  ];

  const renderDocumentWithDropdowns = (content: string) => {
    // Determine which options to show based on context
    const getOptionsForContext = (beforeText: string, afterText: string) => {
      const context = beforeText.toLowerCase() + afterText.toLowerCase();

      if (context.includes('age') || context.includes('years old') || context.includes('aged')) {
        return redactedOptions.ages;
      }
      if (context.includes('$') || context.includes('payment') || context.includes('paid') || context.includes('money')) {
        return redactedOptions.amounts;
      }
      if (context.includes('flight') || context.includes('times') || context.includes('visits') || context.includes('occasions')) {
        return redactedOptions.counts;
      }
      if (context.includes('year') || context.includes('date') || /20\d\d|19\d\d/.test(context)) {
        return redactedOptions.years;
      }
      if (context.includes('island') || context.includes('mansion') || context.includes('property') || context.includes('location')) {
        return redactedOptions.locations;
      }
      if (context.includes('massage') || context.includes('service') || context.includes('activity')) {
        return redactedOptions.activities;
      }
      if (context.includes('foundation') || context.includes('university') || context.includes('agency')) {
        return redactedOptions.organizations;
      }
      // Default to names for people references
      return redactedOptions.names;
    };

    const parts = content.split(/(████+|██)/g);
    return parts.map((part, index, array) => {
      if (part.match(/████+|██/)) {
        const fieldKey = `field_${index}`;
        const beforeText = array.slice(Math.max(0, index - 3), index).join('');
        const afterText = array.slice(index + 1, Math.min(array.length, index + 4)).join('');
        const options = getOptionsForContext(beforeText, afterText);

        return (
          <EnhancedDropdown
            key={index}
            options={options}
            redactedText={part}
            onSelect={(value) => handleRedactedChange(fieldKey, value)}
          />
        );
      }
      return <span key={index}>{part}</span>;
    });
  };

  return (
    <main className="min-h-screen bg-black text-white overflow-x-hidden" style={{ backgroundColor: bgColor }}>
      {/* Stop Sign Flash */}
      {showStopSign && (
        <div className="fixed inset-0 bg-red-600 z-50 flex items-center justify-center">
          <div className="text-white text-[200px] font-bold animate-pulse">
            🛑 STOP
          </div>
        </div>
      )}

      {/* Police Alert */}
      {showPoliceAlert && (
        <div className="fixed inset-0 bg-blue-900 z-50 flex items-center justify-center">
          <div className="text-white text-6xl font-bold text-center animate-flash">
            🚔 POLICE HAVE BEEN NOTIFIED 🚔<br/>
            <span className="text-4xl">{userLocation.police}</span><br/>
            <span className="text-3xl">YOUR IP: {userIP}</span>
          </div>
        </div>
      )}

      {/* Vapor Text Header */}
      <div className="h-screen flex items-center justify-center relative">
        <div className="absolute inset-0 bg-gradient-to-b from-black via-purple-950/20 to-black" />
        <div className="relative z-10 w-full max-w-4xl px-4">
          {isMobile ? (
            // Simple text for mobile
            <h1 className="text-6xl md:text-8xl font-extrabold text-center text-white animate-pulse">
              Epstein Files
            </h1>
          ) : (
            // VaporizeTextCycle for desktop
            <VaporizeTextCycle
              texts={["Epstein Files"]}
              font={{
                fontFamily: "system-ui, -apple-system, sans-serif",
                fontSize: "120px",
                fontWeight: 800
              }}
              color="rgb(255, 255, 255)"
              spread={6}
              density={7}
              animation={{
                vaporizeDuration: 2.5,
                fadeInDuration: 1.2,
                waitDuration: 0.8
              }}
              direction="left-to-right"
              alignment="center"
              tag={Tag.H1}
            />
          )}

          <div className="mt-12 text-center">
            <div className="text-4xl font-bold text-red-500 animate-pulse">
              CALL NOW: 888-EPSTEIN
            </div>
            <div className="text-2xl text-purple-400 mt-2">
              24/7 Confidential Hotline
            </div>
          </div>

        </div>
      </div>


      {/* Document Section */}
      {showDocument && (
        <section id="document-section" className="py-20 px-4">
          <div className="max-w-4xl mx-auto">
            <h2 className="text-5xl font-bold text-center mb-12 text-purple-300">
              Declassified File #{Math.floor(Math.random() * 9000) + 1000}
            </h2>

            <div className="text-center mb-8 p-4 bg-red-900/20 border-2 border-red-500 rounded-lg">
              <div className="text-3xl font-bold text-red-400">
                📞 888-EPSTEIN
              </div>
              <div className="text-xl text-gray-300">
                Report Suspicious Activity
              </div>
            </div>

            <form onSubmit={handleFormSubmit} method="POST" action="/api/submit">
              <div className="mb-8 space-y-6">
                <div className="flex flex-wrap gap-4 justify-center items-end">
                  <MainDropdown
                    options={Object.keys(documentCategories)}
                    placeholder="Select Category..."
                    value={selectedCategory}
                    onChange={handleCategoryChange}
                    label="📁 CLASSIFIED CATEGORIES"
                  />
                  <button
                    type="button"
                    className="bg-gradient-to-r from-purple-600 to-pink-600 text-white px-8 py-3 rounded-lg font-bold text-xl hover:scale-105 transition-transform shadow-xl hover:shadow-purple-500/50"
                    onClick={() => handleGoClick('category')}
                  >
                    🔓 ACCESS
                  </button>
                </div>

                {selectedCategory && (
                  <div className="flex flex-wrap gap-4 justify-center items-end animate-fade-in">
                    <MainDropdown
                      options={documentCategories[selectedCategory as keyof typeof documentCategories]}
                      placeholder="Select Document..."
                      value={selectedDocument}
                      onChange={handleDocumentChange}
                      label="📄 DECLASSIFIED FILES"
                    />
                    <button
                      type="button"
                      className="bg-gradient-to-r from-red-600 to-orange-600 text-white px-8 py-3 rounded-lg font-bold text-xl hover:scale-105 transition-transform shadow-xl hover:shadow-red-500/50"
                      onClick={() => handleGoClick('document')}
                    >
                      🔥 REVEAL
                    </button>
                  </div>
                )}
              </div>

              {documentContent && (
                <div className="bg-gradient-to-br from-gray-900 to-gray-800 border border-gray-700 rounded-lg p-8 shadow-2xl">
                  <div className="border-b border-gray-600 pb-4 mb-6">
                    <div className="flex justify-between items-center">
                      <h3 className="text-3xl font-bold text-red-400 font-mono">
                        CLASSIFIED DOCUMENT
                      </h3>
                      <span className="text-xl text-red-500 font-mono">
                        [REDACTED-{Math.floor(Math.random() * 900) + 100}]
                      </span>
                    </div>
                  </div>

                  <div className="font-mono text-xl leading-relaxed whitespace-pre-line text-gray-300">
                    {renderDocumentWithDropdowns(documentContent)}
                  </div>

                  <div className="mt-8 pt-4 border-t border-gray-600">
                    <div className="flex justify-between items-center text-xl text-gray-500">
                      <div>
                        <span>Document ID: EP-████-████-████</span>
                        <br />
                        <span>Classification: ████████</span>
                      </div>
                      <div className="flex flex-col items-end gap-3">
                        <button
                          type="submit"
                          className="bg-gradient-to-r from-red-600 to-red-800 text-white px-10 py-4 rounded-lg font-bold text-2xl hover:scale-105 transition-transform shadow-xl"
                        >
                          SUBMIT REPORT
                        </button>
                        <div className="text-xl text-yellow-400">
                          Call: 888-EPSTEIN
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              )}
            </form>

          </div>
        </section>
      )}

      {/* Footer */}
      {showDocument && (
        <footer className="py-6 px-4 bg-black border-t border-purple-900/30">
          <div className="max-w-4xl mx-auto text-center">
            <div className="text-2xl font-bold text-yellow-500 mb-2">
              HOTLINE: 888-EPSTEIN
            </div>
            <p className="text-sm text-gray-600">
              SATIRICAL PARODY - NOT REAL DOCUMENTS
            </p>
          </div>
        </footer>
      )}

      <style jsx>{`
        @keyframes fade-in {
          from {
            opacity: 0;
            transform: translateY(20px);
          }
          to {
            opacity: 1;
            transform: translateY(0);
          }
        }

        @keyframes flash {
          0%, 100% {
            opacity: 1;
          }
          50% {
            opacity: 0.5;
          }
        }

        .animate-fade-in {
          animation: fade-in 1s ease-out;
        }

        .animate-flash {
          animation: flash 0.5s ease-in-out infinite;
        }
      `}</style>
    </main>
  );
}