/* ============================================================
   Shared bits: Placeholder, icons, counter hook, logo
   ============================================================ */

// striped placeholder w/ monospace label — pass `img` once a real photo exists
function Ph({ label, img, imgPos = "center", style, className = "" }) {
  if (img) {
    return (
      <div className={"ph ph-photo " + className} style={{ ...style, position: "relative", overflow: "hidden" }}>
        <img src={img} alt={label || ""} loading="lazy" decoding="async" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", objectPosition: imgPos }} />
      </div>);
  }
  return (
    <div className={"ph " + className} data-label={label} style={style} aria-label={label} />);

}

// --- inline icons (simple geometric, no fake illustration) ---
function Icon({ name, size = 18, color = "currentColor", strokeWidth = 1.6 }) {
  const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: color, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" };
  switch (name) {
    case "instagram":
      return <svg {...common}><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="0.6" fill={color} stroke="none" /></svg>;
    case "linkedin":
      return <svg {...common}><rect x="3" y="3" width="18" height="18" rx="2" /><line x1="7" y1="10" x2="7" y2="17" /><circle cx="7" cy="6.7" r="0.7" fill={color} stroke="none" /><path d="M11 17v-4a2.5 2.5 0 0 1 5 0v4" /><line x1="11" y1="10" x2="11" y2="17" /></svg>;
    case "youtube":
      return <svg {...common}><rect x="2.5" y="5" width="19" height="14" rx="4" /><path d="M10 9l5 3-5 3z" fill={color} stroke="none" /></svg>;
    case "x":
      return <svg {...common}><path d="M4 4l16 16M20 4L4 20" /></svg>;
    case "arrow":
      return <svg {...common}><line x1="4" y1="12" x2="19" y2="12" /><polyline points="13 6 19 12 13 18" /></svg>;
    case "menu":
      return <svg {...common}><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" /></svg>;
    case "close":
      return <svg {...common}><line x1="5" y1="5" x2="19" y2="19" /><line x1="19" y1="5" x2="5" y2="19" /></svg>;
    case "flag":
      return <svg {...common}><path d="M5 21V4M5 4h12l-2 4 2 4H5" /></svg>;
    case "plane":
      return <svg {...common}><path d="M2 12l19-8-6 19-3-8-8-3z" /></svg>;
    case "trophy":
      return <svg {...common}><path d="M7 4h10v4a5 5 0 0 1-10 0V4z" /><path d="M7 6H4v1a3 3 0 0 0 3 3M17 6h3v1a3 3 0 0 1-3 3" /><line x1="12" y1="13" x2="12" y2="17" /><line x1="8" y1="20" x2="16" y2="20" /><line x1="10" y1="17" x2="14" y2="17" /></svg>;
    case "bolt":
      return <svg {...common}><polygon points="13 2 4 14 11 14 10 22 20 9 13 9 13 2" /></svg>;
    case "engine":
      return <svg {...common}><rect x="8" y="2.5" width="8" height="9" rx="1" /><line x1="12" y1="11.5" x2="12" y2="17" /><circle cx="12" cy="18.3" r="1.5" fill={color} stroke="none" /><line x1="6.5" y1="21" x2="17.5" y2="21" /><line x1="8" y1="5.5" x2="5.5" y2="5.5" /><line x1="16" y1="5.5" x2="18.5" y2="5.5" /></svg>;
    case "people":
      return <svg {...common}><circle cx="9" cy="8" r="3" /><path d="M3 20a6 6 0 0 1 12 0" /><path d="M16 5.5a3 3 0 0 1 0 5" /><path d="M17 14.2A6 6 0 0 1 21 20" /></svg>;
    case "calendar":
      return <svg {...common}><rect x="3" y="5" width="18" height="16" rx="1.5" /><line x1="3" y1="9" x2="21" y2="9" /><line x1="8" y1="3" x2="8" y2="6" /><line x1="16" y1="3" x2="16" y2="6" /></svg>;
    case "file-download":
      return <svg {...common}><path d="M6 3h8l4 4v14H6z" /><polyline points="14 3 14 7 18 7" /><line x1="12" y1="11" x2="12" y2="17" /><polyline points="9 14 12 17 15 14" /></svg>;
    case "mail":
      return <svg {...common}><rect x="3" y="5" width="18" height="14" rx="1" /><polyline points="3 7 12 13 21 7" /></svg>;
    default:return null;
  }
}

