/* =========================================================
   Enterprise Data Access — functional integration console.

   Guided journey:
     1. Where does your data live?  (platform picker)
     2. Pick your delivery pattern  (recommended + alternative)
     3. Connect                     (setup wizard)

   Webhooks and bucket exports are fully self-serve; CDC, direct
   BI access and Iceberg shares create provisioning requests.
   Every connection is mirrored into the AI knowledge base
   (embeddings) unless the toggle is off.

   The marketing "trust package" lives on the landing page
   (marketing.jsx) — this page stays focused on doing.

   Backend: /api/v1/data-access/connections (api.dataAccess.*).
   Signing secrets are shown exactly once, on create / rotate.
   ========================================================= */

const ED_PATTERNS = [
  {
    id: "webhooks", letter: "A", name: "Signed webhooks",
    latency: "Real-time", direction: "Push", icon: "zap", selfServe: true,
    blurb: "Domain events — call.completed, ticket.created, billing — delivered to your HTTPS endpoint or straight onto your EventBridge bus.",
    stages: [
      { title: "Mikaka outbox", sub: "per-tenant events only", icon: "inbox" },
      { title: "HMAC-SHA256 signed", sub: "id · timestamp · payload", icon: "shield" },
      { title: "Your endpoint / bus", sub: "you verify our signature", icon: "globe" },
    ],
    controls: [
      "Standard Webhooks spec: webhook-id, webhook-timestamp, webhook-signature headers",
      "5-minute timestamp window rejects replays; webhook-id doubles as your idempotency key",
      "Per-tenant signing secret, encrypted at rest, shown once and rotatable anytime",
      "Cross-account EventBridge delivery with IAM role + External ID for AWS-native stacks",
    ],
    bestFor: ["Any platform", "Fastest to ship", "Event-driven systems"],
    confidence: "Events arrive signed and timestamped at your endpoint. You verify our signature — nothing is pullable from our side.",
  },
  {
    id: "exports", letter: "B", name: "Files to your bucket",
    latency: "Batch", direction: "Push", icon: "download", selfServe: true,
    blurb: "Scheduled Parquet / Iceberg drops of your tenant slice into an S3, GCS, ADLS or Huawei OBS bucket that you own and you key.",
    stages: [
      { title: "Tenant-filtered export", sub: "WHERE tenant_id = yours", icon: "filter" },
      { title: "Cross-account role", sub: "External ID · your KMS CMK", icon: "shield" },
      { title: "Your bucket", sub: "Snowpipe · DBMS_CLOUD · COPY", icon: "layers" },
    ],
    controls: [
      "Data lands in your bucket, encrypted with your KMS customer-managed key (BYOK)",
      "Cross-account IAM role gated by an External ID — no shared credentials, no confused deputy",
      "Open formats (Parquet / Iceberg) ingest natively into Snowflake, Redshift, Oracle, BigQuery, Databricks, GaussDB DWS",
      "Revoke your key and the pipeline is cut off instantly — the kill switch is in your hands",
    ],
    bestFor: ["Snowflake", "Redshift", "Oracle ADB", "BigQuery", "Databricks", "Huawei GaussDB"],
    confidence: "Your bucket, your KMS key, your S3 access logs. Revoke the key and we are cut off instantly.",
  },
  {
    id: "cdc", letter: "C", name: "Streaming CDC",
    latency: "Near real-time", direction: "Push", icon: "refresh", selfServe: false,
    blurb: "A live mirror: inserts, updates and deletes stream from a row-filtered Postgres publication into your warehouse.",
    stages: [
      { title: "Row-filtered publication", sub: "WHERE tenant_id = yours, in WAL", icon: "filter" },
      { title: "CDC transport", sub: "Fivetran · Airbyte · DMS · Debezium", icon: "refresh" },
      { title: "Your warehouse", sub: "a continuously updated copy", icon: "chart" },
    ],
    controls: [
      "Postgres 17 row-filtered publications — only your rows ever enter the replication slot",
      "Server-side isolation that does not depend on application RLS",
      "REPLICA IDENTITY configured so update/delete filters hold",
      "Dedicated slots reserved for enterprise accounts and monitored for lag",
    ],
    bestFor: ["Live mirrors", "BigQuery", "Large enterprise tenants"],
    confidence: "A continuously updated copy of only your rows, filtered at the source — not at the destination.",
  },
  {
    id: "direct", letter: "D", name: "Direct BI access",
    latency: "Live", direction: "Pull", icon: "chart", selfServe: false,
    blurb: "Point Tableau, Power BI or Looker at a read replica over JDBC/ODBC with a login that can only ever see your tenant.",
    stages: [
      { title: "Read replica", sub: "never the primary", icon: "layers" },
      { title: "PrivateLink · TLS verify-full", sub: "per-tenant read-only role", icon: "shield" },
      { title: "Your BI tools", sub: "Tableau · Power BI · Looker", icon: "chart" },
    ],
    controls: [
      "Per-tenant read-only database role — tenant bound at the connection, enforced by row-level policy",
      "Served from a read replica so your analytics can never touch production",
      "PrivateLink / VPC peering or strict IP allowlist; TLS verify-full end to end",
      "Short-lived, Vault-issued credentials on a rotation schedule",
    ],
    bestFor: ["Tableau", "Power BI", "Looker", "Ad-hoc SQL"],
    confidence: "Your existing BI stack over a private link, with a read-only login scoped to your tenant and nothing else.",
  },
  {
    id: "iceberg", letter: "E", name: "Zero-copy sharing",
    latency: "Live + batch", direction: "Shared", icon: "sparkles", selfServe: false,
    blurb: "Your slice written once as Apache Iceberg; Snowflake, Oracle, Databricks and Trino read it in place. No ETL, no duplication.",
    stages: [
      { title: "Iceberg tables", sub: "written once, open format", icon: "layers" },
      { title: "REST catalog", sub: "governed, open protocol", icon: "book" },
      { title: "Every engine", sub: "Snowflake · Oracle · Trino · Spark", icon: "globe" },
    ],
    controls: [
      "Open table format — no vendor lock-in, no proprietary export pipeline to trust",
      "Reads are governed through the catalog; grants are auditable and revocable",
      "One copy of the data: nothing drifts, nothing is duplicated across vendors",
      "Pairs with warehouse-native secure data sharing as a zero-movement alternative",
    ],
    bestFor: ["Snowflake", "Oracle ADB", "Databricks", "Lakehouse teams"],
    confidence: "You read the data in place through an open catalog — there is no pipeline to compromise.",
  },
];

