/* bogazici.jsx — Boğaziçi · Vapur: a launchable, fully-interactive experience.
   One ferry-concierge chat app behind THREE API gateways (Apigee / AWS / Kong),
   with Prisma AIRS inspecting every crossing AT the selected gateway. Flip the
   door, send the same message, watch the verdict follow. Self-contained screen
   in the spirit of Eagle Eye — its own Bosphorus theme + chrome.
   "Same ferry. Any strait. Inspected at every crossing." */

/* ---- Bosphorus theme — dark (night water) + light (daylight) ---- */
const V_FONTS = {
  mono: "'JetBrains Mono', ui-monospace, monospace",
  sans: "'Manrope', system-ui, sans-serif",
  serif: "'Cormorant Garamond', serif",
};
const V_THEMES = {
  dark: {
    isDark: true,
    page: "#06181f",
    surface: "#0c2630",
    surfaceAlt: "#0f2e39",
    raised: "#123743",
    line: "rgba(120,200,210,0.13)",
    lineSoft: "rgba(120,200,210,0.07)",
    ink: "#eaf7f8",
    sub: "#9ec3c9",
    faint: "#6d959c",
    teal: "#2bb9c4",
    gold: "#e3a64f",
    terra: "#dd7d52",
    headerBg: "linear-gradient(180deg,#0f2e39,#0c2630)",
    toolbarBg: "rgba(6,18,24,0.82)",
    chipBg: "rgba(120,200,210,0.08)",
    laneBg: "linear-gradient(180deg,#0a2730,#06171e)",
    laneLand: "#0e3038",
    laneShimmer: "rgba(43,185,196,0.07)",
    laneStampBg: "rgba(4,12,16,0.7)",
    ambient: "radial-gradient(900px 380px at 50% -8%, rgba(43,185,196,0.13), transparent 70%), radial-gradient(700px 300px at 90% 110%, rgba(227,166,79,0.08), transparent 70%)",
    ...V_FONTS,
  },
  light: {
    isDark: false,
    page: "#e8f2f3",
    surface: "#ffffff",
    surfaceAlt: "#f1f8f9",
    raised: "#e4f0f1",
    line: "rgba(16,92,100,0.15)",
    lineSoft: "rgba(16,92,100,0.08)",
    ink: "#0b2a2f",
    sub: "#436a70",
    faint: "#6b8f95",
    teal: "#0e8a8f",
    gold: "#bd7d1d",
    terra: "#c05d35",
    headerBg: "linear-gradient(180deg,#ffffff,#f1f8f9)",
    toolbarBg: "rgba(233,243,244,0.86)",
    chipBg: "rgba(16,92,100,0.06)",
    laneBg: "linear-gradient(180deg,#cdedf2,#9fd6e2)",
    laneLand: "#bfe6cd",
    laneShimmer: "rgba(14,110,120,0.10)",
    laneStampBg: "rgba(255,255,255,0.78)",
    ambient: "radial-gradient(900px 380px at 50% -8%, rgba(14,138,143,0.10), transparent 70%), radial-gradient(700px 300px at 90% 110%, rgba(189,125,29,0.07), transparent 70%)",
    ...V_FONTS,
  },
};
const VapurThemeCtx = React.createContext(V_THEMES.dark);
const useV = () => React.useContext(VapurThemeCtx);

const VV = {
  allow: { label: "ALLOW", stamp: "ALLOWED", color: "#34d399", bg: "rgba(52,211,153,0.14)", border: "rgba(52,211,153,0.5)", icon: "ShieldCheck" },
  flag: { label: "FLAG", stamp: "FLAGGED", color: "#f5b53d", bg: "rgba(245,181,61,0.16)", border: "rgba(245,181,61,0.5)", icon: "ShieldAlert" },
  block: { label: "BLOCK", stamp: "BLOCKED", color: "#ff6b7a", bg: "rgba(255,107,122,0.15)", border: "rgba(255,107,122,0.5)", icon: "ShieldX" },
};

const VCAT_ICON = {
  "Prompt Injection": "Syringe",
  "Sensitive Data": "DatabaseZap",
  "PII": "IdCard",
  "Malicious URL": "Link2",
};

const SCANNED_LABEL = {
  prompt: "Prompt only",
  response: "Response only",
  both: "Prompt + Response",
  "prompt+tool+response": "Prompt + Tool + Response",
};

let _vmid = 0;
const vmid = () => "v" + ++_vmid + "-" + Math.random().toString(36).slice(2, 6);
const vfmtTime = (d) => d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });

/* one-time injected keyframes for the crossing animation */
function BogaziciStyle() {
  return (
    <style dangerouslySetInnerHTML={{ __html: `
      @keyframes bgz-bob { 0%,100% { transform: translateY(-50%) rotate(-1.2deg); } 50% { transform: translateY(calc(-50% - 3px)) rotate(1.2deg); } }
      @keyframes bgz-wake { 0% { opacity:0; transform: scaleX(.4); } 40% { opacity:.5; } 100% { opacity:0; transform: scaleX(1.3); } }
      @keyframes bgz-stamp { 0% { opacity:0; transform: translate(-50%,-50%) scale(1.5) rotate(-12deg); } 60% { opacity:1; transform: translate(-50%,-50%) scale(.92) rotate(-12deg); } 100% { opacity:1; transform: translate(-50%,-50%) scale(1) rotate(-12deg); } }
      @keyframes bgz-shimmer { 0% { background-position: 0 0; } 100% { background-position: 220px 0; } }
      .bgz-ferry { transition: left 1.05s cubic-bezier(.45,.05,.3,1); }
      @media (prefers-reduced-motion: reduce) { .bgz-ferry { transition: none; } [style*="bgz-bob"],[style*="bgz-wake"],[style*="bgz-shimmer"]{ animation:none !important; } }
    `}} />
  );
}

/* ---- gateway selector (3 real anchor tabs) ---- */
function GatewayTabs({ active, gw }) {
  const V = useV();
  return (
    <div className="flex flex-wrap items-center gap-2.5">
      <span className="mr-1 text-[11px] font-bold uppercase tracking-[0.18em]" style={{ color: V.faint, fontFamily: V.mono }}>Gateway</span>
      <div className="flex flex-wrap gap-2 rounded-2xl p-1.5" style={{ background: V.surface, border: `1px solid ${V.line}` }}>
        {window.VAPUR_GATEWAY_LIST.map((d) => {
          const on = d.id === active;
          return (
            <a
              key={d.id}
              href={"#/bogazici?gw=" + d.id}
              onClick={(e) => { if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return; e.preventDefault(); gw(d.id); }}
              className="group inline-flex items-center gap-2.5 rounded-xl px-3.5 py-2 text-[13.5px] font-bold transition-all"
              style={{
                background: on ? d.accent : "transparent",
                color: on ? d.accentInk : V.sub,
                boxShadow: on ? `0 8px 22px -10px ${d.accent}` : "none",
              }}
            >
              {d.cloudLogo
                ? <img src={d.cloudLogo} alt="" className="h-4 w-auto" style={{ filter: on ? "none" : "grayscale(.5) opacity(.85)" }} />
                : <span className="flex h-4 w-4 items-center justify-center rounded-[5px] text-[9px] font-black" style={{ background: on ? V.accentInk : d.accent, color: on ? d.accent : V.accentInk }}>K</span>}
              {d.tab}
            </a>
          );
        })}
      </div>
    </div>
  );
}