// --- team lockup logo: per-team mark (image or monogram) + name + discipline ---
function Logo({ team, onClick, compact = false }) {
  team = team || (window.TEAMS && window.TEAMS.gsm) || { name: "Formula Student", discipline: "Formula Student", logo: "uploads/teams/gs-motorsports/logo-transparent.png", mono: "FS" };
  const mark = team.logo ?
    <img src={team.logo} alt={team.name + " logo"} className="logo-mark" style={{ width: 56, height: 56, objectFit: "contain", flexShrink: 0 }} /> :
    <span aria-hidden style={{
      width: 50, height: 50, display: "grid", placeItems: "center", flexShrink: 0,
      border: "2px solid var(--orange)", color: "var(--orange)",
      fontFamily: "var(--f-head)", fontWeight: 700, letterSpacing: 0,
      fontSize: (team.mono || "").length > 2 ? 14 : 20,
    }}>{team.mono}</span>;
  return (
    <button onClick={onClick} aria-label={team.name + " home"}
    style={{ background: "none", border: "none", padding: 0, display: "flex", alignItems: "center", gap: 12 }}>
      {mark}
      {!compact &&
      <span style={{ display: "flex", flexDirection: "column", lineHeight: 0.95, gap: 3 }}>
          <span className="head logo-name" style={{ fontSize: 16, letterSpacing: 0, whiteSpace: "nowrap", color: "var(--text)" }}>{team.name}</span>
          <span className="label logo-sub" style={{ fontSize: 10, color: "var(--muted)", letterSpacing: "0.16em", whiteSpace: "nowrap" }}>{team.discipline}</span>
        </span>
      }
    </button>);

}

// --- count-up hook: animates when `run` flips true ---
function useCountUp(target, run, duration = 1500) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    if (!run) return;
    let raf, start;
    const step = (ts) => {
      if (!start) start = ts;
      const p = Math.min((ts - start) / duration, 1);
      const eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
      setVal(Math.round(eased * target));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [run, target, duration]);
  return val;
}

// --- in-view hook ---
function useInView(threshold = 0.3, defaultSeen = false) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(defaultSeen);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {if (e.isIntersecting) setSeen(true);});
    }, { threshold });
    io.observe(el);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, seen];
}

// per-name manual font-size overrides (set via direct edit)
const NAME_SIZE_OVERRIDES = {
  "Ayush Chouragade": "13px",
  "Deepanshu": "15px",
};

// team member card — shared by TeamPage + ScaffoldPages
function MemberCard({ name, role, tag, src, t = {}, compact, fallbackSrc }) {
  const round = t.cardShape === "rounded";
  const h = compact ? 190 : 230;
  const shown = src || fallbackSrc;
  return (
    <div className="card member-card" style={{ overflow: "hidden", borderRadius: round ? 8 : 0 }}>
      {shown ?
      <img src={shown} alt={name} loading="lazy" decoding="async" style={{ width: "100%", height: h, objectFit: "cover", objectPosition: "center top", display: "block" }} /> :
      <Ph label="PHOTO" style={{ height: h }} />}
      <div style={{ padding: "14px 13px 16px" }}>
        <div className="label" style={{ fontSize: 10, color: "var(--orange)", marginBottom: 6, letterSpacing: "0.06em", lineHeight: 1.25, textWrap: "balance" }}>{tag}</div>
        <div className="head" style={{ lineHeight: 1.05, textWrap: "balance", overflowWrap: "break-word", hyphens: "auto", whiteSpace: "pre-line", fontSize: NAME_SIZE_OVERRIDES[name] || (name.length > 16 ? "14px" : name.length > 12 ? "16px" : "18px") }}>{name}</div>
        {role && <div className="body muted" style={{ fontSize: 13, marginTop: 5, lineHeight: 1.35, whiteSpace: "pre-line" }}>{role}</div>}
      </div>
    </div>);

}