const ED_PLATFORMS = [
  { id: "aws",       name: "AWS",            sub: "Redshift · S3 · Athena",     rec: "exports", alt: "webhooks" },
  { id: "oracle",    name: "Oracle",         sub: "Autonomous DB · Exadata",    rec: "exports", alt: "iceberg" },
  { id: "snowflake", name: "Snowflake",      sub: "Secure sharing · Snowpipe",  rec: "iceberg", alt: "exports" },
  { id: "gcp",       name: "Google Cloud",   sub: "BigQuery",                   rec: "cdc",     alt: "exports" },
  { id: "azure",     name: "Azure",          sub: "Synapse · Fabric",           rec: "exports", alt: "webhooks" },
  { id: "huawei",    name: "Huawei Cloud",   sub: "GaussDB DWS · OBS · DLI",    rec: "exports", alt: "webhooks" },
  { id: "bi",        name: "BI tools",       sub: "Tableau · Power BI · Looker",rec: "direct",  alt: "iceberg" },
  { id: "any",       name: "Not sure yet",   sub: "Start universal",            rec: "webhooks",alt: "exports" },
];

const ED_EVENTS = [
  ["call.completed", "Call completed"],
  ["call.started", "Call started"],
  ["call.missed", "Call missed"],
  ["ticket.created", "Ticket created"],
  ["appointment.booked", "Appointment booked"],
  ["billing.invoice", "Billing invoice"],
];

const ED_STATUS_CHIP = {
  active:       <Chip kind="live" dot>live</Chip>,
  pending:      <Chip kind="warn" dot>awaiting validation</Chip>,
  provisioning: <Chip kind="warn" dot>provisioning</Chip>,
  error:        <Chip kind="danger" dot>error</Chip>,
  disabled:     <Chip kind="neutral">disabled</Chip>,
};

const edCopy = async (text, toast, label = "Copied to clipboard") => {
  try {
    await navigator.clipboard.writeText(text);
    toast({ title: "Copied", body: label });
  } catch {
    toast({ title: "Copy failed", body: "Select and copy the value manually.", kind: "danger" });
  }
};

const ED_VERIFY_SNIPPET = `// Verify a Mikaka webhook (Node.js)
const crypto = require("crypto");
function verify(secret, headers, rawBody) {
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // replay window
  const key = Buffer.from(secret.replace("whsec_", ""), "base64");
  const expected = crypto.createHmac("sha256", key)
    .update(\`\${id}.\${ts}.\${rawBody}\`).digest("base64");
  return headers["webhook-signature"]
    .split(" ").some(s => crypto.timingSafeEqual(
      Buffer.from(s.replace("v1,", "")), Buffer.from(expected)));
}`;

const edTrustPolicy = (externalId) => JSON.stringify({
  Version: "2012-10-17",
  Statement: [{
    Effect: "Allow",
    Principal: { AWS: "arn:aws:iam::MIKAKA_DELIVERY_ACCOUNT:role/mikaka-export-writer" },
    Action: "sts:AssumeRole",
    Condition: { StringEquals: { "sts:ExternalId": externalId } },
  }],
}, null, 2);

// Huawei Cloud IAM custom policy to attach to the delegation agency (OBS write,
// scoped to the export bucket). Policy "Version 1.1" is Huawei's policy syntax.
const edObsAgencyPolicy = (bucket, externalId) => JSON.stringify({
  Version: "1.1",
  Statement: [{
    Effect: "Allow",
    Action: ["obs:object:PutObject", "obs:object:GetObject", "obs:bucket:ListBucket", "obs:bucket:HeadBucket"],
    Resource: [
      `OBS:*:*:bucket:${bucket || "YOUR_BUCKET"}`,
      `OBS:*:*:object:${bucket || "YOUR_BUCKET"}/mikaka/${externalId}/*`,
    ],
  }],
}, null, 2);

/* ---------------- small form primitives ---------------- */

const ED_Field = ({ label, hint, children }) => (
  <label style={{ display: "block", marginBottom: 14 }}>
    <div style={{ fontSize: 12.5, fontWeight: 600, marginBottom: 6 }}>{label}</div>
    {children}
    {hint && <div style={{ fontSize: 11.5, color: "var(--fg-faint)", marginTop: 4 }}>{hint}</div>}
  </label>
);

const ED_Seg = ({ options, value, onChange }) => (
  <div className="seg">
    {options.map(([v, l]) => (
      <button key={v} type="button" className={value === v ? "on" : ""} onClick={() => onChange(v)}>{l}</button>
    ))}
  </div>
);

const ED_EmbedToggle = ({ value, onChange }) => (
  <div
    className="card" role="button" tabIndex={0}
    style={{ padding: "12px 14px", display: "flex", gap: 12, alignItems: "flex-start", cursor: "pointer", borderColor: value ? "var(--mk-purple)" : undefined }}
    onClick={() => onChange(!value)}
    onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onChange(!value); } }}
  >
    <div className={"checkbox " + (value ? "on" : "")} style={{ marginTop: 2 }}>{value && <Icon name="check" size={10}/>}</div>
    <div>
      <div style={{ fontSize: 13, fontWeight: 600 }}>Add to AI knowledge base (embeddings)</div>
      <div style={{ fontSize: 12, color: "var(--fg-muted)", marginTop: 2 }}>
        Mikaka chunks and embeds this connection so your AI Voice Employee knows where your data flows and can answer questions about it.
      </div>
    </div>
  </div>
);

const ED_Code = ({ text, toast, label }) => (
  <div style={{ position: "relative", marginTop: 8 }}>
    <pre style={{ background: "var(--bg-sunken)", border: "1px solid var(--border)", borderRadius: "var(--r-sm)", padding: "12px 14px", fontSize: 11.5, lineHeight: 1.55, overflowX: "auto", whiteSpace: "pre", margin: 0 }}>{text}</pre>
    <button className="btn btn-outline btn-sm" style={{ position: "absolute", top: 8, right: 8 }} onClick={() => edCopy(text, toast, label)}>
      <Icon name="copy" size={12}/> Copy
    </button>
  </div>
);

