// Spellstash homepage — main app

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

// ─────────────────────────────────────────────────────────────
// MOCK DATA — collection
// ─────────────────────────────────────────────────────────────
const COLLECTION = [
  {
    name: "Demonic Tutor",
    type: "Sorcery",
    cost: "1B",
    color: "black",
    glyph: "☠",
    image_normal: "https://cards.scryfall.io/normal/front/a/2/a24b4cb6-cebb-428b-8654-74347a6a8d63.jpg?1763472867",
    locations: [
      { container: "Sythis EDH deck", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "3 weeks ago" },
      { container: "Storage Box B", kind: "box", qty: 2, finish: "unsleeved", condition: "LP", moved: "8 months ago" },
    ],
  },
  {
    name: "Sol Ring",
    type: "Artifact",
    cost: "1",
    color: "colorless",
    glyph: "◇",
    image_normal: "https://cards.scryfall.io/normal/front/8/7/870ec754-a76c-40ea-9b81-81b3dca1f62c.jpg?1775940518",
    locations: [
      { container: "Atraxa Superfriends", kind: "deck", qty: 1, finish: "sleeved, foil", condition: "NM", moved: "4 months ago" },
      { container: "Sythis EDH deck", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "2 weeks ago" },
      { container: "Krenko Goblin Tribal", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "1 year ago" },
      { container: "Staples Binder", kind: "binder", qty: 4, finish: "unsleeved", condition: "NM/LP", moved: "5 days ago" },
      { container: "Storage Box A", kind: "box", qty: 7, finish: "unsleeved", condition: "mixed", moved: "2 years ago" },
    ],
  },
  {
    name: "Misty Rainforest",
    type: "Land — fetch",
    cost: "",
    color: "blue-green",
    glyph: "❉",
    image_normal: "https://cards.scryfall.io/normal/front/8/8/88231c0d-0cc8-44ec-bf95-81d1710ac141.jpg?1738703648",
    locations: [
      { container: "Tatyova Landfall", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "6 weeks ago" },
      { container: "Staples Binder", kind: "binder", qty: 2, finish: "unsleeved", condition: "NM", moved: "1 month ago" },
    ],
  },
  {
    name: "The Great Henge",
    type: "Artifact",
    cost: "7G",
    color: "green",
    glyph: "✧",
    image_normal: "https://cards.scryfall.io/normal/front/6/3/6340e0f3-7f9c-4d71-8daf-e1be5505eb5b.jpg?1689998574",
    locations: [
      { container: "Sythis EDH deck", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "3 weeks ago" },
    ],
  },
  {
    name: "Cyclonic Rift",
    type: "Instant",
    cost: "1U",
    color: "blue",
    glyph: "≈",
    locations: [
      { container: "Atraxa Superfriends", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "4 months ago" },
      { container: "Talrand Spellslinger", kind: "deck", qty: 1, finish: "sleeved, foil", condition: "NM", moved: "2 months ago" },
      { container: "Storage Box B", kind: "box", qty: 1, finish: "unsleeved", condition: "LP", moved: "1 year ago" },
    ],
  },
  {
    name: "Lightning Bolt",
    type: "Instant",
    cost: "R",
    color: "red",
    glyph: "⚡",
    locations: [
      { container: "Krenko Goblin Tribal", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "1 year ago" },
      { container: "Staples Binder", kind: "binder", qty: 4, finish: "unsleeved", condition: "NM/LP", moved: "3 months ago" },
      { container: "Storage Box A", kind: "box", qty: 12, finish: "unsleeved", condition: "mixed", moved: "2 years ago" },
    ],
  },
  {
    name: "Swords to Plowshares",
    type: "Instant",
    cost: "W",
    color: "white",
    glyph: "✦",
    locations: [
      { container: "Sythis EDH deck", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "3 weeks ago" },
      { container: "Atraxa Superfriends", kind: "deck", qty: 1, finish: "sleeved", condition: "NM", moved: "4 months ago" },
      { container: "Staples Binder", kind: "binder", qty: 3, finish: "unsleeved", condition: "NM", moved: "2 months ago" },
    ],
  },
];

const KIND_LABEL = { deck: "Deck", box: "Box", binder: "Binder", other: "Other" };