Object.assign(window, { Ph, Icon, Logo, useCountUp, useInView, MemberCard });

/* ============================================================
   OUR LEGACY — shared story / timeline components
   Used by the hand-built Formula Student page and the
   scaffold teams (Baja, YAN) so every team tells its story
   the same way: prologue → single-flow timeline → epilogue.
   ============================================================ */

// count-up figure for the prologue (fires shortly after mount)
function LegacyFigure({ n, suffix = "", label }) {
  const [run, setRun] = React.useState(false);
  React.useEffect(() => {
    const t = setTimeout(() => setRun(true), 220);
    return () => clearTimeout(t);
  }, []);
  const val = useCountUp(n, run, 1200);
  return (
    <div className="legacy-fig">
      <span className="n"><em>{val}{suffix}</em></span>
      <span className="l">{label}</span>
    </div>
  );
}

// results that read as wins/podiums/awards get a trophy marker
const LEGACY_WIN_RE = /^\s*(1st|2nd|3rd|first|only|winner)\b|award/i;

// one chapter on the timeline spine
function LegacyChapter({ c }) {
  return (
    <div className="legacy-chapter">
      <span className="chapter-dot" aria-hidden="true" />
      <div className="chapter-aside">
        <span className="chapter-year">{c.year}</span>
        {c.series && <span className="chapter-series">{c.series}</span>}
      </div>
      <div className="chapter-main">
        {c.milestone && <div className="chapter-flag"><Icon name="trophy" size={13} /><span>{c.milestone}</span></div>}
        <div className="chapter-photo">
          {c.photo
            ? <img src={c.photo} alt={c.car} loading="lazy" decoding="async" />
            : <Ph label={`${c.car} — CAR PHOTO`} style={{ position: "absolute", inset: 0 }} />}
          <div className="cap">
            <span className="chapter-event">{c.event}</span>
            {c.venue && <span className="chapter-venue">{c.venue}</span>}
          </div>
        </div>
        <div className="chapter-carline">
          <h3 className="chapter-car">{c.car}</h3>
          {c.tag && <span className="chapter-tag">{c.tag}</span>}
        </div>
        {c.story && <p className="chapter-story">{c.story}</p>}
        <ul className="chapter-record" style={{ listStyle: "none", padding: 0 }}>
          {c.results.map((r, k) => {
            const win = LEGACY_WIN_RE.test(r);
            return (
              <li key={k} className={win ? "win" : ""}>
                {win ? <span className="tro"><Icon name="trophy" size={14} /></span> : <span className="dot" />}
                <span className="body">{r}</span>
              </li>);
          })}
        </ul>
      </div>
    </div>
  );
}

