// app.jsx — Jihadeen el-Eden — Sound & Gnosis

const { useState, useEffect, useRef, useMemo, useCallback } = React;

const TWEAKS = {
  depthHue: "deep-blue",
  carouselStyle: "ring",
  showGlyph: true,
  diveLength: 1.1,
  artistName: "Jihadeen el-Eden",
  tagline: "Singer · Songwriter · Creator"
};

const TRACKS = [
  { num: "I",   title: "Gnosis",               id: "2323733927", color: "#e7edf0", slug: "gnosis" },
  { num: "II",  title: "Repeat This After Me", id: "2323725458", color: "#308c8e", slug: "repeat_this_after_me" },
  { num: "III", title: "Enough",               id: "2273384237", color: "#ac7c54", slug: "enough" },
  { num: "IV",  title: "No Creas",             id: "2323750037", color: "#94404a", slug: "no-creas" },
  { num: "V",   title: "No More",              id: "2323748621", color: "#2c291c", slug: "no-more" },
  { num: "VI",  title: "FU",                   id: "2275815038", color: "#d4849c", slug: "fu" },
  { num: "VII", title: "Reflections",          id: "2323727183", color: "#494e4c", slug: "reflections" }
];

const DEPTH_HUES = {
  "deep-blue":  { base: "#060d18", mid: "#0a1828", glow: "#4a7a9a" },
  "abyss-teal": { base: "#02080a", mid: "#04161d", glow: "#2f8a8d" },
  "blackwater": { base: "#03030a", mid: "#08070f", glow: "#5a4a2e" },
  "moss-deep":  { base: "#040806", mid: "#0a1410", glow: "#3d7a52" }
};

const IS_IOS = window.IS_IOS;

// ── LANGUAGE / LOCALIZATION ───────────────────────────────────────────────────
const countryToDialect = {
  MX: 'es-MX', ES: 'es-ES', AR: 'es-AR', UY: 'es-AR',
  CO: 'es-CO', CL: 'es-CL', PE: 'es-PE', VE: 'es-VE',
  EC: 'es-EC', BO: 'es-BO', PY: 'es-PY', CR: 'es-CR',
  PA: 'es-PA', GT: 'es-GT', HN: 'es-HN', SV: 'es-SV',
  NI: 'es-NI', CU: 'es-CU', DO: 'es-DO', PR: 'es-PR',
};
const spanishCountries = Object.keys(countryToDialect);

