/* atoms.jsx, shared building blocks for every screen.
   Theme context, logo, schematic icons (1.5px stroke), money/delta type,
   the seam, nav bar, buttons, segmented control, and the reusable chart. */

const ThemeCtx = React.createContext("graphite");
const useTheme = () => React.useContext(ThemeCtx);

/* Platform: "mobile" (phone bezel) or "web" (centered/full-screen).
   Web suppresses mobile-only patterns like bottom-sheet drawers. */
const PlatformCtx = React.createContext("mobile");
const usePlatform = () => React.useContext(PlatformCtx);

/* ---------- logo ----------------------------------------------------------- */
const Logo = ({ size = 18, color }) => {
  const p = useTheme();
  const id = p === "bone" ? "logoBlack" : "logoWhite";
  const fallback = p === "bone" ? "assets/logo-mark-black.png" : "assets/logo-mark-white.png";
  const src = (typeof window !== "undefined" && window.__resources && window.__resources[id]) || fallback;
  // CSS-mask render keeps edges crisp at every size by using the alpha as a stencil
  // and painting solid color through it — avoids the soft halo the PNG renders with.
  const ink = color || (p === "bone" ? "#14130f" : "#f0ece2");
  return <span role="img" aria-label="Yoshi" style={{ display: "block", height: size, width: size, background: ink,
    WebkitMaskImage: `url(${src})`, maskImage: `url(${src})`, WebkitMaskSize: "contain", maskSize: "contain",
    WebkitMaskRepeat: "no-repeat", maskRepeat: "no-repeat", WebkitMaskPosition: "center", maskPosition: "center",
    flex: "none" }} />;
};