/* ---------------- setup wizard ---------------- */

const ED_SetupWizard = ({ pattern, platform, onClose, onCreated }) => {
  const toast = useToast();
  const [busy, setBusy] = useState(false);
  const [created, setCreated] = useState(null); // response after create (step 2)
  const [testResult, setTestResult] = useState(null);
  const [form, setForm] = useState({
    name: `${pattern.name} — ${platform?.name && platform.id !== "any" ? platform.name : "Main"}`,
    embed: true,
    endpoint_url: "", events: ["call.completed"],
    provider: platform?.id === "huawei" ? "obs" : platform?.id === "gcp" ? "gcs" : platform?.id === "azure" ? "azure" : "s3",
    bucket: "", region: "", role_arn: "", agency: "", domain_id: "", format: "parquet", schedule: "daily",
    destination: "", transport: "fivetran", tables: "",
    bi_tool: "", network: "privatelink", cidrs: "",
    catalog_consumer: "", engine: "", notes: "",
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const buildConfig = () => {
    if (pattern.id === "webhooks") return { endpoint_url: form.endpoint_url.trim(), events: form.events };
    if (pattern.id === "exports") {
      const cfg = {
        provider: form.provider, bucket: form.bucket.trim(), region: form.region.trim(),
        format: form.format, schedule: form.schedule,
      };
      if (form.provider === "s3") cfg.role_arn = form.role_arn.trim();
      if (form.provider === "obs") { cfg.agency = form.agency.trim(); cfg.domain_id = form.domain_id.trim(); }
      return cfg;
    }
    if (pattern.id === "cdc") return {
      destination: form.destination.trim(), transport: form.transport,
      tables: form.tables.split(",").map(s => s.trim()).filter(Boolean), notes: form.notes.trim(),
    };
    if (pattern.id === "direct") return {
      bi_tool: form.bi_tool.trim(), network: form.network,
      cidrs: form.cidrs.split(",").map(s => s.trim()).filter(Boolean), notes: form.notes.trim(),
    };
    return { catalog_consumer: form.catalog_consumer.trim(), engine: form.engine.trim(), notes: form.notes.trim() };
  };

  const submit = async () => {
    if (!form.name.trim()) { toast({ title: "Name required", kind: "danger" }); return; }
    if (pattern.id === "webhooks" && !form.endpoint_url.trim()) { toast({ title: "Endpoint URL required", kind: "danger" }); return; }
    if (pattern.id === "exports" && !form.bucket.trim()) { toast({ title: "Bucket required", kind: "danger" }); return; }
    setBusy(true);
    try {
      const row = await api.dataAccess.create({
        pattern: pattern.id,
        platform: platform?.id || "any",
        name: form.name.trim(),
        config: buildConfig(),
        embed_enabled: form.embed,
      });
      setCreated(row);
      onCreated && onCreated(row);
      toast({ title: "Connection created", body: form.embed ? "Embedding into your AI knowledge base has been queued." : row.name });
    } catch (err) {
      toast({ title: "Could not create connection", body: err?.message || "Try again.", kind: "danger" });
    } finally {
      setBusy(false);
    }
  };

  const sendTest = async () => {
    if (!created?.id) return;
    setBusy(true);
    setTestResult(null);
    try {
      const res = await api.dataAccess.test(created.id);
      setTestResult(res);
      toast(res.ok
        ? { title: "Test delivered", body: `Endpoint answered HTTP ${res.status_code}.` }
        : { title: "Test failed", body: res.detail, kind: "danger" });
    } catch (err) {
      toast({ title: "Test failed", body: err?.message, kind: "danger" });
    } finally {
      setBusy(false);
    }
  };

  const toggleEvent = (ev) => {
    set("events", form.events.includes(ev) ? form.events.filter(e => e !== ev) : [...form.events, ev]);
  };

  const formBody = (
    <>
      <ED_Field label="Connection name">
        <input className="input" value={form.name} onChange={e => set("name", e.target.value)} maxLength={120}/>
      </ED_Field>

      {pattern.id === "webhooks" && (
        <>
          <ED_Field label="Endpoint URL" hint="Public HTTPS endpoint. We send Standard-Webhooks signed POSTs; private/internal hosts are rejected.">
            <input className="input" placeholder="https://api.yourcompany.com/hooks/mikaka" value={form.endpoint_url} onChange={e => set("endpoint_url", e.target.value)}/>
          </ED_Field>
          <ED_Field label="Events to deliver">
            <div className="row gap-2" style={{ flexWrap: "wrap" }}>
              {ED_EVENTS.map(([ev, label]) => {
                const on = form.events.includes(ev);
                return (
                  <button key={ev} type="button" className="chip chip-btn" onClick={() => toggleEvent(ev)}
                          style={on ? { borderColor: "var(--mk-orange)", color: "var(--mk-orange-600)" } : undefined}>
                    {on && <Icon name="check" size={11}/>} {label}
                  </button>
                );
              })}
            </div>
          </ED_Field>
        </>
      )}

      {pattern.id === "exports" && (
        <>
          <ED_Field label="Cloud provider">
            <ED_Seg value={form.provider} onChange={v => set("provider", v)}
                    options={[["s3", "AWS S3"], ["gcs", "Google GCS"], ["azure", "Azure ADLS"], ["obs", "Huawei OBS"]]}/>
          </ED_Field>
          <div className="grid grid-2" style={{ gap: 12 }}>
            <ED_Field label="Bucket name">
              <input className="input" placeholder="acme-mikaka-exports" value={form.bucket} onChange={e => set("bucket", e.target.value)}/>
            </ED_Field>
            <ED_Field label="Region">
              <input className="input" placeholder={form.provider === "obs" ? "af-south-1 (Johannesburg)" : "eu-central-1"} value={form.region} onChange={e => set("region", e.target.value)}/>
            </ED_Field>
          </div>
          {form.provider === "s3" && (
            <ED_Field label="IAM role ARN (we assume this role)" hint="Create a role we can assume; you'll add the External ID we generate in the next step.">
              <input className="input" placeholder="arn:aws:iam::123456789012:role/mikaka-export-writer" value={form.role_arn} onChange={e => set("role_arn", e.target.value)}/>
            </ED_Field>
          )}
          {form.provider === "obs" && (
            <div className="grid grid-2" style={{ gap: 12 }}>
              <ED_Field label="IAM agency name" hint="Create an agency in Huawei IAM delegating OBS write on this bucket to Mikaka; full instructions appear after you create the connection.">
                <input className="input" placeholder="mikaka-export-writer" value={form.agency} onChange={e => set("agency", e.target.value)}/>
              </ED_Field>
              <ED_Field label="Account (domain) ID" hint="Your Huawei Cloud account ID — IAM → My Credentials.">
                <input className="input" placeholder="0a1b2c3d4e5f..." value={form.domain_id} onChange={e => set("domain_id", e.target.value)}/>
              </ED_Field>
            </div>
          )}
          <div className="grid grid-2" style={{ gap: 12 }}>
            <ED_Field label="File format">
              <ED_Seg value={form.format} onChange={v => set("format", v)}
                      options={[["parquet", "Parquet"], ["iceberg", "Iceberg"], ["csv", "CSV"]]}/>
            </ED_Field>
            <ED_Field label="Schedule">
              <ED_Seg value={form.schedule} onChange={v => set("schedule", v)}
                      options={[["hourly", "Hourly"], ["daily", "Daily"], ["weekly", "Weekly"]]}/>
            </ED_Field>
          </div>
        </>
      )}

      {pattern.id === "cdc" && (
        <>
          <ED_Field label="Destination warehouse" hint="Where the live mirror should land.">
            <input className="input" placeholder="BigQuery · dataset analytics_mikaka" value={form.destination} onChange={e => set("destination", e.target.value)}/>
          </ED_Field>
          <ED_Field label="CDC transport">
            <ED_Seg value={form.transport} onChange={v => set("transport", v)}
                    options={[["fivetran", "Fivetran"], ["airbyte", "Airbyte"], ["dms", "AWS DMS"], ["debezium", "Debezium"]]}/>
          </ED_Field>
          <ED_Field label="Tables (comma-separated)" hint="Which datasets to mirror — e.g. calls, call_events, tickets.">
            <input className="input" placeholder="calls, call_events" value={form.tables} onChange={e => set("tables", e.target.value)}/>
          </ED_Field>
        </>
      )}

      {pattern.id === "direct" && (
        <>
          <ED_Field label="BI tool">
            <input className="input" placeholder="Tableau / Power BI / Looker / dbt" value={form.bi_tool} onChange={e => set("bi_tool", e.target.value)}/>
          </ED_Field>
          <ED_Field label="Network path">
            <ED_Seg value={form.network} onChange={v => set("network", v)}
                    options={[["privatelink", "PrivateLink / peering"], ["ip_allowlist", "IP allowlist"]]}/>
          </ED_Field>
          {form.network === "ip_allowlist" && (
            <ED_Field label="Allowed CIDRs (comma-separated)">
              <input className="input" placeholder="203.0.113.0/24" value={form.cidrs} onChange={e => set("cidrs", e.target.value)}/>
            </ED_Field>
          )}
        </>
      )}

      {pattern.id === "iceberg" && (
        <>
          <ED_Field label="Consuming catalog / account" hint="e.g. your Snowflake account locator or Databricks workspace.">
            <input className="input" placeholder="acme-prod.snowflakecomputing.com" value={form.catalog_consumer} onChange={e => set("catalog_consumer", e.target.value)}/>
          </ED_Field>
          <ED_Field label="Query engine">
            <input className="input" placeholder="Snowflake / Trino / Spark / Oracle ADB" value={form.engine} onChange={e => set("engine", e.target.value)}/>
          </ED_Field>
        </>
      )}

      {!pattern.selfServe && (
        <ED_Field label="Notes for the solutions team (optional)">
          <input className="input" placeholder="Timeline, region constraints, security contacts…" value={form.notes} onChange={e => set("notes", e.target.value)}/>
        </ED_Field>
      )}

      <ED_EmbedToggle value={form.embed} onChange={v => set("embed", v)}/>
    </>
  );

  const successBody = created && (
    <>
      <div className="row gap-2" style={{ alignItems: "center", marginBottom: 14 }}>
        <span style={{ width: 34, height: 34, borderRadius: 999, background: "var(--mk-success)", color: "#fff", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
          <Icon name="check" size={16}/>
        </span>
        <div>
          <div style={{ fontSize: 14.5, fontWeight: 600 }}>{created.name}</div>
          <div className="row gap-2" style={{ marginTop: 3 }}>
            {ED_STATUS_CHIP[created.status] || <Chip kind="neutral">{created.status}</Chip>}
            {created.embed_enabled && <Chip kind="neutral">embedding queued</Chip>}
          </div>
        </div>
      </div>

      {pattern.id === "webhooks" && created.signing_secret && (
        <>
          <div style={{ fontSize: 12.5, fontWeight: 600, marginBottom: 4 }}>Signing secret — shown only once</div>
          <div style={{ fontSize: 12, color: "var(--fg-muted)", marginBottom: 6 }}>
            Store it in your secret manager now. You can rotate it later, but this value is never displayed again.
          </div>
          <ED_Code text={created.signing_secret} toast={toast} label="Signing secret"/>
          <div style={{ fontSize: 12.5, fontWeight: 600, margin: "16px 0 4px" }}>Verify our signature</div>
          <ED_Code text={ED_VERIFY_SNIPPET} toast={toast} label="Verification snippet"/>
          <div className="row gap-2" style={{ marginTop: 16, alignItems: "center", flexWrap: "wrap" }}>
            <button className="btn btn-primary btn-sm" onClick={sendTest} disabled={busy}>
              <Icon name="zap" size={13}/> {busy ? "Sending…" : "Send signed test event"}
            </button>
            {testResult && (testResult.ok
              ? <Chip kind="live" dot>delivered · HTTP {testResult.status_code}</Chip>
              : <Chip kind="danger" dot>{testResult.detail}</Chip>)}
          </div>
        </>
      )}

      {pattern.id === "exports" && created.external_id && (
        <>
          <div style={{ fontSize: 12.5, fontWeight: 600, marginBottom: 4 }}>Your External ID</div>
          <div style={{ fontSize: 12, color: "var(--fg-muted)", marginBottom: 6 }}>
            {(created.config?.provider === "obs")
              ? <>Exports are written under the prefix <b>mikaka/{created.external_id}/</b> in your bucket. Scope your agency's policy to that prefix so only your tenant's slice is ever writable.</>
              : <>Add this condition to your role's trust policy. It prevents anyone but your tenant from invoking the delivery role (confused-deputy protection).</>}
          </div>
          <ED_Code text={created.external_id} toast={toast} label="External ID"/>
          {(created.config?.provider === "obs") ? (
            <>
              <div style={{ fontSize: 12.5, fontWeight: 600, margin: "16px 0 4px" }}>Set up the delegation agency in Huawei IAM</div>
              <div style={{ fontSize: 12, color: "var(--fg-muted)", marginBottom: 6, lineHeight: 1.6 }}>
                In <b>IAM → Agencies → Create Agency</b>, choose agency type <b>Cloud account</b>, name it
                <b> {created.config?.agency || "mikaka-export-writer"}</b>, set the delegated account to <b>Mikaka Delivery</b> (we
                confirm our account name during validation), then attach this custom policy:
              </div>
              <ED_Code text={edObsAgencyPolicy(created.config?.bucket, created.external_id)} toast={toast} label="Agency policy JSON"/>
            </>
          ) : (
            <>
              <div style={{ fontSize: 12.5, fontWeight: 600, margin: "16px 0 4px" }}>Trust policy for your role</div>
              <ED_Code text={edTrustPolicy(created.external_id)} toast={toast} label="Trust policy JSON"/>
            </>
          )}
          <div style={{ fontSize: 12, color: "var(--fg-muted)", marginTop: 12 }}>
            Status stays <b>awaiting validation</b> until our delivery service confirms it can {created.config?.provider === "obs" ? "assume the agency" : "assume the role"} and write a test object. You'll see it flip to <b>live</b> here.
          </div>
        </>
      )}

      {!pattern.selfServe && (
        <div style={{ fontSize: 13, color: "var(--fg-muted)", lineHeight: 1.6 }}>
          This pattern needs cloud-side provisioning (replication slots, network paths, or catalog grants), so it starts in
          <b> provisioning</b>. Our solutions team picks it up with your details and confirms the cutover window with your security team.
          Track its status in <b>Your data connections</b> on this page.
        </div>
      )}
    </>
  );

  return (
    <Modal
      open
      onClose={onClose}
      size="lg"
      title={created ? "Connection created" : `Step 3 of 3 — Connect ${pattern.name.toLowerCase()}`}
      sub={created ? null : pattern.blurb}
      footer={created ? (
        <button className="btn btn-primary btn-sm" onClick={onClose}>Done</button>
      ) : (
        <>
          <button className="btn btn-outline btn-sm" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary btn-sm" onClick={submit} disabled={busy}>
            {busy ? "Creating…" : pattern.selfServe ? "Create connection" : "Request provisioning"}
          </button>
        </>
      )}
    >
      {created ? successBody : formBody}
    </Modal>
  );
};

/* ---------------- connection list ---------------- */

const ED_EmbedChip = ({ c }) => {
  if (!c.embed_enabled) return <Chip kind="neutral">AI embeddings off</Chip>;
  if (c.embed_status === "embedded") return <Chip kind="live" dot>in AI knowledge</Chip>;
  if (c.embed_status === "error") return <Chip kind="danger" dot>embed failed</Chip>;
  return <Chip kind="warn" dot>embedding…</Chip>;
};

const ED_ConnectionCard = ({ c, onAction, busy }) => {
  const pattern = ED_PATTERNS.find(p => p.id === c.pattern) || ED_PATTERNS[0];
  const cfg = c.config || {};
  const target = c.pattern === "webhooks" ? cfg.endpoint_url
    : c.pattern === "exports" ? `${(cfg.provider || "s3").toUpperCase()} · ${cfg.bucket || ""}`
    : c.pattern === "cdc" ? cfg.destination
    : c.pattern === "direct" ? cfg.bi_tool
    : cfg.catalog_consumer;
  return (
    <div className="card card-pad">
      <div className="row between" style={{ flexWrap: "wrap", gap: 10 }}>
        <div className="row gap-2" style={{ alignItems: "center", minWidth: 0 }}>
          <span style={{ width: 30, height: 30, borderRadius: 9, background: "var(--mk-orange-50)", color: "var(--mk-orange-600)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 12.5, fontWeight: 700, flexShrink: 0 }}>
            {pattern.letter}
          </span>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.name}</div>
            <div style={{ fontSize: 12, color: "var(--fg-muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
              {pattern.name}{target ? ` → ${target}` : ""}
            </div>
          </div>
        </div>
        <div className="row gap-2" style={{ flexWrap: "wrap" }}>
          {ED_STATUS_CHIP[c.status] || <Chip kind="neutral">{c.status}</Chip>}
          <ED_EmbedChip c={c}/>
        </div>
      </div>
      {(c.last_delivery_at || c.last_error) && (
        <div style={{ fontSize: 11.5, color: c.last_delivery_status === "error" ? "var(--mk-danger)" : "var(--fg-faint)", marginTop: 8 }}>
          {c.last_error
            ? `Last delivery failed: ${c.last_error}`
            : `Last delivery ${new Date(c.last_delivery_at).toLocaleString()} · ${c.last_delivery_status}`}
        </div>
      )}
      <div className="row gap-2" style={{ marginTop: 12, flexWrap: "wrap" }}>
        {c.pattern === "webhooks" && c.status === "active" && (
          <button className="btn btn-outline btn-sm" disabled={busy} onClick={() => onAction("test", c)}>
            <Icon name="zap" size={12}/> Test
          </button>
        )}
        {c.pattern === "webhooks" && (
          <button className="btn btn-outline btn-sm" disabled={busy} onClick={() => onAction("rotate", c)}>
            <Icon name="refresh" size={12}/> Rotate secret
          </button>
        )}
        <button className="btn btn-outline btn-sm" disabled={busy} onClick={() => onAction(c.status === "disabled" ? "enable" : "disable", c)}>
          {c.status === "disabled" ? <><Icon name="play" size={12}/> Enable</> : <><Icon name="pause" size={12}/> Disable</>}
        </button>
        <button className="btn btn-outline btn-sm" disabled={busy} onClick={() => onAction("delete", c)} style={{ color: "var(--mk-danger)" }}>
          <Icon name="x" size={12}/> Delete
        </button>
      </div>
    </div>
  );
};

/* ---------------- journey stepper ---------------- */

const ED_Stepper = ({ current }) => {
  const steps = ["Choose your platform", "Pick the delivery pattern", "Connect"];
  return (
    <div className="row" style={{ gap: 0, marginBottom: 24, flexWrap: "wrap" }}>
      {steps.map((label, i) => {
        const n = i + 1;
        const done = current > n;
        const active = current === n;
        return (
          <React.Fragment key={label}>
            {i > 0 && <div style={{ flex: "0 1 48px", minWidth: 16, height: 2, background: current > i ? "var(--mk-orange)" : "var(--border)", margin: "0 8px", alignSelf: "center", transition: "background .3s" }}/>}
            <div className="row gap-2" style={{ alignItems: "center" }}>
              <span style={{
                width: 26, height: 26, borderRadius: 999, display: "inline-flex", alignItems: "center", justifyContent: "center",
                fontSize: 12.5, fontWeight: 700, transition: "all .3s",
                background: done || active ? "var(--mk-orange)" : "var(--bg-sunken)",
                color: done || active ? "#fff" : "var(--fg-faint)",
                boxShadow: active ? "0 0 0 4px var(--mk-orange-100)" : "none",
              }}>
                {done ? <Icon name="check" size={13}/> : n}
              </span>
              <span style={{ fontSize: 13, fontWeight: active ? 600 : 500, color: active ? "var(--fg)" : "var(--fg-muted)" }}>{label}</span>
            </div>
          </React.Fragment>
        );
      })}
    </div>
  );
};

/* ---------------- page ---------------- */

const EnterpriseDataAccess = () => {
  const toast = useToast();
  const store = MK_USE();
  const [platformId, setPlatformId] = useState(null);          // step 1 — nothing chosen yet
  const [patternId, setPatternId] = useState(null);            // step 2 — set when platform picked
  const [connections, setConnections] = useState([]);
  const [listState, setListState] = useState("loading"); // loading | ready | unauth | unavailable | error
  const [listError, setListError] = useState("");
  const [busyId, setBusyId] = useState(null);
  const [wizard, setWizard] = useState(null); // pattern object when open (step 3)
  const [rotated, setRotated] = useState(null); // {name, secret} after rotation
  const [confirmDelete, setConfirmDelete] = useState(null);
  const stepTwoRef = useRef(null);

  const platform = ED_PLATFORMS.find(p => p.id === platformId) || null;
  const pattern = ED_PATTERNS.find(p => p.id === patternId) || null;
  const journeyStep = !platform ? 1 : 2;

  const loadConnections = async (quiet = true) => {
    try {
      const rows = await api.dataAccess.list();
      setConnections(Array.isArray(rows) ? rows : []);
      setListState("ready");
      if (!quiet) toast({ title: "Connections refreshed" });
    } catch (err) {
      if (err?.status === 401) setListState("unauth");
      else if (err?.status === 503) { setListState("unavailable"); setListError(err?.message || ""); }
      else { setListState("error"); setListError(err?.message || "Could not load connections."); }
    }
  };

  useEffect(() => { loadConnections(); }, []);

  const pickPlatform = (p) => {
    setPlatformId(p.id);
    setPatternId(p.rec);
    // Bring step 2 into view once it renders.
    setTimeout(() => stepTwoRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }), 80);
  };

  const onAction = async (action, c) => {
    if (action === "delete") { setConfirmDelete(c); return; }
    setBusyId(c.id);
    try {
      if (action === "test") {
        const res = await api.dataAccess.test(c.id);
        toast(res.ok
          ? { title: "Test delivered", body: `Endpoint answered HTTP ${res.status_code}.` }
          : { title: "Test failed", body: res.detail, kind: "danger" });
      } else if (action === "rotate") {
        const row = await api.dataAccess.rotateSecret(c.id);
        setRotated({ name: c.name, secret: row.signing_secret });
      } else if (action === "enable" || action === "disable") {
        await api.dataAccess.update(c.id, { enabled: action === "enable" });
        toast({ title: action === "enable" ? "Connection enabled" : "Connection disabled", body: c.name });
      }
      await loadConnections();
    } catch (err) {
      toast({ title: "Action failed", body: err?.message, kind: "danger" });
    } finally {
      setBusyId(null);
    }
  };

  const doDelete = async () => {
    const c = confirmDelete;
    setConfirmDelete(null);
    setBusyId(c.id);
    try {
      await api.dataAccess.remove(c.id);
      toast({ title: "Connection deleted", body: `${c.name} and its knowledge-base entry were removed.` });
      await loadConnections();
    } catch (err) {
      toast({ title: "Delete failed", body: err?.message, kind: "danger" });
    } finally {
      setBusyId(null);
    }
  };

  const hasConnections = listState === "ready" && connections.length > 0;

  return (
    <div className="page page-mount">
      <style>{`
        @keyframes ed-dash { to { stroke-dashoffset: -16; } }
        .ed-flow-line { stroke-dasharray: 5 11; animation: ed-dash 1.1s linear infinite; }
        .ed-platform { cursor: pointer; transition: border-color .15s, transform .15s, box-shadow .15s; }
        .ed-platform:hover { transform: translateY(-1px); box-shadow: var(--sh-md); }
        .ed-platform.on { border-color: var(--mk-orange); box-shadow: 0 0 0 1px var(--mk-orange); }
        .ed-tab { cursor: pointer; transition: border-color .15s, background .15s; }
        .ed-tab.on { border-color: var(--mk-orange); background: var(--mk-orange-50); }
        [data-theme="dark"] .ed-tab.on { background: rgba(242,118,33,.12); }
        .ed-watermark { color: var(--mk-orange-50); }
        [data-theme="dark"] .ed-watermark { color: rgba(242,118,33,.08); }
        @media (prefers-reduced-motion: reduce) { .ed-flow-line { animation: none; } }
      `}</style>

      <div className="page-header">
        <div>
          <h1 className="page-title">Enterprise Data Access</h1>
          <p className="page-sub">Your data, in your cloud, under your keys. Three steps from "where does it live" to a live, governed connection.</p>
        </div>
        <div className="row gap-2">
          <button className="btn btn-outline btn-sm" onClick={() => loadConnections(false)}>
            <Icon name="refresh" size={14}/> Refresh
          </button>
          {hasConnections && pattern && (
            <button className="btn btn-primary btn-sm" onClick={() => setWizard(pattern)}>
              <Icon name="plus" size={14}/> New connection
            </button>
          )}
        </div>
      </div>

      {/* Existing connections come first for returning users */}
      {listState === "unavailable" && (
        <div className="card card-pad" style={{ fontSize: 13, color: "var(--fg-muted)", marginBottom: 24 }}>
          <b>Data access isn't enabled on this environment yet.</b> {listError}
        </div>
      )}
      {listState === "unauth" && (
        <div className="card card-pad" style={{ fontSize: 13, color: "var(--fg-muted)", marginBottom: 24 }}>
          Sign in to your workspace to create and manage live data connections. The setup guide below stays browsable.
        </div>
      )}
      {listState === "error" && (
        <div className="card card-pad" style={{ fontSize: 13, color: "var(--mk-danger)", marginBottom: 24 }}>{listError}</div>
      )}
      {hasConnections && (
        <Section title="Your data connections" sub="Create, test, rotate and revoke without a ticket.">
          <div className="grid grid-2 stagger">
            {connections.map(c => (
              <ED_ConnectionCard key={c.id} c={c} busy={busyId === c.id} onAction={onAction}/>
            ))}
          </div>
        </Section>
      )}

      {/* Guided journey */}
      <Section
        title={hasConnections ? "Add another connection" : "Set up your first connection"}
        sub="Answer one question and we route you to the right pattern — most teams are live in minutes."
      >
        <div className="card card-pad">
          <ED_Stepper current={journeyStep}/>

          {/* Step 1 — platform */}
          <div className="uppercase-kick" style={{ marginBottom: 10 }}>Step 1 · Where does your data live?</div>
          <div className="grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))" }}>
            {ED_PLATFORMS.map(p => (
              <div
                key={p.id}
                className={`card ed-platform ${platformId === p.id ? "on" : ""}`}
                style={{ padding: "14px 16px" }}
                role="button" tabIndex={0}
                onClick={() => pickPlatform(p)}
                onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); pickPlatform(p); } }}
              >
                <div style={{ fontSize: 13.5, fontWeight: 600 }}>{p.name}</div>
                <div style={{ fontSize: 11.5, color: "var(--fg-muted)", marginTop: 2 }}>{p.sub}</div>
              </div>
            ))}
          </div>

          {/* Step 2 — pattern (appears after step 1) */}
          {platform && (
            <div ref={stepTwoRef} className="page-mount" style={{ marginTop: 28 }}>
              <div className="uppercase-kick" style={{ marginBottom: 4 }}>Step 2 · Pick the delivery pattern</div>
              <div style={{ fontSize: 12.5, color: "var(--fg-muted)", marginBottom: 12 }}>
                {platform.id !== "any"
                  ? <>For <b>{platform.name}</b> we recommend <b>{ED_PATTERNS.find(x => x.id === platform.rec)?.name}</b>; {ED_PATTERNS.find(x => x.id === platform.alt)?.name} is the usual alternative.</>
                  : <>Signed webhooks are the universal starting point — every platform can receive them.</>}
              </div>
              <div className="row gap-2" style={{ flexWrap: "wrap", marginBottom: 16 }}>
                {ED_PATTERNS.map(p => {
                  const isRec = platform.rec === p.id;
                  const isAlt = platform.alt === p.id;
                  return (
                    <div
                      key={p.id}
                      className={`card ed-tab ${patternId === p.id ? "on" : ""}`}
                      style={{ padding: "10px 14px", display: "flex", alignItems: "center", gap: 8 }}
                      role="button" tabIndex={0}
                      onClick={() => setPatternId(p.id)}
                      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setPatternId(p.id); } }}
                    >
                      <span style={{ width: 22, height: 22, borderRadius: 7, background: patternId === p.id ? "var(--mk-orange)" : "var(--bg-sunken)", color: patternId === p.id ? "#fff" : "var(--fg-muted)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 11.5, fontWeight: 700 }}>{p.letter}</span>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</span>
                      {isRec && platform.id !== "any" && <Chip kind="live">best fit</Chip>}
                      {isAlt && platform.id !== "any" && <Chip kind="neutral">alt</Chip>}
                    </div>
                  );
                })}
              </div>
              {pattern && (
                <ED_PatternDetail
                  pattern={pattern}
                  recommendedFor={platform.rec === pattern.id && platform.id !== "any" ? platform.name : null}
                  onSetup={() => setWizard(pattern)}
                />
              )}
            </div>
          )}

          {!platform && (
            <div style={{ fontSize: 12.5, color: "var(--fg-faint)", marginTop: 16 }}>
              Pick a platform above to see your recommended delivery pattern.
            </div>
          )}
        </div>
      </Section>

      {/* Quiet trust footer — the full story lives on the landing page */}
      <div className="row between card" style={{ padding: "14px 18px", flexWrap: "wrap", gap: 10 }}>
        <div className="row gap-2" style={{ alignItems: "center", fontSize: 12.5, color: "var(--fg-muted)" }}>
          <Icon name="shield" size={15} style={{ color: "var(--mk-success)" }}/>
          Tenant-scoped at the source · your keys, your kill switch · every delivery audited.
        </div>
        <a className="link-u" style={{ fontSize: 12.5 }} href="/compliance" onClick={(e) => { e.preventDefault(); window.history.pushState({}, "", "/compliance"); window.dispatchEvent(new PopStateEvent("popstate")); }}>
          How we protect your data →
        </a>
      </div>

      {/* Overlays */}
      {wizard && (
        <ED_SetupWizard
          pattern={wizard}
          platform={platform}
          onClose={() => setWizard(null)}
          onCreated={() => loadConnections()}
        />
      )}
      {rotated && (
        <Modal open onClose={() => setRotated(null)} size="md" title="New signing secret" sub={`${rotated.name} — shown only once`}
               footer={<button className="btn btn-primary btn-sm" onClick={() => setRotated(null)}>I've stored it</button>}>
          <div style={{ fontSize: 12.5, color: "var(--fg-muted)", marginBottom: 8 }}>
            Update your secret manager now; the previous secret stops verifying as soon as you deploy this one.
          </div>
          <ED_Code text={rotated.secret || ""} toast={toast} label="Signing secret"/>
        </Modal>
      )}
      {confirmDelete && (
        <Modal open onClose={() => setConfirmDelete(null)} size="sm" title="Delete connection?" sub={confirmDelete.name}
               footer={(
                 <>
                   <button className="btn btn-outline btn-sm" onClick={() => setConfirmDelete(null)}>Cancel</button>
                   <button className="btn btn-primary btn-sm" style={{ background: "var(--mk-danger)", borderColor: "var(--mk-danger)" }} onClick={doDelete}>Delete</button>
                 </>
               )}>
          <div style={{ fontSize: 13, color: "var(--fg-muted)", lineHeight: 1.6 }}>
            Delivery stops immediately and the connection's entry is removed from your AI knowledge base. This cannot be undone.
          </div>
        </Modal>
      )}
    </div>
  );
};

