/* global React */
// Shared UI components: Header, Footer, LanguageSwitcher, ProgramCard, Icon, FormField, FileDrop

const { useState, useEffect, useRef } = React;

// Tiny icon set drawn as inline SVG (kept generic + minimal per brand "premium minimalism")
function Arrow({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <path d="M5 12h14M13 6l6 6-6 6" strokeLinecap="square" />
    </svg>
  );
}
function ArrowLeft({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <path d="M19 12H5M11 6l-6 6 6 6" strokeLinecap="square" />
    </svg>
  );
}
function Check({ size = 24 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="#FFC700" strokeWidth="2.5">
      <path d="M5 12l5 5L20 7" strokeLinecap="square" />
    </svg>
  );
}
function UploadIcon() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <path d="M12 4v12M6 10l6-6 6 6M4 20h16" strokeLinecap="square" />
    </svg>
  );
}
function InstagramIcon({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <rect x="3" y="3" width="18" height="18" rx="5" />
      <circle cx="12" cy="12" r="4" />
      <circle cx="17.5" cy="6.5" r="1" fill="currentColor" stroke="none" />
    </svg>
  );
}

function LanguageSwitcher({ lang, setLang }) {
  return (
    <div className="lang-switch" role="group" aria-label="Language">
      {["en", "es", "ru"].map((code) => (
        <button
          key={code}
          className={lang === code ? "active" : ""}
          onClick={() => setLang(code)}
          aria-pressed={lang === code}
        >
          {code.toUpperCase()}
        </button>
      ))}
    </div>
  );
}