// ─────────────────────────────────────────────────────────────
// CARD VISUAL — original silhouette, NOT an MTG frame
// A vertical tag with a glyph + name + cost. Reads as "a card" without copying.
// ─────────────────────────────────────────────────────────────
function CardTag({ card, size = "md" }) {
  if (!card) return null;
  const dims = size === "lg"
    ? { w: 220, h: 308, glyph: 88, name: 18, cost: 13, pad: 18 }
    : size === "sm"
    ? { w: 64, h: 90, glyph: 28, name: 9, cost: 7, pad: 6 }
    : { w: 140, h: 196, glyph: 56, name: 13, cost: 10, pad: 12 };

  // Real Scryfall image when available — render it directly.
  // Scryfall CDN is the source of truth; we never rehost.
  if (card.image_normal) {
    return (
      <img
        src={card.image_normal}
        alt={card.name || "card"}
        style={{
          width: dims.w,
          height: dims.h,
          borderRadius: dims.w * 0.05,
          boxShadow: "0 12px 32px rgba(0,0,0,0.35), inset 0 0 0 1px rgba(255,255,255,0.08)",
          objectFit: "cover",
          flex: "0 0 auto",
        }}
      />
    );
  }

  // Placeholder fallback — used when no image (mock data, missing field, or load error).
  const colorMap = {
    black: { bg: "oklch(0.22 0.02 280)", fg: "oklch(0.85 0.04 80)", accent: "oklch(0.55 0.08 280)" },
    blue: { bg: "oklch(0.32 0.08 240)", fg: "oklch(0.92 0.02 240)", accent: "oklch(0.7 0.12 240)" },
    red: { bg: "oklch(0.35 0.12 25)", fg: "oklch(0.92 0.02 25)", accent: "oklch(0.7 0.16 25)" },
    green: { bg: "oklch(0.32 0.08 145)", fg: "oklch(0.92 0.02 145)", accent: "oklch(0.65 0.12 145)" },
    white: { bg: "oklch(0.88 0.015 80)", fg: "oklch(0.25 0.02 80)", accent: "oklch(0.6 0.06 80)" },
    colorless: { bg: "oklch(0.55 0.01 240)", fg: "oklch(0.95 0.005 240)", accent: "oklch(0.75 0.02 240)" },
    "blue-green": { bg: "oklch(0.32 0.08 190)", fg: "oklch(0.92 0.02 190)", accent: "oklch(0.7 0.12 190)" },
  };
  const c = colorMap[card.color] || colorMap.colorless;
  const cost = card.cost || card.mana_cost;
  const type = card.type || card.type_line || "";

  return (
    <div
      style={{
        width: dims.w,
        height: dims.h,
        background: c.bg,
        color: c.fg,
        borderRadius: dims.w * 0.05,
        padding: dims.pad,
        display: "flex",
        flexDirection: "column",
        position: "relative",
        boxShadow: "0 12px 32px rgba(0,0,0,0.35), inset 0 0 0 1px rgba(255,255,255,0.08)",
        fontFamily: "var(--cm-serif)",
        overflow: "hidden",
        flex: "0 0 auto",
      }}
    >
      {/* corner cost */}
      {cost && (
        <div style={{
          position: "absolute", top: dims.pad, right: dims.pad,
          fontFamily: "var(--cm-mono)", fontSize: dims.cost,
          opacity: 0.7, letterSpacing: "0.05em",
        }}>{cost}</div>
      )}
      {/* type stripe */}
      <div style={{
        fontFamily: "var(--cm-mono)", fontSize: dims.cost - 1,
        textTransform: "uppercase", letterSpacing: "0.12em",
        opacity: 0.55,
      }}>{type}</div>
      {/* glyph */}
      <div style={{
        flex: 1,
        display: "flex", alignItems: "center", justifyContent: "center",
        fontSize: dims.glyph,
        color: c.accent,
        textShadow: `0 0 ${dims.glyph * 0.4}px ${c.accent}`,
      }}>{card.glyph || "◆"}</div>
      {/* name */}
      <div style={{
        fontSize: dims.name, fontWeight: 500, letterSpacing: "0.01em",
        borderTop: `1px solid ${c.fg}22`, paddingTop: dims.pad * 0.5,
      }}>{card.name}</div>
    </div>
  );
}