/* ---------- icons (schematic · 1.5px · square caps) ------------------------ */
const Icon = ({ name, size = 24, stroke = 1.5, color = "currentColor", style }) => {
  const s = { fill: "none", stroke: color, strokeWidth: stroke, strokeLinecap: "square", strokeLinejoin: "miter" };
  const P = {
    home:     <g {...s}><path d="M4 11 L12 4 L20 11" /><path d="M6 10 V20 H18 V10" /></g>,
    inbox:    <g {...s}><circle cx="5.5" cy="7" r="1.7" /><circle cx="5.5" cy="12" r="1.7" /><circle cx="5.5" cy="17" r="1.7" /><line x1="9.5" y1="7" x2="19" y2="7" /><line x1="9.5" y1="12" x2="19" y2="12" /><line x1="9.5" y1="17" x2="19" y2="17" /></g>,
    chat:     <g {...s}><path d="M4 5 H20 V16 H10 L5 20 V16 H4 Z" /></g>,
    accounts: <g {...s}><path d="M4 9 L12 4 L20 9" /><line x1="3.5" y1="9" x2="20.5" y2="9" /><line x1="6" y1="11" x2="6" y2="18" /><line x1="10" y1="11" x2="10" y2="18" /><line x1="14" y1="11" x2="14" y2="18" /><line x1="18" y1="11" x2="18" y2="18" /><line x1="3.5" y1="20" x2="20.5" y2="20" /></g>,
    profile:  <g {...s}><circle cx="12" cy="8.5" r="3.5" /><path d="M5 20 C5 15.5 8 14 12 14 C16 14 19 15.5 19 20" /></g>,
    menu:     <g {...s}><line x1="4" y1="6.5" x2="20" y2="6.5" /><line x1="4" y1="12" x2="20" y2="12" /><line x1="4" y1="17.5" x2="20" y2="17.5" /></g>,
    back:     <g {...s}><path d="M14 5 L7 12 L14 19" /></g>,
    close:    <g {...s}><line x1="6" y1="6" x2="18" y2="18" /><line x1="18" y1="6" x2="6" y2="18" /></g>,
    external: <g {...s}><path d="M14 5 H19 V10" /><line x1="19" y1="5" x2="11" y2="13" /><path d="M17 14 V19 H5 V7 H10" /></g>,
    eye:      <g {...s}><path d="M3 12 C5.5 7.5 8.5 6 12 6 C15.5 6 18.5 7.5 21 12 C18.5 16.5 15.5 18 12 18 C8.5 18 5.5 16.5 3 12 Z" /><circle cx="12" cy="12" r="2.6" /></g>,
    plus:     <g {...s}><line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /></g>,
    arrow:    <g {...s}><line x1="5" y1="12" x2="19" y2="12" /><path d="M13 6 L19 12 L13 18" /></g>,
    up:       <g {...s}><path d="M5 15 L12 8 L19 15" /></g>,
    down:     <g {...s}><path d="M5 9 L12 16 L19 9" /></g>,
    send:     <g {...s}><path d="M4 12 L20 4 L14 20 L11 13 Z" /></g>,
    swap:     <g {...s}><path d="M7 7 H18 L15 4 M18 7 L15 10" /><path d="M17 17 H6 L9 20 M6 17 L9 14" /></g>,
    check:    <g {...s}><path d="M5 12.5 L10 17.5 L19 6.5" /></g>,
    bolt:     <g {...s}><path d="M13 3 L5 13 H11 L10 21 L18 10 H12 Z" /></g>,
    shield:   <g {...s}><path d="M12 3 L19 6 V11 C19 16 16 19 12 21 C8 19 5 16 5 11 V6 Z" /></g>,
    trade:    <g {...s}><path d="M4 16 L9 10 L13 13 L20 5" /><path d="M20 9 V5 H16" /></g>,
    receipt:  <g {...s}><path d="M6 3 H18 V21 L15.5 19.5 L13 21 L10.5 19.5 L8 21 L6 19.5 Z" /><line x1="9" y1="8" x2="15" y2="8" /><line x1="9" y1="12" x2="15" y2="12" /></g>,
    whatsapp: <g {...s}><circle cx="12" cy="12" r="8" /><path d="M9 8.5 C9 13 11 15 15.5 15 L15.5 12.5 L13.5 13 C12 12 12 10.5 11 9 Z" /></g>,
    mail:     <g {...s}><rect x="4" y="6" width="16" height="12" /><path d="M4 7 L12 13 L20 7" /></g>,
    message:  <g {...s}><path d="M4 5 H20 V15 H12 L7 19 V15 H4 Z" /></g>,
    bell:     <g {...s}><path d="M7 17 V10 C7 7 9 5 12 5 C15 5 17 7 17 10 V17 Z" /><line x1="4" y1="17" x2="20" y2="17" /><path d="M10 20 H14" /></g>,
    bulb:     <g {...s}><path d="M9 14.5 C7.2 13.2 6 11.3 6 9 C6 5.7 8.7 3 12 3 C15.3 3 18 5.7 18 9 C18 11.3 16.8 13.2 15 14.5 V16.5 H9 Z" /><line x1="9.5" y1="19.5" x2="14.5" y2="19.5" /><line x1="10.5" y1="22" x2="13.5" y2="22" /></g>,
    dot:      <g><circle cx="12" cy="12" r="4" fill={color} /></g>,
    gear:     <g {...s}><circle cx="12" cy="12" r="6.6" /><circle cx="12" cy="12" r="2.4" /><path d="M12 5.4 V3 M12 18.6 V21 M5.4 12 H3 M18.6 12 H21 M7.2 7.2 L5.5 5.5 M16.8 16.8 L18.5 18.5 M16.8 7.2 L18.5 5.5 M7.2 16.8 L5.5 18.5" /></g>,
    doc:      <g {...s}><path d="M6 3 H14 L18 7 V21 H6 Z" /><path d="M14 3 V7 H18" /><line x1="9" y1="12" x2="15" y2="12" /><line x1="9" y1="15.5" x2="15" y2="15.5" /></g>,
    lifebuoy: <g {...s}><circle cx="12" cy="12" r="8" /><circle cx="12" cy="12" r="3.2" /><path d="M9.7 9.7 L6.3 6.3 M14.3 9.7 L17.7 6.3 M9.7 14.3 L6.3 17.7 M14.3 14.3 L17.7 17.7" /></g>,
    phone:    <g {...s}><path d="M6 3 H9 L11 8 L8.5 10 C9.5 13 11 14.5 14 15.5 L16 13 L21 15 V18 C21 19.5 20 21 18 21 C10 20 4 14 3 6 C3 4 4.5 3 6 3 Z" /></g>,
    clock:    <g {...s}><circle cx="12" cy="12" r="8" /><path d="M12 7 V12 L15.5 14" /></g>,
    trash:    <g {...s}><path d="M4 7 H20" /><path d="M6.5 7 L7.5 20 H16.5 L17.5 7" /><path d="M9.5 7 V4.5 H14.5 V7" /><line x1="10" y1="10.5" x2="10" y2="16.5" /><line x1="14" y1="10.5" x2="14" y2="16.5" /></g>,
    search:   <g {...s}><circle cx="11" cy="11" r="6" /><line x1="15.5" y1="15.5" x2="20" y2="20" /></g>,
    filter:   <g {...s}><path d="M4 5 H20 L14 12 V19 L10 17 V12 Z" /></g>,
    download: <g {...s}><path d="M12 4 V15" /><path d="M7 11 L12 16 L17 11" /><path d="M5 19 H19" /></g>,
    card:     <g {...s}><rect x="3" y="6" width="18" height="13" /><line x1="3" y1="10" x2="21" y2="10" /><line x1="7" y1="15" x2="11" y2="15" /></g>,
    bank:     <g {...s}><path d="M4 9 L12 4 L20 9" /><line x1="4" y1="9" x2="20" y2="9" /><path d="M6 9 V18 M10 9 V18 M14 9 V18 M18 9 V18" /><line x1="4" y1="20" x2="20" y2="20" /></g>,
    connect:  <g {...s}><circle cx="6.5" cy="12" r="2.5" /><circle cx="17.5" cy="12" r="2.5" /><line x1="9" y1="12" x2="15" y2="12" /></g>,
    lock:     <g {...s}><rect x="5" y="11" width="14" height="9" /><path d="M8 11 V8 A4 4 0 0 1 16 8 V11" /></g>,
    terminal: <g {...s}><rect x="3" y="5" width="18" height="14" /><path d="M7 10 L10 12.5 L7 15" /><line x1="12.5" y1="15" x2="16" y2="15" /></g>,
    copy:     <g {...s}><rect x="8" y="8" width="12" height="12" /><path d="M16 8 V4 H4 V16 H8" /></g>,
    robot:    <g {...s}><circle cx="12" cy="3" r="1" fill={color} stroke="none" /><line x1="12" y1="4" x2="12" y2="6" /><rect x="5" y="6" width="14" height="12" /><circle cx="9.5" cy="11.5" r="1.25" fill={color} stroke="none" /><circle cx="14.5" cy="11.5" r="1.25" fill={color} stroke="none" /><line x1="9.5" y1="15" x2="14.5" y2="15" /><line x1="3" y1="11" x2="5" y2="11" /><line x1="19" y1="11" x2="21" y2="11" /></g>,
    display:  <g {...s}><rect x="4" y="5" width="16" height="10.5" /><line x1="12" y1="15.5" x2="12" y2="18.5" /><line x1="8.5" y1="18.5" x2="15.5" y2="18.5" /></g>,
    easel:    <g {...s}><rect x="4" y="4" width="16" height="10.5" /><line x1="10.2" y1="14.5" x2="9.4" y2="19.5" /><line x1="13.8" y1="14.5" x2="14.6" y2="19.5" /></g>,
    studio:   <g {...s} strokeLinecap="round" strokeLinejoin="round"><path d="M4.5 4 V19.5 H19.5" /><line x1="11.28" y1="10.21" x2="11.14" y2="8.29" /><line x1="13.72" y1="11.29" x2="16.57" y2="9.1" /><circle cx="11.5" cy="13" r="2.8" /><circle cx="11" cy="6.5" r="1.8" /><circle cx="18" cy="8" r="1.8" /></g>,
    route:    <g {...s} strokeLinecap="round" strokeLinejoin="round"><circle cx="16.5" cy="6.5" r="2.3" /><circle cx="7.5" cy="17.5" r="2.3" /><path d="M14.2 6.5 H9 A2.75 2.75 0 0 0 9 12 H15 A2.75 2.75 0 0 1 15 17.5 H9.8" /></g>,
  }[name];
  return <svg width={size} height={size} viewBox="0 0 24 24" style={{ display: "block", flex: "none", ...style }}>{P}</svg>;
};