const translations = {
  en: {
    navGnosis: 'Gnosis',
    navSound: 'Sound',
    navContact: 'Contact',
    descend: 'Descend',
    tagline: 'Singer · Songwriter · Creator',
    depthsCaption: 'You have crossed the surface',
    matrixLabel: 'enter the gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>The path of <em>{a}</em></>,
    gnosisTitleEm: 'awakening',
    bioLead: "Raised in the US and brainwashed with exceptionalism and supremacy toxicity. I managed through life thinking that was living — but it wasn't.",
    bioLeadEm: 'It was just surviving by coping with delusions of prosperity that was only meant for a few.',
    bioP2: 'The moment I saw reality for what it was, was when I knew. That was my gnosis — grown independently, without knowing that history was full of people like me.',
    bioP3: 'Researching Gnosticism, Hermeticism and anything Esoteric validated the gnosis I had received.',
    bioTag1: 'Gnosticism',
    bioTag2: 'Hermeticism',
    bioTag3: 'Esoterica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmissions',
    soundTitle: (b) => <>The sound,{' '}{b}from depth</>,
    soundSub1: 'Gnostic Frequencies — let them speak.',
    soundSub2: 'Drift, do not hurry.',
    soundMeta: 'SoundCloud transmission',
    soundOpen: 'Open on SoundCloud ↗',
    soundPrev: 'Previous track',
    soundNext: 'Next track',
    cardOpen: 'open',
    contactEyebrow: 'The Transmission',
    contactTitle: 'Make contact',
    contactBody1: 'For sync licensing, scoring, collaboration —',
    contactBody2: 'or simply to speak about the work. The line is open.',
    contactEmailLabel: 'Send email',
    contactScLabel: 'Visit SoundCloud',
    contactTikLabel: 'Visit TikTok',
    footerRights: 'All transmissions reserved',
  },
  'es-MX': {
    navGnosis: 'Gnosis',
    navSound: 'Sonido',
    navContact: 'Contacto',
    descend: 'Descender',
    tagline: 'Cantante · Compositor · Creador',
    depthsCaption: 'Has cruzado la superficie',
    matrixLabel: 'entra en la gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>El camino del <em>{a}</em></>,
    gnosisTitleEm: 'despertar',
    bioLead: 'Criado en Estados Unidos y adoctrinado con toxicidad de excepcionalismo y supremacía. Me las arreglé en la vida pensando que eso era vivir — pero no lo era.',
    bioLeadEm: 'Era solo sobrevivir aferrándome a ilusiones de prosperidad que solo estaban destinadas a unos pocos.',
    bioP2: 'El momento en que vi la realidad tal como era, supe. Esa fue mi gnosis — crecida de manera independiente, sin saber que la historia estaba llena de gente como yo.',
    bioP3: 'Investigar Gnosticism, Hermeticism y cualquier cosa Esotérica validó la gnosis que había recibido.',
    bioTag1: 'Gnosticismo',
    bioTag2: 'Hermetismo',
    bioTag3: 'Esotérica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmisiones',
    soundTitle: (b) => <>El sonido,{' '}{b}desde la profundidad</>,
    soundSub1: 'Frecuencias Gnósticas — déjalas hablar.',
    soundSub2: 'Fluye, no te apures.',
    soundMeta: 'Transmisión SoundCloud',
    soundOpen: 'Abrir en SoundCloud ↗',
    soundPrev: 'Pista anterior',
    soundNext: 'Pista siguiente',
    cardOpen: 'abrir',
    contactEyebrow: 'La Transmisión',
    contactTitle: 'Hacer contacto',
    contactBody1: 'Para licencias de sincronización, composición, colaboración —',
    contactBody2: 'o simplemente para hablar del trabajo. La línea está abierta.',
    contactEmailLabel: 'Enviar correo',
    contactScLabel: 'Visitar SoundCloud',
    contactTikLabel: 'Visitar TikTok',
    footerRights: 'Todas las transmisiones reservadas',
  },
  'es-ES': {
    navGnosis: 'Gnosis',
    navSound: 'Sonido',
    navContact: 'Contacto',
    descend: 'Descender',
    tagline: 'Cantante · Compositor · Creador',
    depthsCaption: 'Has cruzado la superficie',
    matrixLabel: 'entra en la gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>El camino del <em>{a}</em></>,
    gnosisTitleEm: 'despertar',
    bioLead: 'Criado en Estados Unidos y adoctrinado con toxicidad de excepcionalismo y supremacía. Me las arreglé en la vida pensando que eso era vivir — pero no lo era.',
    bioLeadEm: 'Era solo sobrevivir aferrándose a ilusiones de prosperidad que solo estaban destinadas a unos pocos.',
    bioP2: 'El momento en que vi la realidad tal como era, supe. Esa fue mi gnosis — crecida de manera independiente, sin saber que la historia estaba llena de gente como yo.',
    bioP3: 'Investigar Gnosticismo, Hermetismo y cualquier cosa Esotérica validó la gnosis que había recibido.',
    bioTag1: 'Gnosticismo',
    bioTag2: 'Hermetismo',
    bioTag3: 'Esotérica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmisiones',
    soundTitle: (b) => <>El sonido,{' '}{b}desde la profundidad</>,
    soundSub1: 'Frecuencias Gnósticas — dejadlas hablar.',
    soundSub2: 'Fluye, no te apresures.',
    soundMeta: 'Transmisión SoundCloud',
    soundOpen: 'Abrir en SoundCloud ↗',
    soundPrev: 'Pista anterior',
    soundNext: 'Pista siguiente',
    cardOpen: 'abrir',
    contactEyebrow: 'La Transmisión',
    contactTitle: 'Hacer contacto',
    contactBody1: 'Para licencias de sincronización, composición, colaboración —',
    contactBody2: 'o simplemente para hablar del trabajo. La línea está abierta.',
    contactEmailLabel: 'Enviar correo',
    contactScLabel: 'Visitar SoundCloud',
    contactTikLabel: 'Visitar TikTok',
    footerRights: 'Todas las transmisiones reservadas',
  },
  'es-AR': {
    navGnosis: 'Gnosis',
    navSound: 'Sonido',
    navContact: 'Contacto',
    descend: 'Descender',
    tagline: 'Cantante · Compositor · Creador',
    depthsCaption: 'Has cruzado la superficie',
    matrixLabel: 'entrá en la gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>El camino del <em>{a}</em></>,
    gnosisTitleEm: 'despertar',
    bioLead: 'Criado en Estados Unidos y adoctrinado con toxicidad de excepcionalismo y supremacía. Me las arreglé en la vida pensando que eso era vivir — pero no lo era.',
    bioLeadEm: 'Era solo sobrevivir aferrándome a ilusiones de prosperidad que solo estaban destinadas a unos pocos.',
    bioP2: 'El momento en que vi la realidad tal como era, supe. Esa fue mi gnosis — crecida de manera independiente, sin saber que la historia estaba llena de gente como yo.',
    bioP3: 'Investigar Gnosticism, Hermeticism y cualquier cosa Esotérica validó la gnosis que había recibido.',
    bioTag1: 'Gnosticismo',
    bioTag2: 'Hermetismo',
    bioTag3: 'Esotérica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmisiones',
    soundTitle: (b) => <>El sonido,{' '}{b}desde la profundidad</>,
    soundSub1: 'Frecuencias Gnósticas — dejalas hablar.',
    soundSub2: 'Fluí, no te apures.',
    soundMeta: 'Transmisión SoundCloud',
    soundOpen: 'Abrir en SoundCloud ↗',
    soundPrev: 'Pista anterior',
    soundNext: 'Pista siguiente',
    cardOpen: 'abrir',
    contactEyebrow: 'La Transmisión',
    contactTitle: 'Hacer contacto',
    contactBody1: 'Para licencias de sincronización, composición, colaboración —',
    contactBody2: 'o simplemente para hablar del trabajo. La línea está abierta.',
    contactEmailLabel: 'Mandar correo',
    contactScLabel: 'Visitar SoundCloud',
    contactTikLabel: 'Visitar TikTok',
    footerRights: 'Todas las transmisiones reservadas',
  },
  'es-CO': {
    navGnosis: 'Gnosis',
    navSound: 'Sonido',
    navContact: 'Contacto',
    descend: 'Descender',
    tagline: 'Cantante · Compositor · Creador',
    depthsCaption: 'Has cruzado la superficie',
    matrixLabel: 'entra en la gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>El camino del <em>{a}</em></>,
    gnosisTitleEm: 'despertar',
    bioLead: 'Criado en Estados Unidos y adoctrinado con toxicidad de excepcionalismo y supremacía. Logré avanzar en la vida pensando que eso era vivir — pero no lo era.',
    bioLeadEm: 'Era solo sobrevivir aferrándome a ilusiones de prosperidad que solo estaban destinadas a unos pocos.',
    bioP2: 'El momento en que vi la realidad tal como era, supe. Esa fue mi gnosis — crecida de manera independiente, sin saber que la historia estaba llena de gente como yo.',
    bioP3: 'Investigar Gnosticism, Hermeticism y cualquier cosa Esotérica validó la gnosis que había recibido.',
    bioTag1: 'Gnosticismo',
    bioTag2: 'Hermetismo',
    bioTag3: 'Esotérica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmisiones',
    soundTitle: (b) => <>El sonido,{' '}{b}desde la profundidad</>,
    soundSub1: 'Frecuencias Gnósticas — déjelas hablar.',
    soundSub2: 'Fluya, no se apresure.',
    soundMeta: 'Transmisión SoundCloud',
    soundOpen: 'Abrir en SoundCloud ↗',
    soundPrev: 'Pista anterior',
    soundNext: 'Pista siguiente',
    cardOpen: 'abrir',
    contactEyebrow: 'La Transmisión',
    contactTitle: 'Hacer contacto',
    contactBody1: 'Para licencias de sincronización, composición, colaboración —',
    contactBody2: 'o simplemente para hablar del trabajo. La línea está abierta.',
    contactEmailLabel: 'Enviar correo',
    contactScLabel: 'Visitar SoundCloud',
    contactTikLabel: 'Visitar TikTok',
    footerRights: 'Todas las transmisiones reservadas',
  },
  'es-CL': {
    navGnosis: 'Gnosis',
    navSound: 'Sonido',
    navContact: 'Contacto',
    descend: 'Descender',
    tagline: 'Cantante · Compositor · Creador',
    depthsCaption: 'Has cruzado la superficie',
    matrixLabel: 'entra en la gnosis',
    gnosisEyebrow: 'Gnosis',
    gnosisTitle: (a) => <>El camino del <em>{a}</em></>,
    gnosisTitleEm: 'despertar',
    bioLead: 'Criado en Estados Unidos y adoctrinado con toxicidad de excepcionalismo y supremacía. Me las arreglé en la vida pensando que eso era vivir — pero no lo era.',
    bioLeadEm: 'Era solo sobrevivir aferrándome a ilusiones de prosperidad que solo estaban destinadas a unos pocos.',
    bioP2: 'El momento en que vi la realidad tal como era, supe. Esa fue mi gnosis — crecida de manera independiente, sin saber que la historia estaba llena de gente como yo.',
    bioP3: 'Investigar Gnosticism, Hermeticism y cualquier cosa Esotérica validó la gnosis que había recibido.',
    bioTag1: 'Gnosticismo',
    bioTag2: 'Hermetismo',
    bioTag3: 'Esotérica',
    bioTag4: 'Gnosis',
    soundEyebrow: 'Transmisiones',
    soundTitle: (b) => <>El sonido,{' '}{b}desde la profundidad</>,
    soundSub1: 'Frecuencias Gnósticas — déjalas hablar.',
    soundSub2: 'Fluye, no te apurí.',
    soundMeta: 'Transmisión SoundCloud',
    soundOpen: 'Abrir en SoundCloud ↗',
    soundPrev: 'Pista anterior',
    soundNext: 'Pista siguiente',
    cardOpen: 'abrir',
    contactEyebrow: 'La Transmisión',
    contactTitle: 'Hacer contacto',
    contactBody1: 'Pa\' licencias de sincronización, composición, colaboración —',
    contactBody2: 'o simplemente pa\' hablar del trabajo. La línea está abierta.',
    contactEmailLabel: 'Mandar correo',
    contactScLabel: 'Visitar SoundCloud',
    contactTikLabel: 'Visitar TikTok',
    footerRights: 'Todas las transmisiones reservadas',
  },
};

// Translation helper — uses dialect fallback chain: country-specific → es-MX → en
function makeGetTranslation(language, country) {
  return function getTranslation(key) {
    const dialect = country && countryToDialect[country];
    if (language === 'es' && dialect && translations[dialect] && translations[dialect][key] !== undefined) {
      return translations[dialect][key];
    }
    if (language === 'es' && translations['es-MX'] && translations['es-MX'][key] !== undefined) {
      return translations['es-MX'][key];
    }
    if (translations['en'] && translations['en'][key] !== undefined) {
      return translations['en'][key];
    }
    return key;
  };
}


// ── Utilities ─────────────────────────────────────────────────────────────────
function lerp(a, b, t) { return a + (b - a) * t; }
function clamp(x, lo = 0, hi = 1) { return Math.max(lo, Math.min(hi, x)); }
function easeInOut(t) { return t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t+2,2)/2; }
function hexToRgb(hex) {
  const n = parseInt(hex.replace('#', ''), 16);
  return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
}

function useElementScrollProgress(ref) {
  const [p, setP] = useState(0);
  useEffect(() => {
    let raf = null;
    const update = () => {
      raf = null;
      const el = ref.current;
      if (!el) return;
      const rect  = el.getBoundingClientRect();
      const total = rect.height - window.innerHeight;
      const v = total <= 0 ? 0 : clamp(-rect.top / total);
      setP(v);
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [ref]);
  return p;
}

// IntersectionObserver scroll-reveal
function useReveal(threshold = 0.15) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        el.querySelectorAll(".reveal").forEach(n => n.classList.add("visible"));
        io.disconnect();
      }
    }, { threshold });
    io.observe(el);
    return () => io.disconnect();
  }, [threshold]);
  return ref;
}