// Relative-time formatter for ISO 8601 timestamps from the API
function relativeTime(iso) {
  if (!iso) return "";
  const now = Date.now();
  const then = new Date(iso).getTime();
  if (isNaN(then)) return iso;
  const diff = Math.max(0, now - then);
  const minutes = diff / 60000;
  const hours = minutes / 60;
  const days = hours / 24;
  const weeks = days / 7;
  const months = days / 30.44;
  const years = days / 365.25;
  if (minutes < 1) return "just now";
  if (minutes < 60) return Math.floor(minutes) + " min ago";
  if (hours < 24) return Math.floor(hours) + " hr" + (Math.floor(hours) === 1 ? "" : "s") + " ago";
  if (days < 7) return Math.floor(days) + " day" + (Math.floor(days) === 1 ? "" : "s") + " ago";
  if (weeks < 4) return Math.floor(weeks) + " week" + (Math.floor(weeks) === 1 ? "" : "s") + " ago";
  if (months < 12) return Math.floor(months) + " month" + (Math.floor(months) === 1 ? "" : "s") + " ago";
  return Math.floor(years) + " year" + (Math.floor(years) === 1 ? "" : "s") + " ago";
}

// ─────────────────────────────────────────────────────────────
// LOGO
// ─────────────────────────────────────────────────────────────
function Logo() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
        <path d="M12 21s-7-7.5-7-12a7 7 0 0 1 14 0c0 4.5-7 12-7 12z" />
        <circle cx="12" cy="9" r="2.4" />
      </svg>
      <span style={{ fontFamily: "var(--cm-serif)", fontSize: 19, letterSpacing: "0.005em" }}>Spellstash</span>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// SEARCH DEMO — interactive
