/* ============================================================
 * Guest Memories, standalone module page (2026-09 redesign)
 * ------------------------------------------------------------
 * Ported from a Claude Design handoff (Guest Memories.dc.html):
 * the export's own DCLogic/sc-for/sc-if templating cannot run on
 * this site (different runtime to our own support.js), so every
 * section here is a from-scratch React reimplementation of the
 * SAME copy, data and visual design, translated into hooks.
 *
 * Sections:
 *   1. Hero + live capture feed
 *   2. Retrieval at runtime (Q&A demo)
 *   2B. 12 primitives grid
 *   3. Live tagging (taxonomy) demo
 *   4. Provenance / admin drill-down
 *   5. Segments & journeys
 *   6. Analytics
 *   7. FAQ + continue the story (shared components)
 *   8. CTA
 * ============================================================ */

const { useState: useStateMem, useEffect: useEffectMem, useRef: useRefMem } = React;

/* === Memory pill, used across sections ================== */
const MemPill = ({ cat, value, conf, src, hue }) => (
  <div className="mp-mempill">
    <div className="mp-mempill-row">
      <span className="mp-mempill-cat" style={{ background: `color-mix(in srgb, ${hue || "var(--accent)"} 12%, transparent)`, color: hue || "var(--accent)" }}>{cat}</span>
      {conf && <span className="mp-mempill-conf">{conf}</span>}
    </div>
    <div className="mp-mempill-v">{value}</div>
    {src && <div className="mp-mempill-src">{src}</div>}
  </div>
);

/* Category -> colour, matches the taxonomy groups in section 3/6 */
const MEM_CAT_COLOR = {
  "Special date": "var(--accent)", "Pet": "var(--accent)", "Family": "var(--accent)", "Loyalty tier": "var(--accent)",
  "Stay pref": "#4f9d8f", "Check-in": "#4f9d8f", "Bed setup": "#4f9d8f", "Quiet room": "#4f9d8f", "Climate": "#4f9d8f", "Floor": "#4f9d8f",
  "Dietary": "#5b6bb0", "Allergy": "#5b6bb0", "Drinks": "#5b6bb0", "Restaurant": "#5b6bb0",
  "Trip purpose": "#c06a4f", "Communication": "#c06a4f", "Spend pattern": "#c06a4f", "Mood": "#c06a4f",
  "Open issue": "#8a6a9c", "Resolved": "#8a6a9c", "Sensitive note": "#8a6a9c",
  "Companion": "#b8843c", "Likely return": "#b8843c", "Brand affinity": "#b8843c", "Last stay": "#b8843c",
};
const memCatColor = (cat) => MEM_CAT_COLOR[cat] || "var(--accent)";

/* ============================================================
 * 1. HERO + LISTENING-ON / PROFILE / READ-BY FLOW DIAGRAM
 * Exact port of dc.html Section 1 (18-item pool, 6 sources, 5
 * consumers, word-by-word extraction -> classify -> commit cycle).
 * ============================================================ */