/* ---------- type atoms ----------------------------------------------------- */
const Eyebrow = ({ children, color = "var(--ink-3)", style }) => (
  <div style={{ fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.14em", textTransform: "uppercase", color, ...style }}>{children}</div>
);

// Mono money with greyed decimals. `size` is px.
const Money = ({ value, size = 16, weight = 500, dp = 2, color = "var(--ink)", dim = "var(--ink-3)", prefix = "$", sign = false, style }) => {
  const m = money(value, dp);
  const lead = sign ? (m.neg ? "−" : "+") : (m.neg ? "−" : "");
  return (
    <span style={{ fontFamily: "var(--f-mono)", fontSize: size, fontWeight: weight, fontVariantNumeric: "tabular-nums", letterSpacing: "-0.01em", color, ...style }}>
      {lead}{prefix}{m.whole}{m.dec && <span style={{ color: dim }}>.{m.dec}</span>}
    </span>
  );
};

const Delta = ({ abs, pct: p, size = 12, showAbs = true }) => {
  const pos = (abs != null ? abs : p) >= 0;
  const c = pos ? "var(--accent-pos)" : "var(--signal-neg)";
  return (
    <span style={{ fontFamily: "var(--f-mono)", fontSize: size, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: c, letterSpacing: "-0.005em" }}>
      {showAbs && abs != null && p != null ? perf(abs, p) : <>{showAbs && abs != null && signed(abs)}{p != null && pct(p)}</>}
    </span>
  );
};

const LiveDot = ({ size = 5, color = "var(--accent)" }) => (
  <span className="yo-pulse" style={{ display: "inline-block", width: size, height: size, background: color, borderRadius: 999, flex: "none" }} />
);

/* ---------- the seam · the signature 1px accent line ----------------------- */
const Seam = ({ draw = false, style }) => (
  <div className={draw ? "yo-seam-draw" : ""} style={{ height: 1, background: "var(--accent)", opacity: draw ? 1 : 0.6, ...style }} />
);

/* ---------- nav bar -------------------------------------------------------- */
const NavBar = ({ title, onBack, right, left, sub, border = true }) => (
  <div style={{ flex: "none", padding: "6px 16px 10px", borderBottom: border ? "1px solid var(--rule)" : "none", display: "flex", alignItems: "center", gap: 10, minHeight: 44 }}>
    {onBack && (
      <button className="press" onClick={onBack} style={{ background: "none", border: "none", padding: 4, margin: "0 -4px", color: "var(--ink)", display: "flex" }}>
        <Icon name="back" size={22} />
      </button>
    )}
    {left}
    <div style={{ minWidth: 0, flex: 1 }}>
      <div style={{ fontFamily: "var(--f-display)", fontSize: 17, fontWeight: 600, letterSpacing: "-0.02em", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{title}</div>
      {sub && <div style={{ fontFamily: "var(--f-display)", fontSize: 11, color: "var(--ink-3)", marginTop: 1 }}>{sub}</div>}
    </div>
    {right}
  </div>
);

/* ---------- buttons -------------------------------------------------------- */
const Btn = ({ kind = "primary", children, onClick, full, style, disabled }) => {
  const base = { fontFamily: "var(--f-display)", fontSize: 14, fontWeight: 600, letterSpacing: "0.01em", padding: "13px 18px", border: "none", borderRadius: 10, cursor: "pointer", width: full ? "100%" : "auto", display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7, whiteSpace: "nowrap", opacity: disabled ? 0.4 : 1, pointerEvents: disabled ? "none" : "auto" };
  const kinds = {
    primary: { background: "var(--accent)", color: "var(--accent-ink)" },
    ghost:   { background: "transparent", color: "var(--ink)", border: "1px solid var(--rule-2)" },
    danger:  { background: "transparent", color: "var(--signal-neg)", border: "1px solid color-mix(in srgb, var(--signal-neg) 40%, transparent)" },
    quiet:   { background: "var(--bg-2)", color: "var(--ink)" },
  }[kind];
  return <button className="press" onClick={onClick} disabled={disabled} style={{ ...base, ...kinds, ...style }}>{children}</button>;
};

/* ---------- segmented control --------------------------------------------- */
const Segmented = ({ options, value, onChange, size = "md" }) => {
  const pad = size === "sm" ? "5px 0" : "7px 0";
  const fs = size === "sm" ? 11 : 12;
  return (
    <div style={{ display: "grid", gridTemplateColumns: `repeat(${options.length}, 1fr)`, border: "1px solid var(--rule-2)", borderRadius: 10, overflow: "hidden" }}>
      {options.map((o, i) => {
        const v = typeof o === "string" ? o : o.value;
        const label = typeof o === "string" ? o : o.label;
        const on = v === value;
        return (
          <button key={v} className="press" onClick={() => onChange(v)} style={{
            padding: pad, background: on ? "var(--ink)" : "transparent", color: on ? "var(--bg)" : "var(--ink-2)",
            border: "none", borderLeft: i > 0 ? "1px solid var(--rule-2)" : "none",
            fontFamily: "var(--f-display)", fontSize: fs, fontWeight: 600, letterSpacing: "0.01em", cursor: "pointer",
          }}>{label}</button>
        );
      })}
    </div>
  );
};

/* ---------- channel glyph -------------------------------------------------- */
const ChannelTag = ({ channel }) => {
  const map = { "in-app": ["message", "In-app"], whatsapp: ["whatsapp", "WhatsApp"], email: ["mail", "Email"], imessage: ["message", "iMessage"] };
  const [icon, label] = map[channel] || ["message", channel];
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontFamily: "var(--f-display)", fontSize: 10, fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)" }}>
      <Icon name={icon} size={13} stroke={1.6} /> {label}
    </span>
  );
};

/* ============================================================
   Chart · reusable line/area with optional markers + scrubber.
   Renders at a fixed coordinate space, scales to container width.
   ============================================================ */
const Chart = ({ data, height = 150, accent = "var(--accent)", fillColor, fill = true, markers = [], activeMarker = null, onPickMarker, scrub = false, onScrub, baseline = true, padY = 10 }) => {
  const fillC = fillColor || accent;
  const W = 350, H = height;
  const svgRef = useRef(null);
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const x = (i) => (i / (data.length - 1)) * W;
  const y = (v) => padY + (1 - (v - min) / range) * (H - padY * 2);
  const path = data.map((v, i) => `${i === 0 ? "M" : "L"}${x(i).toFixed(2)},${y(v).toFixed(2)}`).join(" ");
  const lastX = x(data.length - 1), lastY = y(data[data.length - 1]);

  const [hover, setHover] = useState(null);
  const gesture = useRef({ down: false, moved: false, startX: 0 });
  const interactive = scrub || markers.length > 0;

  const idxFromClient = (clientX) => {
    const rect = svgRef.current.getBoundingClientRect();
    const rel = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    return Math.round(rel * (data.length - 1));
  };
  const onDown = (clientX) => { gesture.current = { down: true, moved: false, startX: clientX }; };
  const onMove = (clientX) => {
    const g = gesture.current;
    if (!g.down) return;
    if (!g.moved && Math.abs(clientX - g.startX) < 5) return;
    g.moved = true;
    if (scrub) { const idx = idxFromClient(clientX); setHover(idx); onScrub && onScrub(idx, data[idx]); }
  };
  const onUp = (clientX) => {
    const g = gesture.current;
    gesture.current = { down: false, moved: false, startX: 0 };
    if (g.moved) { setHover(null); onScrub && onScrub(null); return; }
    // a tap (not a drag) → toggle the nearest marker
    if (markers.length && onPickMarker) {
      const tapped = idxFromClient(clientX);
      let best = -1, bestD = 3;
      markers.forEach((m, i) => { const d = Math.abs(m.idx - tapped); if (d <= bestD) { bestD = d; best = i; } });
      onPickMarker(best === -1 ? null : (activeMarker === best ? null : best));
    }
  };
  const cancel = () => { if (gesture.current.moved) { setHover(null); onScrub && onScrub(null); } gesture.current = { down: false, moved: false, startX: 0 }; };

  return (
    <svg ref={svgRef} width="100%" viewBox={`0 0 ${W} ${H + (markers.length ? 14 : 0)}`} preserveAspectRatio="none"
      style={{ display: "block", overflow: "visible", touchAction: "none" }}
      onPointerDown={interactive ? (e) => { try { e.currentTarget.setPointerCapture(e.pointerId); } catch (_) {} onDown(e.clientX); } : undefined}
      onPointerMove={interactive ? (e) => onMove(e.clientX) : undefined}
      onPointerUp={interactive ? (e) => onUp(e.clientX) : undefined}
      onPointerCancel={interactive ? cancel : undefined}>
      <rect x="0" y="0" width={W} height={H} fill="transparent" />
      {baseline && <line x1="0" y1={H - padY} x2={W} y2={H - padY} stroke="var(--rule)" strokeWidth="1" strokeDasharray="2 3" vectorEffect="non-scaling-stroke" />}
      {fill && <path d={`${path} L${W},${H} L0,${H} Z`} fill={fillC} opacity="0.12" />}
      <path d={path} fill="none" stroke={accent} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
      {/* current pip */}
      <circle cx={lastX} cy={lastY} r="3" fill={accent} />
      <circle cx={lastX} cy={lastY} r="7" fill={accent} opacity="0.16" />
      {/* markers (visual only, taps handled at the svg level) */}
      {markers.map((m, i) => {
        const mx = x(m.idx), my = y(data[m.idx]); const on = activeMarker === i;
        return (
          <g key={i} style={{ pointerEvents: "none" }}>
            <circle className={activeMarker == null ? "yo-mk-pulse" : ""} cx={mx} cy={my} r={on ? 7 : 6} fill={accent} opacity={on ? 0.3 : 0.2} />
            <circle cx={mx} cy={my} r="2.8" fill={accent} stroke="var(--bg)" strokeWidth="1" />
            {on && <line x1={mx} y1={my + 5} x2={mx} y2={H - padY} stroke={accent} strokeWidth="0.8" strokeDasharray="1 2" opacity="0.6" vectorEffect="non-scaling-stroke" />}
          </g>
        );
      })}
      {/* scrubber */}
      {scrub && hover != null && (
        <g>
          <line x1={x(hover)} y1={padY - 4} x2={x(hover)} y2={H - padY} stroke="var(--ink-3)" strokeWidth="1" strokeDasharray="2 2" vectorEffect="non-scaling-stroke" />
          <circle cx={x(hover)} cy={y(data[hover])} r="3.5" fill="var(--bg)" stroke={accent} strokeWidth="1.5" />
        </g>
      )}
    </svg>
  );
};

/* ---------- AI news brief · synthesized summary + cited, clickable sources ---
   `data` = { when, brief:[{t, s, tkr?}], sources:[{pub, head, when, url}] }
   Each clause carries an inline citation that opens its source; a Sources list
   below repeats them as tappable rows that click out to the article. ---------- */
const NewsBrief = ({ data, onAsk, askLabel = "Ask a follow-up", hideSources, hideByline }) => {
  const cite = {
    fontFamily: "var(--f-mono)", fontSize: 9.5, fontWeight: 600, lineHeight: 1,
    verticalAlign: "0.45em", color: "var(--accent)", textDecoration: "none",
    padding: "1px 3px", margin: "0 1px", borderRadius: 4,
    background: "color-mix(in srgb, var(--accent) 12%, transparent)", cursor: "pointer",
  };
  return (
    <div style={{ marginTop: 10, background: "var(--bg-card)", border: "1px solid var(--rule)", borderRadius: 12, overflow: "hidden" }}>
      {/* attribution header */}
      {!hideByline && (
      <div style={{ display: "flex", alignItems: "center", gap: 7, padding: "11px 14px 0" }}>
        <Logo size={13} />
        <span style={{ fontFamily: "var(--f-display)", fontSize: 11.5, fontWeight: 600, letterSpacing: "-0.005em" }}>Synthesized by Yoshi</span>
        <span style={{ marginLeft: "auto", display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--f-mono)", fontSize: 9.5, color: "var(--ink-3)" }}>
          <span style={{ width: 4, height: 4, borderRadius: 999, background: "var(--ink-3)", display: "block", flex: "none" }} /> {data.when}
        </span>
      </div>
      )}

      {/* the synthesis · prose with inline citations */}
      <p style={{ fontFamily: "var(--f-display)", fontSize: 13.5, lineHeight: 1.62, margin: 0, padding: "8px 14px 12px", color: "var(--ink)", textWrap: "pretty" }}>
        {data.brief.map((b, i) => (
          <React.Fragment key={i}>
            {b.tkr && <span style={{ fontFamily: "var(--f-mono)", fontSize: 11, fontWeight: 600, color: "var(--accent)", marginRight: 4 }}>{b.tkr}</span>}
            {b.t}.
            {b.s != null && <a href={data.sources[b.s].url} target="_blank" rel="noopener noreferrer" style={cite} onClick={(e) => e.stopPropagation()}>{b.s + 1}</a>}
            {i < data.brief.length - 1 ? " " : ""}
          </React.Fragment>
        ))}
      </p>

      {/* sources · each row clicks out to the article */}
      {!hideSources && (
        <>
          <div style={{ borderTop: "1px solid var(--rule)", padding: "9px 14px 4px" }}>
            <Eyebrow style={{ fontSize: 9 }}>Sources · {data.sources.length}</Eyebrow>
          </div>
          {data.sources.map((src, i) => (
            <a key={i} href={src.url} target="_blank" rel="noopener noreferrer" className="press"
              style={{ textDecoration: "none", display: "grid", gridTemplateColumns: "20px 1fr auto", gap: 10, alignItems: "center", padding: "9px 14px", borderTop: "1px solid var(--rule)", cursor: "pointer" }}>
              <span style={{ width: 18, height: 18, display: "grid", placeItems: "center", borderRadius: 5, background: "var(--bg-2)", fontFamily: "var(--f-mono)", fontSize: 10, fontWeight: 600, color: "var(--ink-2)" }}>{i + 1}</span>
              <span style={{ minWidth: 0 }}>
                <span style={{ display: "flex", alignItems: "baseline", gap: 7 }}>
                  <span style={{ fontFamily: "var(--f-display)", fontSize: 9, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--accent)" }}>{src.pub}</span>
                  <span style={{ fontFamily: "var(--f-mono)", fontSize: 9, color: "var(--ink-3)" }}>{src.when}</span>
                </span>
                <span style={{ display: "block", fontFamily: "var(--f-display)", fontSize: 12.5, fontWeight: 500, color: "var(--ink)", marginTop: 2, lineHeight: 1.3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{src.head}</span>
              </span>
              <Icon name="external" size={14} color="var(--ink-3)" />
            </a>
          ))}
        </>
      )}

      {/* follow-up affordance */}
      {onAsk && (
        <button className="press" onClick={onAsk} style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "flex-start", gap: 6, borderTop: "1px solid var(--rule)", padding: "11px 14px", background: "none", border: "none", cursor: "pointer", fontFamily: "var(--f-display)", fontSize: 12, fontWeight: 600, color: "var(--accent)", textAlign: "left" }}>
          {askLabel} <Icon name="back" size={13} color="var(--accent)" style={{ transform: "scaleX(-1)" }} />
        </button>
      )}
    </div>
  );
};

/* persistent "You" menu — top-left hamburger, opens the profile/menu screen */
const YouButton = ({ nav }) => (
  <button className="press" onClick={() => nav.tab("profile")} aria-label="Menu" title="Menu"
    style={{ background: "none", border: "none", padding: 6, margin: "0 -6px", display: "grid", placeItems: "center", color: "var(--ink)", cursor: "pointer", flex: "none" }}>
    <Icon name="menu" size={22} />
  </button>
);

Object.assign(window, {
  ThemeCtx, useTheme, Logo, Icon, Eyebrow, Money, Delta, LiveDot, Seam,
  NavBar, Btn, Segmented, ChannelTag, Chart, YouButton, NewsBrief,
});