// ─────────────────────────────────────────────────────────────
function SearchDemo({ autoplay = false, big = false, defaultQuery = "" }) {
  const [query, setQuery] = useState(defaultQuery);
  const [autoplayed, setAutoplayed] = useState(false);
  const [focused, setFocused] = useState(false);
  const [suggestions, setSuggestions] = useState([]);
  const [picked, setPicked] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const inputRef = useRef(null);
  const containerRef = useRef(null);

  // Autoplay typing animation when scrolled into view (once)
  useEffect(() => {
    if (!autoplay || autoplayed) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !autoplayed) {
          setAutoplayed(true);
          const target = "Demonic Tutor";
          let i = 0;
          setQuery("");
          const tick = () => {
            i++;
            setQuery(target.slice(0, i));
            if (i < target.length) setTimeout(tick, 70 + Math.random() * 60);
          };
          setTimeout(tick, 400);
        }
      });
    }, { threshold: 0.4 });
    if (containerRef.current) obs.observe(containerRef.current);
    return () => obs.disconnect();
  }, [autoplay, autoplayed]);

  // Debounced typeahead — public /api/cards/autocomplete (no auth required).
  // Marketing demo Option B: anonymous visitors see image-rich suggestions as
  // they type. The conversion moment is "Sign up to see where YOUR copies live."
  useEffect(() => {
    const q = query.trim();
    if (!q || q.length < 2) {
      setSuggestions([]);
      setLoading(false);
      setError(null);
      return;
    }
    setError(null);
    setLoading(true);
    const id = setTimeout(async () => {
      try {
        const r = await fetch("/api/cards/autocomplete?q=" + encodeURIComponent(q));
        if (!r.ok) throw new Error("HTTP " + r.status);
        const data = await r.json();
        // Backward-compat: old API returned string[], new returns
        // [{name, image_small, oracle_id}, ...]. Normalize.
        const cards = Array.isArray(data)
          ? data.map((item) => typeof item === "string"
              ? { name: item, image_small: null, oracle_id: null }
              : item)
          : [];
        setSuggestions(cards.slice(0, 6));
      } catch (e) {
        setError(e.message || "request failed");
        setSuggestions([]);
      } finally {
        setLoading(false);
      }
    }, 200);
    return () => clearTimeout(id);
  }, [query]);

  // Clear the picked preview the moment the user starts editing again.
  useEffect(() => {
    if (picked && picked.name !== query) setPicked(null);
  }, [query, picked]);

  return (
    <div ref={containerRef} className="cm-demo" data-big={big ? "1" : "0"}>
      {/* search bar */}
      <div className="cm-demo-bar" data-focused={focused ? "1" : "0"}>
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.6 }}>
          <circle cx="11" cy="11" r="7" />
          <path d="m20 20-3.5-3.5" />
        </svg>
        <input
          ref={inputRef}
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onFocus={() => setFocused(true)}
          onBlur={() => setFocused(false)}
          placeholder="Type a card name…"
          aria-label="Try the search"
        />
        <span className="cm-demo-kbd">⌘K</span>
      </div>

      {/* picked preview — selected card with signup CTA */}
      {picked && (
        <div className="cm-demo-pick" key={picked.oracle_id || picked.name}>
          {picked.image_small ? (
            <img src={picked.image_small} alt={picked.name} className="cm-demo-pick-img" />
          ) : (
            <div className="cm-demo-pick-img cm-demo-pick-img--placeholder" aria-hidden="true">⚄</div>
          )}
          <div className="cm-demo-pick-body">
            <div className="cm-demo-pick-name">{picked.name}</div>
            <p className="cm-demo-pick-meta">To see where <em>your</em> copies of {picked.name} live in your collection, sign up. Free to start. 4 containers and 400 cards.</p>
            <div className="cm-demo-pick-actions">
              <a href="/login?signup=1" className="cm-btn cm-btn--primary">Get started, free</a>
              <a href="/login" className="cm-btn cm-btn--ghost cm-btn--sm">Sign in</a>
            </div>
          </div>
        </div>
      )}

      {/* suggestions list — appears as user types, before picking */}
      {!picked && suggestions.length > 0 && (
        <div className="cm-demo-suggest">
          {suggestions.map((s) => (
            <button
              key={s.oracle_id || s.name}
              type="button"
              className="cm-suggest-row"
              onClick={() => setPicked(s)}
            >
              {s.image_small ? (
                <img src={s.image_small} alt="" className="cm-suggest-thumb" loading="lazy" />
              ) : (
                <span className="cm-suggest-thumb cm-suggest-thumb--placeholder" aria-hidden="true">⚄</span>
              )}
              <span style={{ flex: 1, minWidth: 0 }}>{s.name}</span>
            </button>
          ))}
        </div>
      )}

      {/* loading shimmer */}
      {loading && query && !picked && suggestions.length === 0 && (
        <div className="cm-demo-suggest">
          <div className="cm-suggest-row" style={{ opacity: 0.5 }}>
            <span className="cm-suggest-thumb cm-suggest-thumb--placeholder" aria-hidden="true">⚄</span>
            <span className="cm-mono cm-dim">searching…</span>
          </div>
        </div>
      )}

      {/* error state */}
      {!loading && error && query && !picked && (
        <div className="cm-demo-empty">
          <span className="cm-mono">search failed: {error}</span>
          <span className="cm-dim">try again in a moment</span>
        </div>
      )}

      {/* hint chips when no query and no pick */}
      {!query && !loading && !picked && (
        <div className="cm-demo-hint">
          <span className="cm-dim">try one:</span>
          {["Demonic Tutor", "Sol Ring", "Misty Rainforest", "The Great Henge"].map((n) => (
            <button key={n} className="cm-chip" onClick={() => { setQuery(n); inputRef.current?.focus(); }}>{n}</button>
          ))}
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// EMAIL CAPTURE
// ─────────────────────────────────────────────────────────────
function EmailCapture({ id, big = false }) {
  const [email, setEmail] = useState("");
  const [submitted, setSubmitted] = useState(false);
  const onSubmit = (e) => {
    e.preventDefault();
    if (!/^\S+@\S+\.\S+$/.test(email)) return;
    setSubmitted(true);
  };
  if (submitted) {
    return (
      <div className={"cm-form cm-form--done " + (big ? "cm-form--big" : "")}>
        <span className="cm-mono">✓ you're on the list.</span>
        <span className="cm-dim">we'll email {email} when Spellstash opens.</span>
      </div>
    );
  }
  return (
    <form id={id} className={"cm-form " + (big ? "cm-form--big" : "")} onSubmit={onSubmit}>
      <input
        type="email"
        required
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="you@example.com"
        aria-label="Email address"
      />
      <button type="submit" className="cm-btn cm-btn--primary">Get early access</button>
    </form>
  );
}

// ─────────────────────────────────────────────────────────────
// NAV
// ─────────────────────────────────────────────────────────────
function Nav() {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return (
    <nav className="cm-nav" data-scrolled={scrolled ? "1" : "0"}>
      <Logo />
      <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
        <a href="/login" className="cm-btn cm-btn--ghost cm-btn--sm">Sign in</a>
        <a href="/login?signup=1" className="cm-btn cm-btn--primary cm-btn--sm">Get started</a>
      </div>
    </nav>
  );
}

// ─────────────────────────────────────────────────────────────
// HERO
// ─────────────────────────────────────────────────────────────
function Hero() {
  return (
    <section className="cm-hero">
      <div className="cm-hero-copy">
        <div className="cm-eyebrow">For Commander players with too many decks.</div>
        <h1 className="cm-h1">
          Where is your <span className="cm-accent-text">Demonic Tutor</span> right now?
        </h1>
        <p className="cm-sub">
          Spellstash tells you which deck, which binder, or which storage box every card you own is sitting in. Type the card name. See where it is.
        </p>
        <div className="cm-hero-ctas">
          <a href="/login?signup=1" className="cm-btn cm-btn--primary">Get started, free</a>
          <a href="#demo" className="cm-btn cm-btn--ghost">See it work →</a>
        </div>
        <div className="cm-hero-meta">
          <span className="cm-mono cm-dim">// indie, MTG-first, one job</span>
        </div>
      </div>
      <div className="cm-hero-demo">
        <SearchDemo autoplay defaultQuery="" />
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// PAIN
// ─────────────────────────────────────────────────────────────
function Pain() {
  const items = [
    "You bought a $30 upgrade for your Atraxa list six months ago. You want to move it to your new Sythis deck. You cannot remember which of your fourteen built decks it ended up in. You spend forty minutes opening every deck box.",
    "You disassemble a deck and the staples scatter back into 30 different bulk locations. Every rebuild starts with an hour of digging.",
    "You find a fetchland in a random box and you cannot remember if you bought it or if it was supposed to be in a deck you already broke down.",
  ];
  return (
    <section className="cm-pain">
      <h2 className="cm-h2">You have lived this.</h2>
      <div className="cm-pain-list">
        {items.map((t, i) => (
          <p key={i} className="cm-pain-item">
            <span className="cm-pain-num">0{i + 1}</span>
            <span>{t}</span>
          </p>
        ))}
      </div>
      <p className="cm-pain-resolve">Spellstash is the system that does not drift.</p>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// DEMO (full-bleed)
// ─────────────────────────────────────────────────────────────
function Demo() {
  return (
    <section className="cm-demo-section" id="demo">
      <div className="cm-section-head">
        <div className="cm-eyebrow">The demo</div>
        <h2 className="cm-h2">Type a card name. See exactly where it is.</h2>
      </div>
      <div className="cm-demo-frame">
        <div className="cm-demo-frame-bar">
          <span className="cm-frame-dot" /><span className="cm-frame-dot" /><span className="cm-frame-dot" />
          <span className="cm-mono cm-dim" style={{ marginLeft: 12 }}>cardmap / your collection</span>
        </div>
        <div className="cm-demo-frame-body">
          <SearchDemo big defaultQuery="Sol Ring" />
        </div>
      </div>
      <p className="cm-demo-caption">
        Works the other way too. Open any deck or box and see every card inside it, with the date each card landed there.
      </p>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// HOW IT WORKS
// ─────────────────────────────────────────────────────────────
function HowItWorks() {
  const steps = [
    { n: "01", title: "Add your containers.", body: "A container is anything that holds cards. A built deck. A storage box. A binder. Name it whatever you want.", visual: "containers" },
    { n: "02", title: "Add your cards.", body: "Search any card by name from the full Magic database. Drop it into the container it lives in. Set quantity, finish, condition.", visual: "cards" },
    { n: "03", title: "Move them when you swap.", body: "When you scavenge a staple from one deck for another, you tap once. Spellstash keeps the map honest, even when you forget to.", visual: "moves" },
  ];
  return (
    <section className="cm-how">
      <div className="cm-section-head">
        <div className="cm-eyebrow">How it works</div>
        <h2 className="cm-h2">Three steps. That's the whole thing.</h2>
      </div>
      <div className="cm-how-grid">
        {steps.map((s) => (
          <div className="cm-how-step" key={s.n}>
            <div className="cm-how-visual">
              <StepVisual kind={s.visual} />
            </div>
            <div className="cm-how-num cm-mono">{s.n}</div>
            <h3 className="cm-h3">{s.title}</h3>
            <p className="cm-body">{s.body}</p>
          </div>
        ))}
      </div>
    </section>
  );
}

function StepVisual({ kind }) {
  if (kind === "containers") {
    return (
      <div className="cm-vis cm-vis--containers">
        {[
          { label: "Sythis EDH", kind: "deck", count: 100 },
          { label: "Staples Binder", kind: "binder", count: 412 },
          { label: "Storage Box B", kind: "box", count: 1240 },
        ].map((c) => (
          <div className="cm-vis-row" key={c.label}>
            <span className="cm-loc-kind" data-kind={c.kind}>{KIND_LABEL[c.kind]}</span>
            <span>{c.label}</span>
            <span className="cm-mono cm-dim" style={{ marginLeft: "auto" }}>{c.count}</span>
          </div>
        ))}
      </div>
    );
  }
  if (kind === "cards") {
    return (
      <div className="cm-vis cm-vis--cards">
        <div className="cm-vis-stack">
          <CardTag card={COLLECTION[0]} size="sm" />
          <CardTag card={COLLECTION[1]} size="sm" />
          <CardTag card={COLLECTION[3]} size="sm" />
          <CardTag card={COLLECTION[2]} size="sm" />
        </div>
        <div className="cm-vis-arrow cm-mono">→ Sythis EDH</div>
      </div>
    );
  }
  // moves
  return (
    <div className="cm-vis cm-vis--moves">
      <div className="cm-vis-row"><span className="cm-mono cm-dim">14:02</span><span>Sol Ring</span><span className="cm-mono cm-dim">Atraxa → Sythis</span></div>
      <div className="cm-vis-row"><span className="cm-mono cm-dim">14:02</span><span>Cyclonic Rift</span><span className="cm-mono cm-dim">Box B → Talrand</span></div>
      <div className="cm-vis-row"><span className="cm-mono cm-dim">11:48</span><span>The Great Henge</span><span className="cm-mono cm-dim">Binder → Sythis</span></div>
      <div className="cm-vis-row cm-vis-row--dim"><span className="cm-mono cm-dim">Yest.</span><span>Misty Rainforest</span><span className="cm-mono cm-dim">Tatyova → Binder</span></div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// PILLARS
// ─────────────────────────────────────────────────────────────
function Pillars() {
  const items = [
    {
      title: "Per-copy tracking",
      body: "If you own three Sol Rings, Spellstash knows there are three. It knows which one is in which deck. It knows which one is foil.",
      visual: (
        <div className="cm-pill-vis">
          {["#1 sleeved", "#2 sleeved, foil", "#3 unsleeved"].map((t, i) => (
            <div key={i} className="cm-pill-chip"><span className="cm-mono cm-dim">copy</span><span>{t}</span></div>
          ))}
        </div>
      ),
    },
    {
      title: "Reverse lookup",
      body: "Type any card name. See every container that holds a copy of it, with quantity and finish per location.",
      visual: (
        <div className="cm-pill-vis">
          <div className="cm-pill-row"><span>Sythis EDH</span><span className="cm-mono">×1</span></div>
          <div className="cm-pill-row"><span>Atraxa</span><span className="cm-mono">×1</span></div>
          <div className="cm-pill-row"><span>Box A</span><span className="cm-mono">×7</span></div>
        </div>
      ),
    },
    {
      title: "Move history",
      body: "Every move is logged. You can see when a card entered or left a deck and how long it has been sitting there.",
      visual: (
        <div className="cm-pill-vis cm-pill-timeline">
          <div className="cm-tl-line" />
          {[
            { d: "Apr 12", e: "→ Sythis" },
            { d: "Mar 03", e: "→ Box B" },
            { d: "Jan 28", e: "→ Atraxa" },
          ].map((p, i) => (
            <div className="cm-tl-pt" key={i}>
              <span className="cm-tl-dot" />
              <span className="cm-mono cm-dim">{p.d}</span>
              <span>{p.e}</span>
            </div>
          ))}
        </div>
      ),
    },
  ];
  return (
    <section className="cm-pillars">
      <div className="cm-section-head">
        <div className="cm-eyebrow">What it tracks</div>
        <h2 className="cm-h2">Built for the way you actually move cards.</h2>
      </div>
      <div className="cm-pillars-grid">
        {items.map((p, i) => (
          <div className="cm-pillar" key={i}>
            <div className="cm-pillar-visual">{p.visual}</div>
            <h3 className="cm-h3">{p.title}</h3>
            <p className="cm-body">{p.body}</p>
          </div>
        ))}
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// IS NOT
// ─────────────────────────────────────────────────────────────
function IsNot() {
  const items = [
    { strike: "a deck builder", body: "Use Moxfield for that. We sync." },
    { strike: "a price tracker", body: "We show market price as context, not as a portfolio." },
    { strike: "a marketplace", body: "We are not selling your cards. We are helping you find them." },
  ];
  return (
    <section className="cm-isnot">
      <h2 className="cm-h2">What Spellstash is not.</h2>
      <div className="cm-isnot-grid">
        {items.map((it, i) => (
          <div className="cm-isnot-item" key={i}>
            <div className="cm-isnot-strike"><s>{it.strike}</s></div>
            <p className="cm-body">{it.body}</p>
          </div>
        ))}
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// WHO IT'S FOR
// ─────────────────────────────────────────────────────────────
function WhoFor() {
  return (
    <section className="cm-who">
      <div className="cm-who-inner">
        <h2 className="cm-h2">Built for the player with too many decks.</h2>
        <p className="cm-body cm-body--lg">
          If you have one Commander deck and a shoebox of bulk, you do not need Spellstash. If you have ten built decks, a staples binder, three storage boxes, and a sneaking suspicion you bought the same fetchland twice, this is for you.
        </p>
        <div className="cm-who-checklist">
          <div className="cm-check"><span className="cm-check-mark">✓</span><span>10+ built decks</span></div>
          <div className="cm-check"><span className="cm-check-mark">✓</span><span>at least one binder</span></div>
          <div className="cm-check"><span className="cm-check-mark">✓</span><span>cards you cannot find</span></div>
          <div className="cm-check"><span className="cm-check-mark">✓</span><span>a spreadsheet that drifted</span></div>
        </div>
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// PRICING
// ─────────────────────────────────────────────────────────────
function Pricing() {
  return (
    <section className="cm-pricing">
      <div className="cm-section-head">
        <div className="cm-eyebrow">Pricing</div>
        <h2 className="cm-h2">Free for life, on the small stuff.</h2>
      </div>
      <div className="cm-price-grid">
        <div className="cm-price cm-price--free">
          <div className="cm-price-tag">Free</div>
          <div className="cm-price-amount"><span className="cm-mono">$0</span><span className="cm-dim cm-mono">  forever</span></div>
          <ul className="cm-price-list">
            <li>4 containers</li>
            <li>400 cards</li>
            <li>Per-copy tracking</li>
            <li>Move history</li>
          </ul>
          <a href="/login?signup=1" className="cm-btn cm-btn--primary cm-btn--block">Get started, free</a>
        </div>
        <div className="cm-price cm-price--pro">
          <div className="cm-price-tag">Pro</div>
          <div className="cm-price-amount"><span className="cm-mono">$4.99</span><span className="cm-dim cm-mono">  /month</span></div>
          <ul className="cm-price-list">
            <li>Unlimited containers</li>
            <li>Unlimited cards</li>
            <li>Per-copy tracking</li>
            <li>Move history</li>
          </ul>
          <div className="cm-price-roadmap">
            <span className="cm-mono cm-dim">Coming soon</span>
            <span>Mobile scan. Decklist import. Reconciliation mode.</span>
          </div>
          <div className="cm-price-note">
            <span className="cm-mono cm-accent-text">Less than a booster pack.</span>
            <span>Upgrade once you hit your free-tier cap.</span>
          </div>
        </div>
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// FINAL CTA
// ─────────────────────────────────────────────────────────────
function FinalCTA() {
  return (
    <section className="cm-final" id="signup">
      <h2 className="cm-h2 cm-h2--xl">Stop losing cards in your own collection.</h2>
      <div className="cm-final-actions">
        <a href="/login?signup=1" className="cm-btn cm-btn--primary cm-btn--big">Get started, free</a>
        <a href="/login" className="cm-btn cm-btn--ghost">Sign in</a>
      </div>
      <p className="cm-final-note">
        Free to start. 4 containers and 400 cards, no credit card. Upgrade to unlimited for $4.99/month when you fill the stash.
      </p>
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// FOOTER
// ─────────────────────────────────────────────────────────────
function Footer() {
  return (
    <footer className="cm-footer">
      <div className="cm-footer-row">
        <Logo />
        <div className="cm-footer-links">
          <a href="#about">About</a>
          <a href="mailto:hello@cardmap.app">Got a feature you'd kill for? Email me.</a>
        </div>
      </div>
      <div className="cm-footer-fine">
        <span className="cm-mono cm-dim">© 2026 Spellstash</span>
        <span className="cm-mono cm-dim">Spellstash is unaffiliated with Wizards of the Coast. Magic: The Gathering and all card data are property of Wizards of the Coast LLC.</span>
        <span className="cm-mono cm-dim">Card data and images via Scryfall (scryfall.com).</span>
      </div>
    </footer>
  );
}

// ─────────────────────────────────────────────────────────────
// THEME / TWEAKS
// ─────────────────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "dark",
  "accent": "gold",
  "headlineFont": "spectral",
  "density": "comfortable"
}/*EDITMODE-END*/;

const ACCENT_MAP = {
  gold: { c: "oklch(0.78 0.16 75)", fg: "oklch(0.18 0.05 75)", soft: "oklch(0.78 0.16 75 / 0.15)" },
  red: { c: "oklch(0.65 0.2 25)", fg: "oklch(0.97 0.02 25)", soft: "oklch(0.65 0.2 25 / 0.15)" },
  blue: { c: "oklch(0.7 0.16 240)", fg: "oklch(0.15 0.04 240)", soft: "oklch(0.7 0.16 240 / 0.15)" },
  green: { c: "oklch(0.72 0.16 145)", fg: "oklch(0.18 0.04 145)", soft: "oklch(0.72 0.16 145 / 0.15)" },
};

const FONT_MAP = {
  spectral: '"Spectral", Georgia, serif',
  cormorant: '"Cormorant Garamond", Georgia, serif',
  sourceserif: '"Source Serif 4", Georgia, serif',
};

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  useEffect(() => {
    const root = document.documentElement;
    const a = ACCENT_MAP[tweaks.accent] || ACCENT_MAP.gold;
    root.style.setProperty("--cm-accent", a.c);
    root.style.setProperty("--cm-accent-fg", a.fg);
    root.style.setProperty("--cm-accent-soft", a.soft);
    root.style.setProperty("--cm-serif", FONT_MAP[tweaks.headlineFont] || FONT_MAP.spectral);
    root.dataset.theme = tweaks.theme;
    root.dataset.density = tweaks.density;
  }, [tweaks]);

  return (
    <div className="cm-root">
      <a className="cm-skip" href="#main">Skip to content</a>
      <Nav />
      <main id="main">
        <Hero />
        <Pain />
        <Demo />
        <HowItWorks />
        <Pillars />
        <IsNot />
        <WhoFor />
        <Pricing />
        <FinalCTA />
      </main>
      <Footer />

      <TweaksPanel title="Tweaks">
          <TweakSection title="Theme">
            <TweakRadio
              label="Mode"
              value={tweaks.theme}
              options={[{ value: "dark", label: "Dark" }, { value: "light", label: "Light" }]}
              onChange={(v) => setTweak("theme", v)}
            />
            <TweakRadio
              label="Accent"
              value={tweaks.accent}
              options={[
                { value: "gold", label: "Gold" },
                { value: "red", label: "Red" },
                { value: "blue", label: "Blue" },
                { value: "green", label: "Green" },
              ]}
              onChange={(v) => setTweak("accent", v)}
            />
          </TweakSection>
          <TweakSection title="Type">
            <TweakSelect
              label="Headline font"
              value={tweaks.headlineFont}
              options={[
                { value: "spectral", label: "Spectral" },
                { value: "cormorant", label: "Cormorant Garamond" },
                { value: "sourceserif", label: "Source Serif 4" },
              ]}
              onChange={(v) => setTweak("headlineFont", v)}
            />
          </TweakSection>
          <TweakSection title="Layout">
            <TweakRadio
              label="Density"
              value={tweaks.density}
              options={[
                { value: "comfortable", label: "Comfortable" },
                { value: "compact", label: "Compact" },
              ]}
              onChange={(v) => setTweak("density", v)}
            />
          </TweakSection>
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