/* ---------------- explanatory pieces (pipeline + detail) ---------------- */

const ED_FlowArrow = ({ vertical }) => (
  <svg
    className="ed-flow"
    width={vertical ? 16 : 56} height={vertical ? 36 : 16}
    viewBox={vertical ? "0 0 16 36" : "0 0 56 16"}
    aria-hidden
  >
    <line
      className="ed-flow-line"
      x1={vertical ? 8 : 2}  y1={vertical ? 2 : 8}
      x2={vertical ? 8 : 54} y2={vertical ? 34 : 8}
      stroke="var(--mk-orange)" strokeWidth="2" strokeLinecap="round"
    />
  </svg>
);

const ED_StageCard = ({ stage, accent }) => (
  <div className="card" style={{ flex: 1, minWidth: 150, padding: "14px 16px", borderColor: accent ? "var(--mk-orange)" : undefined }}>
    <div className="row gap-2" style={{ alignItems: "center" }}>
      <span style={{ width: 30, height: 30, borderRadius: 10, background: "var(--mk-orange-50)", color: "var(--mk-orange-600)", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
        <Icon name={stage.icon} size={15}/>
      </span>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 13, fontWeight: 600, letterSpacing: "-0.01em" }}>{stage.title}</div>
        <div style={{ fontSize: 11.5, color: "var(--fg-muted)", marginTop: 1 }}>{stage.sub}</div>
      </div>
    </div>
  </div>
);