// timeline with scroll-driven spine fill, dot ignition + year-jump rail
function LegacyTimeline({ chapters }) {
  const ref = React.useRef(null);
  const [active, setActive] = React.useState(0);
  const [railOn, setRailOn] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const fill = el.querySelector(".legacy-spine-fill");
    const items = Array.from(el.querySelectorAll(".legacy-chapter"));
    let raf = null;
    const update = () => {
      raf = null;
      const rect = el.getBoundingClientRect();
      const mid = window.innerHeight * 0.42;
      if (fill) fill.style.height = Math.max(0, Math.min(mid - rect.top - 6, rect.height - 46)) + "px";
      let a = 0;
      items.forEach((it, i) => {
        const on = it.getBoundingClientRect().top <= mid;
        it.classList.toggle("lit", on);
        if (on) a = i;
      });
      setActive(a);
      setRailOn(rect.top < window.innerHeight * 0.75 && rect.bottom > 220);
    };
    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);
    };
  }, [chapters.length]);
  const jump = (i) => {
    const it = ref.current && ref.current.querySelectorAll(".legacy-chapter")[i];
    if (!it) return;
    window.scrollTo({ top: it.getBoundingClientRect().top + window.scrollY - 150, behavior: "smooth" });
  };
  return (
    <div className="legacy-timeline" ref={ref}>
      <span className="legacy-spine-fill" aria-hidden="true" />
      {chapters.map((c, i) => <LegacyChapter key={i} c={c} />)}
      <span className="legacy-finish" aria-hidden="true">
        <span className="pole" />
        <span className="flag" />
      </span>
      <nav className={"legacy-rail" + (railOn ? " show" : "")} aria-label="Jump to a season">
        {chapters.map((c, i) => (
          <button key={i} className={i === active ? "on" : ""} onClick={() => jump(i)} aria-label={c.event}>
            <span className="yr">{c.year !== (chapters[i - 1] || {}).year ? c.year : c.car}</span>
            <span className="tick" />
          </button>
        ))}
      </nav>
    </div>
  );
}

// full page: prologue, single continuous timeline, epilogue
function LegacyStory({ eyebrow, lead, sub, figures = [], ghost, chapters = [], go }) {
  return (
    <main>
      {/* ---- Prologue ---- */}
      <section className="legacy-prologue">
        {ghost && <span className="ghost-years" aria-hidden="true">{ghost}</span>}
        <div className="wrap" style={{ paddingTop: "clamp(40px, 6vw, 72px)", paddingBottom: "clamp(36px, 4vw, 56px)", position: "relative", zIndex: 2 }}>
          {eyebrow && <div className="eyebrow" style={{ marginBottom: 14 }}>{eyebrow}</div>}
          <div className="sec-title" style={{ marginBottom: "clamp(24px, 3.5vw, 40px)" }}>
            <span className="bar" />
            <h1 className="head" style={{ margin: 0, fontSize: "clamp(32px, 5vw, 64px)" }}>Our Legacy</h1>
          </div>
          <div className="legacy-prologue-grid" style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.15fr) minmax(0, 1fr)", gap: "clamp(20px, 3.5vw, 48px)", alignItems: "start" }}>
            <p className="legacy-lead">{lead}</p>
            {sub && <p className="legacy-sub">{sub}</p>}
          </div>
          {figures.length > 0 &&
            <div className="legacy-figs" style={{ marginTop: "clamp(28px, 4vw, 48px)" }}>
              {figures.map((f, i) => <LegacyFigure key={i} {...f} />)}
            </div>}
        </div>
      </section>

      {/* ---- Single-flow timeline ---- */}
      <section className="wrap" style={{ paddingTop: "clamp(56px, 7vw, 96px)", paddingBottom: "clamp(70px, 9vw, 120px)", borderTop: "1px solid var(--border)" }}>
        <LegacyTimeline chapters={chapters} />
      </section>

      {/* ---- Epilogue ---- */}
      <section className="legacy-epilogue">
        <div className="wrap" style={{ paddingTop: "clamp(40px, 5vw, 64px)", paddingBottom: "clamp(40px, 5vw, 64px)" }}>
          <div className="legacy-epi-grid" style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.3fr) auto", gap: 28, alignItems: "end" }}>
            <div>
              <div className="eyebrow" style={{ marginBottom: 16 }}>The Next Chapter</div>
              <h2 className="legacy-epi-title">The story is<br />still being written.</h2>
            </div>
            <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
              <button className="btn btn-primary" onClick={() => { go("team"); window.scrollTo({ top: 0 }); }}>
                Meet the Team <span className="arrow"><Icon name="arrow" size={16} /></span>
              </button>
              <button className="btn btn-ghost" onClick={() => { go("crowdfunding"); window.scrollTo({ top: 0 }); }}>
                Support Us
              </button>
            </div>
          </div>
        </div>
      </section>
    </main>
  );
}

Object.assign(window, { LegacyFigure, LegacyChapter, LegacyTimeline, LegacyStory });