/* ---- "behind this door" info strip (per gateway) ---- */
function DoorStrip({ d }) {
  const V = useV();
  const Cell = ({ k, v, mono }) => (
    <div className="min-w-0">
      <div className="text-[9.5px] font-bold uppercase tracking-[0.16em]" style={{ color: V.faint }}>{k}</div>
      <div className="mt-0.5 line-clamp-2 leading-snug text-[13px] font-semibold" style={{ color: V.ink, fontFamily: mono ? V.mono : V.sans }}>{v}</div>
    </div>
  );
  return (
    <div className="relative overflow-hidden rounded-2xl a-fade" style={{ background: `linear-gradient(100deg, ${d.accent}1f, ${V.surface} 52%)`, border: `1px solid ${d.accent}40` }}>
      <div className="absolute left-0 top-0 h-full w-[3px]" style={{ background: d.accent }} />
      <div className="flex items-center gap-2 px-4 pt-3">
        <span className="flex h-6 w-6 items-center justify-center rounded-lg" style={{ background: d.accent, color: d.accentInk }}>
          <window.Icon name="DoorOpen" size={14} />
        </span>
        <span className="text-[10.5px] font-bold uppercase tracking-[0.2em]" style={{ color: d.accent, fontFamily: V.mono }}>Behind this door</span>
        {d.cloudLogo && <img src={d.cloudLogo} alt={d.cloud} className="ml-1 h-4 w-auto" />}
      </div>
      <div className="grid grid-cols-2 gap-x-5 gap-y-3 px-4 py-3.5 sm:grid-cols-4">
        <Cell k="Cloud" v={d.cloud} />
        <Cell k="Gateway" v={d.gateway} mono />
        <Cell k="Model" v={d.model} mono />
        <Cell k="Scans" v={d.scansLabel} />
      </div>
      <div className="flex items-center gap-2 border-t px-4 py-2.5" style={{ borderColor: V.lineSoft }}>
        <window.Icon name="Radar" size={13} style={{ color: V.teal }} />
        <span className="text-[12px]" style={{ color: V.sub }}>
          <span className="font-bold" style={{ color: V.ink }}>AIRS:</span> {d.insertion} · <span style={{ fontFamily: V.mono }}>{d.airsLine}</span>
        </span>
        {(() => {
          const url = window.vapurConsoleUrl(d.id);
          const label = d.openLabel || ("Open " + (d.short || d.id));
          return (
            <a
              className="ml-auto inline-flex shrink-0 items-center gap-1.5 rounded-lg px-3 py-1.5 text-[12px] font-semibold transition-transform active:scale-[0.97] hover:opacity-90"
              href={url || "#"}
              {...(url ? { target: "_blank", rel: "noopener noreferrer" } : {})}
              title={label}
              style={{ background: d.accent, color: d.accentInk, border: `1px solid ${d.accent}` }}
            >
              {label} <window.Icon name="ExternalLink" size={13} />
            </a>
          );
        })()}
      </div>
    </div>
  );
}

/* ---- the crossing lane (ferry travels through the gate; AIRS stamps it) ---- */
function CrossingLane({ d, crossing }) {
  const V = useV();
  const v = crossing.verdict ? VV[crossing.verdict] : null;
  const ferryLeft = crossing.phase === "idle" ? "3%" : crossing.phase === "blocked" ? "50%" : crossing.phase === "passed" ? "92%" : "50%";
  return (
    <div className="relative mt-4 h-[86px] overflow-hidden rounded-2xl" style={{ background: V.laneBg, border: `1px solid ${V.line}` }}>
      {/* water shimmer */}
      <div className="pointer-events-none absolute inset-0" style={{ opacity: 0.5, backgroundImage: `repeating-linear-gradient(90deg, transparent 0 26px, ${V.laneShimmer} 26px 28px)`, animation: "bgz-shimmer 5s linear infinite" }} />
      {/* landmasses */}
      <div className="absolute left-0 top-0 flex h-full w-[15%] items-center justify-start pl-3" style={{ background: `linear-gradient(90deg,${V.laneLand},transparent)` }}>
        <span className="text-[9.5px] font-bold uppercase tracking-[0.16em]" style={{ color: V.faint, fontFamily: V.mono }}>Europe</span>
      </div>
      <div className="absolute right-0 top-0 flex h-full w-[15%] items-center justify-end pr-3" style={{ background: `linear-gradient(270deg,${V.laneLand},transparent)` }}>
        <span className="text-[9.5px] font-bold uppercase tracking-[0.16em]" style={{ color: V.faint, fontFamily: V.mono }}>Asia</span>
      </div>
      {/* the gate / checkpoint */}
      <div className="absolute left-1/2 top-0 h-full -translate-x-1/2" style={{ width: 2, background: `repeating-linear-gradient(180deg, ${d.accent}99 0 6px, transparent 6px 12px)` }} />
      <div className="absolute left-1/2 top-2 -translate-x-1/2 rounded-full px-2.5 py-1 text-[9.5px] font-bold uppercase tracking-[0.14em]" style={{ background: `${d.accent}26`, color: d.accent, border: `1px solid ${d.accent}66`, fontFamily: V.mono }}>
        {d.short} · AIRS
      </div>
      {/* verdict stamp at the gate */}
      {v && (
        <div className="absolute left-1/2 top-1/2 z-10 rounded-lg px-3 py-1 text-[13px] font-black tracking-wider" style={{ color: v.color, background: V.laneStampBg, border: `2px solid ${v.color}`, transform: "translate(-50%,-50%) rotate(-12deg)", animation: "bgz-stamp .5s cubic-bezier(.22,1,.36,1) both", fontFamily: V.mono }}>
          {v.stamp}
        </div>
      )}
      {/* the ferry */}
      <div className="bgz-ferry absolute top-1/2 z-[5]" style={{ left: ferryLeft, transform: "translateX(-50%)" }}>
        <div style={{ animation: crossing.phase === "sailing" ? "bgz-bob 1.1s ease-in-out infinite" : "none", transform: "translateY(-50%)" }}>
          <span style={{ fontSize: 26, filter: "drop-shadow(0 3px 5px rgba(0,0,0,.5))" }}>🛳️</span>
        </div>
      </div>
    </div>
  );
}