// Mobile-only compact language picker. Default is whatever lang prop is set to
// (English by default elsewhere). Shows current code + a chevron; tap reveals
// the other two options in a small dropdown panel. Closes on outside click,
// Escape, or after picking an option.
function LanguageDropdown({ lang, setLang }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {
      if (ref.current && !ref.current.contains(e.target)) setOpen(false);
    };
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onDoc);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);
  const others = ["en", "es", "ru"].filter((c) => c !== lang);
  return (
    <div className={"lang-dropdown" + (open ? " is-open" : "")} ref={ref}>
      <button
        className="lang-dropdown-btn"
        onClick={() => setOpen((o) => !o)}
        aria-haspopup="listbox"
        aria-expanded={open}
        aria-label="Language"
      >
        <span>{lang.toUpperCase()}</span>
        <svg className="lang-chev" width="10" height="6" viewBox="0 0 10 6" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden="true">
          <path d="M1 1l4 4 4-4" strokeLinecap="square" strokeLinejoin="miter" />
        </svg>
      </button>
      {open && (
        <ul className="lang-dropdown-menu" role="listbox">
          {others.map((code) => (
            <li key={code} role="option">
              <button
                onClick={() => { setLang(code); setOpen(false); }}
              >
                {code.toUpperCase()}
              </button>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

function Header({ lang, setLang, navigate, onDark, route }) {
  const t = window.I18N[lang];
  // Smart nav: on home page, scroll to the section; elsewhere, navigate to the dedicated page.
  const goPrograms = () => {
    if (route && route.name === "home") {
      const el = document.getElementById("programs");
      if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
    } else {
      navigate({ name: "home" });
      setTimeout(() => {
        const el = document.getElementById("programs");
        if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
      }, 60);
    }
  };
  // "Our cases" lives as an in-page section between Programs and Partners on the home page.
  // From any inner page we navigate home first, then scroll once the section mounts.
  const goCases = () => {
    if (route && route.name === "home") {
      const el = document.getElementById("cases");
      if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
    } else {
      navigate({ name: "home" });
      setTimeout(() => {
        const el = document.getElementById("cases");
        if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
      }, 60);
    }
  };
  const isActive = (n) => route && route.name === n;
  // Brand click: always returns the user to the very top of the home page,
  // whether they're on home (where navigate() wouldn't trigger a hashchange)
  // or on any inner page.
  const goHomeTop = () => {
    if (route && route.name === "home") {
      window.scrollTo({ top: 0, behavior: "smooth" });
    } else {
      navigate({ name: "home" });
      setTimeout(() => window.scrollTo({ top: 0, behavior: "auto" }), 60);
    }
  };
  return (
    <header className={"site-header" + (onDark ? " on-dark" : "")}>
      <div className="container row">
        <div className="brand" onClick={goHomeTop} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); goHomeTop(); } }}>
          <img src={(window.__resources && window.__resources[onDark ? "logoWhite" : "logoNavy"]) || (onDark ? "assets/logo-new-white.png" : "assets/logo-new.png")} alt="FirstSteps" />
          <div className="brand-text">
            FirstSteps
            <small>Football placement</small>
          </div>
        </div>
        <nav className="header-nav">
          <button className="nav-lk" onClick={goPrograms}>{t.nav.programs}</button>
          <button className="nav-lk" onClick={goCases}>{t.nav.cases}</button>
          <button className={"nav-lk" + (isActive("partners") ? " is-active" : "")} onClick={() => navigate({ name: "partners" })}>{t.nav.partners}</button>
          <button className={"nav-lk" + (isActive("collaboration") ? " is-active" : "")} onClick={() => navigate({ name: "collaboration" })}>{t.nav.collab}</button>
          <button className={"nav-lk" + (isActive("about") ? " is-active" : "")} onClick={() => navigate({ name: "about" })}>{t.nav.about}</button>
        </nav>
        <div className="header-right">
          {/* Desktop: inline 3-pill switcher. Mobile (<=980px): collapsed
              dropdown — CSS toggles which one is visible. */}
          <LanguageSwitcher lang={lang} setLang={setLang} />
          <LanguageDropdown lang={lang} setLang={setLang} />
          <button
            className="btn btn-primary btn-sm header-cta"
            onClick={goPrograms}
          >
            {t.cta.talkToUs} <Arrow size={12} />
          </button>
        </div>
      </div>
    </header>
  );
}

function Footer({ lang, navigate }) {
  const t = window.I18N[lang].footer;
  const programs = window.PROGRAMS;
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-grid">
          <div className="footer-brand">
            <img src={(window.__resources && window.__resources.logoWhite) || "assets/logo-new-white.png"} alt="FirstSteps" />
            <p>{t.tagline}</p>
          </div>
          <div>
            <h4>{t.programsCol}</h4>
            {programs.slice(0, 4).map((p) => (
              <span key={p.id} className="lk" onClick={() => navigate({ name: "program", id: p.id })}>
                {p.title[lang]}
              </span>
            ))}
          </div>
          <div>
            <h4>{t.companyCol}</h4>
            <span className="lk" onClick={() => navigate({ name: "about" })}>{t.about}</span>
            <span className="lk" onClick={() => navigate({ name: "partners" })}>{t.partners}</span>
            <span className="lk" onClick={() => navigate({ name: "collaboration" })}>{t.collab}</span>
          </div>
          <div>
            <h4>{t.contactCol}</h4>
            <a
              className="lk lk-ig"
              href="https://www.instagram.com/firststeps_world/"
              target="_blank"
              rel="noopener noreferrer"
              onClick={(e) => {
                e.preventDefault();
                window.open("https://www.instagram.com/firststeps_world/", "_blank", "noopener,noreferrer");
              }}
            >
              <InstagramIcon size={16} />
              <span>firststeps_world</span>
            </a>
            <span className="lk">{t.langs}</span>
          </div>
        </div>
        <div className="footer-bottom">
          <span>{t.copyright}</span>
        </div>
      </div>
    </footer>
  );
}

function ProgramCard({ program, idx, lang, navigate }) {
  const t = window.I18N[lang];
  const price = window.PROGRAM_PRICES && window.PROGRAM_PRICES[program.id]
    ? window.PROGRAM_PRICES[program.id][lang]
    : null;
  return (
    <div
      className="program-card"
      onClick={() => navigate({ name: "program", id: program.id })}
      role="button"
      tabIndex={0}
      onKeyDown={(e) => { if (e.key === "Enter") navigate({ name: "program", id: program.id }); }}
    >
      <div className="program-num">0{idx + 1} / 06</div>
      <h3 className="program-title">{program.title[lang]}</h3>
      <p className="program-desc">{program.short[lang]}</p>
      <div className="program-meta">
        <span><span className="dot">●</span> {program.duration[lang]}</span>
        <span><span className="dot">●</span> {program.location[lang]}</span>
      </div>
      {price && (
        <div className="program-price">
          <span className="program-price-label">{lang === "ru" ? "Стоимость" : (lang === "es" ? "Precio" : "Price")}</span>
          <span className="program-price-val">{price}</span>
        </div>
      )}
      <span className="program-arrow" aria-hidden="true">
        <Arrow size={14} />
      </span>
    </div>
  );
}

function Field({ label, required, error, hint, children }) {
  return (
    <div className={"field" + (error ? " error" : "")}>
      <label>
        {label}
        {required && <span className="req">*</span>}
      </label>
      {children}
      {error && <span className="err">{error}</span>}
      {!error && hint && <span className="hint">{hint}</span>}
    </div>
  );
}

function FileDrop({ lang, file, setFile }) {
  const t = window.I18N[lang].form;
  const inputRef = useRef(null);
  return (
    <div
      className={"file-drop" + (file ? " has-file" : "")}
      onClick={() => inputRef.current && inputRef.current.click()}
      onDragOver={(e) => e.preventDefault()}
      onDrop={(e) => {
        e.preventDefault();
        const f = e.dataTransfer.files && e.dataTransfer.files[0];
        if (f) setFile(f);
      }}
      role="button"
      tabIndex={0}
    >
      <div className="icon"><UploadIcon /></div>
      <div className="ttl">{file ? file.name : t.cvDrop}</div>
      <div className="sub">{file ? Math.round(file.size / 1024) + " KB" : t.cvHint}</div>
      <input
        ref={inputRef}
        type="file"
        accept=".pdf,.doc,.docx"
        onChange={(e) => setFile(e.target.files && e.target.files[0])}
      />
    </div>
  );
}

// Intro splash — shown on first home view per session. Logo animates: "f1rst" fades up,
// then "steps" travels from bottom-left to its final position above the "t".
function IntroSplash({ lang, onDone }) {
  const tagline = {
    en: "Your path to professional football",
    es: "Tu camino al fútbol profesional",
    ru: "Твой путь в профессиональный футбол",
  }[lang] || "Your path to professional football";

  const [leaving, setLeaving] = useState(false);

  useEffect(() => {
    const leaveAt  = setTimeout(() => setLeaving(true), 3000);
    const removeAt = setTimeout(onDone, 3600);
    return () => { clearTimeout(leaveAt); clearTimeout(removeAt); };
  }, [onDone]);

  const skip = () => { setLeaving(true); setTimeout(onDone, 450); };

  return (
    <div className={"intro" + (leaving ? " leaving" : "")} onClick={skip}>
      <div className="intro-inner">
        <div className="intro-logo">
          <span className="intro-first">f<span className="one">1</span>rst</span>
          <span className="intro-steps">steps</span>
        </div>
        <div className="intro-tagline">
          <span className="bar"></span>{tagline}<span className="bar"></span>
        </div>
      </div>
      <button className="intro-skip" onClick={(e) => { e.stopPropagation(); skip(); }}>
        Skip →
      </button>
    </div>
  );
}

// ---------- VIDEO CAROUSEL ----------
// Auto-playing, muted, looping carousel for short MP4s. Used on the home page
// "Our cases" section and on the full-year program "Program overview" section.
// Controls per active card: play/pause, sound, expand (modal on desktop, native
// fullscreen on small viewports), plus a click-to-seek scrubber with timecode.
function VideoCarousel({ videos, labels, className }) {
  // videos: [{ src, title, subtitle? }]
  const [active, setActive] = useState(0);
  const [muted, setMuted] = useState(true);
  const [playing, setPlaying] = useState(true);
  const [progress, setProgress] = useState(0); // 0..1
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [expanded, setExpanded] = useState(false);
  const refs = useRef([]);
  const expandedRef = useRef(null);
  const scrubRef = useRef(null);

  const total = videos.length;
  const go = (delta) => setActive((i) => (i + delta + total) % total);

  // Only the active card plays — others pause and rewind so they don't waste
  // bandwidth or jump audibly when the user steps through them. Switching slides
  // also resets the play/progress state so the new clip starts cleanly.
  useEffect(() => {
    refs.current.forEach((v, i) => {
      if (!v) return;
      v.muted = muted;
      if (i === active) {
        try { v.currentTime = 0; } catch (e) {}
        if (playing) {
          const p = v.play();
          if (p && p.catch) p.catch(() => {});
        } else {
          v.pause();
        }
      } else {
        v.pause();
        try { v.currentTime = 0; } catch (e) {}
      }
    });
    setProgress(0);
    setCurrentTime(0);
  }, [active]); // eslint-disable-line react-hooks/exhaustive-deps

  // Honour play/pause + mute toggles on the active video without resetting time.
  useEffect(() => {
    const v = refs.current[active];
    if (!v) return;
    v.muted = muted;
    if (playing) {
      const p = v.play();
      if (p && p.catch) p.catch(() => {});
    } else {
      v.pause();
    }
  }, [playing, muted, active]);

  // Mobile gets native fullscreen (browser/OS chrome). Desktop gets a contained
  // overlay so the page stays visible around it. In BOTH cases we pause the
  // inline video while the expanded copy is active so its audio isn't duplicated.
  const openExpanded = () => {
    const inline = refs.current[active];
    if (inline) { try { inline.pause(); } catch (e) {} }
    const isMobile = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(max-width: 720px)").matches;
    if (isMobile) {
      if (inline) {
        const req = inline.requestFullscreen || inline.webkitEnterFullscreen || inline.webkitRequestFullscreen;
        if (req) {
          // On mobile the same <video> goes fullscreen — no second element, so
          // resume playback there. Listen for the exit event to come back.
          try {
            req.call(inline);
            const onExit = () => {
              document.removeEventListener("fullscreenchange", onExit);
              document.removeEventListener("webkitfullscreenchange", onExit);
              // Resume inline playback if we're still on the same slide and the
              // user hasn't paused it.
              if (playing && refs.current[active]) {
                const p = refs.current[active].play();
                if (p && p.catch) p.catch(() => {});
              }
            };
            document.addEventListener("fullscreenchange", onExit);
            document.addEventListener("webkitfullscreenchange", onExit);
            const p = inline.play();
            if (p && p.catch) p.catch(() => {});
            return;
          } catch (e) {}
        }
      }
    }
    setExpanded(true);
  };
  const closeExpanded = () => setExpanded(false);

  // When the overlay is open, sync source + play state on the modal copy and
  // make sure the inline copy stays paused so we don't get two audio streams.
  useEffect(() => {
    if (!expanded) return;
    const inline = refs.current[active];
    if (inline) { try { inline.pause(); } catch (e) {} }
    if (!expandedRef.current) return;
    const v = expandedRef.current;
    v.muted = muted;
    const p = v.play();
    if (p && p.catch) p.catch(() => {});
  }, [expanded, active, muted]);

  // When the overlay closes, resume inline playback if the user had it playing
  // (and the slide hasn't changed). The mute state is already shared.
  useEffect(() => {
    if (expanded) return;
    const v = refs.current[active];
    if (!v) return;
    v.muted = muted;
    if (playing) {
      const p = v.play();
      if (p && p.catch) p.catch(() => {});
    }
  }, [expanded]); // eslint-disable-line react-hooks/exhaustive-deps

  // Esc closes the overlay.
  useEffect(() => {
    if (!expanded) return;
    const onKey = (e) => { if (e.key === "Escape") setExpanded(false); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [expanded]);

  // Track play position of the active video for the scrubber.
  const onTimeUpdate = (e) => {
    const v = e.target;
    if (!v || !v.duration || isNaN(v.duration)) return;
    setProgress(v.currentTime / v.duration);
    setCurrentTime(v.currentTime);
  };
  const onLoadedMeta = (e) => {
    const v = e.target;
    if (v && v.duration && !isNaN(v.duration)) setDuration(v.duration);
  };

  // Click or drag along the scrubber → seek the active video.
  const seekFromEvent = (e) => {
    const bar = scrubRef.current;
    const v = refs.current[active];
    if (!bar || !v || !v.duration || isNaN(v.duration)) return;
    const rect = bar.getBoundingClientRect();
    const x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;
    const ratio = Math.max(0, Math.min(1, x / rect.width));
    v.currentTime = ratio * v.duration;
    setProgress(ratio);
    setCurrentTime(v.currentTime);
  };
  const onScrubMouseDown = (e) => {
    seekFromEvent(e);
    const move = (ev) => seekFromEvent(ev);
    const up   = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup",   up);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup",   up);
  };

  const fmt = (s) => {
    if (!s || isNaN(s)) return "0:00";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60);
    return m + ":" + (sec < 10 ? "0" : "") + sec;
  };

  return (
    <div className={"video-carousel" + (className ? " " + className : "")}>
      <div className="vc-stage">
        <div className="vc-track">
          {videos.map((v, i) => {
            // Position by signed offset from active, normalised into [-N/2, N/2)
            // so the carousel wraps cleanly. -2/-1/0/+1/+2 are visible, the rest
            // sit in the "hidden" pose far behind.
            let offset = i - active;
            if (offset >  total / 2) offset -= total;
            if (offset < -total / 2) offset += total;
            const posMap = { "-2": "far-left", "-1": "left", "0": "center", "1": "right", "2": "far-right" };
            const pos = posMap[offset] || "hidden";
            const isActiveSlide = pos === "center";
            return (
              <div key={v.src} className={"vc-slide vc-" + pos} onClick={() => { if (!isActiveSlide) setActive(i); }}>
                <div className="vc-frame">
                  <video
                    ref={(el) => { refs.current[i] = el; }}
                    src={v.src}
                    muted
                    loop
                    playsInline
                    preload={Math.abs(offset) <= 1 ? "auto" : "metadata"}
                    onTimeUpdate={isActiveSlide ? onTimeUpdate : undefined}
                    onLoadedMetadata={isActiveSlide ? onLoadedMeta : undefined}
                    onClick={isActiveSlide ? (e) => { e.stopPropagation(); setPlaying((p) => !p); } : undefined}
                  />
                  {isActiveSlide && !playing && (
                    <button
                      className="vc-big-play"
                      onClick={(e) => { e.stopPropagation(); setPlaying(true); }}
                      aria-label="Play"
                    >
                      <svg width="28" height="28" viewBox="0 0 24 24" fill="currentColor"><path d="M7 4l14 8-14 8z"/></svg>
                    </button>
                  )}
                  {isActiveSlide && (
                    <div className="vc-controlbar" onClick={(e) => e.stopPropagation()}>
                      <button
                        className="vc-cb-btn"
                        onClick={() => setPlaying((p) => !p)}
                        aria-label={playing ? "Pause" : "Play"}
                        title={playing ? "Pause" : "Play"}
                      >
                        {playing ? (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14"/><rect x="14" y="5" width="4" height="14"/></svg>
                        ) : (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M7 4l14 8-14 8z"/></svg>
                        )}
                      </button>
                      <span className="vc-cb-time">{fmt(currentTime)}</span>
                      <div
                        className="vc-scrub-bar"
                        ref={scrubRef}
                        onMouseDown={onScrubMouseDown}
                        onTouchStart={(e) => seekFromEvent(e)}
                        onTouchMove={(e) => seekFromEvent(e)}
                        role="slider"
                        aria-valuemin={0}
                        aria-valuemax={100}
                        aria-valuenow={Math.round(progress * 100)}
                      >
                        <div className="vc-scrub-fill" style={{ width: (progress * 100) + "%" }} />
                        <div className="vc-scrub-thumb" style={{ left: (progress * 100) + "%" }} />
                      </div>
                      <span className="vc-cb-time">{fmt(duration)}</span>
                      <button
                        className="vc-cb-btn"
                        onClick={() => setMuted((m) => !m)}
                        aria-label={labels.sound}
                        title={labels.sound}
                      >
                        {muted ? (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 5L6 9H3v6h3l5 4V5z" strokeLinejoin="round"/><path d="M22 9l-6 6M16 9l6 6" strokeLinecap="round"/></svg>
                        ) : (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 5L6 9H3v6h3l5 4V5z" strokeLinejoin="round"/><path d="M16 8.5a5 5 0 010 7M19 6a8 8 0 010 12" strokeLinecap="round"/></svg>
                        )}
                      </button>
                      <button
                        className="vc-cb-btn"
                        onClick={openExpanded}
                        aria-label={labels.expand}
                        title={labels.expand}
                      >
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" strokeLinecap="square"/></svg>
                      </button>
                    </div>
                  )}
                </div>
                {v.title && <div className="vc-caption">{v.title}</div>}
              </div>
            );
          })}

          {/* Prev/next sit inside the track, hugging the active slide so the
              click target is right next to what it controls. */}
          <button className="vc-nav vc-prev" onClick={() => go(-1)} aria-label="Previous">
            <ArrowLeft size={20} />
          </button>
          <button className="vc-nav vc-next" onClick={() => go(1)} aria-label="Next">
            <Arrow size={20} />
          </button>
        </div>
      </div>

      <div className="vc-dots" role="tablist">
        {videos.map((v, i) => (
          <button
            key={v.src}
            className={"vc-dot" + (i === active ? " is-active" : "")}
            onClick={() => setActive(i)}
            aria-label={"Video " + (i + 1)}
          />
        ))}
      </div>

      {expanded && (
        <div className="vc-overlay" onClick={closeExpanded} role="dialog" aria-modal="true">
          <div className="vc-overlay-frame" onClick={(e) => e.stopPropagation()}>
            <button className="vc-overlay-close" onClick={closeExpanded} aria-label={labels.close}>×</button>
            <video
              ref={expandedRef}
              src={videos[active].src}
              controls
              autoPlay
              loop
              playsInline
            />
          </div>
        </div>
      )}
    </div>
  );
}

// Expose to other scripts
Object.assign(window, {
  Arrow, ArrowLeft, Check, UploadIcon, InstagramIcon,
  LanguageSwitcher, LanguageDropdown, Header, Footer, ProgramCard, Field, FileDrop, IntroSplash,
  VideoCarousel,
});