const ED_Pipeline = ({ pattern }) => {
  const [narrow, setNarrow] = useState(() => window.innerWidth < 760);
  useEffect(() => {
    const onResize = () => setNarrow(window.innerWidth < 760);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  return (
    <div
      key={pattern.id}
      className="page-mount"
      style={{ display: "flex", flexDirection: narrow ? "column" : "row", alignItems: "center", gap: 4, margin: "18px 0 22px" }}
    >
      {pattern.stages.map((stage, i) => (
        <React.Fragment key={stage.title}>
          {i > 0 && <ED_FlowArrow vertical={narrow}/>}
          <ED_StageCard stage={stage} accent={i === 1}/>
        </React.Fragment>
      ))}
    </div>
  );
};

const ED_PatternDetail = ({ pattern, recommendedFor, onSetup }) => (
  <div className="card card-pad" style={{ position: "relative", overflow: "hidden", background: "var(--bg-sunken)" }}>
    <div className="ed-watermark" style={{ position: "absolute", top: -34, right: -10, fontSize: 130, fontWeight: 700, lineHeight: 1, userSelect: "none", pointerEvents: "none" }}>
      {pattern.letter}
    </div>
    <div className="row between" style={{ flexWrap: "wrap", gap: 10, position: "relative" }}>
      <div>
        <div className="row gap-2" style={{ alignItems: "center", flexWrap: "wrap" }}>
          <h3 style={{ margin: 0, fontSize: 19, fontWeight: 600, letterSpacing: "-0.02em" }}>
            Pattern {pattern.letter} — {pattern.name}
          </h3>
          {recommendedFor && <Chip kind="live" dot>recommended for {recommendedFor}</Chip>}
          {pattern.selfServe
            ? <Chip kind="neutral">self-serve</Chip>
            : <Chip kind="neutral">provisioned</Chip>}
        </div>
        <div className="row gap-2" style={{ marginTop: 8, flexWrap: "wrap" }}>
          <Chip kind="neutral">{pattern.latency}</Chip>
          <Chip kind="neutral">{pattern.direction}</Chip>
          {pattern.bestFor.map(b => <Chip key={b} kind="neutral">{b}</Chip>)}
        </div>
      </div>
      <button className="btn btn-primary btn-sm" onClick={onSetup}>
        <Icon name="arrow-right" size={14}/> {pattern.selfServe ? "Continue — set up now" : "Continue — request provisioning"}
      </button>
    </div>

    <p style={{ fontSize: 13.5, color: "var(--fg-muted)", maxWidth: 640, margin: "12px 0 0", position: "relative" }}>{pattern.blurb}</p>

    <ED_Pipeline pattern={pattern}/>

    <div className="uppercase-kick" style={{ marginBottom: 10 }}>How it stays yours</div>
    <div className="grid grid-2" style={{ gap: 10 }}>
      {pattern.controls.map(c => (
        <div key={c} className="row gap-2" style={{ alignItems: "flex-start", fontSize: 12.5, color: "var(--fg-muted)" }}>
          <span style={{ color: "var(--mk-success)", marginTop: 1, flexShrink: 0 }}><Icon name="check" size={13}/></span>
          <span>{c}</span>
        </div>
      ))}
    </div>

    <div style={{ marginTop: 18, padding: "12px 16px", borderLeft: "3px solid var(--mk-orange)", background: "var(--bg-elev)", borderRadius: "0 var(--r-sm) var(--r-sm) 0", fontSize: 13, fontStyle: "italic", color: "var(--fg-muted)" }}>
      “{pattern.confidence}”
    </div>
  </div>
);

Object.assign(window, { EnterpriseDataAccess });