/* ---- chat message row ---- */
function VapurMessage({ msg }) {
  const V = useV();
  if (msg.role === "user") {
    return (
      <div className="flex justify-end a-pop">
        <div className="max-w-[80%]">
          <div className="rounded-2xl rounded-br-md px-4 py-2.5 text-[14px] leading-relaxed" style={{ background: V.teal, color: "#04222a", whiteSpace: "pre-wrap", fontWeight: 500 }}>{msg.text}</div>
          <div className="mt-1 pr-1 text-right text-[10.5px]" style={{ color: V.faint }}>{vfmtTime(msg.time)}</div>
        </div>
      </div>
    );
  }
  const blocked = msg.blocked;
  return (
    <div className="flex justify-start gap-2.5 a-pop">
      <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full" style={{ background: "linear-gradient(135deg,#13414e,#0c2b34)", border: `1px solid ${V.line}`, fontSize: 16 }}>🛳️</div>
      <div className="max-w-[82%]">
        {blocked ? (
          <div className="rounded-2xl rounded-tl-md px-4 py-3" style={{ background: "rgba(255,107,122,0.08)", border: `1px solid ${VV.block.border}` }}>
            <div className="mb-1.5 flex items-center gap-1.5 text-[10.5px] font-bold uppercase tracking-wider" style={{ color: VV.block.color }}>
              <window.Icon name="ShieldX" size={13} /> Intercepted by AIRS at the gateway
            </div>
            <div className="text-[14px] leading-relaxed" style={{ color: V.ink, whiteSpace: "pre-wrap" }}>{msg.text}</div>
          </div>
        ) : (
          <div className="rounded-2xl rounded-tl-md px-4 py-2.5 text-[14px] leading-relaxed" style={{ background: V.surfaceAlt, color: V.ink, whiteSpace: "pre-wrap", border: `1px solid ${V.lineSoft}` }}>{msg.text}</div>
        )}
        <div className="mt-1 flex items-center gap-2 pl-1 text-[10.5px]" style={{ color: V.faint }}>
          <span>{vfmtTime(msg.time)}</span>
          {msg.flagged && <span className="inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 font-semibold" style={{ background: VV.flag.bg, color: VV.flag.color }}><window.Icon name="Flag" size={9} /> Flagged</span>}
        </div>
      </div>
    </div>
  );
}

/* ---- AIRS inspector panel (per-gateway verdict, categories, latency) ---- */
function VapurInspector({ d, latest, log, busy }) {
  const V = useV();
  const v = latest ? VV[latest.airs.verdict] : null;
  return (
    <div className="flex h-full flex-col overflow-hidden rounded-2xl" style={{ background: V.surface, border: `1px solid ${V.line}` }}>
      {/* header */}
      <div className="flex items-center justify-between px-4 py-3.5" style={{ borderBottom: `1px solid ${V.line}`, background: V.headerBg }}>
        <div className="flex items-center gap-2.5">
          <div className="flex h-8 w-8 items-center justify-center rounded-xl" style={{ background: "linear-gradient(135deg,#2bb9c4,#13414e)", color: "#04222a", animation: "lr-pulse-ring 2.6s infinite" }}>
            <window.Icon name="Radar" size={17} />
          </div>
          <div className="leading-tight">
            <div className="text-[13.5px] font-bold" style={{ color: V.ink }}>AIRS Inspector</div>
            <div className="text-[10px] font-semibold uppercase tracking-[0.16em]" style={{ color: V.faint }}>At the {d.short} gateway</div>
          </div>
        </div>
        <span className="inline-flex items-center gap-1.5 rounded-full px-2 py-1 text-[10px] font-bold" style={{ background: `${d.accent}22`, color: d.accent, fontFamily: V.mono }}>
          <span className="inline-block h-1.5 w-1.5 rounded-full" style={{ background: busy ? V.gold : d.accent, boxShadow: `0 0 8px ${busy ? V.gold : d.accent}` }} />
          {busy ? "scanning…" : "live"}
        </span>
      </div>

      <div className="lr-scroll min-h-0 flex-1 overflow-y-auto p-4">
        {!latest ? (
          <div className="mt-8 flex flex-col items-center text-center">
            <div className="flex h-12 w-12 items-center justify-center rounded-2xl" style={{ background: V.surfaceAlt, color: V.faint }}><window.Icon name="ScanSearch" size={22} /></div>
            <p className="mt-3 max-w-[15rem] text-[12.5px] leading-relaxed" style={{ color: V.faint }}>No crossing yet. Send a message — or fire a preset below — to watch AIRS inspect it at the {d.short} gateway.</p>
          </div>
        ) : (
          <>
            {/* big verdict */}
            <div className="relative overflow-hidden rounded-xl a-pop" style={{ background: v.bg, border: `1px solid ${v.border}` }}>
              <div className="flex items-center justify-between px-3.5 py-3">
                <span className="inline-flex items-center gap-2 text-[16px] font-black tracking-wide" style={{ color: v.color }}><window.Icon name={v.icon} size={20} /> {v.label}</span>
                <span className="inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-[10px] font-bold" style={{ background: `${d.accent}22`, color: d.accent, fontFamily: V.mono }}>
                  {d.cloudLogo && <img src={d.cloudLogo} alt="" className="h-3 w-auto" />} {d.short}
                </span>
              </div>
            </div>

            {/* meta rows */}
            <div className="mt-3 space-y-px overflow-hidden rounded-xl" style={{ border: `1px solid ${V.line}` }}>
              <InspRow k="Categories">
                {latest.airs.categories.length ? (
                  <div className="flex flex-wrap justify-end gap-1.5">
                    {latest.airs.categories.map((c) => (
                      <span key={c} className="inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10.5px] font-semibold" style={{ background: V.raised, color: V.ink, border: `1px solid ${V.line}` }}>
                        <window.Icon name={VCAT_ICON[c] || "Tag"} size={10} style={{ color: v.color }} /> {c}
                      </span>
                    ))}
                  </div>
                ) : <span style={{ color: V.faint }}>—</span>}
              </InspRow>
              <InspRow k="Scanned"><span style={{ color: V.ink, fontFamily: V.mono }}>{SCANNED_LABEL[latest.airs.scanned] || latest.airs.scanned}</span></InspRow>
              <InspRow k="Latency"><span style={{ color: V.ink, fontFamily: V.mono }}>{latest.airs.latencyMs} ms</span></InspRow>
              <InspRow k="Gateway"><span style={{ color: V.ink }}>{d.cloud}</span></InspRow>
            </div>

            {/* tool-scan note (AWS) */}
            {latest.airs.toolScanned && (
              <div className="mt-3 flex items-start gap-2 rounded-xl px-3 py-2.5" style={{ background: VV.allow.bg, border: `1px solid ${VV.allow.border}` }}>
                <window.Icon name="Wrench" size={14} style={{ color: VV.allow.color, marginTop: 1 }} />
                <span className="text-[12px] leading-relaxed" style={{ color: V.ink }}>Tool call <span style={{ fontFamily: V.mono, color: VV.allow.color }}>lookup_ferry</span> was scanned too — on AWS the Lambda <span className="font-semibold">is</span> the agent, so AIRS sees the tool call, not just the prompt and response.</span>
              </div>
            )}

            {/* tool call (agent used lookup_ferry) — surfaced here, not in chat */}
            {latest.toolCall && (
              <div className="mt-3 overflow-hidden rounded-xl" style={{ border: `1px solid ${V.line}` }}>
                <div className="flex items-center gap-1.5 px-3 py-2" style={{ background: V.surfaceAlt }}>
                  <window.Icon name="Settings2" size={11} style={{ color: V.gold }} />
                  <span className="text-[10px] font-bold uppercase tracking-[0.14em]" style={{ color: V.faint }}>Tool call</span>
                </div>
                <div className="space-y-1.5 px-3 py-2.5" style={{ background: V.surface }}>
                  <div className="text-[13px] font-semibold" style={{ fontFamily: V.mono, color: V.ink }}>lookup_ferry</div>
                  <div className="flex items-center gap-1.5 text-[12.5px] font-medium" style={{ color: V.teal }}>
                    {latest.toolCall.args.from_pier} <window.Icon name="ArrowRight" size={12} /> {latest.toolCall.args.to_pier}
                  </div>
                  <div className="text-[12px] leading-relaxed" style={{ fontFamily: V.mono, color: V.gold }}>{latest.toolCall.result}</div>
                </div>
              </div>
            )}

            {/* scan log */}
            {log.length > 1 && (
              <div className="mt-5">
                <div className="mb-2 text-[10px] font-bold uppercase tracking-[0.18em]" style={{ color: V.faint, fontFamily: V.mono }}>Crossing log</div>
                <div className="space-y-1.5">
                  {log.slice(0, 6).map((e) => {
                    const ev = VV[e.airs.verdict];
                    return (
                      <div key={e.id} className="flex items-center gap-2 rounded-lg px-2.5 py-1.5" style={{ background: V.surfaceAlt }}>
                        <window.Icon name={ev.icon} size={13} style={{ color: ev.color }} />
                        <span className="min-w-0 flex-1 truncate text-[11.5px]" style={{ color: V.sub }}>{e.userText}</span>
                        <span className="shrink-0 text-[9px] font-bold uppercase" style={{ color: V.faint, fontFamily: V.mono }}>{e.gw}</span>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
          </>
        )}
      </div>
    </div>
  );
}
function InspRow({ k, children }) {
  const V = useV();
  return (
    <div className="flex items-center justify-between gap-3 px-3 py-2.5" style={{ background: V.surfaceAlt }}>
      <span className="shrink-0 text-[10px] font-bold uppercase tracking-[0.14em]" style={{ color: V.faint }}>{k}</span>
      <div className="min-w-0 text-right text-[12.5px]">{children}</div>
    </div>
  );
}

/* ============================================================ */
function Bogazici({ gw, navigate, onBack }) {
  const active = window.VAPUR_GATEWAYS[gw] ? gw : "apigee";
  const d = window.VAPUR_GATEWAYS[active];
  const [mode, setMode] = React.useState(() => { try { return localStorage.getItem("bogazici-theme") || "dark"; } catch (e) { return "dark"; } });
  const V = V_THEMES[mode] || V_THEMES.dark;
  const toggleMode = () => setMode((m) => { const n = m === "dark" ? "light" : "dark"; try { localStorage.setItem("bogazici-theme", n); } catch (e) {} return n; });
  const [messages, setMessages] = React.useState([]);
  const [events, setEvents] = React.useState([]);
  const [busy, setBusy] = React.useState(false);
  const [draft, setDraft] = React.useState("");
  const [crossing, setCrossing] = React.useState({ phase: "idle", verdict: null });
  const scrollRef = React.useRef(null);
  const resetTimer = React.useRef(null);

  React.useEffect(() => { const el = scrollRef.current; if (el) el.scrollTop = el.scrollHeight; }, [messages, busy]);
  React.useEffect(() => () => clearTimeout(resetTimer.current), []);

  const goGateway = (id) => navigate("#/bogazici?gw=" + id);

  async function fire(text, preset) {
    const v = (text != null ? text : draft).trim();
    if (!v || busy) return;
    setDraft("");
    setMessages((m) => [...m, { id: vmid(), role: "user", text: v, time: new Date() }]);
    setBusy(true);
    // launch the crossing animation (never blocks the chat)
    clearTimeout(resetTimer.current);
    setCrossing({ phase: "sailing", verdict: null });

    const { reply, toolCall, airs } = await window.sendVapur(active, v, preset ? { preset } : undefined);
    const blocked = airs.verdict === "block";
    const flagged = airs.verdict === "flag";
    setMessages((m) => [...m, { id: vmid(), role: "bot", text: reply, time: new Date(), blocked, flagged, toolCall, toolScanned: airs.toolScanned }]);
    setEvents((ev) => [{ id: vmid(), time: new Date(), userText: v, reply, airs, gw: d.short, blocked, toolCall }, ...ev]);
    setBusy(false);
    setCrossing({ phase: blocked || flagged ? "blocked" : "passed", verdict: airs.verdict });
    resetTimer.current = setTimeout(() => setCrossing({ phase: "idle", verdict: null }), 3200);
  }

  const presets = window.VAPUR_PRESETS.filter((p) => !p.awsOnly || active === "aws");
  const empty = messages.length === 0;
  const latest = events[0] || null;

  return (
    <VapurThemeCtx.Provider value={V}>
    <div className="relative h-full w-full overflow-hidden a-fade" style={{ background: V.page, fontFamily: V.sans }}>
      <BogaziciStyle />
      {/* ambient water glow */}
      <div className="pointer-events-none absolute inset-0" style={{ background: V.ambient }} />

      {/* presenter toolbar */}
      <div className="relative z-10 flex h-12 items-center justify-between px-4" style={{ background: V.toolbarBg, backdropFilter: "blur(14px)", borderBottom: `1px solid ${V.line}` }}>
        <button onClick={onBack} className="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-[13px] font-medium transition-colors" style={{ color: V.sub }}>
          <window.Icon name="ArrowLeft" size={16} /> Back to hub
        </button>
        <div className="flex items-center gap-2">
          <window.RoseMark size={18} color={V.terra} petals={6} />
          <span className="hidden text-[12px] sm:inline" style={{ color: V.faint }}>Last Rose · <span style={{ color: V.sub }}>Boğaziçi</span></span>
          <window.OpenInNewTab href={"#/bogazici?gw=" + active} size={13} className="h-7 w-7" title="Open Boğaziçi in new tab" style={{ color: V.sub, background: V.surface, border: `1px solid ${V.line}` }} />
        </div>
        <div className="flex items-center gap-2">
          <button onClick={toggleMode} aria-label={V.isDark ? "Switch to light theme" : "Switch to dark theme"} className="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-[12.5px] font-semibold transition-colors" style={{ color: V.sub, background: V.chipBg, border: `1px solid ${V.line}` }}>
            <window.Icon name={V.isDark ? "Sun" : "Moon"} size={14} style={{ color: V.teal }} />
            <span className="hidden sm:inline">{V.isDark ? "Light" : "Dark"}</span>
          </button>
          <span className="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-[12.5px] font-semibold" style={{ background: `${V.teal}1c`, color: V.teal, border: `1px solid ${V.teal}44` }}>
            <window.Icon name="Waves" size={14} /> Boğaziçi
          </span>
        </div>
      </div>

      <div className="lr-scroll relative z-10 h-[calc(100%-48px)] overflow-y-auto">
        <div className="mx-auto max-w-[1320px] px-5 py-6 sm:px-7">
          {/* title */}
          <div className="a-fade-up">
            <div className="flex items-baseline gap-3">
              <h1 style={{ fontFamily: V.serif, color: V.ink }} className="text-[34px] font-medium leading-none">Boğaziçi</h1>
              <span className="text-[13px]" style={{ color: V.faint, fontFamily: V.mono }}>· Vapur</span>
            </div>
            <p className="mt-1.5 text-[14.5px] italic" style={{ color: V.gold, fontFamily: V.serif }}>"Same ferry. Any strait. Inspected at every crossing."</p>
          </div>

          {/* selector */}
          <div className="mt-5"><GatewayTabs active={active} gw={goGateway} /></div>

          {/* door strip */}
          <div className="mt-4"><DoorStrip d={d} /></div>

          {/* crossing lane */}
          <CrossingLane d={d} crossing={crossing} />

          {/* chat + inspector */}
          <div className="mt-5 grid grid-cols-1 gap-5 lg:grid-cols-[1fr_minmax(330px,374px)]" style={{ alignItems: "stretch" }}>
            {/* chat column */}
            <div className="flex flex-col overflow-hidden rounded-2xl" style={{ background: V.surface, border: `1px solid ${V.line}`, height: "clamp(440px, 64vh, 720px)" }}>
              <div className="flex items-center justify-between px-4 py-3" style={{ borderBottom: `1px solid ${V.line}`, background: V.headerBg }}>
                <div className="flex items-center gap-2.5">
                  <div className="flex h-9 w-9 items-center justify-center rounded-full" style={{ background: "linear-gradient(135deg,#13414e,#0c2b34)", border: `1px solid ${V.line}`, fontSize: 18 }}>🛳️</div>
                  <div className="leading-tight">
                    <div className="text-[14px] font-bold" style={{ color: V.ink }}>Vapur</div>
                    <div className="text-[11.5px]" style={{ color: V.faint }}>Bosphorus Ferry Concierge · Online</div>
                  </div>
                </div>
                <div className="flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-semibold" style={{ background: `${d.accent}1c`, color: d.accent }}>
                  <window.Icon name="ShieldCheck" size={13} /> Guarded at {d.short}
                </div>
              </div>

              <div ref={scrollRef} className="lr-scroll flex-1 space-y-4 overflow-y-auto px-4 py-5">
                {empty ? (
                  <div className="flex h-full flex-col items-center justify-center text-center">
                    <div className="flex h-14 w-14 items-center justify-center rounded-full" style={{ background: "linear-gradient(135deg,#13414e,#0c2b34)", border: `1px solid ${V.line}`, fontSize: 30 }}>🛳️</div>
                    <div className="mt-3 text-[17px] font-bold" style={{ color: V.ink }}>Merhaba! I'm Vapur 👋</div>
                    <p className="mt-1 max-w-sm text-[13px] leading-relaxed" style={{ color: V.sub }}>Ferry concierge for the Bosphorus. Flip the gateway above, then send me anything — or fire a crossing below.</p>
                    <div className="mt-5 flex w-full max-w-sm flex-col gap-2">
                      {window.VAPUR_STARTERS.map((s, i) => (
                        <button key={i} onClick={() => fire(s.text)} className="group flex items-center gap-3 rounded-xl px-3.5 py-3 text-left text-[13.5px] font-medium transition-all hover:-translate-y-0.5" style={{ background: V.surfaceAlt, border: `1px solid ${V.line}`, color: V.ink }}>
                          <span className="flex h-8 w-8 items-center justify-center rounded-lg" style={{ background: `${V.teal}1c`, color: V.teal }}><window.Icon name={s.icon} size={16} /></span>
                          <span className="flex-1">{s.label}</span>
                          <window.Icon name="ArrowRight" size={15} style={{ color: V.faint }} className="opacity-0 transition-opacity group-hover:opacity-100" />
                        </button>
                      ))}
                    </div>
                  </div>
                ) : (
                  <>
                    {messages.map((m) => <VapurMessage key={m.id} msg={m} />)}
                    {busy && (
                      <div className="flex items-center gap-2.5 a-fade">
                        <div className="flex h-8 w-8 items-center justify-center rounded-full" style={{ background: "linear-gradient(135deg,#13414e,#0c2b34)", border: `1px solid ${V.line}`, fontSize: 16 }}>🛳️</div>
                        <div className="rounded-2xl rounded-tl-md px-4 py-3" style={{ background: V.surfaceAlt }}>
                          <span className="inline-flex items-center gap-1">{[0, 1, 2].map((i) => <span key={i} className="inline-block h-1.5 w-1.5 rounded-full" style={{ background: V.teal, animation: `lr-blink 1.2s ${i * 0.16}s infinite ease-in-out` }} />)}</span>
                        </div>
                      </div>
                    )}
                  </>
                )}
              </div>

              {/* preset crossings */}
              <div className="flex flex-wrap gap-2 px-4 pt-3" style={{ borderTop: `1px solid ${V.line}` }}>
                {presets.map((p) => {
                  const accent = p.expect === "allow" ? V.teal : p.expect === "flag" ? VV.flag.color : VV.block.color;
                  return (
                    <button key={p.key} onClick={() => fire(p.text, p)} disabled={busy}
                      className="inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-[12px] font-semibold transition-all hover:-translate-y-0.5 disabled:opacity-40"
                      style={{ background: `${accent}14`, color: accent, border: `1px solid ${accent}44` }}>
                      <window.Icon name={p.icon} size={13} /> {p.label}
                      {p.awsOnly && <span className="rounded px-1 text-[8.5px] font-black" style={{ background: `${d.accent}33`, color: d.accent }}>AWS</span>}
                    </button>
                  );
                })}
              </div>

              {/* composer */}
              <div className="px-4 pb-3.5 pt-2.5">
                <div className="flex items-end gap-2 rounded-2xl px-3 py-2" style={{ background: V.surfaceAlt, border: `1px solid ${V.line}` }}>
                  <textarea rows={1} value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); fire(); } }} placeholder="Message Vapur…" className="lr-scroll max-h-28 flex-1 resize-none bg-transparent py-1.5 text-[14px] outline-none" style={{ color: V.ink }} />
                  <button onClick={() => fire()} disabled={busy || !draft.trim()} className="flex h-9 w-9 items-center justify-center rounded-xl transition-all active:scale-95 disabled:opacity-40" style={{ background: d.accent, color: d.accentInk }}>
                    <window.Icon name="Send" size={16} />
                  </button>
                </div>
                <div className="mt-2 flex items-center justify-center gap-1.5 text-[10.5px]" style={{ color: V.faint }}>
                  <window.Icon name="Lock" size={10} /> Every crossing is inspected by AIRS at the {d.short} gateway.
                </div>
              </div>
            </div>

            {/* inspector column */}
            <div style={{ height: "clamp(440px, 64vh, 720px)" }}>
              <VapurInspector d={d} latest={latest} log={events} busy={busy} />
            </div>
          </div>
        </div>
      </div>
    </div>
    </VapurThemeCtx.Provider>
  );
}

window.Bogazici = Bogazici;
