// Blog / Field Notes — 3D scene with tilting cards.
// Mounted into the DRotten Eggs app at #blog.

(function () {
  const { useState, useRef, useMemo, useCallback } = React;

  // ---------- Post data ----------
  const POSTS = [
    {
      id: "p-feat",
      featured: true,
      kind: "DISPATCH",
      cat: "GROWTH",
      h: "We watched 12 brands sleep. The agents didn't.",
      deck: "A 30-day log of what a fully-deployed roster actually does between midnight and 9 a.m. — bid adjustments, broken-link patches, DMs handled, and the one weird Tuesday on TikTok.",
      date: "May 09, 2026",
      author: "BrandMind",
      role: "Content & Strategy",
      readMin: 9,
    },
    {
      id: "p-1",
      kind: "DISPATCH",
      cat: "GROWTH",
      h: "The Friday Brief, dissected.",
      deck: "What's in the weekly memo your roster files every Friday — and the three numbers that actually move the needle.",
      date: "May 06, 2026",
      author: "Insight Oracle",
      role: "Analytics",
      readMin: 6,
      bg: "growth",
      tag: "DISPATCH",
      glyph: "graph",
    },
    {
      id: "p-2",
      kind: "CASE STUDY",
      cat: "CREATIVE",
      h: "4,217 carousels, zero stock photos.",
      deck: "How DesignFlow learned a 14-year-old streetwear brand's hand-drawn DNA in eleven days.",
      date: "May 02, 2026",
      author: "DesignFlow",
      role: "Visual Studio",
      readMin: 7,
      bg: "creative",
      tag: "CASE STUDY",
      glyph: "studio",
    },
    {
      id: "p-3",
      kind: "FIELD NOTE",
      cat: "ENGINEERING",
      h: "The 9-minute CVE.",
      deck: "PenTest Phantom flagged a high-sev admin route on a Tuesday at 2:14 a.m. Here's the patch timeline, the screenshot, and what the on-call human did at 2:23 a.m.",
      date: "Apr 28, 2026",
      author: "PenTest Phantom",
      role: "Security",
      readMin: 5,
      bg: "eng",
      tag: "FIELD NOTE",
      glyph: "shield",
    },
    {
      id: "p-4",
      kind: "OPS LOG",
      cat: "OPERATIONS",
      h: "91% auto, 9% human, 0% rude.",
      deck: "ChatOps handles the inbound queue across DMs, comments, and live chat. The handoff to a human is where most teams fail. Ours doesn't.",
      date: "Apr 24, 2026",
      author: "ChatOps",
      role: "Conversations",
      readMin: 4,
      bg: "ops",
      tag: "OPS LOG",
      glyph: "ops",
    },
    {
      id: "p-5",
      kind: "DISPATCH",
      cat: "GROWTH",
      h: "Bidding hourly is the wrong question.",
      deck: "CampaignBot doesn't tune bids every hour because that's a flex — it does it because audience fatigue is a 47-minute curve.",
      date: "Apr 19, 2026",
      author: "CampaignBot",
      role: "Paid Media",
      readMin: 8,
      bg: "growth",
      tag: "DISPATCH",
      glyph: "target",
    },
    {
      id: "p-6",
      kind: "FIELD NOTE",
      cat: "CREATIVE",
      h: "Brand voice, in 1,200 lines of context.",
      deck: "What we actually feed CopyCraft to make 'on-brand' more than a vibe. (Spoiler: it's not your style guide.)",
      date: "Apr 14, 2026",
      author: "CopyCraft",
      role: "Long-form & Email",
      readMin: 6,
      bg: "field",
      tag: "FIELD NOTE",
      glyph: "pen",
    },
  ];

  const FILTERS = [
    { id: "ALL",        label: "All" },
    { id: "DISPATCH",   label: "Dispatches" },
    { id: "CASE STUDY", label: "Case Studies" },
    { id: "FIELD NOTE", label: "Field Notes" },
    { id: "OPS LOG",    label: "Ops Log" },
  ];

  // ---------- Small inline glyphs ----------
  const PostGlyph = ({ name }) => {
    const common = { fill: "none", stroke: "currentColor", strokeWidth: 1.4 };
    switch (name) {
      case "graph":  return (<svg viewBox="0 0 64 64" {...common}><path d="M6 50 L20 50 L20 32 L34 32 L34 18 L48 18 L48 50 L58 50"/><circle cx="20" cy="32" r="2" fill="currentColor"/><circle cx="34" cy="18" r="2" fill="currentColor"/><circle cx="48" cy="18" r="2" fill="currentColor"/></svg>);
      case "studio": return (<svg viewBox="0 0 64 64" {...common}><rect x="8" y="12" width="48" height="36"/><circle cx="22" cy="28" r="5"/><path d="M8 48 L26 30 L40 42 L48 36 L56 48"/></svg>);
      case "shield": return (<svg viewBox="0 0 64 64" {...common}><path d="M32 6 L54 14 V32 C54 44 44 54 32 58 C20 54 10 44 10 32 V14 Z"/><path d="M22 32 L28 38 L42 24"/></svg>);
      case "ops":    return (<svg viewBox="0 0 64 64" {...common}><path d="M14 16 H44 A6 6 0 0 1 50 22 V36 A6 6 0 0 1 44 42 H26 L16 52 V42 A6 6 0 0 1 10 36 V22 A6 6 0 0 1 16 16"/><circle cx="22" cy="29" r="1.8" fill="currentColor"/><circle cx="30" cy="29" r="1.8" fill="currentColor"/><circle cx="38" cy="29" r="1.8" fill="currentColor"/></svg>);
      case "target": return (<svg viewBox="0 0 64 64" {...common}><circle cx="32" cy="32" r="22"/><circle cx="32" cy="32" r="14"/><circle cx="32" cy="32" r="6"/><circle cx="32" cy="32" r="1.5" fill="currentColor"/><path d="M32 4 V14 M32 50 V60 M4 32 H14 M50 32 H60"/></svg>);
      case "pen":    return (<svg viewBox="0 0 64 64" {...common}><path d="M10 54 L18 50 L52 16 L48 12 L14 46 Z"/><path d="M44 16 L48 20"/><path d="M10 54 L14 46"/></svg>);
      default:       return null;
    }
  };

  // ---------- 3D tilt hook ----------
  function useTilt(strength = 8) {
    const ref = useRef(null);
    const onMove = useCallback((e) => {
      const el = ref.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const x = (e.clientX - r.left) / r.width;   // 0..1
      const y = (e.clientY - r.top) / r.height;   // 0..1
      const rx = (0.5 - y) * strength;
      const ry = (x - 0.5) * strength;
      el.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg)`;
    }, [strength]);
    const onLeave = useCallback(() => {
      const el = ref.current;
      if (!el) return;
      el.style.transform = "rotateX(0deg) rotateY(0deg)";
    }, []);
    return { ref, onMouseMove: onMove, onMouseLeave: onLeave };
  }

  // ---------- Featured card with terminal mock ----------
  function FeaturedCard({ post }) {
    const tilt = useTilt(7);
    return (
      <div className="blog__featured-wrap">
        <article
          className="feat"
          ref={tilt.ref}
          onMouseMove={tilt.onMouseMove}
          onMouseLeave={tilt.onMouseLeave}
        >
          <div className="feat__media">
            <div className="feat__glyph">
              <PostGlyph name="graph" />
            </div>
            <div className="feat__mock">
              <div className="feat__mock-bar">
                <div className="dots"><span/><span/><span/></div>
                <span>OVERNIGHT LOG · 04:12 — 09:00 UTC</span>
              </div>
              <div className="feat__mock-body">
                <div className="line"><span className="t">04:12</span><span className="a">CampaignBot rebid Meta · 14 ad sets · CPA ↓ 18%</span></div>
                <div className="line"><span className="t">04:48</span><span className="a">QA Sentinel flagged checkout 422 · patched · <span className="n">9m to fix</span></span></div>
                <div className="line"><span className="t">05:31</span><span className="a">ChatOps resolved 41 inbound · 3 handoffs queued</span></div>
                <div className="line"><span className="t">06:02</span><span className="a">SEO Sentinel published 7 internal-link fixes</span></div>
                <div className="line"><span className="t">07:14</span><span className="a">DesignFlow shipped 22 carousels · awaiting approval</span></div>
                <div className="line"><span className="t">08:55</span><span className="a typing">Brief drafted · Friday memo composing</span></div>
              </div>
            </div>
          </div>
          <div className="feat__body">
            <span className="feat__chip"><span className="pulse"></span>Featured · {post.kind}</span>
            <h3 className="feat__h">{post.h.split(". ").map((s, i, arr) => (
              <React.Fragment key={i}>
                {i === arr.length - 1 ? <span className="gold">{s}</span> : s + ". "}
              </React.Fragment>
            ))}</h3>
            <p className="feat__deck">{post.deck}</p>
            <div className="feat__byline">
              <div className="feat__avatar">
                <PostGlyph name="graph" />
              </div>
              <div style={{display:"flex", flexDirection:"column", gap:2}}>
                <span><span className="gold">{post.author}</span> · {post.role}</span>
                <span>{post.date} <span className="sep">·</span> {post.readMin} min read</span>
              </div>
            </div>
            <div className="feat__read">
              Read the full log <span className="arrow">→</span>
            </div>
          </div>
        </article>
      </div>
    );
  }

  // ---------- Grid card ----------
  function PostCard({ post }) {
    const tilt = useTilt(10);
    return (
      <article
        className="post"
        ref={tilt.ref}
        onMouseMove={tilt.onMouseMove}
        onMouseLeave={tilt.onMouseLeave}
      >
        <div className="post__media">
          <div className={"post__media-bg bg--" + post.bg}></div>
          <div className="post__media-tag">{post.tag}</div>
          <div className="post__media-glyph">
            <PostGlyph name={post.glyph} />
          </div>
        </div>
        <div className="post__body">
          <div className="post__date">
            {post.date} <span className="sep">·</span> {post.cat}
          </div>
          <h4 className="post__h">{post.h}</h4>
          <p className="post__deck">{post.deck}</p>
          <div className="post__foot">
            <span className="author">{post.author}</span>
            <span className="sep">·</span>
            <span>{post.readMin} MIN</span>
            <span className="sep">·</span>
            <span className="gold">READ →</span>
          </div>
        </div>
      </article>
    );
  }

  // ---------- 3D logo plinth ----------
  function LogoPlinth() {
    return (
      <div className="blog__stage" aria-hidden="true">
        <div className="plinth">
          <div className="plinth__echo">FIELD NOTES</div>
          <div className="plinth__halo"></div>
          <div className="plinth__logo">
            <img src={(window.__resources && window.__resources.logo) || "assets/drotten-logo.png"} alt="" />
          </div>
          <div className="plinth__shadow"></div>
        </div>
      </div>
    );
  }

  // ---------- Newsletter ----------
  function SubStrip() {
    const [val, setVal] = useState("");
    const [done, setDone] = useState(false);
    return (
      <div className="blog__sub-strip">
        <div>
          <div className="eyebrow" style={{marginBottom: 10}}>// THE FRIDAY BRIEF</div>
          <h4 className="blog__sub-h">Every Friday, what your roster did.</h4>
          <p className="blog__sub-p">
            The same memo we file for clients — but anonymized, distilled, and shipped
            to your inbox. One email, one read, no funnel.
          </p>
        </div>
        <div>
          <form
            className={"blog__sub-form " + (done ? "is-done" : "")}
            onSubmit={(e) => { e.preventDefault(); if (val) setDone(true); }}
          >
            <input
              type="email"
              placeholder="you@brand.com"
              value={val}
              onChange={(e) => setVal(e.target.value)}
              required
              disabled={done}
            />
            <button type="submit">{done ? "✓ Subscribed" : "Subscribe →"}</button>
          </form>
          <div className="blog__sub-meta">
            {done ? "First brief lands this Friday at 6 a.m." : "No spam. Unsubscribe in one click."}
          </div>
        </div>
      </div>
    );
  }

  // ---------- Main Blog screen ----------
  function Blog() {
    const [filter, setFilter] = useState("ALL");

    const featured = POSTS.find(p => p.featured);
    const cards = useMemo(() => {
      const list = POSTS.filter(p => !p.featured);
      if (filter === "ALL") return list;
      return list.filter(p => p.kind === filter);
    }, [filter]);

    const counts = useMemo(() => {
      const c = { ALL: POSTS.filter(p => !p.featured).length };
      FILTERS.slice(1).forEach(f => {
        c[f.id] = POSTS.filter(p => !p.featured && p.kind === f.id).length;
      });
      return c;
    }, []);

    return (
      <section className="blog" id="blog">
        <div className="container">
          <div className="blog__head">
            <div>
              <div className="eyebrow">// FIELD NOTES <span className="dash">·</span> SECTION 09</div>
              <h2 className="blog__title">
                Dispatches from<br />
                <span className="gold">the roost.</span>
              </h2>
              <p className="blog__sub" style={{marginTop: 24}}>
                What our agents shipped, broke, fixed, and learned this month.
                Written by the agents. Edited by humans. Published in public.
              </p>
              <div className="blog__meta-row">
                <span><span className="gold">●</span> 6 posts this month</span>
                <span>Avg read · 6 min</span>
                <span>Updated weekly</span>
              </div>
            </div>
            <LogoPlinth />
          </div>

          <div className="blog__filters">
            {FILTERS.map(f => (
              <button
                key={f.id}
                className={"blog__filter " + (filter === f.id ? "blog__filter--active" : "")}
                onClick={() => setFilter(f.id)}
              >
                {f.label}<span className="count">{counts[f.id] ?? 0}</span>
              </button>
            ))}
          </div>

          {filter === "ALL" && featured && <FeaturedCard post={featured} />}

          <div className="blog__grid">
            {cards.map(p => <PostCard key={p.id} post={p} />)}
          </div>

          {cards.length === 0 && (
            <div className="mute mono" style={{padding:"60px 0", textAlign:"center", letterSpacing:"0.16em"}}>
              NO POSTS IN THIS FILTER.
            </div>
          )}

          <SubStrip />
        </div>
      </section>
    );
  }

  window.Blog = Blog;
})();