// ── LANGUAGE TOGGLE ───────────────────────────────────────────────────────────
function LanguageToggle({ language, toggleLanguage, scrolled }) {
  return (
    <button
      className={`language-toggle-btn${scrolled ? " scrolled" : ""}`}
      onClick={toggleLanguage}
      aria-label={`Switch to ${language === 'en' ? 'Spanish' : 'English'}`}
      title={`Switch to ${language === 'en' ? 'Spanish' : 'English'}`}
    >
      {language === 'en' ? 'EN / ES' : 'ES / EN'}
    </button>
  );
}

// ── NAV ───────────────────────────────────────────────────────────────────────
function Nav({ scrolled, isLoading, navVisible, t }) {
  const [open, setOpen] = useState(false);
  const close = useCallback(() => setOpen(false), []);

  useEffect(() => {
    if (!open) return;
    const onScroll = () => close();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [open, close]);

  return (
    <>
      <nav className={`nav${scrolled ? " scrolled" : " light"}${isLoading ? " fade-in-nav" : ""}${navVisible ? " nav-visible" : ""}`}>
        <a href="#top" className="nav-sigil"><img src="/assets/aeon_cross.svg" alt="Jihadeen sigil" className="nav-sigil-icon" /></a>
        <div className="nav-divider"/>
        <ul className="nav-links">
          <li><a href="#gnosis" onClick={close}>{t('navGnosis')}</a></li>
          <li><a href="#sound" onClick={close}>{t('navSound')}</a></li>
          <li><a href="#contact" onClick={close}>{t('navContact')}</a></li>
        </ul>
        <button
          className={`nav-hamburger${open ? " open" : ""}`}
          onClick={() => setOpen(o => !o)}
          aria-label="Toggle navigation"
          aria-expanded={open}
        >
          <span/><span/><span/>
        </button>
      </nav>
      {open && (
        <div className={`nav-mobile-menu${scrolled ? " scrolled" : " light"}`} role="navigation">
          <a href="#gnosis" className="nav-mobile-link" onClick={close}>{t('navGnosis')}</a>
          <a href="#sound"  className="nav-mobile-link" onClick={close}>{t('navSound')}</a>
          <a href="#contact" className="nav-mobile-link" onClick={close}>{t('navContact')}</a>
        </div>
      )}
    </>
  );
}

// ── DIVE STAGE ────────────────────────────────────────────────────────────────
function DiveStage({ tweaks, isLoading, scrollY = 0, t }) {
  const wrapRef = useRef(null);
  // Background and hero text are locked — no scroll-driven motion
  const STATIC = {
    oceanScale: 1.35,
    oceanTY: 0,
    oceanBrightness: 0.88,
    oceanSat: 1.0,
    oceanBlur: 0,
    veilOpacity: 0,
    abyssOpacity: 0,
    causticsOpacity: 0,
    shaftsOpacity: 0,
    bubblesIntensity: 0,
    heroOpacity: 1,
    heroTY: 0,
    descendOpacity: 1,
    depthsCaptionOpacity: 1
  };

  return (
    <div ref={wrapRef} className="dive-wrap" style={{ height: `${tweaks.diveLength * 100}vh` }}>
      <div className="dive-stage">

        {/* Ocean image — parallax background */}
        <div className="ocean-layer" style={{
          transform: `translateY(${scrollY * 0.3}px) scale(${STATIC.oceanScale})`,
          filter: `brightness(${STATIC.oceanBrightness}) saturate(${STATIC.oceanSat}) blur(${STATIC.oceanBlur}px)`
        }}>
          <img src="assets/hero-bg.png" alt="" draggable="false"/>
        </div>

        {/* 3-D depth vignette — hides image bottom edge */}
        <div className="depth-vignette"/>

        {/* Underwater veil — hidden */}
        <div className="veil-layer" style={{ opacity: STATIC.veilOpacity }}/>

        {/* Caustic light — parallax mid-ground */}
        <div className="caustics-layer" style={{
          opacity: STATIC.causticsOpacity,
          transform: `translateY(${scrollY * 0.25}px)`
        }}>
          <Caustics/>
        </div>

        {/* Light shafts — parallax mid-ground */}
        <div className="shafts-layer" style={{
          opacity: STATIC.shaftsOpacity,
          transform: `translateY(${scrollY * 0.2}px)`
        }}>
          <LightShafts/>
        </div>

        {/* Abyss — hidden */}
        <div className="abyss-layer" style={{ opacity: STATIC.abyssOpacity }}/>

        <Bubbles intensity={STATIC.bubblesIntensity}/>

        {/* Hero — locked on the horizon */}
        <div className="hero-content" style={{
          opacity: STATIC.heroOpacity,
          transform: `translateY(${STATIC.heroTY}vh)`
        }}>
          {tweaks.showGlyph && (
            <div className={isLoading ? "fade-in-pleroma" : ""} style={{ transform: `translateY(${scrollY * 0.15}px)` }}>
              <HeroGlyph/>
            </div>
          )}
          <h1 className="hero-name">
            {tweaks.artistName.split(/\s+/).map((w, i, arr) => (
              <span key={i} className={`${i === 0 ? "float" : ""}${i === 0 && isLoading ? " fade-in-jihadeen" : ""}${i === arr.length - 1 ? " name-last" : ""}${i === arr.length - 1 && isLoading ? " fade-in-el-eden" : ""}`.trim()}>{w}</span>
            ))}
          </h1>
          <p className={`hero-tagline${isLoading ? " fade-in-tagline" : ""}`}>{t('tagline')}</p>
          <div className={`hero-divider${isLoading ? " fade-in-symbol" : ""}`}>
            <span className="divider-line"/>
            <span className="hero-aeon-symbol">
              <img src="/assets/aeon_cross.svg" alt="Aeon Cross" />
            </span>
            <span className="divider-line right"/>
          </div>
        </div>

        <div className={`descend-cue${isLoading ? " fade-in-descend" : ""}`} style={{ opacity: STATIC.descendOpacity }}>
          <span>{t('descend')}</span>
          <span className="descend-line"/>
        </div>

      </div>
    </div>
  );
}

function HeroGlyph() {
  const rings = [24, 38, 52, 66];
  const nodes = [];
  const spokes = 12;
  for (let s = 0; s < spokes; s++) {
    const a = (s * 360) / spokes;
    const rad = (a * Math.PI) / 180;
    nodes.push({ cx: 70 + Math.cos(rad) * 24, cy: 70 + Math.sin(rad) * 24, r: 1.6 });
    nodes.push({ cx: 70 + Math.cos(rad) * 38, cy: 70 + Math.sin(rad) * 38, r: 2.2 });
    nodes.push({ cx: 70 + Math.cos(rad) * 52, cy: 70 + Math.sin(rad) * 52, r: 1.6 });
    if (s % 3 === 0) {
      nodes.push({ cx: 70 + Math.cos(rad) * 66, cy: 70 + Math.sin(rad) * 66, r: 2.6, outer: true });
    }
  }
  return (
    <svg className="hero-glyph" viewBox="0 0 140 140" aria-hidden="true">
      <defs>
        <radialGradient id="pleroma-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="rgba(201,147,58,0.35)"/>
          <stop offset="40%" stopColor="rgba(74,122,154,0.15)"/>
          <stop offset="100%" stopColor="rgba(74,122,154,0)"/>
        </radialGradient>
        <radialGradient id="pleroma-core" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="rgba(240,192,96,0.9)"/>
          <stop offset="100%" stopColor="rgba(201,147,58,0)"/>
        </radialGradient>
      </defs>
      {/* soft glow behind rings */}
      <circle cx="70" cy="70" r="56" fill="url(#pleroma-glow)" opacity="0.6"/>
      {/* concentric rings */}
      {rings.map((r, i) => (
        <circle key={i} cx="70" cy="70" r={r}
          fill="none"
          stroke="rgba(74,122,154,0.45)"
          strokeWidth={i === 0 ? 0.6 : 0.4}
          opacity={0.7 + i * 0.08}
        />
      ))}
      {/* cross rings (horizontal / vertical arcs) */}
      <line x1="18" y1="70" x2="122" y2="70" stroke="rgba(74,122,154,0.35)" strokeWidth="0.4"/>
      <line x1="70" y1="18" x2="70" y2="122" stroke="rgba(74,122,154,0.35)" strokeWidth="0.4"/>
      <line x1="30" y1="30" x2="110" y2="110" stroke="rgba(74,122,154,0.22)" strokeWidth="0.4"/>
      <line x1="110" y1="30" x2="30" y2="110" stroke="rgba(74,122,154,0.22)" strokeWidth="0.4"/>
      {/* nodes on rings */}
      {nodes.map((n, i) => (
        <circle key={i} cx={n.cx} cy={n.cy} r={n.r}
          fill={n.outer ? "rgba(201,147,58,0.85)" : "rgba(138,170,186,0.9)"}
          opacity={n.outer ? 0.9 : 0.75}
        />
      ))}
      {/* central core */}
      <circle cx="70" cy="70" r="8" fill="url(#pleroma-core)" opacity="0.9"/>
      <circle cx="70" cy="70" r="3" fill="rgba(240,192,96,0.95)"/>
      {/* slow rotation ring */}
      <circle cx="70" cy="70" r="62" fill="none" stroke="rgba(74,122,154,0.25)" strokeWidth="0.5" strokeDasharray="3 9" opacity="0.6">
        <animateTransform attributeName="transform" type="rotate" from="0 70 70" to="360 70 70" dur="60s" repeatCount="indefinite"/>
      </circle>
      <circle cx="70" cy="70" r="58" fill="none" stroke="rgba(201,147,58,0.2)" strokeWidth="0.4" strokeDasharray="2 12" opacity="0.5">
        <animateTransform attributeName="transform" type="rotate" from="360 70 70" to="0 70 70" dur="80s" repeatCount="indefinite"/>
      </circle>
    </svg>
  );
}

function Caustics() {
  return (
    <svg viewBox="0 0 100 100" preserveAspectRatio="none" className="caustics-svg">
      <defs>
        <radialGradient id="cs1" cx="20%" cy="20%" r="40%">
          <stop offset="0%" stopColor="rgba(255,255,255,0.45)"/>
          <stop offset="100%" stopColor="rgba(255,255,255,0)"/>
        </radialGradient>
        <radialGradient id="cs2" cx="70%" cy="10%" r="50%">
          <stop offset="0%" stopColor="rgba(180,220,255,0.35)"/>
          <stop offset="100%" stopColor="rgba(180,220,255,0)"/>
        </radialGradient>
        <radialGradient id="cs3" cx="40%" cy="0%" r="70%">
          <stop offset="0%" stopColor="rgba(220,240,255,0.25)"/>
          <stop offset="100%" stopColor="rgba(220,240,255,0)"/>
        </radialGradient>
      </defs>
      <rect width="100" height="100" fill="url(#cs1)"/>
      <rect width="100" height="100" fill="url(#cs2)"/>
      <rect width="100" height="100" fill="url(#cs3)"/>
    </svg>
  );
}

function LightShafts() {
  return (
    <svg viewBox="0 0 100 100" preserveAspectRatio="none" className="shafts-svg">
      <defs>
        <linearGradient id="shaft1" x1="50%" y1="0%" x2="60%" y2="100%">
          <stop offset="0%" stopColor="rgba(200,220,255,0.14)"/>
          <stop offset="100%" stopColor="rgba(200,220,255,0)"/>
        </linearGradient>
        <linearGradient id="shaft2" x1="50%" y1="0%" x2="40%" y2="100%">
          <stop offset="0%" stopColor="rgba(255,235,200,0.09)"/>
          <stop offset="100%" stopColor="rgba(255,235,200,0)"/>
        </linearGradient>
        <linearGradient id="shaft3" x1="50%" y1="0%" x2="55%" y2="100%">
          <stop offset="0%" stopColor="rgba(180,210,255,0.16)"/>
          <stop offset="100%" stopColor="rgba(180,210,255,0)"/>
        </linearGradient>
      </defs>
      <polygon points="20,0 32,0 50,100 40,100" fill="url(#shaft1)"/>
      <polygon points="45,0 55,0 60,100 50,100" fill="url(#shaft2)"/>
      <polygon points="68,0 80,0 75,100 60,100" fill="url(#shaft3)"/>
    </svg>
  );
}

function Bubbles({ intensity }) {
  const bubbles = useMemo(() => Array.from({ length: 18 }, () => ({
    x: Math.random() * 100,
    size: 2 + Math.random() * 6,
    dur: 8 + Math.random() * 14,
    delay: -Math.random() * 12,
    drift: -10 + Math.random() * 20
  })), []);

  return (
    <div className="bubbles-layer" style={{ opacity: intensity }}>
      {bubbles.map((b, i) => (
        <span key={i} className="bubble" style={{
          left: `${b.x}%`,
          width: `${b.size}px`,
          height: `${b.size}px`,
          animationDuration: `${b.dur}s`,
          animationDelay: `${b.delay}s`,
          "--drift": `${b.drift}px`
        }}/>
      ))}
    </div>
  );
}

// ── DIVE TRANSITION ───────────────────────────────────────────────────────────
function DiveTransition() {
  const rings = useMemo(() => Array.from({ length: 12 }, (_, i) => ({
    z: i * 80,
    opacity: 0.08 + (i / 12) * 0.28,
    scale: 0.3 + i * 0.06
  })), []);

  const motes = useMemo(() => Array.from({ length: 22 }, () => ({
    x: 5 + Math.random() * 90,
    size: 1.5 + Math.random() * 3,
    dur: 5 + Math.random() * 9,
    delay: -Math.random() * 12,
    mx: -24 + Math.random() * 48
  })), []);

  return (
    <div className="dive-transition">
      <div className="dive-tunnel">
        <div className="dive-rings">
          {rings.map((r, i) => (
            <div key={i} className="dive-ring" style={{
              "--z": r.z,
              opacity: r.opacity,
              width:  `${30 + r.scale * 100}%`,
              height: `${30 + r.scale * 100}%`,
              top:    `${(100 - (30 + r.scale * 100)) / 2}%`,
              left:   `${(100 - (30 + r.scale * 100)) / 2}%`
            }}/>
          ))}
        </div>
      </div>
      <div className="dive-glow"/>
      {motes.map((m, i) => (
        <span key={i} className="dive-mote" style={{
          left: `${m.x}%`,
          width: `${m.size}px`,
          height: `${m.size}px`,
          animationDuration: `${m.dur}s`,
          animationDelay: `${m.delay}s`,
          "--mx": `${m.mx}px`
        }}/>
      ))}
    </div>
  );
}

// ── MATRIX TRANSITION ────────────────────────────────────────────────────────
const MATRIX_CHARS =
  'ابتثجحخدذرزسشصضطظعغفقكلمنهوي' +
  'אבגדהוזחטיכלמנסעפצקרשת' +
  '٠١٢٣٤٥٦٧٨٩' +
  '☿⊕⊗△▽✦◈⬡♄♃♂♀☽☉' +
  '0123456789';

function MatrixTransition({ scrollY = 0, t }) {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    const FS = 22;           // larger cell = fewer columns = less density
    const chars = MATRIX_CHARS.split('');
    let animId, cols, drops, speeds;
    let mouse = { x: -1, y: -1 };
    let bursts = [];
    let ripples = [];

    function resize() {
      canvas.width  = canvas.offsetWidth;
      canvas.height = canvas.offsetHeight;
      cols   = Math.floor(canvas.width / FS);
      drops  = Array.from({ length: cols }, () => -Math.random() * (canvas.height / FS) * 1.5);
      speeds = Array.from({ length: cols }, () => 0.18 + Math.random() * 0.32);
    }

    function rndChar() { return chars[Math.floor(Math.random() * chars.length)]; }

    function draw() {
      const now = Date.now();

      // ghost trail: faster clear = shorter, less cluttered trails
      ctx.fillStyle = 'rgba(0,0,0,0.12)';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      ctx.font = `${FS}px "Cinzel", monospace`;

      // ── column rain ─────────────────────────────────────────────────────
      for (let i = 0; i < cols; i++) {
        const x = i * FS;
        const y = drops[i] * FS;

        // mouse proximity (radius 160px)
        const mdx = x - mouse.x, mdy = y - mouse.y;
        const mdist = Math.sqrt(mdx * mdx + mdy * mdy);
        const mInfluence = mouse.x >= 0 ? Math.max(0, 1 - mdist / 160) : 0;

        // ripple influence
        let rBoost = 0;
        for (const r of ripples) {
          const age = (now - r.t) / 900;
          const ring = age * 260;
          const rdx = x - r.x, rdy = y - r.y;
          const rdist = Math.sqrt(rdx * rdx + rdy * rdy);
          if (Math.abs(rdist - ring) < 28) rBoost = Math.max(rBoost, (1 - age) * 2.5);
        }

        const totalBoost = 1 + mInfluence * 2.2 + rBoost;

        // head character — bright gold/white
        const glow = mInfluence + rBoost * 0.5;
        if (glow > 0.05) {
          ctx.shadowBlur  = 14;
          ctx.shadowColor = `rgba(240,192,96,${Math.min(1, glow)})`;
        } else {
          ctx.shadowBlur = 0;
        }
        // bottom-zone crystallization: chars get brighter as they approach the title text
        const bottomFrac = clamp((y - canvas.height * 0.5) / (canvas.height * 0.4));
        const headAlpha = 0.72 + mInfluence * 0.15 + bottomFrac * 0.22;
        ctx.fillStyle = `rgba(255,242,215,${Math.min(1, headAlpha)})`;
        ctx.fillText(rndChar(), x, y);
        ctx.shadowBlur = 0;

        // trail — gold fading to deep teal
        const trailLen = 14;
        for (let t = 1; t < trailLen; t++) {
          const ty = y - t * FS;
          if (ty < -FS) break;
          const fade = (1 - t / trailLen);
          const r2 = Math.round(lerp(201, 20,  t / trailLen));
          const g2 = Math.round(lerp(147, 55,  t / trailLen));
          const b2 = Math.round(lerp(58,  130, t / trailLen));
          ctx.fillStyle = `rgba(${r2},${g2},${b2},${fade * (0.38 + mInfluence * 0.3)})`;
          ctx.fillText(rndChar(), x, ty);
        }

        // advance — crystallize (slow down) near the bottom title zone
        const nearBottom = clamp((y - canvas.height * 0.52) / (canvas.height * 0.4));
        const crystalMult = 1 - nearBottom * 0.78;
        drops[i] += speeds[i] * totalBoost * Math.max(0.22, crystalMult);
        if (drops[i] * FS > canvas.height + FS * 10 && Math.random() > 0.972) {
          drops[i] = -Math.random() * 25;
        }
      }

      // ── burst particles ──────────────────────────────────────────────────
      bursts = bursts.filter(b => now - b.t < 1100);
      for (const b of bursts) {
        const age  = (now - b.t) / 1100;
        const fade = 1 - age;
        b.particles.forEach(p => {
          const px = b.x + p.vx * age * 120;
          const py = b.y + p.vy * age * 120 + age * age * 40; // slight gravity
          ctx.globalAlpha = fade * p.a;
          ctx.shadowBlur  = 8;
          ctx.shadowColor = 'rgba(240,192,96,0.8)';
          ctx.fillStyle   = `rgba(${Math.round(lerp(255,201,age))},${Math.round(lerp(242,147,age))},${Math.round(lerp(215,58,age))},1)`;
          ctx.fillText(p.ch, px, py);
          ctx.shadowBlur  = 0;
        });
        ctx.globalAlpha = 1;
      }

      // ── expanding sacred geometry ─────────────────────────────────────────
      ripples = ripples.filter(r => now - r.t < 900);
      for (const r of ripples) {
        const age    = (now - r.t) / 900;
        const radius = age * 260;
        const alpha  = (1 - age) * 0.65;
        const cx = r.x, cy = r.y;

        ctx.save();
        ctx.globalAlpha = alpha;
        ctx.strokeStyle = '#c9933a';
        ctx.fillStyle   = '#c9933a';
        ctx.lineWidth   = 1.2;

        switch (r.shape) {

          case 0: { // MONAD — hexagon + 4 rings + sun rays
            ctx.beginPath();
            for (let i = 0; i < 6; i++) {
              const a = (i / 6) * Math.PI * 2 - Math.PI / 2;
              i === 0 ? ctx.moveTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius)
                      : ctx.lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
            }
            ctx.closePath(); ctx.stroke();
            for (let i = 0; i < 6; i++) {
              const a = (i / 6) * Math.PI * 2 - Math.PI / 2;
              ctx.beginPath();
              ctx.arc(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius, radius * 0.045, 0, Math.PI * 2);
              ctx.fill();
            }
            ctx.lineWidth = 1;
            for (const rf of [0.84, 0.66, 0.48, 0.30]) {
              ctx.beginPath(); ctx.arc(cx, cy, radius * rf, 0, Math.PI * 2); ctx.stroke();
            }
            ctx.lineWidth = 0.8;
            for (let i = 0; i < 24; i++) {
              const a = (i / 24) * Math.PI * 2;
              ctx.beginPath();
              ctx.moveTo(cx + Math.cos(a) * radius * 0.16, cy + Math.sin(a) * radius * 0.16);
              ctx.lineTo(cx + Math.cos(a) * radius * 0.27, cy + Math.sin(a) * radius * 0.27);
              ctx.stroke();
            }
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.13, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 1: { // FLOWER OF LIFE — 7 overlapping circles
            ctx.lineWidth = 1;
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.5, 0, Math.PI * 2); ctx.stroke();
            for (let i = 0; i < 6; i++) {
              const a = (i / 6) * Math.PI * 2;
              const px = cx + Math.cos(a) * radius * 0.5;
              const py = cy + Math.sin(a) * radius * 0.5;
              ctx.beginPath(); ctx.arc(px, py, radius * 0.5, 0, Math.PI * 2); ctx.stroke();
            }
            ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.04, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 2: { // 6-POINTED STAR (Star of David) + rings
            ctx.lineWidth = 1.2;
            for (let tri = 0; tri < 2; tri++) {
              ctx.beginPath();
              for (let i = 0; i < 3; i++) {
                const a = (i / 3) * Math.PI * 2 - Math.PI / 2 + tri * Math.PI;
                i === 0 ? ctx.moveTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius)
                        : ctx.lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
              }
              ctx.closePath(); ctx.stroke();
            }
            ctx.lineWidth = 0.8;
            for (const rf of [0.75, 0.5]) {
              ctx.beginPath(); ctx.arc(cx, cy, radius * rf, 0, Math.PI * 2); ctx.stroke();
            }
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.08, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 3: { // 5-POINTED STAR
            ctx.lineWidth = 1.2;
            ctx.beginPath();
            for (let i = 0; i < 10; i++) {
              const a = (i / 10) * Math.PI * 2 - Math.PI / 2;
              const r2 = i % 2 === 0 ? radius : radius * 0.42;
              i === 0 ? ctx.moveTo(cx + Math.cos(a) * r2, cy + Math.sin(a) * r2)
                      : ctx.lineTo(cx + Math.cos(a) * r2, cy + Math.sin(a) * r2);
            }
            ctx.closePath(); ctx.stroke();
            ctx.lineWidth = 0.8;
            ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.42, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.08, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 4: { // VESICA PISCIS — two overlapping circles + outer ring
            ctx.lineWidth = 1;
            const off = radius * 0.5;
            ctx.beginPath(); ctx.arc(cx - off, cy, radius * 0.87, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx + off, cy, radius * 0.87, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.07, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 5: { // MANDALA — concentric rings with radial spokes + dots
            ctx.lineWidth = 1;
            for (const rf of [1, 0.75, 0.5, 0.28]) {
              ctx.beginPath(); ctx.arc(cx, cy, radius * rf, 0, Math.PI * 2); ctx.stroke();
            }
            ctx.lineWidth = 0.7;
            for (let i = 0; i < 12; i++) {
              const a = (i / 12) * Math.PI * 2;
              ctx.beginPath();
              ctx.moveTo(cx + Math.cos(a) * radius * 0.28, cy + Math.sin(a) * radius * 0.28);
              ctx.lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
              ctx.stroke();
            }
            for (let i = 0; i < 12; i++) {
              const a = (i / 12) * Math.PI * 2;
              ctx.beginPath();
              ctx.arc(cx + Math.cos(a) * radius * 0.75, cy + Math.sin(a) * radius * 0.75, radius * 0.04, 0, Math.PI * 2);
              ctx.fill();
            }
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.1, 0, Math.PI * 2); ctx.fill();
            break;
          }

          case 6: { // METATRON'S CUBE — 13 circles + connecting lines
            ctx.lineWidth = 0.7;
            const centers = [[cx, cy]];
            for (let i = 0; i < 6; i++) {
              const a = (i / 6) * Math.PI * 2;
              centers.push([cx + Math.cos(a) * radius * 0.5, cy + Math.sin(a) * radius * 0.5]);
            }
            for (let i = 0; i < 6; i++) {
              const a = (i / 6) * Math.PI * 2 + Math.PI / 6;
              centers.push([cx + Math.cos(a) * radius, cy + Math.sin(a) * radius]);
            }
            // connecting lines between all centers
            for (let i = 0; i < centers.length; i++) {
              for (let j = i + 1; j < centers.length; j++) {
                ctx.beginPath();
                ctx.moveTo(centers[i][0], centers[i][1]);
                ctx.lineTo(centers[j][0], centers[j][1]);
                ctx.stroke();
              }
            }
            ctx.lineWidth = 1;
            for (const [px, py] of centers) {
              ctx.beginPath(); ctx.arc(px, py, radius * 0.5, 0, Math.PI * 2); ctx.stroke();
            }
            break;
          }

          case 7: { // GOLDEN SPIRAL (Fibonacci approximation)
            ctx.lineWidth = 1.2;
            ctx.beginPath();
            let started = false;
            for (let t = 0; t <= Math.PI * 6; t += 0.06) {
              const rr = radius * (t / (Math.PI * 6));
              const sx = cx + rr * Math.cos(t);
              const sy = cy + rr * Math.sin(t);
              if (!started) { ctx.moveTo(sx, sy); started = true; }
              else ctx.lineTo(sx, sy);
            }
            ctx.stroke();
            // outer circle framing the spiral
            ctx.lineWidth = 0.8;
            ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
            // golden rectangles (3 nested)
            for (const rf of [1, 0.618, 0.382]) {
              const w = radius * rf * 2, h = radius * rf * 1.236;
              ctx.strokeRect(cx - w / 2, cy - h / 2, w, h);
            }
            ctx.beginPath(); ctx.arc(cx, cy, radius * 0.05, 0, Math.PI * 2); ctx.fill();
            break;
          }
        }

        ctx.restore();
      }

      animId = requestAnimationFrame(draw);
    }

    const onMouseMove = e => {
      const rect = canvas.getBoundingClientRect();
      mouse.x = e.clientX - rect.left;
      mouse.y = e.clientY - rect.top;
    };
    const onMouseLeave = () => { mouse.x = -1; mouse.y = -1; };
    const onClick = e => {
      const rect = canvas.getBoundingClientRect();
      const cx = e.clientX - rect.left;
      const cy = e.clientY - rect.top;
      // 28 particles flying in all directions
      const particles = Array.from({ length: 28 }, () => {
        const angle = Math.random() * Math.PI * 2;
        const speed = 0.4 + Math.random() * 0.6;
        return { ch: rndChar(), vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed, a: 0.7 + Math.random() * 0.3 };
      });
      bursts.push({ x: cx, y: cy, t: Date.now(), particles });
      ripples.push({ x: cx, y: cy, t: Date.now(), shape: Math.floor(Math.random() * 8) });
    };

    const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    function drawStatic() {
      ctx.fillStyle = 'rgba(0,0,0,1)';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.font = `${FS}px "Cinzel", monospace`;
      for (let i = 0; i < cols; i++) {
        const y = drops[i] * FS;
        if (y > 0 && y < canvas.height) {
          ctx.fillStyle = 'rgba(255,242,215,0.35)';
          ctx.fillText(rndChar(), i * FS, y);
          for (let t = 1; t < 8; t++) {
            const ty = y - t * FS;
            if (ty < 0) break;
            const fade = (1 - t / 8) * 0.3;
            ctx.fillStyle = `rgba(201,147,58,${fade})`;
            ctx.fillText(rndChar(), i * FS, ty);
          }
        }
      }
    }

    resize();
    if (prefersReducedMotion) {
      drawStatic();
      const onResizeStatic = () => { resize(); drawStatic(); };
      window.addEventListener('resize', onResizeStatic);
      return () => window.removeEventListener('resize', onResizeStatic);
    }

    draw();

    const onResize = () => { resize(); };
    window.addEventListener('resize', onResize);
    canvas.addEventListener('mousemove', onMouseMove);
    canvas.addEventListener('mouseleave', onMouseLeave);
    canvas.addEventListener('click', onClick);

    return () => {
      cancelAnimationFrame(animId);
      window.removeEventListener('resize', onResize);
      canvas.removeEventListener('mousemove', onMouseMove);
      canvas.removeEventListener('mouseleave', onMouseLeave);
      canvas.removeEventListener('click', onClick);
    };
  }, []);

  return (
    <div className="matrix-transition" style={{ transform: `translateY(${scrollY * 0.1}px)` }}>
      <canvas ref={canvasRef} className="matrix-canvas" aria-hidden="true"/>
      <div className="matrix-label">
        <span className="matrix-label-text">✦ &nbsp; {t('matrixLabel')} &nbsp; ✦</span>
      </div>
    </div>
  );
}

// ── GNOSIS SECTION ────────────────────────────────────────────────────────────
function GnosisSection({ scrollY = 0, t }) {
  const ref = useReveal();
  return (
    <section id="gnosis" className="depths-section" ref={ref} style={{ paddingBottom: "300px", paddingTop: "111px" }}>
      <Particles count={28} scrollY={scrollY} parallaxSpeed={0.2}/>
      <div className="depths-inner" style={{ transform: `translateY(${scrollY * 0.08}px)` }}>
        <div className="section-header">
          <div className="reveal">
            <span className="section-eyebrow">☿ &nbsp; {t('gnosisEyebrow')}</span>
          </div>
          <h2 className="section-title reveal reveal-delay-1">
            {t('gnosisTitle')(t('gnosisTitleEm'))}
          </h2>
        </div>

        <div className="bio-grid">
          <div className="bio-glyphs reveal reveal-delay-2">
            <BioGlyphs/>
          </div>
          <div className="bio-body">
            <p className="bio-lead reveal reveal-delay-2">
              {t('bioLead')}{" "}
              <em>{t('bioLeadEm')}</em>
            </p>
            <p className="reveal reveal-delay-3">
              {t('bioP2')}
            </p>
            <p className="reveal reveal-delay-3">
              {t('bioP3')}
            </p>
            <div className="bio-tags reveal reveal-delay-4">
              {[t('bioTag1'), t('bioTag2'), t('bioTag3'), t('bioTag4')].map(tag => (
                <a
                  key={tag}
                  href={`https://www.google.com/search?q=${encodeURIComponent(tag)}`}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="bio-tag"
                  title={`Search for ${tag}`}
                >{tag}</a>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function BioGlyphs() {
  return (
    <svg viewBox="0 0 180 320" className="bio-glyphs-svg">
      <g stroke="currentColor" fill="none" strokeWidth="0.5" opacity="0.7">
        <circle cx="90" cy="50" r="36"/>
        <circle cx="90" cy="50" r="22"/>
        <circle cx="90" cy="50" r="10"/>
        <polygon points="90,18 122,76 58,76"/>
        <line x1="90" y1="86" x2="90" y2="160"/>
        <circle cx="90" cy="180" r="22"/>
        <circle cx="90" cy="180" r="2" fill="currentColor"/>
        <line x1="90" y1="200" x2="90" y2="260"/>
        <path d="M70,260 Q90,290 110,260"/>
        <path d="M76,272 Q90,295 104,272"/>
        <line x1="90" y1="292" x2="90" y2="316"/>
      </g>
      <text x="90" y="50" textAnchor="middle" dy="4"
            fontFamily="serif" fontSize="14" fill="currentColor" opacity="0.9">☿</text>
    </svg>
  );
}

function Particles({ count = 24, scrollY = 0, parallaxSpeed = 0 }) {
  const items = useMemo(() => Array.from({ length: count }, () => ({
    x: Math.random() * 100,
    y: Math.random() * 100,
    size: 0.6 + Math.random() * 1.6,
    dur: 4 + Math.random() * 10,
    delay: -Math.random() * 8
  })), [count]);

  return (
    <div className="particles" style={{ transform: parallaxSpeed ? `translateY(${scrollY * parallaxSpeed}px)` : undefined }}>
      {items.map((p, i) => (
        <span key={i} className="particle" style={{
          left: `${p.x}%`,
          top: `${p.y}%`,
          width: `${p.size}px`,
          height: `${p.size}px`,
          animationDuration: `${p.dur}s`,
          animationDelay: `${p.delay}s`
        }}/>
      ))}
    </div>
  );
}

// ── SOUND CAROUSEL ────────────────────────────────────────────────────────────
function SoundCarousel({ style, t }) {
  const [active, setActive] = useState(0);
  const total = TRACKS.length;
  const next = useCallback(() => setActive(a => (a + 1) % total), [total]);
  const prev = useCallback(() => setActive(a => (a - 1 + total) % total), [total]);
  const ref  = useReveal(0.1);

  const touchStartX = useRef(null);
  const touchEndX   = useRef(null);
  const minSwipe    = 50;

  const handleTouchStart = e => {
    touchStartX.current = e.targetTouches[0].clientX;
    touchEndX.current   = null;
  };
  const handleTouchMove = e => {
    touchEndX.current = e.targetTouches[0].clientX;
  };
  const handleTouchEnd = () => {
    if (touchStartX.current === null || touchEndX.current === null) return;
    const dist = touchStartX.current - touchEndX.current;
    if (dist > minSwipe)  next();
    if (dist < -minSwipe) prev();
  };

  useEffect(() => {
    const onKey = e => {
      if (e.key === "ArrowRight") next();
      if (e.key === "ArrowLeft")  prev();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [next, prev]);

  return (
    <section id="sound" className={`sound-section style-${style || "ring"}`} style={{ paddingBottom: "300px" }} ref={ref}>
      <Particles count={45} scrollY={scrollY} parallaxSpeed={0.15}/>

      <div className="sound-header">
        <div className="reveal">
          <span className="section-eyebrow">⊕ &nbsp; {t('soundEyebrow')}</span>
        </div>
        <h2 className="section-title reveal reveal-delay-1">{t('soundTitle')(<br className="mobile-break" />)}</h2>
        <p className="section-sub reveal reveal-delay-2">
          {t('soundSub1')}
        </p>
        <p className="section-sub reveal reveal-delay-3" style={{ marginTop: '0.55rem', opacity: 0.75 }}>
          <em>{t('soundSub2')}</em>
        </p>
      </div>

      <div className="carousel-stage reveal"
           onTouchStart={handleTouchStart}
           onTouchMove={handleTouchMove}
           onTouchEnd={handleTouchEnd}
           onTouchCancel={handleTouchEnd}>
        <button className="car-nav prev" onClick={prev} aria-label={t('soundPrev')}>
          <span>‹</span>
        </button>
        <button className="car-nav next" onClick={next} aria-label={t('soundNext')}>
          <span>›</span>
        </button>

        <div className="carousel-track">
          {TRACKS.map((trk, i) => {
            const offset = (i - active + total) % total;
            const rel    = offset > total / 2 ? offset - total : offset;
            return (
              <CarouselCard key={trk.id} track={trk} rel={rel}
                            active={i === active} onClick={() => setActive(i)} t={t}/>
            );
          })}
        </div>

        <div className="car-dots">
          {TRACKS.map((trk, i) => (
            <button key={trk.id} className={`car-dot${i === active ? " on" : ""}`}
                    onClick={() => setActive(i)} aria-label={trk.title}>
              <span/>
            </button>
          ))}
        </div>

        <div className="car-meta" style={{ marginTop: "60px" }}>
          <div className="car-meta-row">
            <span className="car-meta-num">{TRACKS[active].num}</span>
            <div className="car-meta-rule"/>
            <span className="car-meta-count">
              {String(active + 1).padStart(2,"0")} / {String(total).padStart(2,"0")}
            </span>
          </div>
          <h3 className="car-meta-title">{TRACKS[active].title}</h3>
          <p className="car-meta-artist">Jihadeen el-Eden — {t('soundMeta')}</p>
        </div>
      </div>
    </section>
  );
}

function CarouselCard({ track, rel, active, onClick, t }) {
  const renderIframe = Math.abs(rel) <= 1;
  const absRel  = Math.abs(rel);
  const tx      = rel * 300;
  const scale   = active ? 1 : Math.max(0.62, 1 - absRel * 0.16);
  const opacity = absRel >= 3 ? 0 : Math.max(0.12, 1 - absRel * 0.3);
  const blur    = active ? 0 : Math.min(5, absRel * 1.4);
  const z       = 100 - Math.round(absRel * 10);
  const rot     = rel * -5;

  const iframeSrc =
    `https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/` +
    `soundcloud%253Atracks%253A${track.id}` +
    `&color=%23${track.color.replace("#","")}` +
    `&auto_play=false&hide_related=true&show_comments=false` +
    `&show_user=true&show_reposts=false&show_teaser=false&visual=true`;

  return (
    <article
      className={`car-card${active ? " active" : ""}`}
      style={{
        transform: `translateX(calc(-50% + ${tx}px)) scale(${scale}) rotateY(${rot}deg)`,
        opacity,
        filter: `blur(${blur}px)`,
        zIndex: z,
        "--accent": track.color,
        ...(() => { const c = hexToRgb(track.color); return { "--accent-r": c.r, "--accent-g": c.g, "--accent-b": c.b }; })()
      }}
      onClick={onClick}
    >
      <div className="car-card-outer">
        <span className="card-corner tl"/>
        <span className="card-corner tr"/>
        <span className="card-corner bl"/>
        <span className="card-corner br"/>
        <div className="car-card-frame">
          <div className="card-num"><span>{track.num}</span></div>

          {renderIframe ? (
            <div className="card-iframe-wrap">
              <iframe
                title={track.title}
                className="card-iframe"
                scrolling="no"
                frameBorder="0"
                allow="autoplay; encrypted-media"
                src={iframeSrc}
              />
            </div>
          ) : (
            <div className="card-placeholder">
              <div className="card-placeholder-disc"/>
              <span className="card-placeholder-title">{track.title}</span>
            </div>
          )}

          <div className="card-footer">
            <span className="card-title-line">{track.title}</span>
            <a className="card-permalink"
               href={`https://soundcloud.com/jihadeeneleden/${track.slug}`}
               target="_blank" rel="noopener"
               onClick={e => e.stopPropagation()}>
              ↗ {t('cardOpen')}
            </a>
          </div>
        </div>
      </div>
    </article>
  );
}

// ── CONTACT ───────────────────────────────────────────────────────────────────
function ContactSection({ scrollY = 0, t }) {
  const ref = useReveal();
  return (
    <section id="contact" className="contact-section" ref={ref} style={{ paddingTop: "144px" }}>
      <Particles count={35} scrollY={scrollY} parallaxSpeed={0.15}/>
      <div className="contact-inner">
        <div className="contact-symbol reveal">
          <img src="/assets/aeons_cross.png" alt="Aeon Cross" />
        </div>

        <div className="reveal reveal-delay-1">
          <span className="section-eyebrow">✦ &nbsp; {t('contactEyebrow')}</span>
        </div>
        <h2 className="contact-title reveal reveal-delay-1">{t('contactTitle')}</h2>
        <p className="contact-body reveal reveal-delay-2">
          {t('contactBody1')}<br/>
          {t('contactBody2')}
        </p>

        <div className="contact-icons-container reveal reveal-delay-3">
          <a
            href="mailto:jihadeeneleden@proton.me"
            className="contact-icon-btn"
            title="Email"
            aria-label={t('contactEmailLabel')}
          >
            <img src="/assets/email_icon.png" alt="Email" className="contact-icon-image"/>
          </a>

          <a
            href="https://soundcloud.com/jihadeeneleden"
            target="_blank"
            rel="noopener noreferrer"
            className="contact-icon-btn"
            title="SoundCloud"
            aria-label={t('contactScLabel')}
          >
            <img src="/assets/soundcloud_icon.png" alt="SoundCloud" className="contact-icon-image"/>
          </a>

          <a
            href="https://www.tiktok.com/@jihadeeneleden"
            target="_blank"
            rel="noopener noreferrer"
            className="contact-icon-btn"
            title="TikTok"
            aria-label={t('contactTikLabel')}
          >
            <img src="/assets/tiktok_icon.png" alt="TikTok" className="contact-icon-image"/>
          </a>
        </div>
      </div>

      <footer className="site-footer reveal reveal-delay-4">
        <span className="footer-name">Jihadeen el-Eden</span>
        <span className="footer-mark">⊕ &nbsp; MMXXVI &nbsp; ⊕</span>
        <span>{t('footerRights')}</span>
      </footer>
    </section>
  );
}

// ── iOS COMPONENTS ────────────────────────────────────────────────────────────
function IOSHero({ tweaks, t }) {
  return (
    <div className="ios-hero">
      <div className="ios-hero-inner">
        {tweaks.showGlyph && <HeroGlyph/>}
        <h1 className="hero-name">
          {tweaks.artistName.split(/\s+/).map((w, i, arr) => (
            <span key={i} className={`${i === 0 ? "float" : ""}${i === arr.length - 1 ? " name-last" : ""}`.trim()}>{w}</span>
          ))}
        </h1>
        <p className="hero-tagline">{t('tagline')}</p>
        <div className="hero-divider">
          <span className="divider-line"/>
          <span className="hero-aeon-symbol">
            <img src="/assets/aeon_cross.svg" alt="Aeon Cross" />
          </span>
          <span className="divider-line right"/>
        </div>
      </div>
      <div className="descend-cue">
        <span>{t('descend')}</span>
        <span className="descend-line"/>
      </div>
    </div>
  );
}

function IOSMusicList({ t }) {
  const [openIdx, setOpenIdx] = useState(0);
  const ref = useReveal(0.1);

  return (
    <section id="sound" className="ios-music-section" ref={ref}>
      <div className="sound-header">
        <div className="reveal">
          <span className="section-eyebrow">⊕ &nbsp; {t('soundEyebrow')}</span>
        </div>
        <h2 className="section-title reveal reveal-delay-1">{t('soundTitle')(<br className="mobile-break" />)}</h2>
        <p className="section-sub reveal reveal-delay-2">
          {t('soundSub1')}
        </p>
        <p className="section-sub reveal reveal-delay-3" style={{ marginTop: '0.55rem', opacity: 0.75 }}>
          <em>{t('soundSub2')}</em>
        </p>
      </div>

      <div className="ios-music-list reveal">
        {TRACKS.map((track, idx) => {
          const isOpen = idx === openIdx;
          const c = hexToRgb(track.color);
          return (
            <div
              key={track.id}
              className={`ios-music-item${isOpen ? " open" : ""}`}
              onClick={() => setOpenIdx(isOpen ? -1 : idx)}
              style={{ "--accent": track.color, "--accent-r": c.r, "--accent-g": c.g, "--accent-b": c.b }}
            >
              <div className="ios-music-header">
                <span className="ios-music-num">{track.num}</span>
                <span className="ios-music-title">{track.title}</span>
                <span className="ios-music-arrow">{isOpen ? "−" : "+"}</span>
              </div>
              {isOpen && (
                <div className="ios-music-body">
                  <iframe
                    title={track.title}
                    className="ios-music-iframe"
                    scrolling="no"
                    frameBorder="0"
                    allow="autoplay; encrypted-media"
                    src={`https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/soundcloud%253Atracks%253A${track.id}&color=%23${track.color.replace("#","")}&auto_play=false&hide_related=true&show_comments=false&show_user=true&show_reposts=false&show_teaser=false&visual=true`}
                  />
                  <a
                    className="ios-music-link"
                    href={`https://soundcloud.com/jihadeeneleden/${track.slug}`}
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    {t('soundOpen')}
                  </a>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </section>
  );
}

function IOSApp() {
  const tweaks = TWEAKS;
  const [scrolled, setScrolled] = useState(false);
  const [language, setLanguage] = useState('en');
  const [country, setCountry] = useState(null);

  const t = useMemo(() => makeGetTranslation(language, country), [language, country]);

  useEffect(() => {
    const savedLanguage = localStorage.getItem('preferredLanguage');
    const savedCountry  = localStorage.getItem('detectedCountry');
    if (savedLanguage) {
      setLanguage(savedLanguage);
      if (savedCountry) setCountry(savedCountry);
      return;
    }
    fetch('https://ipapi.co/json/')
      .then(r => r.json())
      .then(data => {
        const detectedCountry = data.country_code;
        setCountry(detectedCountry);
        localStorage.setItem('detectedCountry', detectedCountry);
        setLanguage(spanishCountries.includes(detectedCountry) ? 'es' : 'en');
      })
      .catch(() => setLanguage('en'));
  }, []);

  const toggleLanguage = useCallback(() => {
    setLanguage(prev => {
      const next = prev === 'en' ? 'es' : 'en';
      localStorage.setItem('preferredLanguage', next);
      return next;
    });
  }, []);

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 60);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const hue = DEPTH_HUES[tweaks.depthHue] || DEPTH_HUES["deep-blue"];

  return (
    <div id="top" className="ios-app" style={{
      "--depth-base": hue.base,
      "--depth-mid":  hue.mid,
      "--depth-glow": hue.glow
    }}>
      <LanguageToggle language={language} toggleLanguage={toggleLanguage} scrolled={scrolled}/>
      <Nav scrolled={scrolled} isLoading={false} t={t}/>
      <IOSHero tweaks={tweaks} t={t}/>
      <GnosisSection t={t}/>
      <IOSMusicList t={t}/>
      <ContactSection t={t}/>
    </div>
  );
}

// ── APP ───────────────────────────────────────────────────────────────────────
function App() {
  const tweaks = TWEAKS;
  const [scrolled, setScrolled] = useState(false);
  const [navVisible, setNavVisible] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [scrollY, setScrollY] = useState(0);
  const isMobileRef = useRef(window.innerWidth < 480);

  const [language, setLanguage] = useState('en');
  const [country, setCountry] = useState(null);

  const t = useMemo(() => makeGetTranslation(language, country), [language, country]);

  useEffect(() => {
    const savedLanguage = localStorage.getItem('preferredLanguage');
    const savedCountry  = localStorage.getItem('detectedCountry');
    if (savedLanguage) {
      setLanguage(savedLanguage);
      if (savedCountry) setCountry(savedCountry);
      return;
    }
    fetch('https://ipapi.co/json/')
      .then(r => r.json())
      .then(data => {
        const detectedCountry = data.country_code;
        setCountry(detectedCountry);
        localStorage.setItem('detectedCountry', detectedCountry);
        setLanguage(spanishCountries.includes(detectedCountry) ? 'es' : 'en');
      })
      .catch(() => setLanguage('en'));
  }, []);

  const toggleLanguage = useCallback(() => {
    setLanguage(prev => {
      const next = prev === 'en' ? 'es' : 'en';
      localStorage.setItem('preferredLanguage', next);
      return next;
    });
  }, []);

  useEffect(() => {
    const onScroll = () => {
      setScrolled(window.scrollY > 60);
      if (isMobileRef.current) {
        const gnosis = document.getElementById('gnosis');
        if (gnosis) {
          const rect = gnosis.getBoundingClientRect();
          const gnosisDepth = -rect.top / rect.height;
          setNavVisible(gnosisDepth >= 3.0);
        }
      }
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  useEffect(() => {
    if (isLoading) {
      document.body.classList.add('loading');
      document.documentElement.classList.add('loading');

      const timer = setTimeout(() => {
        setIsLoading(false);
        document.body.classList.remove('loading');
        document.documentElement.classList.remove('loading');
      }, 4500);

      return () => clearTimeout(timer);
    }
  }, [isLoading]);

  useEffect(() => {
    if (isMobileRef.current) return;

    let ticking = false;
    const handleScroll = () => {
      if (!ticking) {
        requestAnimationFrame(() => {
          setScrollY(window.scrollY);
          ticking = false;
        });
        ticking = true;
      }
    };

    window.addEventListener('scroll', handleScroll, { passive: true });
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const hue = DEPTH_HUES[tweaks.depthHue] || DEPTH_HUES["deep-blue"];

  return (
    <div id="top" style={{
      "--depth-base": hue.base,
      "--depth-mid":  hue.mid,
      "--depth-glow": hue.glow
    }}>
      <LanguageToggle language={language} toggleLanguage={toggleLanguage} scrolled={scrolled}/>
      <Nav scrolled={scrolled} isLoading={isLoading} navVisible={navVisible} t={t}/>
      <DiveStage tweaks={tweaks} isLoading={isLoading} scrollY={scrollY} t={t}/>
      <MatrixTransition scrollY={scrollY} t={t}/>
      <GnosisSection scrollY={scrollY} t={t}/>
      <SoundCarousel style={tweaks.carouselStyle} t={t}/>
      <ContactSection scrollY={scrollY} t={t}/>
    </div>
  );
}

const Root = IS_IOS ? IOSApp : App;
ReactDOM.createRoot(document.getElementById("root")).render(<Root/>);