const MEM_POOL = [
  { cat: "Special date", val: "Anniversary · 14 May, annual", src: "Voice", conf: "0.96", quote: "“…it’s our anniversary so we’d love…”" },
  { cat: "Pet", val: "Dachshund · Frankie · 8 kg", src: "WhatsApp", conf: "0.94", quote: "“Frankie is coming, hope that’s still ok”" },
  { cat: "Dietary", val: "Partner vegetarian", src: "Email", conf: "0.91", quote: "“my partner doesn’t eat meat”" },
  { cat: "Stay pref", val: "High floor, sea view", src: "Inferred", conf: "0.88", quote: "Inferred from 2 previous stays" },
  { cat: "Allergy", val: "Shellfish · severe", src: "WhatsApp", conf: "0.97", quote: "“no shellfish for me, it’s serious”" },
  { cat: "Bed setup", val: "Twin beds for second guest", src: "PMS note", conf: "0.93", quote: "Front desk note · check-in" },
  { cat: "Family", val: "Travelling with mother", src: "Web chat", conf: "0.90", quote: "“my mother is joining us this time”" },
  { cat: "Communication", val: "Prefers WhatsApp over email", src: "Inferred", conf: "0.86", quote: "Inferred from 9 replies" },
  { cat: "Check-in", val: "Late check-in · after 22:00", src: "Voice", conf: "0.92", quote: "“our flight lands quite late”" },
  { cat: "Spend pattern", val: "Books the spa most stays", src: "Inferred", conf: "0.84", quote: "Inferred from 4 bookings" },
  { cat: "Quiet room", val: "Wants quiet, away from lobby", src: "Email", conf: "0.89", quote: "“somewhere quiet if possible”" },
  { cat: "Drinks", val: "Sancerre · no ice in water", src: "PMS note", conf: "0.87", quote: "Sommelier note · La Terraza" },
  { cat: "Trip purpose", val: "Wedding anniversary trip", src: "Voice", conf: "0.95", quote: "“we’re celebrating, it’s a big one”" },
  { cat: "Sensitive note", val: "Reacts to housekeeping fragrance", src: "Web chat", conf: "0.90", quote: "“the room spray gave me a headache”" },
  { cat: "Companion", val: "Same partner across 4 stays", src: "Inferred", conf: "0.92", quote: "Inferred from stay history" },
  { cat: "Climate", val: "Prefers AC off, windows open", src: "WhatsApp", conf: "0.88", quote: "“we like the windows open at night”" },
  { cat: "Loyalty tier", val: "Gold · since 2022", src: "PMS note", conf: "0.99", quote: "Loyalty sync · membership record" },
  { cat: "Restaurant", val: "Always books La Terraza", src: "Inferred", conf: "0.85", quote: "Inferred from 5 covers" },
];
const HERO_SRC_TILE = { WhatsApp: 0, Voice: 1, Email: 2, "Web chat": 3, Instagram: 4, "PMS note": 5 };
const HERO_SOURCES = [
  { name: "WhatsApp", caption: "Chat threads", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78"><path d="M3 15l1-3a6 6 0 1 1 2.6 2.3z" strokeLinejoin="round" /></svg> },
  { name: "Voice calls", caption: "Transcripts", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinecap="round" strokeLinejoin="round"><rect x="6.5" y="2" width="5" height="9" rx="2.5" /><path d="M4 8.5a5 5 0 0 0 10 0 M9 13.5v2.5 M6.5 16h5" /></svg> },
  { name: "Email", caption: "Inbound threads", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78"><rect x="2" y="4" width="14" height="10" rx="1.5" /><path d="M2.5 5l6.5 4.6L15.5 5" /></svg> },
  { name: "Web chat", caption: "Site widget", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78"><rect x="3" y="3" width="12" height="9" rx="2" /><path d="M3.5 12l-1 3 3.2-1.1" strokeLinejoin="round" /></svg> },
  { name: "Instagram DM", caption: "IG · FB · DM", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78"><rect x="3" y="3" width="12" height="12" rx="3.5" /><circle cx="9" cy="9" r="3" /><circle cx="13" cy="5" r="0.8" fill="var(--ink)" stroke="none" /></svg> },
  { name: "PMS & staff notes", caption: "Front desk", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78"><rect x="4" y="2" width="10" height="14" rx="1.5" /><path d="M6.5 6h5 M6.5 9h5 M6.5 12h3" /></svg> },
];
const HERO_CONSUMERS = [
  { name: "Concierge agent", caption: "Every reply", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinejoin="round"><path d="M3 4h12v8H7l-3 3z" /></svg> },
  { name: "Journeys", caption: "Email · SMS", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinecap="round"><circle cx="4" cy="4.5" r="1.6" /><circle cx="9" cy="9" r="1.6" /><circle cx="14" cy="13.5" r="1.6" /><path d="M5.4 5.6L7.6 7.9 M10.4 10.1l2.2 2.3" /></svg> },
  { name: "Segments", caption: "Live filters", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinecap="round"><path d="M2.5 4h13 M4.5 9h9 M7 14h4" /></svg> },
  { name: "Room notes", caption: "Ops · F&B", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinejoin="round"><path d="M2 12V6.5l7-4 7 4V12 M2 12h14 M6.5 12V9h5v3" /></svg> },
  { name: "Offers", caption: "Upsell timing", icon: <svg width="17" height="17" viewBox="0 0 18 18" fill="none" stroke="var(--ink)" strokeWidth="1.4" strokeOpacity="0.78" strokeLinejoin="round"><path d="M9 3l1.7 4.2L15 8.6l-4.3 1.4L9 14.4 7.3 10 3 8.6l4.3-1.4z" /></svg> },
];
/* absolute positions, transcribed verbatim from the 1240x600 handoff canvas */
const HERO_SRC_POS = [18, 116, 214, 312, 410, 508];
const HERO_CONSUMER_POS = [28, 140, 252, 364, 476];
const HERO_SRC_PATHS = ["M208,50 C272,50 256,125 320,125", "M208,148 C272,148 256,194 320,194", "M208,246 C272,246 256,262 320,262", "M208,344 C272,344 256,331 320,331", "M208,442 C272,442 256,399 320,399", "M208,540 C272,540 256,468 320,468"];
const HERO_CONSUMER_PATHS = ["M920,136 C982,136 970,66 1032,66", "M920,215 C982,215 970,178 1032,178", "M920,293 C982,293 970,290 1032,290", "M920,371 C982,371 970,402 1032,402", "M920,450 C982,450 970,514 1032,514"];

function heroSeedRow(i) {
  const age = [11, 26, 44, 70, 110][i];
  const p = MEM_POOL[(i + 3) % MEM_POOL.length];
  return { id: "seed" + i, cat: p.cat, val: p.val, src: p.src, conf: p.conf, quote: p.quote, phase: "done", born: -age };
}

function MemoryCaptureFeed() {
  const [rows, setRows] = useStateMem(() => [0, 1, 2, 3, 4].map(heroSeedRow));
  const [count, setCount] = useStateMem(47);
  const [countScale, setCountScale] = useStateMem(1);
  const [clock, setClock] = useStateMem(0);
  const [activeSrc, setActiveSrc] = useStateMem(-1);
  const [activeConsumer, setActiveConsumer] = useStateMem(-1);
  const poolIdx = useRefMem(8);
  const consumerIdx = useRefMem(0);
  const timers = useRefMem([]);
  const clockRef = useRefMem(0);
  const wrapRef = useRefMem(null);
  const [scale, setScale] = useStateMem(1);

  useEffectMem(() => {
    const el = wrapRef.current;
    if (!el || typeof ResizeObserver === "undefined") return;
    const ro = new ResizeObserver((entries) => {
      const w = entries[0].contentRect.width;
      if (w > 0) setScale(Math.min(1, w / 1240));
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  useEffectMem(() => {
    let alive = true;
    const schedule = (fn, ms) => { const id = setTimeout(() => { if (alive) fn(); }, ms); timers.current.push(id); return id; };
    const clockInt = setInterval(() => { if (alive) { clockRef.current += 1; setClock(clockRef.current); } }, 1000);

    function cycle() {
      const p = MEM_POOL[poolIdx.current % MEM_POOL.length];
      poolIdx.current++;
      const id = "m" + Date.now() + "-" + poolIdx.current;
      const words = p.val.split(" ");
      setRows((r) => [{ id, cat: p.cat, val: p.val, words, src: p.src, conf: p.conf, quote: p.quote, phase: "arriving", revealed: 0 }, ...r].slice(0, 6));
      setActiveSrc(HERO_SRC_TILE[p.src] ?? -1);
      schedule(function typeNext(i) {
        return () => {
          if (i === 0) setRows((r) => r.map((row) => (row.id === id ? { ...row, phase: "extracting" } : row)));
          if (i > words.length) { schedule(classify, 300); return; }
          setRows((r) => r.map((row) => (row.id === id ? { ...row, revealed: i } : row)));
          schedule(typeNext(i + 1), 110);
        };
      }(0), 700);
      function classify() {
        setRows((r) => r.map((row) => (row.id === id ? { ...row, phase: "classifying" } : row)));
        schedule(commit, 520);
      }
      function commit() {
        const chan = consumerIdx.current % HERO_CONSUMERS.length;
        consumerIdx.current++;
        setRows((r) => r.map((row) => (row.id === id ? { ...row, phase: "done", revealed: 99, born: clockRef.current, flash: true } : row)));
        setCount((c) => c + 1);
        setActiveConsumer(chan);
        setCountScale(1.14);
        schedule(() => setCountScale(1), 260);
        schedule(() => setRows((r) => r.map((row) => (row.id === id ? { ...row, flash: false } : row))), 720);
        schedule(() => setActiveConsumer(-1), 950);
        schedule(() => setActiveSrc(-1), 950);
        schedule(cycle, 1100);
      }
    }
    schedule(cycle, 1600);
    return () => { alive = false; clearInterval(clockInt); timers.current.forEach(clearTimeout); timers.current = []; };
  }, []);

  const statusText = rows[0]?.phase === "arriving" ? (rows[0].src === "Inferred" ? "Reviewing stay history" : "New message on " + rows[0].src)
    : rows[0]?.phase === "extracting" ? "Extracting the detail worth keeping"
    : rows[0]?.phase === "classifying" ? "Filing into " + rows[0].cat.toLowerCase()
    : "Profile synced · read by every agent";

  return (
    <div className="memhero-flow-scroll" ref={wrapRef} style={{ height: 54 + 600 * scale }}>
      <div className="memhero-flow" style={{ position: "relative", width: 1240, maxWidth: 1240, height: 600, margin: "54px 0 0", transform: `scale(${scale})`, transformOrigin: "top left" }}>
        <div className="memhero-col-label" style={{ position: "absolute", top: -30, left: 22 }}><span className="memhero-col-dot" />Listening on</div>
        <div className="memhero-col-label" style={{ position: "absolute", top: -30, right: 22 }}>Read by<span className="memhero-col-dot" /></div>

        <div className="memhero-aura" />

        <svg width="1240" height="600" viewBox="0 0 1240 600" style={{ position: "absolute", inset: 0, overflow: "visible", pointerEvents: "none" }}>
          <g fill="none" stroke="rgba(237,77,134,0.30)" strokeWidth="1.5" strokeDasharray="5 7">
            {HERO_SRC_PATHS.map((d, i) => <path key={i} d={d} />)}
          </g>
          <g fill="none" stroke="rgba(237,77,134,0.30)" strokeWidth="1.5" strokeDasharray="5 7">
            {HERO_CONSUMER_PATHS.map((d, i) => <path key={i} d={d} />)}
          </g>
          <g>
            {HERO_SRC_PATHS.map((d, i) => <circle key={i} r="3.5" fill="var(--accent)"><animateMotion dur="2.8s" begin={i * 0.5 + "s"} repeatCount="indefinite" path={d} /></circle>)}
            {HERO_CONSUMER_PATHS.map((d, i) => <circle key={i} r="3.5" fill="#C42E68"><animateMotion dur="3.0s" begin={i * 0.6 + 0.3 + "s"} repeatCount="indefinite" path={d} /></circle>)}
          </g>
        </svg>

        {HERO_SOURCES.map((s, i) => (
          <div key={s.name} className="memhero-tile" style={{ position: "absolute", left: 20, top: HERO_SRC_POS[i], width: 188, height: 64 }}>
            <div className="memhero-tile-inner">
              <span className="memhero-tile-icon">{s.icon}</span>
              <span className="memhero-tile-copy"><span className="memhero-tile-name">{s.name}</span><span className="memhero-tile-cap">{s.caption}</span></span>
            </div>
            {activeSrc === i && <div className="memhero-tile-glow" />}
          </div>
        ))}
        {HERO_CONSUMERS.map((c, i) => (
          <div key={c.name} className="memhero-tile" style={{ position: "absolute", left: 1032, top: HERO_CONSUMER_POS[i], width: 188, height: 76 }}>
            <div className="memhero-tile-inner">
              <span className="memhero-tile-icon">{c.icon}</span>
              <span className="memhero-tile-copy"><span className="memhero-tile-name">{c.name}</span><span className="memhero-tile-cap">{c.caption}</span></span>
            </div>
            {activeConsumer === i && <div className="memhero-tile-glow" />}
          </div>
        ))}

        <div className="memhero-card" style={{ position: "absolute", left: 320, top: 30, width: 600, height: 540 }}>
          <div className="memhero-card-head">
            <div className="memhero-avatar"><span className="memhero-avatar-ping" /><span className="memhero-avatar-mark">DM</span></div>
            <div className="memhero-card-id">
              <span className="memhero-card-name">Dimitri Mitsopoulos</span>
              <span className="memhero-card-sub">Guest memory · profile #84412</span>
            </div>
            <div className="memhero-card-meta">
              <span className="memhero-listening"><span className="memhero-listening-dot" />LISTENING</span>
              <span className="memhero-count"><span style={{ display: "inline-block", fontWeight: 600, color: "var(--ink)", transform: `scale(${countScale})`, transition: "transform 0.25s ease" }}>{count.toLocaleString("en-US")}</span> memories</span>
            </div>
          </div>
          <div className="memhero-scanbar"><div className="memhero-scanbar-fill" /></div>
          <div className="memhero-status-row">
            <span className="memhero-status-spin" />
            <span className="memhero-status-text">{statusText}</span>
          </div>
          <div className="memhero-rows">
            {rows.map((r) => (
              <div key={r.id} className="memhero-row">
                {r.flash && <span className="memhero-row-flash" />}
                <div className="memhero-row-top">
                  {r.phase === "done" ? <span className="memhero-row-dot" style={{ background: memCatColor(r.cat) }} /> : <span className="memhero-row-spin" />}
                  <span className="memhero-row-title">
                    {r.phase === "arriving" ? r.quote : (r.words || r.val.split(" ")).slice(0, r.phase === "done" ? 99 : r.revealed).join(" ")}
                    {r.phase !== "done" && r.phase !== "arriving" && <span className="memhero-cursor" />}
                  </span>
                  {(r.phase === "done" || r.phase === "classifying") && <span className="memhero-row-cat" style={{ color: memCatColor(r.cat), background: `color-mix(in srgb, ${memCatColor(r.cat)} 14%, transparent)` }}>{r.cat}</span>}
                </div>
                <div className="memhero-row-sub">
                  {r.phase === "done" ? (
                    <>
                      <span className="memhero-row-src">{r.src}</span><span className="memhero-row-dim">·</span>
                      <span>{clock - r.born <= 0 ? "just now" : (clock - r.born) + "s ago"}</span><span className="memhero-row-dim">·</span>
                      <span>conf {r.conf}</span>
                    </>
                  ) : (
                    <span className="memhero-row-draftlabel">{r.phase === "arriving" ? "listening" : r.phase === "extracting" ? "extracting" : "classifying"}</span>
                  )}
                </div>
              </div>
            ))}
          </div>
          <div className="memhero-card-foot">
            <span className="memhero-foot-a"><span className="memhero-foot-dot" />One profile across every property in the group</span>
            <span className="memhero-foot-b">Every memory traced to its source</span>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============================================================
 * 2B. TWELVE PRIMITIVES
 * ============================================================ */
const MEM_PRIMS = [
  { num: "01", kicker: "CAPTURE", title: "Nobody has to type it", body: "Every inbound message, call transcript, email and staff note is read for details worth keeping.", bullets: ["WhatsApp · voice · email · social", "Web chat · PMS · staff notes", "30+ languages, same taxonomy"], quote: "“The detail is saved before the conversation ends.”" },
  { num: "02", kicker: "TAXONOMY", title: "38 typed slots", body: "Not a notes field. Each memory lands in a category agents, segments and journeys already understand.", bullets: ["38 first-class categories", "Custom categories per property", "Typed values, never free text"], quote: "“A notes field is a place details go to die.”" },
  { num: "03", kicker: "PROVENANCE", title: "Traced to the line", body: "Channel, timestamp, message ID and agent are attached to every memory, for ever.", bullets: ["Original message kept", "One click to the source", "Full audit for every edit"], quote: "“Open any memory and see who said it, and when.”" },
  { num: "04", kicker: "CONFIDENCE", title: "Scored, never assumed", body: "A stated fact and a guess are not the same thing, so they never carry the same weight.", bullets: ["Per-memory confidence score", "Low scores held for review", "Stated beats inferred, always"], quote: "“The system knows the difference between told and guessed.”" },
  { num: "05", kicker: "DEDUPLICATION", title: "One truth per fact", body: "The same preference said five times across five channels stays one memory, with five sources.", bullets: ["Merged on capture", "Sources accumulate", "No duplicate clutter"], quote: "“Said five ways, stored once.”" },
  { num: "06", kicker: "INFERENCE", title: "What they never said", body: "Repeat behaviour becomes its own memory, clearly labelled as inferred rather than stated.", bullets: ["Patterns across stays", "Marked as inferred", "Overridden by anything stated"], quote: "“Four stays, same partner. That is worth knowing.”" },
  { num: "07", kicker: "RETRIEVAL", title: "Folded into every reply", body: "Relevant memories are fetched and passed to the agent before a single word is composed.", bullets: ["Ranked by relevance", "Same store on every channel", "No template, no copy-paste"], quote: "“The agent already knew before it answered.”" },
  { num: "08", kicker: "SEGMENTS", title: "Memories as filters", body: "Every category is a queryable field, so audiences are built out of what guests actually told you.", bullets: ["Any category, any operator", "Live counts, recomputed", "Group or single property"], quote: "“Returning pet-parents with an anniversary. One query.”" },
  { num: "09", kicker: "JOURNEYS", title: "Read at send time", body: "Each step re-reads the profile as it sends, so nothing goes out based on a stale snapshot.", bullets: ["Personalised per guest", "Never a frozen merge field", "Steps skip when irrelevant"], quote: "“The email is written the second before it is sent.”" },
  { num: "10", kicker: "HUMAN CONTROL", title: "Edit, pin or forget", body: "Staff correct anything the extractor got wrong, and a forgotten memory disappears everywhere at once.", bullets: ["Inline correction", "Pin the ones that matter", "Forget propagates instantly"], quote: "“The AI proposes. Your team decides.”" },
  { num: "11", kicker: "PRIVACY", title: "Your tenant only", body: "Guest memories stay inside your tenant and are never used to train a shared model.", bullets: ["Isolated per tenant", "No shared-model training", "Deletion honoured end to end"], quote: "“Your guests’ words never leave your walls.”" },
  { num: "12", kicker: "GROUP GRAPH", title: "One guest, every property", body: "Group-level memories follow the guest; property-specific ones stay where they belong.", bullets: ["Group + per-property scope", "Recognised at every hotel", "Scoped memories stay scoped"], quote: "“Known at the second hotel as well as the first.”" },
];

/* Exact per-primitive artwork, transcribed verbatim from the handoff (172×50 viewBox, #ED4D86 -> var(--accent)). */
const PRIM_ART = [
  <svg key="0" width="172" height="50" viewBox="0 0 172 50" fill="none"><g stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1"><rect x="12" y="5" width="30" height="8" rx="4" /><rect x="12" y="17" width="22" height="8" rx="4" /><rect x="12" y="29" width="34" height="8" rx="4" /><rect x="12" y="41" width="26" height="8" rx="4" /></g><g stroke="var(--accent)" strokeOpacity="0.4" strokeWidth="1"><path d="M46 9 C82 9 98 25 122 25" /><path d="M38 21 C78 21 98 25 122 25" /><path d="M50 33 C84 33 98 25 122 25" /><path d="M42 45 C80 45 98 25 122 25" /></g><circle cx="130" cy="25" r="10.5" stroke="var(--accent)" strokeOpacity="0.28" /><circle cx="130" cy="25" r="6" fill="var(--accent)" /></svg>,
  <svg key="1" width="172" height="50" viewBox="0 0 172 50" fill="none"><path d="M4 25h16" stroke="var(--accent)" strokeOpacity="0.5" strokeWidth="1" strokeDasharray="3 3" /><g stroke="#0E0D0C" strokeOpacity="0.14" strokeWidth="1"><rect x="26" y="8" width="30" height="14" rx="4" /><rect x="62" y="8" width="30" height="14" rx="4" /><rect x="134" y="8" width="30" height="14" rx="4" /><rect x="26" y="28" width="30" height="14" rx="4" /><rect x="62" y="28" width="30" height="14" rx="4" /><rect x="98" y="28" width="30" height="14" rx="4" /><rect x="134" y="28" width="30" height="14" rx="4" /></g><rect x="98" y="8" width="30" height="14" rx="4" fill="var(--accent)" fillOpacity="0.12" stroke="var(--accent)" strokeWidth="1" /><path d="M108 15l3 3 6-6.5" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /></svg>,
  <svg key="2" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="10" y="10" width="52" height="24" rx="6" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1" /><path d="M18 34v7l8-7z" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1" strokeLinejoin="round" /><rect x="16" y="16" width="16" height="4" rx="2" fill="#0E0D0C" fillOpacity="0.14" /><rect x="35" y="16" width="20" height="4" rx="2" fill="var(--accent)" fillOpacity="0.4" /><rect x="16" y="25" width="28" height="4" rx="2" fill="#0E0D0C" fillOpacity="0.14" /><path d="M72 25h28" stroke="var(--accent)" strokeOpacity="0.5" strokeWidth="1" strokeDasharray="3 3" /><path d="M95 21l5 4-5 4" stroke="var(--accent)" strokeOpacity="0.75" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" /><rect x="108" y="13" width="54" height="24" rx="6" fill="var(--accent)" fillOpacity="0.08" stroke="var(--accent)" strokeOpacity="0.55" strokeWidth="1" /><rect x="115" y="19" width="22" height="4" rx="2" fill="var(--accent)" fillOpacity="0.7" /><rect x="115" y="27" width="34" height="4" rx="2" fill="var(--accent)" fillOpacity="0.28" /></svg>,
  <svg key="3" width="172" height="50" viewBox="0 0 172 50" fill="none"><path d="M50 40a36 36 0 0 1 72 0" stroke="#0E0D0C" strokeOpacity="0.1" strokeWidth="3" strokeLinecap="round" /><path d="M50 40a36 36 0 0 1 60 -30" stroke="var(--accent)" strokeWidth="3" strokeLinecap="round" /><path d="M86 40L108 16" stroke="var(--accent)" strokeWidth="1.4" strokeLinecap="round" /><circle cx="86" cy="40" r="3.2" fill="var(--accent)" /><path d="M128 34l5 3" stroke="var(--accent)" strokeOpacity="0.35" strokeWidth="1.4" strokeLinecap="round" /><path d="M44 34l-5 3" stroke="#0E0D0C" strokeOpacity="0.15" strokeWidth="1.4" strokeLinecap="round" /></svg>,
  <svg key="4" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="12" y="7" width="46" height="12" rx="4" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.13" strokeWidth="1" /><rect x="18" y="18" width="46" height="12" rx="4" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.13" strokeWidth="1" /><rect x="24" y="29" width="46" height="12" rx="4" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.13" strokeWidth="1" /><path d="M80 25h20 M95 20l5 5-5 5" stroke="var(--accent)" strokeOpacity="0.75" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" /><rect x="110" y="17" width="50" height="16" rx="6" fill="var(--accent)" fillOpacity="0.1" stroke="var(--accent)" strokeWidth="1" /><path d="M119 25l3.5 3.5 7-8" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /><rect x="135" y="23" width="18" height="4" rx="2" fill="var(--accent)" fillOpacity="0.45" /></svg>,
  <svg key="5" width="172" height="50" viewBox="0 0 172 50" fill="none"><path d="M18 43h136" stroke="#0E0D0C" strokeOpacity="0.12" strokeWidth="1" /><path d="M32 34L60 27L88 30L116 21" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" /><g fill="#0E0D0C" fillOpacity="0.26"><circle cx="32" cy="34" r="3" /><circle cx="60" cy="27" r="3" /><circle cx="88" cy="30" r="3" /><circle cx="116" cy="21" r="3" /></g><path d="M116 21L146 13" stroke="var(--accent)" strokeWidth="1.2" strokeDasharray="3 3" strokeLinecap="round" /><circle cx="148" cy="12.5" r="6" fill="var(--accent)" fillOpacity="0.14" stroke="var(--accent)" strokeWidth="1.2" /><circle cx="148" cy="12.5" r="2" fill="var(--accent)" /></svg>,
  <svg key="6" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="12" y="16" width="66" height="18" rx="6" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1" /><rect x="19" y="23" width="30" height="4" rx="2" fill="#0E0D0C" fillOpacity="0.15" /><path d="M55 30.5l9.5-9.5 3.5 3.5-9.5 9.5H55z" fill="var(--accent)" fillOpacity="0.12" stroke="var(--accent)" strokeWidth="1.1" strokeLinejoin="round" /><circle cx="108" cy="25" r="10" fill="var(--accent)" fillOpacity="0.1" stroke="var(--accent)" strokeWidth="1.2" /><path d="M103.5 25l3.2 3.2 6.4-7.2" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /><circle cx="140" cy="25" r="10" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1.2" /><path d="M136.5 21.5l7 7 M143.5 21.5l-7 7" stroke="#0E0D0C" strokeOpacity="0.24" strokeWidth="1.3" strokeLinecap="round" /></svg>,
  <svg key="7" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="26" y="7" width="120" height="10" rx="5" fill="#0E0D0C" fillOpacity="0.1" /><rect x="42" y="20" width="88" height="10" rx="5" fill="var(--accent)" fillOpacity="0.3" /><rect x="60" y="33" width="52" height="10" rx="5" fill="var(--accent)" /><g stroke="#0E0D0C" strokeOpacity="0.12" strokeWidth="1"><path d="M26 17L42 20 M146 17L130 20 M42 30L60 33 M130 30L112 33" /></g></svg>,
  <svg key="8" width="172" height="50" viewBox="0 0 172 50" fill="none"><path d="M22 30h124" stroke="#0E0D0C" strokeOpacity="0.12" strokeWidth="1" /><g stroke="var(--accent)" strokeOpacity="0.3" strokeWidth="1"><path d="M34 25v-8 M66 25v-8 M98 25v-8" /></g><g fill="#fff" stroke="var(--accent)" strokeOpacity="0.55" strokeWidth="1.2"><circle cx="34" cy="30" r="4.5" /><circle cx="66" cy="30" r="4.5" /><circle cx="98" cy="30" r="4.5" /></g><g fill="var(--accent)" fillOpacity="0.25"><rect x="26" y="11" width="16" height="5" rx="2.5" /><rect x="58" y="11" width="16" height="5" rx="2.5" /><rect x="90" y="11" width="16" height="5" rx="2.5" /></g><circle cx="134" cy="30" r="9" fill="var(--accent)" /><path d="M129.5 27h9v6h-9z M129.5 27l4.5 3.4 4.5-3.4" stroke="#fff" strokeWidth="1.1" strokeLinejoin="round" fill="none" /></svg>,
  <svg key="9" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="12" y="16" width="66" height="18" rx="6" fill="#fff" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1" /><rect x="19" y="23" width="30" height="4" rx="2" fill="#0E0D0C" fillOpacity="0.15" /><path d="M55 30.5l9.5-9.5 3.5 3.5-9.5 9.5H55z" fill="var(--accent)" fillOpacity="0.12" stroke="var(--accent)" strokeWidth="1.1" strokeLinejoin="round" /><circle cx="108" cy="25" r="10" fill="var(--accent)" fillOpacity="0.1" stroke="var(--accent)" strokeWidth="1.2" /><path d="M103.5 25l3.2 3.2 6.4-7.2" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /><circle cx="140" cy="25" r="10" stroke="#0E0D0C" strokeOpacity="0.16" strokeWidth="1.2" /><path d="M136.5 21.5l7 7 M143.5 21.5l-7 7" stroke="#0E0D0C" strokeOpacity="0.24" strokeWidth="1.3" strokeLinecap="round" /></svg>,
  <svg key="10" width="172" height="50" viewBox="0 0 172 50" fill="none"><rect x="14" y="5" width="144" height="40" rx="10" stroke="#0E0D0C" strokeOpacity="0.1" strokeWidth="1" strokeDasharray="4 4" /><path d="M86 9l15 5.2v8.4c0 8-6.5 11.8-15 14.5-8.5-2.7-15-6.5-15-14.5v-8.4z" fill="var(--accent)" fillOpacity="0.08" stroke="var(--accent)" strokeWidth="1.2" strokeLinejoin="round" /><circle cx="86" cy="22" r="3.2" stroke="var(--accent)" strokeWidth="1.2" /><path d="M86 25.2v5" stroke="var(--accent)" strokeWidth="1.2" strokeLinecap="round" /></svg>,
  <svg key="11" width="172" height="50" viewBox="0 0 172 50" fill="none"><g stroke="var(--accent)" strokeOpacity="0.32" strokeWidth="1"><path d="M75 20C62 15 56 13 44 12" /><path d="M75 30C62 35 56 37 44 38" /><path d="M97 20C110 15 116 13 128 12" /><path d="M97 30C110 35 116 37 128 38" /></g><g stroke="#0E0D0C" strokeOpacity="0.28" strokeWidth="1.1" strokeLinejoin="round"><path d="M27 17v-7l7-4 7 4v7z" /><path d="M27 43v-7l7-4 7 4v7z" /><path d="M131 17v-7l7-4 7 4v7z" /><path d="M131 43v-7l7-4 7 4v7z" /></g><circle cx="86" cy="25" r="13" stroke="var(--accent)" strokeOpacity="0.22" strokeWidth="1" /><circle cx="86" cy="25" r="8" fill="var(--accent)" /><circle cx="86" cy="22.4" r="2.4" fill="#fff" /><path d="M81.6 30.2c0-2.1 2-3.2 4.4-3.2s4.4 1.1 4.4 3.2" fill="#fff" /></svg>,
];

function MemoryPrimitives() {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: 16 }}>
      {MEM_PRIMS.map((p, i) => (
        <Reveal key={p.num} delay={(i % 3) * 60} style={{ background: "#fff", border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, overflow: "hidden", display: "flex", flexDirection: "column" }}>
          <div style={{ height: 92, background: "#faf8f5", borderBottom: "1px solid rgba(20,20,20,0.05)", display: "flex", alignItems: "center", justifyContent: "center" }}>
            {PRIM_ART[i]}
          </div>
          <div style={{ padding: "18px 20px 20px", display: "flex", flexDirection: "column", flex: 1 }}>
            <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, fontWeight: 600, letterSpacing: "0.12em", color: "var(--accent)", marginBottom: 8 }}>{p.num} · {p.kicker}</div>
            <div style={{ fontFamily: "var(--f-display)", fontSize: 18, fontWeight: 400, color: "var(--ink)", letterSpacing: "-0.01em" }}>{p.title}</div>
            <div style={{ fontSize: 12.5, lineHeight: 1.55, color: "var(--ink-3)", marginTop: 8 }}>{p.body}</div>
            <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 6 }}>
              {p.bullets.map((b) => (
                <div key={b} style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 12, color: "var(--ink-2)" }}>
                  <span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--accent)", marginTop: 6, flex: "none" }} />{b}
                </div>
              ))}
            </div>
            <div style={{ marginTop: 14, paddingTop: 12, borderTop: "1px solid rgba(20,20,20,0.06)", fontFamily: "var(--f-display)", fontStyle: "italic", fontSize: 12.5, lineHeight: 1.5, color: "#9a8f93" }}>{p.quote}</div>
          </div>
        </Reveal>
      ))}
    </div>
  );
}

/* ============================================================
 * 2. RETRIEVAL AT RUNTIME
 * ============================================================ */
const MEM_PILL_POOL = [
  ["Special date", "Anniversary · May 14"], ["Pet", "Frankie · 8 kg"], ["Dietary", "Partner vegetarian"], ["Stay pref", "High floor"],
  ["Loyalty tier", "Gold · 2022"], ["Allergy", "Shellfish"], ["Bed setup", "Twin beds"], ["Family", "With mother"],
  ["Check-in", "After 22:00"], ["Climate", "AC off"], ["Drinks", "Sancerre"], ["Quiet room", "Away from lobby"],
  ["Trip purpose", "Anniversary trip"], ["Communication", "WhatsApp first"], ["Last stay", "Suite 412"], ["Spend pattern", "Spa most stays"],
  ["Companion", "Same partner"], ["Mood", "Wants quiet"], ["Open issue", "Spa noise · Mar"], ["Resolved", "Breakfast credit"],
  ["Sensitive note", "Fragrance"], ["Brand affinity", "3 properties"], ["Likely return", "May–June"], ["Restaurant", "La Terraza"],
  ["Floor", "Sea view side"], ["Pet", "Bed + bowl"], ["Dietary", "No red meat"], ["Special date", "Birthday · Sep 2"],
  ["Stay pref", "Early housekeeping"], ["Drinks", "No ice in water"],
];
const MEM_RETRIEVAL_EXAMPLES = [
  {
    channel: "WhatsApp",
    question: "Hi, can we book the same room as last time?",
    answer: "Welcome back, Mr. Mitsopoulos. Suite 412 is free 14–17 May and I have held it for you.",
    hits: [
      { cat: "Last stay", v: "Suite 412 · 14–17 Mar 2025", src: "PMS note" },
      { cat: "Stay pref", v: "High floor, sea view", src: "Inferred" },
    ],
    lit: [3, 14],
  },
  {
    channel: "Voice",
    question: "We would like a table for our anniversary dinner.",
    answer: "Booked for the 14th at 20:30, with the vegetarian tasting menu noted for your partner.",
    hits: [
      { cat: "Special date", v: "Anniversary · 14 May", src: "Voice" },
      { cat: "Dietary", v: "Partner vegetarian", src: "Email" },
    ],
    lit: [0, 8],
  },
  {
    channel: "Email",
    question: "Anything we should confirm before we arrive?",
    answer: "Frankie’s bed is already in the room, and we have kept you on the quiet side, away from the lobby.",
    hits: [
      { cat: "Pet", v: "Dachshund · Frankie · 8 kg", src: "WhatsApp" },
      { cat: "Quiet room", v: "Away from lobby", src: "Email" },
    ],
    lit: [5, 19],
  },
  {
    channel: "Web chat",
    question: "Is the kitchen able to handle allergies?",
    answer: "Your severe shellfish allergy is already flagged with every kitchen in the hotel, including room service.",
    hits: [
      { cat: "Allergy", v: "Shellfish · severe", src: "WhatsApp" },
      { cat: "Restaurant", v: "Always books La Terraza", src: "Inferred" },
    ],
    lit: [11, 23],
  },
];
const MEM_RETRIEVAL_STEPS = ["Identify the guest", "Fetch memories", "Rank by relevance", "Compose the reply"];
const CHANNEL_ICON = {
  WhatsApp: <svg width="13" height="13" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinejoin="round"><path d="M3 15l1-3a6 6 0 1 1 2.6 2.3z" /></svg>,
  Voice: <svg width="13" height="13" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><rect x="6.5" y="2" width="5" height="9" rx="2.5" /><path d="M4 8.5a5 5 0 0 0 10 0 M9 13.5v2.5 M6.5 16h5" /></svg>,
  Email: <svg width="13" height="13" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.5"><rect x="2" y="4" width="14" height="10" rx="1.5" /><path d="M2.5 5l6.5 4.6L15.5 5" /></svg>,
  "Web chat": <svg width="13" height="13" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.5"><rect x="3" y="3" width="12" height="9" rx="2" /><path d="M3.5 12l-1 3 3.2-1.1" strokeLinejoin="round" /></svg>,
};

function MemoryRetrievalDemo() {
  const [idx, setIdx] = useStateMem(0);
  const [phase, setPhase] = useStateMem("asking");
  const [qTyped, setQTyped] = useStateMem(0);
  const [aTyped, setATyped] = useStateMem(0);
  const [scanned, setScanned] = useStateMem(0);
  const timers = useRefMem([]);

  useEffectMem(() => {
    let alive = true;
    const schedule = (fn, ms) => { const id = setTimeout(() => { if (alive) fn(); }, ms); timers.current.push(id); return id; };
    const ex = MEM_RETRIEVAL_EXAMPLES[idx];
    let scanInt;

    setPhase("asking"); setQTyped(0); setATyped(0); setScanned(0);
    let qi = 0;
    const qInt = setInterval(() => {
      qi = Math.min(ex.question.length, qi + 2);
      setQTyped(qi);
      if (qi >= ex.question.length) {
        clearInterval(qInt);
        schedule(() => {
          setPhase("searching");
          scanInt = setInterval(() => setScanned((s) => Math.min(47, s + 3)), 45);
        }, 400);
        schedule(() => {
          clearInterval(scanInt);
          setScanned(47);
          setPhase("matched");
          schedule(() => {
            setPhase("answered");
            let ai = 0;
            const aInt = setInterval(() => {
              ai = Math.min(ex.answer.length, ai + 2);
              setATyped(ai);
              if (ai >= ex.answer.length) clearInterval(aInt);
            }, 18);
          }, 700);
        }, 1300);
      }
    }, 24);

    schedule(() => setIdx((i) => (i + 1) % MEM_RETRIEVAL_EXAMPLES.length), 4600 + 1300 + 950);
    return () => { alive = false; clearInterval(qInt); clearInterval(scanInt); timers.current.forEach(clearTimeout); timers.current = []; };
  }, [idx]);

  const ex = MEM_RETRIEVAL_EXAMPLES[idx];
  const activeStep = phase === "asking" ? 0 : phase === "searching" ? 1 : phase === "matched" ? 2 : 3;
  const rShowResult = phase === "matched" || phase === "answered";
  const rShowAnswer = phase === "answered";
  const rSearching = phase === "searching";
  const stepData = [
    { label: "Identify the guest", done: "Matched to profile #84412", active: "Resolving number → profile", pending: "Awaiting contact" },
    { label: "Fetch memories", done: "Whole profile loaded", active: `${scanned} of 47 read`, pending: "Awaiting profile" },
    { label: "Rank by relevance", done: `${ex.hits.length} memories selected`, active: "Scoring against the question", pending: "Awaiting memories" },
    { label: "Compose the reply", done: `Sent on ${ex.channel}`, active: "Writing with memories in context", pending: "Awaiting selection" },
  ];
  const rStatus = phase === "asking" ? "Waiting for the guest"
    : phase === "searching" ? `${scanned} of 47 memories read`
    : phase === "matched" ? `${ex.hits.length} relevant memories selected`
    : "Reply composed with memory in context";

  return (
    <>
      {/* Responsive-only overrides: this component is otherwise entirely
          inline-styled (see memory-styles.jsx header). Below ~760px the
          two-pane layout can't hold its 42% conversation pane + fixed
          760px height without clipping, so it stacks instead. */}
      <style>{`
        .mem-retrieval-split { height: 760px; }
        .mem-retrieval-pane-left { width: 42%; border-right: 1px solid rgba(20,20,20,0.07); }
        .mem-retrieval-pills { grid-template-columns: repeat(3, minmax(0, 1fr)); }
        .mem-retrieval-callout { padding: 42px 48px; }
        .mem-retrieval-callout-item { min-width: 300px; }
        @media (max-width: 760px) {
          .mem-retrieval-split { flex-direction: column; height: auto; }
          .mem-retrieval-pane-left { width: 100%; border-right: none; border-bottom: 1px solid rgba(20,20,20,0.07); }
          .mem-retrieval-pills { grid-template-columns: repeat(2, minmax(0, 1fr)); }
          .mem-retrieval-callout { padding: 28px 24px; }
          .mem-retrieval-callout-item { min-width: 0; flex-basis: 100%; }
        }
      `}</style>
      <div className="mem-retrieval-split" style={{ marginTop: 50, display: "flex", background: "#fff", border: "1px solid rgba(20,20,20,0.07)", borderRadius: 22, boxShadow: "0 44px 86px -30px rgba(45,20,35,0.32), 0 4px 14px rgba(0,0,0,0.05)", overflow: "hidden" }}>
        {/* LEFT: guest-side conversation */}
        <div className="mem-retrieval-pane-left" style={{ padding: "36px 32px", display: "flex", flexDirection: "column" }}>
          <div style={{ display: "inline-flex", alignItems: "center", gap: 9, alignSelf: "flex-start", padding: "6px 13px", borderRadius: 999, background: "rgba(237,77,134,0.08)", marginBottom: 22 }}>
            <span style={{ display: "inline-flex", alignItems: "center" }}>{CHANNEL_ICON[ex.channel]}</span>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", color: "var(--accent)" }}>Guest · via {ex.channel}</span>
          </div>

          <div style={{ display: "flex", alignItems: "flex-start", gap: 11 }}>
            <span style={{ flex: "none", width: 30, height: 30, borderRadius: "50%", background: "#efe9e1", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 600, color: "var(--ink-3)" }}>DM</span>
            <div style={{ background: "#f4f1ec", border: "1px solid rgba(20,20,20,0.05)", borderRadius: "4px 15px 15px 15px", padding: "12px 15px", fontSize: 15, lineHeight: 1.45, color: "var(--ink)", maxWidth: 300 }}>
              {phase === "asking" ? ex.question.slice(0, qTyped) : ex.question}
              {phase === "asking" && qTyped < ex.question.length && <span style={{ display: "inline-block", width: 2, height: 15, background: "var(--ink-3)", marginLeft: 1, verticalAlign: -2, animation: "gm-cursor 0.9s steps(1) infinite" }} />}
            </div>
          </div>

          <div style={{ flex: 1, margin: "24px 0 16px", display: "flex", flexDirection: "column" }}>
            {stepData.map((sd, i) => {
              const isDone = i < activeStep, isActive = i === activeStep;
              const sub = isDone ? sd.done : isActive ? sd.active : sd.pending;
              return (
                <div key={sd.label} style={{ display: "flex", gap: 14 }}>
                  <div style={{ display: "flex", flexDirection: "column", alignItems: "center", flex: "none" }}>
                    <span style={{ width: 24, height: 24, borderRadius: "50%", border: `2px solid ${isDone || isActive ? "var(--accent)" : "rgba(20,20,20,0.20)"}`, background: isDone ? "var(--accent)" : "#fff", display: "flex", alignItems: "center", justifyContent: "center" }}>
                      {isDone && <svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2.5 6.2l2.2 2.2L9.5 3.5" /></svg>}
                      {isActive && <span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--accent)", animation: "gm-dot-pulse 1.2s ease-in-out infinite" }} />}
                    </span>
                    {i < 3 && <span style={{ width: 2, flex: 1, minHeight: 28, background: i < activeStep ? "var(--accent)" : "rgba(20,20,20,0.10)" }} />}
                  </div>
                  <div style={{ paddingBottom: 18 }}>
                    <div style={{ fontSize: 13.5, fontWeight: 600, color: isDone || isActive ? "#0E0D0C" : "#8B857C" }}>{sd.label}</div>
                    <div style={{ marginTop: 2, fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)" }}>{sub}</div>
                  </div>
                </div>
              );
            })}
          </div>

          <div style={{ minHeight: 150, display: "flex", alignItems: "flex-end" }}>
            {rShowAnswer && (
              <div style={{ display: "flex", alignItems: "flex-end", gap: 11, flexDirection: "row-reverse", animation: "gm-fade-up 0.45s ease both", width: "100%" }}>
                <span style={{ flex: "none", width: 30, height: 30, borderRadius: "50%", background: "radial-gradient(circle at 35% 30%, #F8B7CF, var(--accent) 60%, #C42E68)", display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 12px -3px rgba(237,77,134,0.5)" }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5.4a3 3 0 0 0-5.7-1.3A2.7 2.7 0 0 0 4 7a2.7 2.7 0 0 0-1 4.6A2.8 2.8 0 0 0 4.6 16a2.6 2.6 0 0 0 3.4 2.4A2.6 2.6 0 0 0 12 19.4z" /><path d="M12 5.4a3 3 0 0 1 5.7-1.3A2.7 2.7 0 0 1 20 7a2.7 2.7 0 0 1 1 4.6A2.8 2.8 0 0 1 19.4 16a2.6 2.6 0 0 1-3.4 2.4A2.6 2.6 0 0 1 12 19.4z" /><path d="M12 5.4V19.4" /></svg>
                </span>
                <div style={{ background: "linear-gradient(135deg,var(--accent),#C42E68)", color: "#fff", borderRadius: "15px 4px 15px 15px", padding: "13px 16px", maxWidth: 310 }}>
                  <div style={{ fontSize: 15, lineHeight: 1.5 }}>
                    {ex.answer.slice(0, aTyped)}
                    {aTyped < ex.answer.length && <span style={{ display: "inline-block", width: 2, height: 14, background: "#fff", marginLeft: 1, verticalAlign: -2, animation: "gm-cursor 0.9s steps(1) infinite" }} />}
                  </div>
                  <div style={{ marginTop: 9, paddingTop: 9, borderTop: "1px solid rgba(255,255,255,0.22)", fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.06em", color: "rgba(255,255,255,0.82)" }}>Composed from {ex.hits.length} memories</div>
                </div>
              </div>
            )}
          </div>
        </div>

        {/* RIGHT: whole memory store, scanned live */}
        <div style={{ flex: 1, padding: "32px 34px", display: "flex", flexDirection: "column", background: "linear-gradient(180deg, #fdfbf8, #fbf8f4)" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <span style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)" }}>Memory store · profile #84412</span>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 10, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--ink-3)" }}>47 memories · 3 properties</span>
          </div>

          <div style={{ position: "relative", flex: 1, marginTop: 18, padding: 18, borderRadius: 14, background: "#fff", border: "1px solid rgba(20,20,20,0.06)", overflow: "hidden" }}>
            <div className="mem-retrieval-pills" style={{ display: "grid", gap: 8, alignContent: "flex-start" }}>
              {MEM_PILL_POOL.map((p, i) => {
                const lit = rShowResult && ex.lit.indexOf(i) >= 0;
                return (
                  <span key={i} style={{ display: "flex", flexDirection: "column", gap: 2, padding: "7px 9px", borderRadius: 9, border: `1px solid ${lit ? "rgba(237,77,134,0.55)" : "rgba(20,20,20,0.07)"}`, background: lit ? "rgba(237,77,134,0.07)" : "#fdfcfa", boxShadow: lit ? "0 8px 20px -10px rgba(237,77,134,0.7)" : "none", transition: "all 0.35s ease" }}>
                    <span style={{ fontFamily: "var(--f-mono)", fontSize: 8, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", color: lit ? "var(--accent)" : "rgba(20,20,20,0.32)" }}>{p[0]}</span>
                    <span style={{ fontSize: 10.5, color: lit ? "#0E0D0C" : "rgba(20,20,20,0.30)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p[1]}</span>
                  </span>
                );
              })}
            </div>
            {rSearching && <span style={{ position: "absolute", top: 0, bottom: 0, left: 0, width: "32%", background: "linear-gradient(90deg, transparent, rgba(237,77,134,0.16), transparent)", animation: "gm-bar-scan 1.1s linear infinite", pointerEvents: "none" }} />}
            {rShowResult && (
              <div style={{ position: "absolute", left: 16, right: 16, bottom: 16, border: "1px solid rgba(237,77,134,0.22)", borderRadius: 14, padding: "16px 18px", background: "rgba(255,255,255,0.97)", boxShadow: "0 18px 38px -18px rgba(237,77,134,0.5)", animation: "gm-fade-up 0.42s ease both" }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
                  <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 13.5, fontWeight: 600, color: "var(--ink)" }}>
                    <span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--accent)", boxShadow: "0 0 0 4px rgba(237,77,134,0.16)" }} />Folded into this reply
                  </span>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 10, fontWeight: 600, padding: "3px 9px", borderRadius: 6, background: "rgba(79,157,143,0.12)", color: "#3f8a7d" }}>{ex.hits.length} of 47</span>
                </div>
                <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                  {ex.hits.map((h) => (
                    <div key={h.cat} style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 12px", borderRadius: 10, background: "#faf8f4", border: "1px solid rgba(20,20,20,0.05)" }}>
                      <span style={{ fontFamily: "var(--f-mono)", fontSize: 8.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", padding: "2px 7px", borderRadius: 5, color: memCatColor(h.cat), background: `color-mix(in srgb, ${memCatColor(h.cat)} 12%, transparent)`, flex: "none" }}>{h.cat}</span>
                      <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, color: "var(--ink)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{h.v}</span>
                      <span style={{ flex: "none", fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-3)" }}>{h.src}</span>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>

          <div style={{ marginTop: 16, display: "flex", alignItems: "center", gap: 12 }}>
            <div style={{ flex: 1, height: 4, borderRadius: 999, background: "rgba(237,77,134,0.10)", overflow: "hidden" }}>
              <div style={{ height: "100%", borderRadius: 999, background: "linear-gradient(90deg,var(--accent),#C42E68)", width: `${Math.round((scanned / 47) * 100)}%`, transition: "width 0.2s linear" }} />
            </div>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)", whiteSpace: "nowrap" }}>{rStatus}</span>
          </div>
        </div>
      </div>

      <div className="mem-retrieval-callout" style={{ marginTop: 42, background: "var(--ink)", borderRadius: 20, display: "flex", alignItems: "center", gap: 48, flexWrap: "wrap" }}>
        <div className="mem-retrieval-callout-item" style={{ flex: 1 }}>
          <h3 style={{ fontFamily: "var(--f-display)", fontWeight: 400, fontSize: 32, lineHeight: 1.12, letterSpacing: "-0.01em", margin: 0, color: "#fff" }}>
            A guest never forgets<br />
            <span style={{ fontStyle: "italic", fontWeight: 400, background: "linear-gradient(92deg,#F48BB4,var(--accent))", WebkitBackgroundClip: "text", backgroundClip: "text", color: "transparent" }}>that you forgot.</span>
          </h3>
        </div>
        <div className="mem-retrieval-callout-item" style={{ flex: 1 }}>
          <p style={{ fontSize: 16, lineHeight: 1.62, color: "#b9b3ad", margin: 0 }}>
            Being asked the same question a third time is the moment a loyal guest becomes a transaction. Memory is the difference between a hotel that recognises someone and a system that processes them.
          </p>
          <div style={{ marginTop: 18, fontFamily: "var(--f-mono)", fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.08em", color: "#6e6862" }}>
            One profile · <span style={{ color: "var(--accent)" }}>every property</span> · every channel · every agent
          </div>
        </div>
      </div>
    </>
  );
}

/* ============================================================
 * 3. LIVE TAGGING (TAXONOMY)
 * ============================================================ */
const MEM_TAG_COLS = [
  { name: "Identity & lifecycle", color: "var(--accent)", seed: [["FAMILY", "Travelling with mother"], ["LOYALTY TIER", "Gold · since 2022"]] },
  { name: "Stay preferences", color: "#4f9d8f", seed: [["PILLOW", "Firm · two of"], ["CHECK-IN TIME", "Late · post 22:00"]] },
  { name: "Dining & dietary", color: "#5b6bb0", seed: [["ALLERGY", "Shellfish · severe"], ["RESTAURANT", "Books La Terraza"]] },
  { name: "Behaviour & context", color: "#c06a4f", seed: [["MOOD", "Wants quiet, decompressing"], ["TRIP PURPOSE", "Wedding anniversary"]] },
  { name: "Issues & resolution", color: "#8a6a9c", seed: [["RESOLVED", "Breakfast credit given"], ["SENSITIVE NOTE", "Housekeeping fragrance"]] },
  { name: "Inferred", color: "#b8843c", seed: [["LIKELY RETURN", "May–June window"], ["COMPANION", "Same partner · 4 stays"]] },
];
const MEM_TAG_SCENARIOS = [
  { src: "WhatsApp · inbound", pre: "Hello again! We’ll be back May 14–17, our ", hi: "anniversary", post: ". Same suite if possible", col: 0, chip: "SPECIAL DATE", val: "Anniversary · May 14" },
  { src: "WhatsApp · inbound", pre: "Same suite if possible? ", hi: "Frankie", post: " is coming, hope that’s still ok", col: 0, chip: "PET", val: "Dachshund · Frankie" },
  { src: "Email · inbound", pre: "One thing to flag: ", hi: "my partner doesn’t eat meat", post: ", is that easy for you?", col: 2, chip: "DIETARY", val: "Partner vegetarian" },
  { src: "Voice · transcript", pre: "Could we have ", hi: "twin beds", post: " this time, my mother is joining", col: 1, chip: "BED SETUP", val: "Twin beds · second guest" },
  { src: "Web chat", pre: "Last time the spa music was ", hi: "far too loud", post: " in the afternoon", col: 4, chip: "OPEN ISSUE", val: "Spa noise · Mar stay" },
  { src: "Voice · transcript", pre: "We ", hi: "always", post: " do the tasting menu when we come", col: 3, chip: "SPEND PATTERN", val: "Books tasting menu most stays" },
  { src: "No message", pre: "Fourth stay booked with the same companion", hi: "", post: "", col: 5, chip: "COMPANION", val: "Same partner · 4 stays", noQuote: true },
  { src: "WhatsApp · inbound", pre: "Could you put us on a ", hi: "high floor", post: ", sea side if there is one?", col: 1, chip: "FLOOR", val: "High floor, sea view" },
];

function MemoryTaggingDemo() {
  const [scIdx, setScIdx] = useStateMem(0);
  const [phase, setPhase] = useStateMem("reading");
  const [placed, setPlaced] = useStateMem(() => MEM_TAG_COLS.map((c) => c.seed.map(([chip, val]) => ({ chip, val, fresh: false }))));
  const timers = useRefMem([]);

  useEffectMem(() => {
    let alive = true;
    const schedule = (fn, ms) => { const id = setTimeout(() => { if (alive) fn(); }, ms); timers.current.push(id); return id; };
    setPhase("reading");
    schedule(() => setPhase("sorting"), 1200);
    schedule(() => {
      const sc = MEM_TAG_SCENARIOS[scIdx];
      setPlaced((prev) => {
        const next = prev.map((col) => col.map((x) => ({ ...x, fresh: false })));
        const key = sc.chip + "|" + sc.val;
        next[sc.col] = [{ chip: sc.chip, val: sc.val, fresh: true }, ...next[sc.col].filter((x) => x.chip + "|" + x.val !== key)].slice(0, 3);
        return next;
      });
      setPhase("placed");
    }, 2200);
    schedule(() => setScIdx((i) => (i + 1) % MEM_TAG_SCENARIOS.length), 4300);
    return () => { alive = false; timers.current.forEach(clearTimeout); timers.current = []; };
  }, [scIdx]);

  const sc = MEM_TAG_SCENARIOS[scIdx];
  const hiOn = phase === "sorting" || phase === "placed";
  const sorting = phase === "sorting";

  return (
    <>
      {/* Responsive-only overrides: this component is otherwise entirely
          inline-styled (see memory-styles.jsx header). The 3x2 category
          grid and its fixed 660px shell height don't fit a phone-width
          container, so the grid drops to 1 column and the shell height
          becomes content-driven below ~700px. */}
      <style>{`
        .memtag-shell { height: 660px; }
        .memtag-header { flex-wrap: nowrap; }
        .memtag-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: 1fr 1fr; }
        @media (max-width: 700px) {
          .memtag-shell { height: auto; }
          .memtag-header { flex-wrap: wrap; row-gap: 8px; }
          .memtag-grid { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
        }
      `}</style>
    <div className="memtag-shell" style={{ marginTop: 50, background: "#fff", border: "1px solid rgba(20,20,20,0.07)", borderRadius: 22, boxShadow: "0 44px 86px -30px rgba(45,20,35,0.32), 0 4px 14px rgba(0,0,0,0.05)", overflow: "hidden", display: "flex", flexDirection: "column" }}>
      <div className="memtag-header" style={{ padding: "20px 26px", borderBottom: "1px solid rgba(20,20,20,0.06)", display: "flex", alignItems: "center", gap: 16, background: "linear-gradient(180deg,#fdfbf8,#fff)" }}>
        <span style={{ flex: "none", display: "inline-flex", alignItems: "center", gap: 7, fontFamily: "var(--f-mono)", fontSize: 9.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--accent)" }}>
          <span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--accent)", animation: "gm-dot-pulse 1.4s ease-in-out infinite" }} />{sc.src}
        </span>
        <div style={{ flex: 1, minWidth: 0, fontSize: 15, lineHeight: 1.45, color: "var(--ink-2)" }}>
          {sc.noQuote ? (
            <span style={{ fontStyle: "italic", color: "var(--ink-3)" }}>{sc.pre}</span>
          ) : (
            <>
              <span style={{ color: "var(--ink-3)" }}>“</span>{sc.pre}
              <span style={{ background: hiOn ? "color-mix(in srgb, var(--accent) 16%, transparent)" : "transparent", color: hiOn ? "var(--accent)" : "inherit", fontWeight: 600, padding: "1px 4px", borderRadius: 5, transition: "all 0.3s ease" }}>{sc.hi}</span>
              {sc.post}<span style={{ color: "var(--ink-3)" }}>”</span>
            </>
          )}
        </div>
        <span style={{ flex: "none", display: "inline-flex", alignItems: "center", gap: 9, fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)" }}>
          {sorting && <span style={{ width: 11, height: 11, borderRadius: "50%", border: "1.5px solid rgba(237,77,134,0.25)", borderTopColor: "var(--accent)", animation: "gm-spin 0.7s linear infinite" }} />}
          {phase === "reading" ? "reading…" : sorting ? "matching a category…" : `→ ${MEM_TAG_COLS[sc.col].name}`}
        </span>
      </div>

      <div className="memtag-grid" style={{ flex: 1, minHeight: 0, display: "grid" }}>
        {MEM_TAG_COLS.map((c, ci) => (
          <div key={c.name} style={{ borderRight: "1px solid rgba(20,20,20,0.06)", borderBottom: "1px solid rgba(20,20,20,0.06)", padding: "16px 18px", display: "flex", flexDirection: "column", minHeight: 0, background: phase === "placed" && sc.col === ci ? "rgba(237,77,134,0.035)" : "#fff", transition: "background 0.4s ease" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12, flex: "none" }}>
              <span style={{ width: 8, height: 8, borderRadius: "50%", background: c.color }} />
              <span style={{ fontFamily: "var(--f-display)", fontSize: 16, color: "var(--ink)" }}>{c.name}</span>
              <span style={{ marginLeft: "auto", fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-3)" }}>{placed[ci].length}</span>
            </div>
            <div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", gap: 7, overflow: "hidden" }}>
              {placed[ci].map((p) => (
                <div key={p.chip + p.val} style={{ padding: "7px 11px", borderRadius: 9, border: `1px solid ${p.fresh ? "rgba(237,77,134,0.45)" : "rgba(20,20,20,0.07)"}`, background: p.fresh ? "rgba(237,77,134,0.05)" : "#fdfcfa" }}>
                  <div style={{ fontFamily: "var(--f-mono)", fontSize: 8.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", color: c.color }}>{p.chip}</div>
                  <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.val}</div>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>

      <div style={{ flex: "none", padding: "14px 26px", textAlign: "center", fontFamily: "var(--f-mono)", fontSize: 10.5, letterSpacing: "0.04em", color: "var(--ink-3)", background: "#fdfbf8" }}>
        38 first-class categories · custom categories per property · <span style={{ color: "var(--ink)" }}>all queryable from segments</span>
      </div>
    </div>
    </>
  );
}

/* ============================================================
 * 4. PROVENANCE / ADMIN DRILL-DOWN
 * ============================================================ */
const MEM_PROV_SEED = [
  { cat: "Special date", val: "Anniversary · 14 May, annual", src: "Voice · Apr 22", conf: "0.96" },
  { cat: "Pet", val: "Dachshund · Frankie · 8 kg", src: "WhatsApp · Mar 12", conf: "0.94" },
  { cat: "Allergy", val: "Shellfish · severe", src: "WhatsApp · Feb 03", conf: "0.97" },
  { cat: "Dietary", val: "Partner vegetarian", src: "Email · Apr 04", conf: "0.91" },
  { cat: "Stay pref", val: "High floor, sea view", src: "Inferred · 2 stays", conf: "0.88" },
  { cat: "Quiet room", val: "Away from lobby", src: "Email · Apr 04", conf: "0.89" },
  { cat: "Loyalty tier", val: "Gold · since 2022", src: "PMS · synced", conf: "0.99" },
];
const MEM_GM_MARK = (
  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
    <path d="M12 5.4a3 3 0 0 0-5.7-1.3A2.7 2.7 0 0 0 4 7a2.7 2.7 0 0 0-1 4.6A2.8 2.8 0 0 0 4.6 16a2.6 2.6 0 0 0 3.4 2.4A2.6 2.6 0 0 0 12 19.4z" />
    <path d="M12 5.4a3 3 0 0 1 5.7-1.3A2.7 2.7 0 0 1 20 7a2.7 2.7 0 0 1 1 4.6A2.8 2.8 0 0 1 19.4 16a2.6 2.6 0 0 1-3.4 2.4A2.6 2.6 0 0 1 12 19.4z" />
    <path d="M12 5.4V19.4" />
  </svg>
);
function MemAdminTopbar() {
  return (
    <div style={{ height: 38, flex: "none", background: "#15121a", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 16px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 13 }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--f-mono)", fontSize: 9.5, fontWeight: 600, letterSpacing: "0.1em", color: "#F48BB4" }}><span style={{ width: 6, height: 6, borderRadius: "50%", background: "#F48BB4" }} />ADMIN</span>
        <span style={{ color: "#fff", fontSize: 12, fontWeight: 600 }}>Marenia Collection</span>
        <svg width="9" height="9" viewBox="0 0 12 12" fill="none" stroke="#6b6675" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M3 4.5l3 3 3-3" /></svg>
      </div>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 6, color: "#8b8694", fontSize: 11 }}>
        <svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"><path d="M6.5 3L3.5 6l3 3 M3.5 6h5.5" /></svg>Back to Admin
      </span>
    </div>
  );
}
const MEM_PROV_DETAILS = [
  {
    i: 0,
    confNote: "Stated directly by the guest and confirmed on a later stay. High enough to be used without review.",
    prov: [["Channel", "Voice · +30 210 ••• •72"], ["Extracted", "Apr 22, 14:08 · Concierge agent"], ["Message ID", "msg_9f31c · turn 4"], ["Scope", "Group-wide · all properties"]],
    msgPre: "We are coming back in May, ", msgHi: "it’s our anniversary", msgPost: ", so we would love something special.",
    uses: ["Pre-stay journey · T-21d", "Concierge agent replies", "Segment · upcoming anniversary"],
  },
  {
    i: 1,
    confNote: "Named entity plus a weight, both stated in the same message. Re-confirmed at the last check-in.",
    prov: [["Channel", "WhatsApp · +30 210 ••• •72"], ["Extracted", "Mar 12, 09:41 · Memory extractor"], ["Message ID", "msg_71ba4 · turn 2"], ["Scope", "Group-wide · all properties"]],
    msgPre: "Same suite if possible? ", msgHi: "Frankie", msgPost: " is coming, hope that’s still ok 🐶",
    uses: ["Room note · housekeeping", "WhatsApp pet welcome kit", "Segment · pet-parents"],
  },
  {
    i: 2,
    confNote: "Safety-relevant category. Always surfaced to staff and never auto-expired, whatever the confidence.",
    prov: [["Channel", "WhatsApp · +30 210 ••• •72"], ["Extracted", "Feb 03, 18:22 · Memory extractor"], ["Message ID", "msg_44c07 · turn 7"], ["Scope", "Group-wide · flagged to F&B"]],
    msgPre: "One important thing: ", msgHi: "no shellfish for me, it’s serious", msgPost: ", anaphylaxis.",
    uses: ["Kitchen allergen flag", "Room service checks", "Concierge agent replies"],
  },
];

function MemoryProvenanceDemo() {
  const [idx, setIdx] = useStateMem(0);
  const [phase, setPhase] = useStateMem("closed");
  const timers = useRefMem([]);

  useEffectMem(() => {
    let alive = true;
    const schedule = (fn, ms) => { const id = setTimeout(() => { if (alive) fn(); }, ms); timers.current.push(id); return id; };
    setPhase("opening");
    schedule(() => setPhase("conf"), 700);
    schedule(() => setPhase("source"), 1900);
    schedule(() => setPhase("usage"), 3200);
    schedule(() => setIdx((i) => (i + 1) % MEM_PROV_DETAILS.length), 5600);
    return () => { alive = false; timers.current.forEach(clearTimeout); timers.current = []; };
  }, [idx]);

  const rowRank = { closed: 0, opening: 1, conf: 2, source: 3, usage: 4 }[phase] || 0;
  const seedRow = MEM_PROV_SEED[idx % MEM_PROV_SEED.length];
  const detail = MEM_PROV_DETAILS[idx % MEM_PROV_DETAILS.length];
  const color = memCatColor(seedRow.cat);
  const openRowIdx = idx % MEM_PROV_DETAILS.length;

  return (
    <div style={{ marginTop: 48, borderRadius: 14, overflow: "hidden", boxShadow: "0 50px 100px -34px rgba(45,20,35,0.42), 0 8px 24px rgba(0,0,0,0.07)", border: "1px solid rgba(20,20,20,0.10)", background: "#fff", height: 880, display: "flex", flexDirection: "column" }}>
      <MemAdminTopbar />

      <div style={{ height: 50, flex: "none", background: "#fff", borderBottom: "1px solid rgba(20,20,20,0.08)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 18px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
          <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="var(--ink-3)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M10 3L5 8l5 5" /></svg>
          <span style={{ width: 26, height: 26, borderRadius: 7, background: "linear-gradient(135deg,var(--accent),#C42E68)", display: "flex", alignItems: "center", justifyContent: "center" }}>{MEM_GM_MARK}</span>
          <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink)" }}>Guest Memories</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 20, fontSize: 12.5, color: "var(--ink-3)", overflowX: "auto", scrollbarWidth: "none" }}>
          <span style={{ color: "var(--ink)", fontWeight: 600, borderBottom: "2px solid var(--accent)", paddingBottom: 15, marginBottom: -16 }}>Profiles</span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>Review queue <span style={{ background: "var(--ink)", color: "#fff", fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, padding: "1px 6px", borderRadius: 9 }}>7</span></span>
          <span>Categories</span><span>Segments</span><span>Journeys</span><span>Analytics</span>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="var(--ink-4)" strokeWidth="1.5" strokeLinecap="round"><path d="M3 3l8 8 M11 3l-8 8" /></svg>
        </div>
      </div>

      <div style={{ position: "relative", flex: 1, minHeight: 0, background: "#faf9f6", overflow: "hidden" }}>
        <div style={{ position: "absolute", inset: 0, padding: "26px 30px", overflow: "hidden" }}>
          <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 24 }}>
            <div style={{ display: "flex", gap: 14 }}>
              <span style={{ flex: "none", width: 46, height: 46, borderRadius: "50%", background: "radial-gradient(circle at 35% 30%, #F8B7CF, var(--accent) 58%, #C42E68)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", fontSize: 15, fontWeight: 700 }}>DM</span>
              <div>
                <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                  <span style={{ fontSize: 22, fontWeight: 700, letterSpacing: "-0.01em", color: "var(--ink)" }}>Dimitri Mitsopoulos</span>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", padding: "3px 8px", borderRadius: 6, background: "rgba(237,77,134,0.10)", color: "var(--accent)" }}>Gold · since 2022</span>
                </div>
                <div style={{ fontSize: 13, lineHeight: 1.5, color: "var(--ink-3)", maxWidth: 600, marginTop: 4 }}>Profile #84412 · 6 stays across 3 properties · last seen on WhatsApp today. Memories are shared across the group; property-scoped memories stay with their hotel.</div>
              </div>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 14, flex: "none" }}>
              <svg width="16" height="16" viewBox="0 0 18 18" fill="none" stroke="var(--ink-3)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M15 4v4h-4 M3 14v-4h4 M14.5 8a6 6 0 0 0-10.6-2.5L3 8 M3.5 10a6 6 0 0 0 10.6 2.5L15 10" /></svg>
              <span style={{ display: "inline-flex", alignItems: "center", gap: 7, background: "var(--ink)", color: "#fff", fontSize: 13, fontWeight: 600, padding: "9px 15px", borderRadius: 9 }}>
                <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#fff" strokeWidth="1.7" strokeLinecap="round"><path d="M6 2v8 M2 6h8" /></svg>Add memory
              </span>
            </div>
          </div>

          <div style={{ marginTop: 20, display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, overflow: "hidden", background: "#fff" }}>
            {[["MEMORIES", "47", "on this profile"], ["CATEGORIES", "19", "of 38 in use"], ["SOURCES", "5", "channels contributing"], ["EDITED BY STAFF", "3", "corrections kept"]].map(([k, v, s], i) => (
              <div key={k} style={{ padding: "16px 20px", borderLeft: i > 0 ? "1px solid rgba(20,20,20,0.07)" : "none" }}>
                <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, letterSpacing: "0.08em", color: "var(--ink-4)" }}>{k}</div>
                <div style={{ fontSize: 22, fontWeight: 700, color: "var(--ink)", marginTop: 2 }}>{v}</div>
                <div style={{ fontSize: 11, color: "var(--ink-3)" }}>{s}</div>
              </div>
            ))}
          </div>

          <div style={{ marginTop: 18, display: "flex", alignItems: "center", gap: 16 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--f-mono)", fontSize: 10, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--ink-3)" }}>
              <svg width="12" height="12" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"><path d="M2 3h10 M4 7h6 M6 11h2" /></svg>Filter
            </span>
            <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--accent)" }}>All</span>
            <span style={{ fontSize: 12.5, color: "var(--ink-3)" }}>Stated</span>
            <span style={{ fontSize: 12.5, color: "var(--ink-3)" }}>Inferred</span>
            <span style={{ fontSize: 12.5, color: "var(--ink-3)" }}>Staff-added</span>
            <span style={{ marginLeft: "auto", fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-4)" }}>Sorted by last updated</span>
          </div>

          <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 9 }}>
            {MEM_PROV_SEED.map((r, i) => {
              const open = i === openRowIdx && rowRank >= 1;
              const rc = memCatColor(r.cat);
              return (
                <div key={r.cat} style={{ border: `1px solid ${open ? "rgba(237,77,134,0.45)" : "rgba(20,20,20,0.08)"}`, borderRadius: 12, padding: "12px 16px", background: open ? "rgba(237,77,134,0.04)" : "#fff", display: "flex", alignItems: "center", gap: 14, transition: "all 0.35s ease" }}>
                  <span style={{ width: 8, height: 8, borderRadius: "50%", flex: "none", background: rc }} />
                  <span style={{ flex: "none", fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", padding: "3px 8px", borderRadius: 6, color: rc, background: `color-mix(in srgb, ${rc} 14%, transparent)`, width: 112, textAlign: "center" }}>{r.cat}</span>
                  <span style={{ flex: 1, minWidth: 0, fontSize: 13.5, color: "var(--ink)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.val}</span>
                  <span style={{ flex: "none", fontFamily: "var(--f-mono)", fontSize: 10, color: "var(--ink-3)", width: 150, textAlign: "right" }}>{r.src}</span>
                  <span style={{ flex: "none", display: "flex", alignItems: "center", gap: 7, width: 96 }}>
                    <span style={{ flex: 1, height: 4, borderRadius: 999, background: "rgba(20,20,20,0.07)", overflow: "hidden" }}><span style={{ display: "block", height: "100%", width: `${Math.round(parseFloat(r.conf) * 100)}%`, background: rc }} /></span>
                    <span style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-3)" }}>{r.conf}</span>
                  </span>
                  <span style={{ flex: "none", fontSize: 11.5, color: "var(--accent)" }}>Open</span>
                </div>
              );
            })}
          </div>
        </div>

        {rowRank >= 1 && (
          <>
            <div style={{ position: "absolute", inset: 0, background: "rgba(20,14,20,0.46)" }} />
            <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", padding: 16 }}>
              <div style={{ width: 620, maxWidth: "100%", maxHeight: "100%", background: "#fff", borderRadius: 16, boxShadow: "0 40px 90px -30px rgba(0,0,0,0.5)", display: "flex", flexDirection: "column", overflow: "hidden" }}>
                <div style={{ padding: "20px 26px 16px", flex: "none", borderBottom: "1px solid rgba(20,20,20,0.06)" }}>
                  <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
                    <div style={{ minWidth: 0 }}>
                      <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", padding: "3px 9px", borderRadius: 6, color, background: `color-mix(in srgb, ${color} 14%, transparent)` }}>{seedRow.cat}</span>
                      <div style={{ fontFamily: "var(--f-display)", fontSize: 26, letterSpacing: "-0.01em", color: "var(--ink)", marginTop: 10 }}>{seedRow.val}</div>
                    </div>
                    <svg width="15" height="15" viewBox="0 0 14 14" fill="none" stroke="var(--ink-4)" strokeWidth="1.5" strokeLinecap="round" style={{ flex: "none", marginTop: 4 }}><path d="M3 3l8 8 M11 3l-8 8" /></svg>
                  </div>
                </div>

                <div style={{ padding: "18px 26px", display: "flex", flexDirection: "column", gap: 16, flex: 1, minHeight: 0, overflow: "hidden" }}>
                  <div>
                    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }}>
                      <span style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--ink-3)" }}>Confidence</span>
                      <span style={{ fontFamily: "var(--f-mono)", fontSize: 11, fontWeight: 600, color }}>{rowRank >= 2 ? seedRow.conf : ""}</span>
                    </div>
                    <div style={{ height: 6, borderRadius: 999, background: "rgba(20,20,20,0.06)", overflow: "hidden" }}>
                      <div style={{ height: "100%", borderRadius: 999, width: rowRank >= 2 ? `${Math.round(parseFloat(seedRow.conf) * 100)}%` : "0%", background: "linear-gradient(90deg,var(--accent),#C42E68)", transition: "width 0.7s cubic-bezier(0.22,0.61,0.36,1)" }} />
                    </div>
                    <div style={{ marginTop: 7, fontSize: 11.5, color: "var(--ink-3)" }}>{detail.confNote}</div>
                  </div>

                  <div style={{ border: "1px solid rgba(20,20,20,0.08)", borderRadius: 12, overflow: "hidden", background: "#faf9f6" }}>
                    <div style={{ padding: "9px 14px", borderBottom: "1px solid rgba(20,20,20,0.06)", fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--ink-3)" }}>Provenance</div>
                    {detail.prov.map(([k, v]) => (
                      <div key={k} style={{ display: "flex", alignItems: "center", gap: 14, padding: "8px 14px", borderBottom: "1px solid rgba(20,20,20,0.04)" }}>
                        <span style={{ flex: "none", width: 92, fontFamily: "var(--f-mono)", fontSize: 9, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--ink-4)" }}>{k}</span>
                        <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, color: "var(--ink-2)" }}>{v}</span>
                      </div>
                    ))}
                  </div>

                  {rowRank >= 3 && (
                    <div style={{ animation: "gm-fade-up 0.4s ease both" }}>
                      <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--ink-3)", marginBottom: 8 }}>The original message</div>
                      <div style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
                        <span style={{ flex: "none", width: 26, height: 26, borderRadius: "50%", background: "#efe9e1", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 600, color: "var(--ink-3)" }}>DM</span>
                        <div style={{ background: "#f4f1ec", border: "1px solid rgba(20,20,20,0.05)", borderRadius: "3px 13px 13px 13px", padding: "10px 14px", fontSize: 13.5, lineHeight: 1.5, color: "var(--ink)" }}>{detail.msgPre}<span style={{ background: `color-mix(in srgb, ${color} 14%, transparent)`, color, fontWeight: 600, padding: "1px 4px", borderRadius: 5 }}>{detail.msgHi}</span>{detail.msgPost}</div>
                      </div>
                    </div>
                  )}

                  {rowRank >= 4 && (
                    <div style={{ animation: "gm-fade-up 0.4s ease both" }}>
                      <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--ink-3)", marginBottom: 8 }}>Where it is read</div>
                      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                        {detail.uses.map((u) => (
                          <span key={u} style={{ display: "inline-flex", alignItems: "center", gap: 7, padding: "6px 11px", borderRadius: 8, border: "1px solid rgba(237,77,134,0.18)", background: "rgba(237,77,134,0.05)", fontSize: 11.5, color: "var(--ink-2)" }}>
                            <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--accent)" }} />{u}
                          </span>
                        ))}
                      </div>
                    </div>
                  )}

                  <div style={{ display: "flex", gap: 9, alignItems: "flex-start", padding: "10px 13px", borderRadius: 10, background: "rgba(237,77,134,0.06)", border: "1px solid rgba(237,77,134,0.14)" }}>
                    <svg width="13" height="13" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinejoin="round" style={{ flex: "none" }}><path d="M9 2.2l6 2.1v4.4c0 3.6-2.7 5.6-6 6.6-3.3-1-6-3-6-6.6V4.3z" /></svg>
                    <span style={{ fontSize: 11, lineHeight: 1.45, color: "#8a6b78" }}>This memory lives in your tenant only. It is never used to train a shared model, and forgetting it removes it from every agent, segment and journey immediately.</span>
                  </div>
                </div>

                <div style={{ flex: "none", padding: "13px 26px", borderTop: "1px solid rgba(20,20,20,0.06)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                  <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: 12.5, color: "var(--ink-3)" }}>
                    <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"><path d="M2 7h10 M7 2v10" /></svg>Edit value
                  </span>
                  <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                    <span style={{ border: "1px solid rgba(20,20,20,0.14)", color: "var(--ink-2)", fontSize: 13, fontWeight: 600, padding: "8px 15px", borderRadius: 9 }}>Forget</span>
                    <span style={{ background: "var(--ink)", color: "#fff", fontSize: 13, fontWeight: 600, padding: "9px 18px", borderRadius: 9 }}>Pin to profile</span>
                  </div>
                </div>
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

/* ============================================================
 * 5. SEGMENTS & JOURNEYS
 * ============================================================ */
const MEM_SG_RULES = [
  { join: "Where", field: "Memory · Pet", op: "is", val: "any" },
  { join: "And", field: "Memory · Special date", op: "within", val: "next 30 days" },
  { join: "And", field: "Stays", op: "≥", val: "2" },
];
const MEM_SG_COUNTS = [4180, 962, 284];
const MEM_SG_STEPS = [
  { t: "T-21d", label: "Email · “We’ve blocked your usual suite”", reads: "Stay pref · Last stay" },
  { t: "T-14d", label: "WhatsApp · pet welcome kit upsell", reads: "Pet" },
  { t: "T-7d", label: "Email · anniversary tasting menu offer", reads: "Special date · Dietary" },
  { t: "T-1d", label: "SMS · “Frankie’s bed is ready”", reads: "Pet · Bed setup" },
];

function MemorySegmentJourneyDemo() {
  const [cycleKey, setCycleKey] = useStateMem(0);
  const [step, setStep] = useStateMem(0);
  const [count, setCount] = useStateMem(MEM_SG_COUNTS[0]);
  const [showJourney, setShowJourney] = useStateMem(false);
  const [sent, setSent] = useStateMem(0);
  const timers = useRefMem([]);

  useEffectMem(() => {
    let alive = true;
    const schedule = (fn, ms) => { const id = setTimeout(() => { if (alive) fn(); }, ms); timers.current.push(id); return id; };

    setStep(0); setCount(MEM_SG_COUNTS[0]); setShowJourney(false); setSent(0);
    for (let i = 1; i <= 3; i++) {
      schedule(() => { setStep(i); setCount(MEM_SG_COUNTS[i - 1]); }, i * 1100);
    }
    schedule(() => setShowJourney(true), 4200);
    for (let k = 1; k <= 4; k++) schedule(() => setSent(k), 4500 + k * 750);
    schedule(() => setCycleKey((k) => k + 1), 9800);
    return () => { alive = false; timers.current.forEach(clearTimeout); timers.current = []; };
  }, [cycleKey]);

  const recomputing = step > 0 && step < 3;

  return (
    <>
      <div style={{ marginTop: 50, background: "#fff", border: "1px solid rgba(20,20,20,0.07)", borderRadius: 22, boxShadow: "0 44px 86px -30px rgba(45,20,35,0.32), 0 4px 14px rgba(0,0,0,0.05)", overflow: "hidden", padding: 34, display: "flex", flexWrap: "wrap", gap: 26, alignItems: "stretch", minHeight: 600 }}>
        <div style={{ flex: "1 1 360px", minWidth: 0, border: "1px solid rgba(20,20,20,0.08)", borderRadius: 16, padding: "24px 26px", display: "flex", flexDirection: "column", background: "linear-gradient(180deg,#fdfbf8,#fff)" }}>
          <span style={{ alignSelf: "flex-start", fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", padding: "3px 9px", borderRadius: 6, background: "rgba(237,77,134,0.10)", color: "var(--accent)" }}>Segment</span>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 24, letterSpacing: "-0.01em", color: "var(--ink)", marginTop: 12 }}>Returning pet-parents · upcoming anniversary</div>
          <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginTop: 10 }}>
            <span style={{ fontFamily: "var(--f-display)", fontSize: 44, lineHeight: 1, color: "var(--ink)" }}>{count.toLocaleString("en-US")}</span>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 11, color: "var(--ink-3)" }}>guests</span>
            {recomputing && (
              <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--accent)" }}>
                <span style={{ width: 10, height: 10, borderRadius: "50%", border: "1.5px solid rgba(237,77,134,0.25)", borderTopColor: "var(--accent)", animation: "gm-spin 0.7s linear infinite" }} />recomputing
              </span>
            )}
          </div>

          <div style={{ marginTop: 22, display: "flex", flexDirection: "column", gap: 9, flex: 1 }}>
            {MEM_SG_RULES.map((r, i) => (
              <div key={r.field} style={{ display: "flex", flexDirection: "column", gap: 7, padding: "12px 14px", borderRadius: 11, border: `1px solid ${i === step - 1 ? "rgba(237,77,134,0.4)" : "rgba(20,20,20,0.08)"}`, background: i === step - 1 ? "rgba(237,77,134,0.05)" : "#fff", opacity: i < step ? 1 : 0.28, transition: "opacity 0.4s ease, border-color 0.4s ease, background 0.4s ease" }}>
                <span style={{ display: "flex", alignItems: "baseline", gap: 9, minWidth: 0 }}>
                  <span style={{ flex: "none", fontFamily: "var(--f-mono)", fontSize: 9, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--ink-4)" }}>{r.join}</span>
                  <span style={{ flex: 1, minWidth: 0, fontSize: 13.5, fontWeight: 600, color: "var(--ink)" }}>{r.field}</span>
                </span>
                <span style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 10, padding: "3px 8px", borderRadius: 6, background: "rgba(20,20,20,0.05)", color: "var(--ink-3)", whiteSpace: "nowrap" }}>{r.op}</span>
                  <span style={{ fontSize: 12.5, color: "var(--ink-2)" }}>{r.val}</span>
                </span>
              </div>
            ))}
          </div>

          <div style={{ marginTop: 16, paddingTop: 14, borderTop: "1px dashed rgba(20,20,20,0.10)", display: "flex", alignItems: "center", gap: 8, fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--ink-3)" }}>
            <span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--accent)", animation: "gm-dot-pulse 1.6s ease-in-out infinite" }} />Live count · recomputed every minute
          </div>
        </div>

        <div style={{ flex: "1 1 360px", minWidth: 0, border: "1px solid rgba(20,20,20,0.08)", borderRadius: 16, padding: "24px 26px", display: "flex", flexDirection: "column", background: "linear-gradient(180deg,#fdfbf8,#fff)" }}>
          <span style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <span style={{ fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", padding: "3px 9px", borderRadius: 6, background: "rgba(91,107,176,0.12)", color: "#5b6bb0" }}>Journey</span>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontFamily: "var(--f-mono)", fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.07em", padding: "3px 9px", borderRadius: 6, background: "rgba(237,77,134,0.08)", color: "var(--accent)" }}>
              <svg width="14" height="9" viewBox="0 0 16 10" fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M14 5H2 M6 1L2 5l4 4" /></svg>Driven by this segment
            </span>
          </span>
          <div style={{ fontFamily: "var(--f-display)", fontSize: 24, letterSpacing: "-0.01em", color: "var(--ink)", marginTop: 12 }}>Anniversary pre-stay · pet-parents</div>
          <div style={{ fontSize: 12.5, color: "var(--ink-3)", marginTop: 6 }}>Each step re-reads the guest’s own memories at send time.</div>

          <div style={{ marginTop: 20, display: "flex", flexDirection: "column", gap: 9, flex: 1 }}>
            {MEM_SG_STEPS.map((s, i) => {
              const sent2 = showJourney && i < sent;
              return (
                <div key={s.t} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 14px", borderRadius: 11, border: `1px solid ${sent2 ? "rgba(79,157,143,0.35)" : "rgba(20,20,20,0.08)"}`, background: sent2 ? "rgba(79,157,143,0.05)" : "#fff", opacity: showJourney ? (sent2 ? 1 : 0.34) : 0.2, transition: "opacity 0.4s ease, border-color 0.4s ease, background 0.4s ease" }}>
                  <span style={{ flex: "none", fontFamily: "var(--f-mono)", fontSize: 10, fontWeight: 600, color: "#5b6bb0", width: 38 }}>{s.t}</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, lineHeight: 1.4, color: "var(--ink)" }}>{s.label}</div>
                    <div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-4)", marginTop: 2 }}>reads · {s.reads}</div>
                  </div>
                  {sent2 && (
                    <span style={{ flex: "none", width: 18, height: 18, borderRadius: "50%", background: "#4f9d8f", display: "flex", alignItems: "center", justifyContent: "center" }}>
                      <svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="#fff" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M2.5 6.2l2.2 2.2L9.5 3.5" /></svg>
                    </span>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      </div>

      <div style={{ marginTop: 32, textAlign: "center", fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.04em", color: "var(--ink-3)" }}>
        Any memory category is a filter field · <span style={{ color: "var(--ink)" }}>segments recompute themselves</span> · journeys personalise at send, not at build.
      </div>
    </>
  );
}

/* ============================================================
 * 6. ANALYTICS
 * ============================================================ */
const MEM_AN_TOTALS = [70, 82, 95, 118, 150, 132, 148, 122, 138, 152, 141, 162, 178, 166, 186, 200, 174, 158, 152, 204, 232, 224, 214, 152, 176, 226, 234, 212, 124, 96, 62];
const MEM_AN_LABELS = { 0: "May 22", 6: "May 28", 12: "Jun 3", 18: "Jun 9", 24: "Jun 15", 30: "Jun 21" };
const MEM_AN_ROWS = [
  { cat: "Dietary & allergy", group: "Dining", pct: 78, held: "3,412", src: "WhatsApp", used: "High" },
  { cat: "Special dates", group: "Identity", pct: 64, held: "2,802", src: "Voice", used: "High" },
  { cat: "Stay preferences", group: "Stay", pct: 59, held: "2,584", src: "Inferred", used: "High" },
  { cat: "Pets", group: "Identity", pct: 41, held: "1,796", src: "WhatsApp", used: "Medium" },
  { cat: "Trip purpose", group: "Behaviour", pct: 33, held: "1,445", src: "Web chat", used: "Medium" },
];
const MEM_AN_ROW_COLORS = ["#5b6bb0", "var(--accent)", "#4f9d8f", "#c06a4f", "#8a6a9c"];
const MEM_AN_USED_COLOR = { High: "#3f8a7d", Medium: "#b8843c" };
const fmtN = (n) => n.toLocaleString("en-US");

const MEM_AN_DESIGN_WIDTH = 1216;

function MemoryAnalytics() {
  const [progress, setProgress] = useStateMem(0);
  const ref = useRefMem(null);
  const wrapRef = useRefMem(null);
  const started = useRefMem(false);
  const [scale, setScale] = useStateMem(1);

  useEffectMem(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting && !started.current) {
        started.current = true;
        let p = 0;
        const int = setInterval(() => {
          p = Math.min(1, p + 0.045);
          setProgress(p);
          if (p >= 1) clearInterval(int);
        }, 24);
        io.disconnect();
      }
    }, { threshold: 0.3 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);

  // This panel is a fixed-chrome admin-screen mockup (392px stat column,
  // a 6-column data table) rather than reflowable content, so it is scaled
  // as a unit to fit its container instead of trying to restack its
  // internals — same technique as the hero flow diagram in memory-page.
  useEffectMem(() => {
    const el = wrapRef.current;
    if (!el || typeof ResizeObserver === "undefined") return;
    const ro = new ResizeObserver((entries) => {
      const w = entries[0].contentRect.width;
      if (w > 0) setScale(Math.min(1, w / MEM_AN_DESIGN_WIDTH));
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  const cu = (n) => Math.round(n * progress);
  const maxTotal = Math.max(...MEM_AN_TOTALS);

  return (
    <div ref={wrapRef} style={{ marginTop: 50, height: 880 * scale, overflow: "hidden" }}>
    <div ref={ref} style={{ width: MEM_AN_DESIGN_WIDTH, borderRadius: 14, overflow: "hidden", boxShadow: "0 50px 100px -34px rgba(45,20,35,0.42), 0 8px 24px rgba(0,0,0,0.07)", border: "1px solid rgba(20,20,20,0.10)", background: "#fff", height: 880, display: "flex", flexDirection: "column", transform: `scale(${scale})`, transformOrigin: "top left" }}>
      <MemAdminTopbar />

      <div style={{ height: 50, flex: "none", background: "#fff", borderBottom: "1px solid rgba(20,20,20,0.08)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 18px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
          <span style={{ width: 26, height: 26, borderRadius: 7, background: "linear-gradient(135deg,var(--accent),#C42E68)", display: "flex", alignItems: "center", justifyContent: "center" }}>{MEM_GM_MARK}</span>
          <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink)" }}>Guest Memories</span>
          <span style={{ width: 1, height: 16, background: "rgba(20,20,20,0.12)" }} />
          <span style={{ fontSize: 13, color: "var(--ink-3)" }}>Analytics</span>
        </div>
      </div>

      <div style={{ flex: "none", padding: "16px 24px", display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 12, borderBottom: "1px solid rgba(20,20,20,0.05)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 2, background: "#f4f1ec", borderRadius: 9, padding: 3, fontSize: 11.5, color: "var(--ink-3)" }}>
          {["24H", "7D", "14D", "1M", "3M"].map((t) => (
            <span key={t} style={{ padding: "5px 10px", borderRadius: 7, background: t === "1M" ? "#fff" : "transparent", color: t === "1M" ? "var(--ink)" : "inherit", fontWeight: t === "1M" ? 600 : 400, boxShadow: t === "1M" ? "0 1px 2px rgba(0,0,0,0.06)" : "none" }}>{t}</span>
          ))}
        </div>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 7, border: "1px solid rgba(20,20,20,0.12)", borderRadius: 9, padding: "7px 12px", fontSize: 12, color: "var(--ink-2)" }}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="var(--ink-3)" strokeWidth="1.3"><rect x="2" y="3" width="10" height="9" rx="1.5" /><path d="M2 5.5h10 M4.5 1.5V3.5 M9.5 1.5V3.5" /></svg>May 22 – Jun 21, 2026
        </span>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 7, border: "1px solid rgba(20,20,20,0.12)", borderRadius: 9, padding: "7px 12px", fontSize: 12, color: "var(--ink-2)" }}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="var(--ink-3)" strokeWidth="1.3" strokeLinejoin="round"><path d="M2 12V5l5-3 5 3v7 M5.5 12V8.5h3V12" /></svg>All Hotels<svg width="9" height="9" viewBox="0 0 12 12" fill="none" stroke="var(--ink-4)" strokeWidth="1.4"><path d="M3 4.5l3 3 3-3" /></svg>
        </span>
      </div>

      <div style={{ flex: 1, minHeight: 0, overflow: "hidden", padding: "22px 24px", display: "flex", flexDirection: "column", gap: 18 }}>
        <div style={{ display: "flex", gap: 18 }}>
          <div style={{ width: 392, flex: "none", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
            <div style={{ border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, padding: 16 }}>
              <span style={{ display: "inline-flex", width: 30, height: 30, borderRadius: 9, background: "rgba(237,77,134,0.08)", alignItems: "center", justifyContent: "center", marginBottom: 12 }}><svg width="15" height="15" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.4" strokeLinejoin="round"><path d="M3 4h12v8H7l-3 3z" /></svg></span>
              <div style={{ fontSize: 24, fontWeight: 700, color: "var(--ink)" }}>{fmtN(cu(18420))}</div>
              <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink)", marginTop: 2 }}>Memories captured</div>
              <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>across every channel</div>
            </div>
            <div style={{ border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, padding: 16 }}>
              <span style={{ display: "inline-flex", width: 30, height: 30, borderRadius: 9, background: "rgba(237,77,134,0.08)", alignItems: "center", justifyContent: "center", marginBottom: 12 }}><svg width="15" height="15" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="9" r="6.5" /><path d="M6 9l2 2 4-4" /></svg></span>
              <div style={{ fontSize: 24, fontWeight: 700, color: "var(--ink)" }}>{cu(72)}%</div>
              <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink)", marginTop: 2 }}>Used in a reply</div>
              <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>within 30 days of capture</div>
            </div>
            <div style={{ border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, padding: 16 }}>
              <span style={{ display: "inline-flex", width: 30, height: 30, borderRadius: 9, background: "rgba(237,77,134,0.08)", alignItems: "center", justifyContent: "center", marginBottom: 12 }}><svg width="15" height="15" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="6.2" r="2.8" /><path d="M3.6 15c0-2.9 2.4-4.4 5.4-4.4s5.4 1.5 5.4 4.4" /></svg></span>
              <div style={{ fontSize: 24, fontWeight: 700, color: "var(--ink)" }}>{fmtN(cu(5137))}</div>
              <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink)", marginTop: 2 }}>Guests with a profile</div>
              <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>at least one memory held</div>
            </div>
            <div style={{ border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, padding: 16 }}>
              <span style={{ display: "inline-flex", width: 30, height: 30, borderRadius: 9, background: "rgba(237,77,134,0.08)", alignItems: "center", justifyContent: "center", marginBottom: 12 }}><svg width="15" height="15" viewBox="0 0 18 18" fill="none" stroke="var(--accent)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M9 2.5L16 15H2z" /><path d="M9 7v3.5 M9 12.7v0.2" /></svg></span>
              <div style={{ fontSize: 24, fontWeight: 700, color: "var(--ink)" }}>{cu(6)}</div>
              <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink)", marginTop: 2 }}>Thin categories</div>
              <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>under-captured, worth prompting</div>
            </div>
          </div>

          <div style={{ flex: 1, minWidth: 0, border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, padding: "18px 20px", display: "flex", flexDirection: "column" }}>
            <div style={{ fontSize: 14, fontWeight: 700, color: "var(--ink)" }}>Captured vs used</div>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 2 }}>Daily memories captured, and how many were read by an agent or journey</div>
            <div style={{ display: "flex", gap: 34, marginTop: 14 }}>
              <div style={{ borderLeft: "3px solid #F8B7CF", paddingLeft: 9 }}><div style={{ fontSize: 17, fontWeight: 700, color: "var(--ink)" }}>{fmtN(cu(4482))}</div><div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--ink-3)" }}>Captured</div></div>
              <div style={{ borderLeft: "3px solid var(--accent)", paddingLeft: 9 }}><div style={{ fontSize: 17, fontWeight: 700, color: "var(--ink)" }}>{fmtN(cu(3226))}</div><div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--ink-3)" }}>Read in a reply</div></div>
              <div style={{ borderLeft: "3px solid #4f9d8f", paddingLeft: 9 }}><div style={{ fontSize: 17, fontWeight: 700, color: "var(--ink)" }}>{fmtN(cu(148))}</div><div style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--ink-3)" }}>Staff corrections</div></div>
            </div>
            <div style={{ flex: 1, display: "flex", alignItems: "flex-end", gap: 3, marginTop: 16, minHeight: 0 }}>
              {MEM_AN_TOTALS.map((t, i) => {
                const ratio = 0.5 + ((i * 29) % 100) / 100 * 0.24;
                const bh = Math.round((t / maxTotal) * 180);
                const uh = Math.round(bh * ratio);
                return (
                  <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "flex-end", alignItems: "center", height: 180 }}>
                    <div style={{ width: "64%", maxWidth: 15, transform: `scaleY(${progress})`, transformOrigin: "bottom", transition: "transform 0.65s cubic-bezier(0.22,0.61,0.36,1)", transitionDelay: `${(i * 0.02).toFixed(3)}s`, display: "flex", flexDirection: "column", justifyContent: "flex-end" }}>
                      <div style={{ height: `${bh - uh}px`, background: "var(--accent-soft)", borderRadius: "3px 3px 0 0" }} />
                      <div style={{ height: `${uh}px`, background: "var(--accent)" }} />
                    </div>
                  </div>
                );
              })}
            </div>
            <div style={{ display: "flex", gap: 3, marginTop: 7 }}>
              {MEM_AN_TOTALS.map((_, i) => (
                <div key={i} style={{ flex: 1, minWidth: 0, textAlign: "center", fontFamily: "var(--f-mono)", fontSize: 8.5, color: "var(--ink-4)", whiteSpace: "nowrap", overflow: "visible" }}>{MEM_AN_LABELS[i] || ""}</div>
              ))}
            </div>
          </div>
        </div>

        <div style={{ flex: 1, minHeight: 0, border: "1px solid rgba(20,20,20,0.08)", borderRadius: 14, overflow: "hidden", display: "flex", flexDirection: "column" }}>
          <div style={{ padding: "16px 20px 12px" }}>
            <div style={{ fontSize: 14, fontWeight: 700, color: "var(--ink)" }}>Coverage by category</div>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 2 }}>Share of returning guests who have this memory on file, and how often it changed a reply</div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr 2fr 0.8fr 1fr 0.8fr", gap: 10, padding: "8px 20px", borderTop: "1px solid rgba(20,20,20,0.06)", borderBottom: "1px solid rgba(20,20,20,0.06)", fontFamily: "var(--f-mono)", fontSize: 9, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--ink-3)" }}>
            <span>Category</span><span>Group</span><span>Coverage</span><span>Held</span><span>Top source</span><span>Used</span>
          </div>
          <div style={{ flex: 1, minHeight: 0, overflow: "hidden" }}>
            {MEM_AN_ROWS.map((r, i) => (
              <div key={r.cat} style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr 2fr 0.8fr 1fr 0.8fr", gap: 10, alignItems: "center", padding: "10px 20px", borderBottom: "1px solid rgba(20,20,20,0.04)", opacity: progress, transition: "opacity 0.5s ease", transitionDelay: `${(i * 0.05).toFixed(2)}s` }}>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 12.5, color: "var(--ink)" }}><span style={{ width: 7, height: 7, borderRadius: "50%", background: MEM_AN_ROW_COLORS[i] }} />{r.cat}</span>
                <span style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-3)" }}>{r.group}</span>
                <span style={{ display: "flex", alignItems: "center", gap: 9 }}>
                  <span style={{ flex: 1, height: 6, borderRadius: 999, background: "rgba(20,20,20,0.06)", overflow: "hidden" }}><span style={{ display: "block", height: "100%", background: MEM_AN_ROW_COLORS[i], width: `${r.pct * progress}%`, transition: "width 0.7s cubic-bezier(0.22,0.61,0.36,1)", transitionDelay: `${(i * 0.05).toFixed(2)}s` }} /></span>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-2)", width: 34 }}>{cu(r.pct)}%</span>
                </span>
                <span style={{ fontSize: 12, color: "var(--ink-2)" }}>{r.held}</span>
                <span style={{ fontFamily: "var(--f-mono)", fontSize: 9.5, padding: "2px 8px", borderRadius: 6, background: "rgba(20,20,20,0.05)", color: "var(--ink-3)", justifySelf: "flex-start" }}>{r.src}</span>
                <span style={{ fontSize: 12, fontWeight: 600, color: MEM_AN_USED_COLOR[r.used] || "var(--ink-3)" }}>{r.used}</span>
              </div>
            ))}
          </div>
          <div style={{ padding: "11px 20px", borderTop: "1px solid rgba(20,20,20,0.06)", display: "flex", alignItems: "center", justifyContent: "space-between", fontFamily: "var(--f-mono)", fontSize: 10.5, color: "var(--ink-3)" }}>
            <span>Showing 5 of 38 categories</span>
            <span style={{ color: "var(--accent)" }}>Prompt agents to capture thin categories →</span>
          </div>
        </div>
      </div>
    </div>
    </div>
  );
}

/* Expose everything shared.jsx / memory.html need on window,
   matching the convention every other src/*.jsx file uses. */
Object.assign(window, {
  MemPill,
  MemoryCaptureFeed,
  MemoryPrimitives,
  MemoryRetrievalDemo,
  MemoryTaggingDemo,
  MemoryProvenanceDemo,
  MemorySegmentJourneyDemo,
  MemoryAnalytics,
});
