// ── Veritee · Explorer tab (the Veritee Ledger) ────────────────────────────
const { useState: useStateExp, useEffect: useEffectExp } = React;

function relTime(ms) {
  if (!Number.isFinite(ms)) return "n/a";
  const diff = Date.now() - ms;
  const m = Math.round(diff / 60000);
  if (m < 60) return m + "m ago";
  const h = Math.round(m / 60);
  if (h < 48) return h + "h ago";
  return Math.round(h / 24) + "d ago";
}
// Sync freshness reads in seconds while it is recent.
function syncAgo(ms) {
  if (!Number.isFinite(ms)) return "n/a";
  const s = Math.max(0, Math.round((Date.now() - ms) / 1000));
  return s < 60 ? s + "s ago" : relTime(ms);
}
function fmtDate(ms) {
  if (!Number.isFinite(ms)) return "n/a";
  const dt = new Date(ms);
  return dt.toISOString().replace("T", " ").slice(0, 19) + " UTC";
}
// Git-style short hash for row displays: random hashes never share prefixes,
// so a leading slice identifies a record as well as head…tail — and reads
// cleaner. Copy buttons still carry the full value (Mono's `full` prop).
const shortHash = (s, n = 8) => (typeof s === "string" && s.length > n + 1 ? s.slice(0, n) + "…" : s);
// Counts reach thousands per day — group digits so they stay readable.
const fmtCount = (n) => (typeof n === "number" ? n.toLocaleString("en-US") : n);

// Midnight preprod explorer link for a contract address.
// NOTE: the contract-page path is unverified — confirm in a browser and adjust if it 404s.
const explorerContractUrl = (addr) => `https://preprod.midnightexplorer.com/contracts/${addr}`;

/* ── Shareable deep links ──
   #explorer/reg/<registration-id> opens that registration's drawer;
   #explorer/app/<app-key> opens that app's verification stream. The Explorer
   mirrors its state into the hash (see effects in <Explorer/>), so the address
   bar is always shareable; this button copies it explicitly. */
const CopyLinkButton = ({ hash, style }) => {
  const [done, setDone] = useStateExp(false);
  const copy = () => {
    const url = window.location.origin + window.location.pathname + hash;
    navigator.clipboard.writeText(url).then(() => {
      setDone(true);
      setTimeout(() => setDone(false), 1600);
    }).catch(() => { window.prompt("Copy link:", url); });
  };
  return (
    <Button variant="small" onClick={copy} title="Copy shareable link" style={{ color: done ? "var(--v-teal)" : "var(--v-ink)", ...style }}>
      {done ? "Copied" : "Copy link"}
    </Button>
  );
};

/* Centered empty / loading state inside a table or grid. */
const EmptyState = ({ children, boxed }) => (
  <div style={{ ...(boxed ? vCard : {}), padding: "48px 22px", textAlign: "center", fontSize: 14, opacity: boxed ? 1 : 0.78, color: "var(--v-ink-78)" }}>{children}</div>
);

/* ── Application tile (reg view) ──
   The Docker-Hub "repository" model: a tile is an application, and its
   Build-Reproduced TEE Images are the rows inside — each image row opens that
   registration's drawer; the footer opens the app's verification stream. The
   tile identicon is seeded by the app key, so it is stable across new image
   registrations. */
// Tiles show the newest IMAGES_COLLAPSED images; a third row expands the
// rest. A tile with exactly one extra image just shows it (the expander row
// would take the same space), and an active search expands every tile so a
// matching image is never hidden.
const IMAGES_COLLAPSED = 2;
const AppTile = ({ app, images, verCount, onOpenImage, onOpenStream, forceOpen }) => {
  const featured = images[0];
  const [open, setOpen] = useStateExp(false);
  const collapsible = images.length > IMAGES_COLLAPSED + 1;
  const expanded = open || forceOpen || !collapsible;
  const shown = expanded ? images : images.slice(0, IMAGES_COLLAPSED);
  const hidden = images.length - IMAGES_COLLAPSED;
  return (
    <div className="v-lift" style={{ ...vCard, display: "flex", flexDirection: "column" }}>
      {/* app identity */}
      <div style={{ padding: "18px 20px 14px" }}>
        <div style={{ display: "flex", gap: 14, alignItems: "flex-start" }}>
          <Identicon seed={app.applicationId || app.appHash} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div title={app.name || undefined} style={{ fontFamily: "var(--font-display)", fontSize: 20, lineHeight: 1.05, display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", overflowWrap: "anywhere" }}>{app.name || "Unnamed application"}</div>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1.5, color: "var(--v-teal)", display: "block", marginTop: 3 }}>
              {images.length} image{images.length === 1 ? "" : "s"}
              {app.environment === "staging" && <span style={{ color: "var(--status-warning)" }}> · on staging</span>}
            </span>
          </div>
        </div>
        <p style={{ margin: "12px 0 0", fontSize: 13, lineHeight: 1.55, opacity: 0.78, display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", minHeight: "2.4em" }}>
          {featured.dapp.desc !== "n/a" ? featured.dapp.desc : "—"}
        </p>
      </div>

      {/* image rows (newest first) */}
      <div style={{ flex: 1 }}>
        <div style={{ ...vLabel, display: "flex", alignItems: "baseline", padding: "7px 20px", borderTop: "var(--v-border)", background: "var(--v-canvas)" }}>
          <span>Images</span>
          <span style={{ marginLeft: "auto" }}>attestations</span>
        </div>
        {shown.map((r) => (
          <div key={r.key} onClick={() => onOpenImage(r)} className="tem-img-row v-wash" style={{
            display: "flex", alignItems: "center", gap: 10, padding: "9px 20px", borderTop: "1px solid var(--v-ink)", cursor: "pointer",
          }}>
            <span style={{ width: 14, height: 14, background: r.revoked ? "var(--v-surface)" : "var(--v-teal-tint)", border: "var(--v-border)", flexShrink: 0 }} />
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, minWidth: 0, flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: r.revoked ? "var(--v-danger)" : "var(--v-ink)" }}>{shortHash(r.id, 10)}</span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, opacity: 0.7, whiteSpace: "nowrap" }}>{relTime(r.issued_at)}</span>
            {r.revoked
              ? <Chip tone="danger">REVOKED</Chip>
              : r.os_release
                // Linked images show their base OS release instead of the format
                // chip; the release's attestation_mode already names the format.
                ? <Chip title={"Base OS release " + r.os_release.release_version + " · " + attestationMeta(r.attestation_format).pill}>{osChipShort(r.os_release)}</Chip>
                : <Chip>{attestationMeta(r.attestation_format).pill}</Chip>}
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, minWidth: 56, textAlign: "right", color: verCount(r) > 0 ? "var(--v-ink)" : "var(--v-ink-40)", whiteSpace: "nowrap" }}>{fmtCount(verCount(r))}</span>
          </div>
        ))}
        {collapsible && !forceOpen && (
          <button onClick={() => setOpen(!open)} className="tem-img-row v-wash" aria-expanded={open} style={{
            display: "flex", alignItems: "center", gap: 10, width: "100%", padding: "9px 20px", cursor: "pointer",
            border: "none", borderTop: "1px solid var(--v-ink)", background: "var(--v-surface)", color: "var(--v-teal)",
            fontFamily: "var(--font-mono)", fontSize: 12, textAlign: "left",
          }}>
            <span style={{ width: 14, height: 14, border: "2px dashed var(--v-teal)", flexShrink: 0 }} />
            <span style={{ flex: 1 }}>{open ? "Show fewer images" : `+${hidden} more image${hidden === 1 ? "" : "s"}`}</span>
            <Icon.Chevron size={8} dir={open ? "up" : "down"} />
          </button>
        )}
      </div>

      {/* footer: app-level attestation activity → the verification stream */}
      {app.environment === "staging" && app.verifications === null ? (
        <div style={{ padding: "11px 20px", borderTop: "var(--v-border)", background: "var(--v-canvas)", fontFamily: "var(--font-mono)", fontSize: 11.5, opacity: 0.78 }}>
          Staging runtime attestations unavailable
        </div>
      ) : <button onClick={onOpenStream} title="Browse this app's verification stream" className="v-stream-btn" style={{
        display: "flex", alignItems: "center", gap: 8, width: "100%", padding: "11px 20px", cursor: "pointer",
        border: "none", borderTop: "var(--v-border)", background: "var(--v-ink)", color: "var(--v-canvas)", textAlign: "left", fontFamily: "var(--font-mono)",
      }}>
        <span style={{ fontSize: 13, fontWeight: 500 }}>{fmtCount(app.verifications)}</span>
        <span style={{ fontSize: 11.5, opacity: 0.8 }}>runtime attestations</span>
        <span style={{ marginLeft: "auto", display: "inline-flex", alignItems: "center", gap: 6, fontSize: 11.5, whiteSpace: "nowrap" }}>
          {app.lastVerifiedAt ? "verified " + relTime(Date.parse(app.lastVerifiedAt)) : "none yet"} <Icon.ArrowRight />
        </span>
      </button>}
    </div>
  );
};

/* ── Field row helpers for detail drawer ── */
const Field = ({ label, children, mono, copyable }) => (
  <div className="tem-field" style={{ display: "grid", gridTemplateColumns: "180px 1fr", gap: 18, padding: "12px 0", borderBottom: "1px solid var(--v-hair)", alignItems: "start" }}>
    <div style={{ fontSize: 12, fontFamily: "var(--font-mono)", color: "var(--v-teal)", paddingTop: 2 }}>{label}</div>
    <div style={{ fontSize: 13, fontFamily: "var(--font-mono)", minWidth: 0, wordBreak: "break-all" }}>
      {mono ? <Mono copyable={copyable}>{children}</Mono> : children}
    </div>
  </div>
);

/* ── Base OS release (OS release registry ledgers) — shared with Stats.jsx ── */
const OS_ACCEPTANCE = {
  dev_signature_verified: { pill: "osDevSigned", desc: "Release manifest signed by an enrolled Veritee developer key and checked by the Warden" },
  warden_reproduced: { pill: "osReproduced", desc: "Base image independently rebuilt and matched by the Warden" },
};
const OsAcceptancePill = ({ acceptance }) => {
  const m = OS_ACCEPTANCE[acceptance];
  return m ? <span title={m.desc}><StatusPill kind={m.pill} /></span> : <Mono color="var(--v-ink-70)">{acceptance}</Mono>;
};
const osChipLabel = (rel) => "OS " + rel.release_version;
// Tiles are narrow: drop the build-flavour suffix ("0.5.3-raw-sev-snp" → "0.5.3").
const osChipShort = (rel) => "OS " + rel.release_version.split("-")[0];
const osMatches = (r, q) => Boolean(r.os_release
  && (r.os_release.release_version.toLowerCase().includes(q) || r.os_release.os_key.includes(q)));

const OsReleaseFields = ({ rel }) => (
  <>
    <Field label="release_version" mono>{rel.release_version}</Field>
    <Field label="acceptance"><OsAcceptancePill acceptance={rel.acceptance} /></Field>
    <Field label="os_key" mono copyable>{rel.os_key}</Field>
    <Field label="raw_disk_sha256" mono copyable>{rel.raw_disk_sha256}</Field>
    <Field label="pcr4" mono copyable>{rel.pcr4}</Field>
    <Field label="pcr4 bank · profile" mono>{rel.pcr4_bank} · {rel.pcr4_profile}</Field>
    <Field label="attestation_mode" mono>{rel.attestation_mode}</Field>
    <Field label="evidence_digest" mono copyable>{rel.evidence_digest}</Field>
  </>
);

/* ── Attestation evidence viewer (MAA token, raw SEV-SNP report, or unknown) ── */
const ATTESTATION_FORMATS = {
  "maa-jwt": { title: "MAA attestation token", field: "maa_token", pill: "MAA", rowLabel: "MAA token" },
  "sev-snp-report": { title: "AMD SEV-SNP report", field: "snp_report", pill: "SEV-SNP", rowLabel: "SNP report" },
  unknown: { title: "Attestation evidence · unknown format", field: "attestation", pill: "UNKNOWN", rowLabel: "TEE report" },
};
const attestationMeta = (format) => ATTESTATION_FORMATS[format] || ATTESTATION_FORMATS.unknown;

const AttestationEvidence = ({ value, format }) => {
  const [open, setOpen] = useStateExp(false);
  const meta = attestationMeta(format);
  const box = { border: "var(--v-border)", background: "var(--v-surface)" };
  if (!value) {
    return <div style={{ ...box, padding: "14px 16px", fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.7 }}>{meta.field} · n/a</div>;
  }
  // MAA tokens are ASCII text (byte length = char length); SNP reports and
  // unknown payloads arrive as hex (two chars per byte).
  const isHex = format !== "maa-jwt" && /^[0-9a-f]*$/i.test(value);
  const charsPerByte = isHex ? 2 : 1;
  const bytes = Math.ceil(value.length / charsPerByte);
  const PREVIEW = 320;
  const shown = open || value.length <= PREVIEW ? value : value.slice(0, PREVIEW);
  return (
    <div style={box}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 16px", borderBottom: "1px solid var(--v-ink)", background: "var(--v-canvas)" }}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>{meta.field} · {bytes} bytes{isHex ? " · hex" : ""}</span>
        {value.length > PREVIEW && (
          <Button variant="small" onClick={() => setOpen(!open)}>
            {open ? "Collapse" : "Expand"} <Icon.Chevron size={8} dir={open ? "up" : "down"} />
          </Button>
        )}
      </div>
      <div style={{ padding: "14px 16px", fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1.7, wordBreak: "break-all" }}>
        {shown}{!open && value.length > PREVIEW && <span style={{ color: "var(--v-teal)" }}>… {bytes - Math.floor(PREVIEW / charsPerByte)} more bytes</span>}
      </div>
    </div>
  );
};

/* ── Callout box (revocation, transitional MAA, decision note) ── */
const Callout = ({ tone = "teal", children, style }) => {
  const danger = tone === "danger";
  return (
    <div style={{
      display: "flex", gap: 14, alignItems: "flex-start", padding: "14px 18px", border: `2px solid ${danger ? "var(--v-danger)" : "var(--v-ink)"}`,
      background: danger ? "var(--v-danger-tint)" : "var(--v-surface)", boxShadow: `4px 4px 0 ${danger ? "var(--v-danger)" : "var(--v-teal)"}`, ...style,
    }}>
      <span style={{ marginTop: 2, lineHeight: 0 }}>{danger ? <Icon.X size={18} color="var(--v-danger)" /> : <Icon.Check size={20} color="var(--v-teal)" />}</span>
      <p style={{ margin: 0, fontSize: 13.5, lineHeight: 1.55 }}>{children}</p>
    </div>
  );
};

/* ── Stack identity: one registration = the whole stack, silicon → app ──
   Mirrors the Overview's StackedLayers visual with this record's real
   measurements. Every layer answers the same three things in the same
   order: which one (sub), its on-chain measurements (fields, named as in
   the record), and the two provenance rows "measured by" / "vouched by".
   The OS layer reads the on-chain release when the ledger has an OS
   release registry and says so plainly when it does not. */
// Every Warden check — report verification, measurement reproduction,
// signature checks, OS rebuilds — runs inside a Veritee TEE. Said once in
// the card header and on each Warden pill, not baked into the pill labels.
const WARDEN_TEE = "The Warden itself runs inside a Veritee TEE: its checks are performed in an attested confidential VM.";
const VOUCH_TITLES = {
  hardwareSigned: "Signed by the AMD secure processor; the report is verified by the Warden. " + WARDEN_TEE,
  wardenReproduced: "Expected measurements reproduced from source by the Warden. " + WARDEN_TEE,
  osReproduced: "Base image rebuilt from source and matched by the Warden. " + WARDEN_TEE,
  osDevSigned: "Release manifest signed by an enrolled Veritee developer and checked by the Warden; not yet independently rebuilt. " + WARDEN_TEE,
  unregistered: "This ledger has no OS release registry, so nothing on chain vouches for the base OS beyond its PCR4 measurement.",
  revoked: "The app developer withdrew trust from this registration.",
};
const StackLayer = ({ glyph, bg, fg, label, sub, fields, measured, vouched }) => {
  const key = { color: "var(--v-teal)" };
  const val = { display: "inline-flex", alignItems: "center", gap: 8, flexWrap: "wrap", minWidth: 0 };
  return (
    <div style={{ display: "grid", gridTemplateColumns: "44px 1fr", gap: 14, padding: "14px 18px", borderTop: "1px solid var(--v-ink)", alignItems: "start" }}>
      <GlyphTile glyph={glyph} bg={bg} fg={fg} />
      <div style={{ minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
          <span style={{ fontSize: 15, fontWeight: 600 }}>{label}</span>
          <span style={{ fontSize: 12.5, opacity: 0.7, minWidth: 0 }}>{sub}</span>
        </div>
        <div style={{ marginTop: 7, display: "grid", gridTemplateColumns: "140px minmax(0, 1fr)", gap: "3px 10px", fontFamily: "var(--font-mono)", fontSize: 11.5, alignItems: "baseline" }} className="tem-stack-row">
          {fields.map(([k, v, tag]) => (
            <React.Fragment key={k}>
              <span style={key}>{k}</span>
              <span style={val}>
                {v && v !== "n/a" ? <Mono copyable full={v} size={11.5}>{shortHash(v, 32)}</Mono> : <span style={{ opacity: 0.5 }}>n/a</span>}
                {tag}
              </span>
            </React.Fragment>
          ))}
          <span style={key}>measured by</span>
          <span style={{ ...val, opacity: 0.8 }}>{measured}</span>
          <span style={key}>vouched by</span>
          <span style={val}><span title={VOUCH_TITLES[vouched.pill]}><StatusPill kind={vouched.pill} /></span><span style={{ opacity: 0.8 }}>{vouched.text}</span></span>
        </div>
      </div>
    </div>
  );
};
const StackIdentity = ({ rec }) => {
  const rel = rec.os_release;
  const fmt = attestationMeta(rec.attestation_format);
  const tag = (text, title) => <span title={title}><Chip tone="teal">{text}</Chip></span>;
  const osBinding = "Contract-enforced: put_dapp rejects a registration whose PCR4 differs from the linked OS release.";
  const osLayer = rel ? {
    sub: "Veritee OS " + rel.release_version,
    fields: [["PCR4", rec.pcrs["4"], rel.pcr4_matches && tag("= OS release", osBinding)], ["raw_disk_sha256", rel.raw_disk_sha256]],
    measured: "vTPM at boot · raw disk hash from the release manifest",
    vouched: rel.acceptance === "warden_reproduced"
      ? { pill: "osReproduced", text: "Warden rebuilt and matched the image · contract enforces the PCR4 binding" }
      : rel.acceptance === "dev_signature_verified"
        ? { pill: "osDevSigned", text: "Warden checked the developer signature · contract enforces the PCR4 binding" }
        : { pill: "unregistered", text: "unknown acceptance state" },
  } : {
    sub: "Veritee base OS image",
    fields: [["PCR4", rec.pcrs["4"]]],
    measured: "vTPM at boot",
    vouched: { pill: "unregistered", text: "no OS release registry on this ledger" },
  };
  return (
    <div style={vCard}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 12, flexWrap: "wrap", padding: "12px 18px", background: "var(--v-canvas)" }} title={WARDEN_TEE}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase" }}>Stack identity</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--v-teal)" }}>silicon → boot → OS → app · sealed as one</span>
      </div>
      <StackLayer glyph="CPU" bg="var(--v-ink)" fg="var(--v-canvas)" label="Silicon" sub="AMD SEV-SNP confidential VM"
        fields={[["maa_hash", rec.maa_hash, tag(fmt.pill, fmt.title + " stored on chain")]]}
        measured="AMD secure processor · signed launch report"
        vouched={{ pill: "hardwareSigned", text: "AMD-signed report · verified by the Warden at registration" }} />
      <StackLayer glyph="BOOT" bg="var(--v-ink)" fg="var(--v-canvas)" label="Boot chain" sub="UEFI firmware · configuration · drivers · boot manager"
        fields={["0", "1", "2", "3"].map((k) => ["PCR" + k, rec.pcrs[k]])}
        measured="vTPM at boot"
        vouched={{ pill: "wardenReproduced", text: "expected values reproduced from source" }} />
      <StackLayer glyph="OS" bg="var(--v-canvas)" fg="var(--v-ink)" label="Base OS" {...osLayer} />
      <StackLayer glyph="APP" bg="var(--v-teal-tint)" fg="var(--v-ink)" label="Application"
        sub={rec.dapp.name !== "n/a" ? rec.dapp.name : "Unnamed application"}
        fields={[
          // UI names for the on-chain application_root_hash and app_hash.
          ["app_disk_hash", rec.app_root_hash],
          ["app_metadata_hash", rec.app_hash],
        ]}
        measured="dm-verity app disk · extended into PCR 15 at boot"
        vouched={rec.revoked
          ? { pill: "revoked", text: "trust withdrawn by the app developer" }
          : { pill: "wardenReproduced", text: "build reproduced from source" }} />
    </div>
  );
};

/* ── Runtime attestations for one registration (registration drawer) ──
   The latest few decisions against this image, fetched page-one only from
   the archive; the full list opens in the app's stream, filtered to this
   image. */
const RUNTIME_PREVIEW = 5;
const RuntimeAttestations = ({ rec, onOpen, onViewAll }) => {
  const D = window.VERITEE_DATA;
  const unavailable = rec.environment === "staging" && !D.stagingArchiveReady;
  const [page, setPage] = useStateExp({ items: [], total: 0, loading: !unavailable, error: false });
  useEffectExp(() => {
    if (unavailable) return undefined;
    let alive = true;
    window.VERITEE_API.fetchVerifications({ registrationId: rec.id, environment: rec.environment, limit: RUNTIME_PREVIEW })
      .then((p) => { if (alive) setPage({ items: p.items, total: p.total, loading: false, error: false }); })
      .catch((err) => {
        console.error("[veritee] runtime attestations fetch failed:", err);
        if (alive) setPage({ items: [], total: 0, loading: false, error: true });
      });
    return () => { alive = false; };
  }, [rec.key]);

  const note = (text) => <div style={{ padding: "14px 18px", fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.7 }}>{text}</div>;
  return (
    <div style={{ marginTop: 32 }}>
      <SectionLabel style={{ marginBottom: 12 }}>
        Runtime attestations{!unavailable && !page.loading && !page.error ? " · " + fmtCount(page.total) : ""}
      </SectionLabel>
      <div style={{ border: "var(--v-border)", background: "var(--v-surface)" }}>
        {unavailable ? note("The staging verification archive is not connected.")
          : page.loading ? note("Loading runtime attestations…")
          : page.error ? note("Could not load runtime attestations.")
          : page.items.length === 0 ? note(rec.revoked ? "No runtime attestations were recorded before revocation." : "No runtime attestations recorded for this image yet.")
          : page.items.map((v, i) => {
            const rejected = v.decision_status === "rejected";
            return (
              <div key={v.key} onClick={() => onOpen(v)} className="v-wash" style={{
                display: "grid", gridTemplateColumns: "84px minmax(0,1fr) auto", gap: 14, alignItems: "center", padding: "8px 16px",
                borderTop: i === 0 ? "none" : "1px solid var(--v-faint)", cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 11.5,
              }}>
                <span style={{ justifySelf: "start", fontSize: 9.5, letterSpacing: "0.08em", textTransform: "uppercase", color: rejected ? "var(--v-danger)" : "var(--v-ink)", background: rejected ? "var(--v-danger-tint)" : "var(--v-teal-tint)", border: `1px solid ${rejected ? "var(--v-danger)" : "var(--v-ink)"}`, padding: "1px 7px", whiteSpace: "nowrap" }}>
                  {rejected ? "rejected" : "verified"}
                </span>
                <span style={{ opacity: 0.7, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{fmtDate(v.issued_at)}</span>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6, whiteSpace: "nowrap" }}>
                  <span style={{ color: "var(--v-teal)" }}>call_id</span>{shortHash(v.call_id, 10)}
                </span>
              </div>
            );
          })}
        {!unavailable && !page.loading && page.total > page.items.length && (
          <button onClick={onViewAll} className="v-wash" style={{
            display: "flex", alignItems: "center", gap: 8, width: "100%", padding: "9px 16px", cursor: "pointer",
            border: "none", borderTop: "1px solid var(--v-ink)", background: "var(--v-canvas)", color: "var(--v-ink)",
            fontFamily: "var(--font-mono)", fontSize: 12, textAlign: "left",
          }}>
            <span style={{ flex: 1 }}>View all {fmtCount(page.total)} in the verification stream</span>
            <Icon.ArrowRight size={8} />
          </button>
        )}
      </div>
    </div>
  );
};

/* ── Drawer shell: scrim + cream panel sliding in from the right ── */
const Drawer = ({ onClose, label, pills, title, id, children }) => (
  <div style={{ position: "fixed", inset: 0, zIndex: 100 }}>
    <div onClick={onClose} style={{ position: "absolute", inset: 0, background: "var(--bg-scrim)", animation: "temFade 160ms steps(2)" }} />
    <div style={{
      position: "absolute", top: 0, right: 0, height: "100%", width: "min(680px, 94vw)",
      background: "var(--v-canvas)", borderLeft: "var(--v-border)", boxShadow: "-6px 0 0 rgba(0,48,88,0.25)",
      overflowY: "auto", animation: "temSlide 200ms steps(4)",
    }}>
      <div style={{ position: "sticky", top: 0, zIndex: 2, background: "var(--v-surface)", borderBottom: "var(--v-border)" }}>
        <WindowBar label={label} onClose={onClose} />
        <div className="tem-drawer-body" style={{ padding: "20px 32px 18px" }}>
          <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", marginBottom: 14 }}>{pills}</div>
          <h3 style={{ fontFamily: "var(--font-display)", fontSize: 34, lineHeight: 1, margin: "0 0 8px" }}>{title}</h3>
          <div style={{ display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
            <Mono copyable color="var(--v-ink-78)" size={12}>{id}</Mono>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--v-teal)" }}>id = sha256(record)</span>
          </div>
        </div>
      </div>
      <div className="tem-drawer-body" style={{ padding: "24px 32px 56px" }}>{children}</div>
    </div>
  </div>
);

/* ── Detail drawer (measurement registrations, type 0) ── */
const RecordDrawer = ({ rec, onClose, onOpenVerification, onViewAllVerifications }) => {
  const D = window.VERITEE_DATA;
  const pcrOrder = ["0", "1", "2", "3", "4", "12", "13"];
  const appJson = JSON.stringify({ name: rec.dapp.name, description: rec.dapp.desc, deployment_url: rec.dapp.url }, null, 2);
  const group = { marginTop: 32 };
  return (
    <Drawer onClose={onClose} label="registration · type 0x00" title={rec.dapp.name} id={rec.id} pills={<>
      <StatusPill kind="registration" />
      {rec.environment === "staging" && <StatusPill kind="staging" />}
      {rec.revoked && <StatusPill kind="revoked" />}
      <Chip style={{ fontSize: 11, padding: "2px 9px", background: "var(--v-surface)" }}>{attestationMeta(rec.attestation_format).pill}</Chip>
      {rec.os_release && <Chip style={{ fontSize: 11, padding: "2px 9px", background: "var(--v-surface)" }}>{osChipShort(rec.os_release)}</Chip>}
      <CopyLinkButton hash={"#explorer/reg/" + rec.key} style={{ marginLeft: "auto" }} />
    </>}>
      {/* revocation notice — forward-only: history stays, no new verifications */}
      {rec.revoked && (
        <Callout tone="danger" style={{ marginBottom: 28 }}>
          <strong style={{ color: "var(--v-danger)", fontWeight: 600 }}>Revoked.</strong> The app developer withdrew trust from this measurement on <Mono size={12}>{fmtDate(rec.revoked_at)}</Mono>. Verifications recorded before revocation remain historically valid; the Warden refuses new verifications against this entry.
        </Callout>
      )}

      {/* the whole stack this one registration identifies */}
      <StackIdentity rec={rec} />

      {/* latest runtime decisions against this image */}
      <RuntimeAttestations rec={rec} onOpen={onOpenVerification} onViewAll={() => onViewAllVerifications(rec)} />

      {/* record meta */}
      <div style={group}>
        <SectionLabel>Record</SectionLabel>
        <Field label="Environment">{rec.environment === "staging" ? <StatusPill kind="staging" /> : "Production"}</Field>
        <Field label="Contract address">
          <Mono copyable>{rec.contract}</Mono>
          {rec.contract !== "n/a" && <div style={{ marginTop: 6 }}><a href={explorerContractUrl(rec.contract)} target="_blank" rel="noopener noreferrer" className="v-link" style={{ fontSize: 12 }}>View on explorer <Icon.ArrowUpRight size={10} /></a></div>}
        </Field>
        <Field label="version">{rec.version}</Field>
        <Field label="record_type">0x00 · measurement reproduction</Field>
        {rec.application_id && rec.application_id !== "n/a" && <Field label="application_id" mono copyable>{rec.application_id}</Field>}
        <Field label="dapp_id" mono copyable>{rec.dapp.id}</Field>
        <Field label="attestation_url">
          {rec.attestation_url && rec.attestation_url !== "n/a" ? (
            <a href={rec.attestation_url} target="_blank" rel="noopener noreferrer" className="v-link" style={{ wordBreak: "break-all" }}>
              {rec.attestation_url} <Icon.ArrowUpRight size={10} />
            </a>
          ) : <span style={{ opacity: 0.6 }}>n/a</span>}
        </Field>
        <Field label="tls_mode">{rec.tls_mode || "n/a"}</Field>
        <Field label="issued_at">{fmtDate(rec.issued_at)}</Field>
        {rec.revoked && <Field label="revoked_at">{fmtDate(rec.revoked_at)}</Field>}
      </div>

      {/* application metadata */}
      <div style={group}>
        <SectionLabel style={{ marginBottom: 12 }}>app_details · 1024 bytes</SectionLabel>
        <pre style={{ margin: 0, padding: "16px 18px", border: "var(--v-border)", background: "var(--v-surface)", fontFamily: "var(--font-mono)", fontSize: 12.5, lineHeight: 1.6, overflowX: "auto" }}>{appJson}</pre>
      </div>

      {/* PCR measurements */}
      <div style={group}>
        <SectionLabel style={{ marginBottom: 12 }}>extra_pcrs · 224 bytes</SectionLabel>
        <div style={{ border: "var(--v-border)", background: "var(--v-surface)" }}>
          {pcrOrder.map((k, i) => (
            <div key={k} style={{ display: "grid", gridTemplateColumns: "56px 1fr", gap: 14, padding: "10px 16px", borderTop: i === 0 ? "none" : "1px solid var(--v-ink)", alignItems: "baseline" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--v-teal)", fontWeight: 500 }}>PCR{k}</span>
              <div style={{ minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", fontSize: 11.5, opacity: 0.7, marginBottom: 3 }}>
                  {k === "4" && rec.os_release ? D.PCR_LABELS[k] + " · bound to the registered base OS release" : D.PCR_LABELS[k]}
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                  <Mono size={12}>{rec.pcrs[k]}</Mono>
                  {k === "4" && rec.os_release && rec.os_release.pcr4_matches && (
                    <span title="Contract-enforced: put_dapp rejects a registration whose PCR4 differs from the linked OS release."><Chip tone="teal">= OS release</Chip></span>
                  )}
                </div>
              </div>
            </div>
          ))}
        </div>
        <div style={{ marginTop: 14 }}>
          <Field label="app_disk_hash" mono copyable>{rec.app_root_hash}</Field>
          <Field label="app_metadata_hash" mono copyable>{rec.app_hash}</Field>
        </div>
      </div>

      {/* base OS release — only on OS release registry ledgers */}
      {rec.os_release && (
        <div style={group}>
          <SectionLabel style={{ marginBottom: 12 }}>Base OS release · os_releases</SectionLabel>
          <p style={{ margin: "0 0 12px", fontSize: 13, lineHeight: 1.55, opacity: 0.78 }}>
            The Warden admitted this image against an approved Veritee base OS release. The release manifest is developer-signed and retained in the Warden's immutable archive; the contract stores its digests and refuses any image whose PCR4 differs from the release's.
          </p>
          <OsReleaseFields rel={rec.os_release} />
        </div>
      )}

      {/* attestation evidence (MAA token or raw SEV-SNP report) */}
      <div style={group}>
        <SectionLabel style={{ marginBottom: 12 }}>{attestationMeta(rec.attestation_format).title}{rec.attestation_format !== "unknown" && <> · Bytes&lt;16384&gt;</>}</SectionLabel>
        {rec.attestation_format === "maa-jwt" && (
          <Callout style={{ marginBottom: 16 }}>
            <strong style={{ fontWeight: 600 }}>Transitional.</strong> This record carries an MAA token; the contract now also accepts the raw SEV-SNP report directly.
          </Callout>
        )}
        <AttestationEvidence value={rec.attestation} format={rec.attestation_format} />
        <div style={{ marginTop: 14 }}>
          <Field label="maa_hash = sha256(attestation)" mono copyable>{rec.maa_hash}</Field>
        </div>
      </div>
    </Drawer>
  );
};

/* ── Detail drawer (runtime decisions) ──
   Record content lives in the immutable archive and is committed by an
   on-chain Merkle anchor. */
const VerificationDrawer = ({ rec, onClose, onOpenRegistration }) => {
  const parent = window.VERITEE_DATA.records.find((r) => r.type === 0 && r.environment === rec.environment && r.id === rec.registration_id) || null;
  const rejected = rec.decision_status === "rejected";
  return (
    <Drawer onClose={onClose} label="verification · type 0x01" title={rec.dapp.name} id={rec.id} pills={<>
      <StatusPill kind={rejected ? "rejected" : "verification"} />
      {rec.environment === "staging" && <StatusPill kind="staging" />}
      {rec.batch_prefix && rec.batch_prefix !== "n/a" && <Chip style={{ fontSize: 11, padding: "2px 9px", background: "var(--v-surface)" }}>batch {rec.batch_prefix}</Chip>}
    </>}>
      <SectionLabel>Record</SectionLabel>
      <Field label="version">{rec.version}</Field>
      <Field label="record_type">0x01 · attestation verification</Field>
      <Field label="decision_status">{rec.decision_status}</Field>
      {rec.batch_prefix && rec.batch_prefix !== "n/a" && <Field label="batch_prefix">{rec.batch_prefix}</Field>}
      {rec.application_id && rec.application_id !== "n/a" && <Field label="application_id" mono copyable>{rec.application_id}</Field>}
      <Field label="verified_at">{fmtDate(rec.issued_at)}</Field>

      {/* decision commitments */}
      <SectionLabel style={{ marginTop: 32 }}>Commitments</SectionLabel>
      <Field label="registration_id">
        <div style={{ display: "flex", flexDirection: "column", gap: 6, minWidth: 0 }}>
          <Mono copyable>{rec.registration_id}</Mono>
          {parent && (
            <button onClick={() => onOpenRegistration(parent)} className="v-link" style={{ background: "none", border: "none", cursor: "pointer", padding: 0, fontFamily: "var(--font-mono)", fontSize: 12, display: "inline-flex", alignItems: "center", gap: 5, alignSelf: "flex-start" }}>
              View registration <Icon.ArrowRight size={8} />
            </button>
          )}
        </div>
      </Field>
      <Field label="attestation_hash" mono copyable>{rec.attestation_hash}</Field>
      <Field label="call_id" mono copyable>{rec.call_id}</Field>
      <Field label="result_hash" mono copyable>{rec.result_hash}</Field>
      {rec.diagnostics && <Field label="diagnostics" mono>{JSON.stringify(rec.diagnostics)}</Field>}

      <Callout tone={rejected ? "danger" : "teal"} style={{ marginTop: 32 }}>
        <strong style={{ fontWeight: 600, color: rejected ? "var(--v-danger)" : "var(--v-ink)" }}>{rejected ? "Rejected decision." : "Verified decision."}</strong> This record is stored in the immutable verification archive and committed through its Merkle batch anchor.
      </Callout>
    </Drawer>
  );
};

const StatCard = ({ value, label }) => (
  <div style={{ ...vCard, padding: "16px 18px 14px" }}>
    <div style={{ fontFamily: "var(--font-mono)", fontSize: 28, fontWeight: 500, letterSpacing: "-0.02em", lineHeight: 1 }}>{value}</div>
    <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--v-teal)", marginTop: 8, letterSpacing: "0.04em" }}>{label}</div>
  </div>
);

/* Big-numeral stat for the ledger.status window. */
const LedgerStat = ({ value, label }) => (
  <div style={{ minWidth: 0 }}>
    <div style={{ fontFamily: "var(--font-mono)", fontSize: 26, fontWeight: 500, letterSpacing: "-0.02em", lineHeight: 1 }}>{value}</div>
    <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--v-teal)", marginTop: 6, letterSpacing: "0.04em" }}>{label}</div>
  </div>
);

/* Segmented control (view switch, tile/list toggle). */
const segBtn = (on, last) => ({
  border: "none", borderRight: last ? "none" : "var(--v-border)", cursor: "pointer",
  background: on ? "var(--v-ink)" : "var(--v-surface)", color: on ? "var(--v-canvas)" : "var(--v-ink)",
});

// One page of the drill-down verification stream.
const VER_PAGE = 50;
const ROLLUP_COLS = "minmax(200px,2fr) minmax(110px,1fr) 100px 110px 110px";
const STREAM_COLS = "96px 190px 130px 1fr 1fr";

const Explorer = ({ goStats }) => {
  const D = window.VERITEE_DATA;
  const [query, setQuery] = useStateExp("");
  const [view, setView] = useStateExp("reg"); // reg | ver
  const [sel, setSel] = useStateExp(null);
  // Registrations render as Docker-Hub-style image tiles or the classic
  // grouped list — the toolbar toggle flips between them.
  const [regLayout, setRegLayout] = useStateExp("tiles"); // tiles | list
  // Verifications are aggregate-first: null = per-app rollup table; an
  // AppSummary row = that app's paginated stream (fetched server-side).
  const [appSel, setAppSel] = useStateExp(null);
  // Optional narrowing of the app stream to one image (registration record),
  // set from a registration drawer's "View all" link.
  const [imgFilter, setImgFilter] = useStateExp(null);
  const [stream, setStream] = useStateExp({ items: [], total: 0, nextBefore: null, loading: false, loadingMore: false, error: false });

  // Re-render every 10s so the "synced … ago" label keeps counting between
  // data refreshes (data.jsx re-fetches on the backend's poll interval).
  const [, tick] = useStateExp(0);
  useEffectExp(() => {
    const t = setInterval(() => tick((n) => n + 1), 10000);
    return () => clearInterval(t);
  }, []);

  const switchView = (k) => { setView(k); setAppSel(null); setQuery(""); setImgFilter(null); };
  const openApp = (app) => { setAppSel(app); setQuery(""); setImgFilter(null); };
  // Registration drawer → that app's stream, filtered to the image.
  const viewImageStream = (rec) => {
    const app = ((D.summary && D.summary.apps) || []).find((a) => (a.registrationIds || []).includes(rec.key));
    if (!app) return;
    setSel(null); setView("ver"); setAppSel(app); setQuery(""); setImgFilter(rec);
    window.scrollTo(0, 0);
  };

  // The arrival hash, captured before the mirror effect below rewrites it.
  const [initialHash] = useStateExp(() => window.location.hash || "");

  // Apply a shared deep link (#explorer/reg/<id> or #explorer/app/<key>) once
  // the data has landed — the hash is parsed here rather than at mount because
  // registrations and the app rollup arrive async.
  useEffectExp(() => {
    if (D.loading) return;
    const parts = initialHash.replace("#", "").split("/");
    if (parts[0] !== "explorer" || parts.length < 3) return;
    if (parts[1] === "reg") {
      const rec = D.records.find((r) => r.key === parts[2]);
      if (rec) setSel(rec);
    } else if (parts[1] === "app") {
      const app = ((D.summary && D.summary.apps) || []).find((a) => a.key === parts[2]);
      if (app) { setView("ver"); setAppSel(app); }
    }
  }, [D.loading]);

  // Mirror the shareable state back into the hash so the address bar can be
  // copied at any time. A registration drawer wins over an app drill-down (the
  // drawer is what the person is looking at); tab switches are handled by App.
  useEffectExp(() => {
    let h = "#explorer";
    if (sel && sel.type === 0) h = "#explorer/reg/" + sel.key;
    else if (appSel) h = "#explorer/app/" + appSel.key;
    window.history.replaceState(null, "", h);
  }, [sel, appSel]);

  // Per-registration verification activity, aggregated server-side (the
  // stream itself is never fully loaded — it grows by thousands per day).
  const regActivity = (D.summary && D.summary.registrations) || {};
  const verCount = (rec) => rec.environment === "staging" && !D.stagingArchiveReady
    ? "n/a" : (regActivity[rec.key] ? regActivity[rec.key].verifications : 0);

  // Drill-down stream: (re)fetch the first page when the app or the query
  // changes; typing is debounced since the search runs server-side.
  useEffectExp(() => {
    if (view !== "ver" || !appSel) return undefined;
    let alive = true;
    setStream((s) => ({ ...s, loading: true, error: false }));
    const t = setTimeout(async () => {
      try {
        const page = await window.VERITEE_API.fetchVerifications({ app: appSel.key, registrationId: imgFilter ? imgFilter.id : null, q: query.trim() || null, limit: VER_PAGE });
        if (alive) setStream({ items: page.items, total: page.total, nextBefore: page.nextBefore, loading: false, loadingMore: false, error: false });
      } catch (err) {
        console.error("[veritee] verification stream fetch failed:", err);
        if (alive) setStream({ items: [], total: 0, nextBefore: null, loading: false, loadingMore: false, error: true });
      }
    }, query.trim() ? 250 : 0);
    return () => { alive = false; clearTimeout(t); };
  }, [view, appSel, query, imgFilter]);

  // Live refresh: when data.jsx lands a new snapshot, quietly re-fetch an
  // open stream's first page so new decisions appear. Skipped once the person
  // has paged back with "Load older" (replacing the list would lose their
  // place) and while a load is already running.
  useEffectExp(() => {
    if (view !== "ver" || !appSel || stream.loading || stream.loadingMore || stream.items.length > VER_PAGE) return undefined;
    let alive = true;
    window.VERITEE_API.fetchVerifications({ app: appSel.key, registrationId: imgFilter ? imgFilter.id : null, q: query.trim() || null, limit: VER_PAGE })
      .then((page) => { if (alive) setStream((s) => ({ ...s, items: page.items, total: page.total, nextBefore: page.nextBefore, error: false })); })
      .catch(() => {});
    return () => { alive = false; };
  }, [D]);

  const loadMore = async () => {
    if (!stream.nextBefore || stream.loadingMore) return;
    setStream((s) => ({ ...s, loadingMore: true }));
    try {
      const page = await window.VERITEE_API.fetchVerifications({ app: appSel.key, registrationId: imgFilter ? imgFilter.id : null, q: query.trim() || null, before: stream.nextBefore, limit: VER_PAGE });
      setStream((s) => ({ ...s, items: s.items.concat(page.items), total: page.total, nextBefore: page.nextBefore, loadingMore: false }));
    } catch (err) {
      console.error("[veritee] verification stream fetch failed:", err);
      setStream((s) => ({ ...s, loadingMore: false }));
    }
  };

  // Registrations view rows (client-side filter — registrations stay small).
  // Hex fields are stored lower-case, so a lower-cased query matches directly.
  let rows = D.records.filter((r) => {
    if (r.type !== 0 || view !== "reg") return false;
    if (query.trim()) {
      const q = query.toLowerCase();
      return r.dapp.name.toLowerCase().includes(q) || r.id.includes(q) || r.dapp.id.toLowerCase().includes(q) || osMatches(r, q);
    }
    return true;
  });

  // Apps are ordered by recent activity: most recently verified first, then
  // apps never verified, newest image registration first. The server rolls
  // apps up busiest-first, but all-time counts reward old bursts and bury the
  // apps that are live right now.
  const recById = new Map(D.records.map((r) => [r.key, r]));
  const newestImageAt = (app) => Math.max(0, ...(app.registrationIds || []).map((id) => (recById.get(id) || {}).issued_at || 0));
  const lastVerifiedMs = (app) => (app.lastVerifiedAt ? Date.parse(app.lastVerifiedAt) : 0);
  const byActivity = (a, b) => (lastVerifiedMs(b) - lastVerifiedMs(a)) || (newestImageAt(b) - newestImageAt(a));

  // Apps rollup rows (client-side filter — one row per app).
  const q = query.trim().toLowerCase();
  const appRows = ((D.summary && D.summary.apps) || []).filter((a) =>
    !q || (a.name || "").toLowerCase().includes(q) || a.key.includes(q) || (a.appHash || "").includes(q)
  ).sort(byActivity);

  // Application tiles (reg view, tile layout): one tile per app in activity
  // order, its images resolved from the registration records, newest first.
  // A query matches on the app or on any of its images.
  const appTiles = (D.measurementApps || [])
    .slice().sort(byActivity)
    .map((app) => ({
      app,
      images: (app.registrationIds || []).map((id) => recById.get(id)).filter(Boolean)
        .sort((a, b) => (b.issued_at || 0) - (a.issued_at || 0)),
    }))
    .filter(({ app, images }) => images.length > 0 && (
      !q || (app.name || "").toLowerCase().includes(q) || app.key.includes(q)
        || images.some((r) => r.id.includes(q) || r.dapp.name.toLowerCase().includes(q) || osMatches(r, q))
    ));

  const views = [{ k: "reg", label: "Build-Reproduced TEE Images" }, { k: "ver", label: "Runtime Attestation Verifications" }];

  // Measurements view: group the filtered rows by application_id, preserving
  // newest-first order. `rows` is already newest-first, so the first row seen
  // for each id fixes the group order, and records stay newest-first within a
  // group. Records with no application_id (n/a) collect into a trailing
  // "Ungrouped" section. The verifications view is a flat activity stream.
  const UNGROUPED = "__ungrouped__";
  const groupMap = new Map();
  if (view === "reg") rows.forEach((r) => {
    const key = r.application_id && r.application_id !== "n/a" ? r.application_id : UNGROUPED;
    if (!groupMap.has(key)) groupMap.set(key, []);
    groupMap.get(key).push(r);
  });
  // Real application groups first (in first-seen order), then any ungrouped.
  const groups = [...groupMap.entries()]
    .filter(([k]) => k !== UNGROUPED)
    .map(([appId, recs]) => ({ appId, recs, name: recs[0].dapp.name }));
  if (groupMap.has(UNGROUPED)) groups.push({ appId: null, recs: groupMap.get(UNGROUPED), name: "Ungrouped" });

  const syncedAt = D.status && D.status.syncedAt ? Date.parse(D.status.syncedAt) : NaN;
  const notice = { margin: "0 0 14px", padding: "8px 12px", border: "2px solid var(--v-danger)", background: "var(--v-danger-tint)", color: "var(--v-danger)", fontSize: 13 };

  return (
    <div className="tem-page" style={{ maxWidth: 1280, margin: "0 auto", padding: "40px 56px 96px" }}>
      {/* hero: headline left, ledger.status window right */}
      <div className="tem-hero-grid" style={{ display: "grid", gridTemplateColumns: "minmax(0,1.4fr) minmax(280px,0.8fr)", gap: 40, alignItems: "end", marginBottom: 36 }}>
        <div style={{ minWidth: 0 }}>
          <Eyebrow style={{ marginBottom: 14 }}>On-chain explorer · {D.network.replace(" · ", " ")}</Eyebrow>
          <h1 style={{ fontFamily: "var(--font-display)", fontSize: "clamp(40px,4.8vw,62px)", lineHeight: 0.98, margin: "0 0 18px", textWrap: "balance" }}>
            Prove your endpoint runs only the <span style={{ color: "var(--v-teal)" }}>authorized image</span>.
          </h1>
          <p style={{ fontSize: 16, lineHeight: 1.6, margin: 0, maxWidth: 560, opacity: 0.86 }}>
            Every application below is sealed as one identity across silicon, boot, OS, and code. Each one is reproduced from source, logged on-chain, and re-verified at runtime. Data handled with zero exposure.
          </p>
        </div>
        <div style={{ ...vCard, position: "relative", marginTop: 72 }}>
          <img src="assets/manatee-bust.png" alt="Veritee mascot" className="v-pixel" style={{ position: "absolute", right: 16, bottom: "calc(100% + 2px)", width: 104, height: "auto", pointerEvents: "none" }} />
          <WindowBar small label="ledger.status" />
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", padding: "16px 18px 14px", gap: 12 }}>
            <LedgerStat value={D.loading ? "…" : fmtCount(D.stats.applications)} label="applications" />
            <LedgerStat value={D.loading ? "…" : fmtCount(D.stats.registrations)} label="TEE images" />
            <LedgerStat value={D.loading ? "…" : fmtCount(D.stats.verifications)} label={D.staging && D.staging.enabled && !D.stagingArchiveReady ? "prod attestations" : "attestations"} />
          </div>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: "8px 18px 10px", borderTop: "1px solid var(--v-ink)", fontFamily: "var(--font-mono)", fontSize: 11.5 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 7 }}>
              {D.loading ? <><PixelSquare size={7} blink />syncing from contract…</>
                : D.error ? <><PixelSquare size={7} color="var(--v-danger)" />ledger unavailable</>
                : <><PixelSquare size={7} blink />synced {syncAgo(syncedAt)}</>}
            </span>
            {goStats && <a href="#status" className="v-link" onClick={(e) => { e.preventDefault(); goStats(); }}>Status →</a>}
          </div>
        </div>
      </div>

      {D.error && <p role="status" style={notice}>Production measurements are currently unavailable.</p>}
      {D.staging && (D.staging.error || (D.staging.enabled && !D.staging.syncedAt)) && (
        <p role="status" style={{ ...notice, borderColor: "var(--v-ink)", background: "var(--v-warn-tint)", color: "var(--v-ink)" }}>Staging measurements are currently unavailable. Production data is shown independently.</p>
      )}

      {/* toolbar */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 16, marginBottom: 14 }}>
        <div className="tem-viewtabs" style={{ display: "flex", border: "var(--v-border)", background: "var(--v-surface)" }}>
          {views.map((f, i) => (
            <button key={f.k} onClick={() => switchView(f.k)} className={view === f.k ? undefined : "v-wash"} style={{
              ...segBtn(view === f.k, i === views.length - 1), padding: "9px 16px", fontSize: 13, fontFamily: "var(--font-sans)", fontWeight: 600,
            }}>{f.label}</button>
          ))}
        </div>
        <div style={{ display: "flex", alignItems: "stretch", gap: 10, flex: "0 1 460px", minWidth: 260 }}>
          <label className="v-search" style={{ display: "flex", alignItems: "center", gap: 10, background: "var(--v-surface)", border: "var(--v-border)", padding: "0 14px", flex: 1, minWidth: 0 }}>
            <Icon.Search />
            <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder={view === "reg" ? "Search by id, app name, or OS release…" : appSel ? "Search by call_id, registration_id, or result_hash…" : "Search applications…"} style={{ background: "none", border: "none", outline: "none", color: "var(--v-ink)", fontFamily: "var(--font-mono)", fontSize: 13, width: "100%", padding: "10px 0" }} />
          </label>
          {view === "reg" && (
            <div style={{ display: "flex", border: "var(--v-border)", background: "var(--v-surface)", flexShrink: 0 }}>
              {[{ k: "tiles", I: Icon.Grid, title: "Tile view" }, { k: "list", I: Icon.List, title: "List view" }].map(({ k, I, title }, i) => (
                <button key={k} onClick={() => setRegLayout(k)} title={title} className={regLayout === k ? undefined : "v-wash"} style={{
                  ...segBtn(regLayout === k, i === 1), width: 36, display: "flex", alignItems: "center", justifyContent: "center",
                }}><I /></button>
              ))}
            </div>
          )}
        </div>
      </div>

      {/* view explainer */}
      <div style={{ display: "flex", gap: 10, alignItems: "flex-start", margin: "0 0 18px 2px" }}>
        <span style={{ marginTop: 3, lineHeight: 0 }}><Icon.Info color="var(--v-teal)" /></span>
        <p style={{ fontSize: 13.5, lineHeight: 1.6, margin: 0, opacity: 0.78 }}>
          {view === "reg" ? (
            <>A Build-Reproduced TEE Image is a registered application build whose fingerprint, across silicon, boot, OS, and application code, was reproduced from source and logged on-chain.</>
          ) : (
            <>An attestation verification confirms, at run-time, that a TEE still matches the build-reproduced measurements logged on-chain at registration.{appSel ? "" : " Pick an application to open its verification stream."}{D.staging && D.staging.enabled && !D.stagingArchiveReady ? " The staging Warden archive is not connected." : ""}</>
          )}
        </p>
      </div>

      {/* tiles (reg view · one tile per application, images as rows) */}
      {view === "reg" && regLayout === "tiles" && (
        appTiles.length > 0 ? (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 340px), 1fr))", gap: 22 }}>
            {appTiles.map(({ app, images }) => (
              <AppTile key={app.key} app={app} images={images} verCount={verCount} forceOpen={Boolean(q)}
                onOpenImage={(r) => setSel(r)}
                onOpenStream={() => { setView("ver"); setAppSel(app); setQuery(""); window.scrollTo(0, 0); }} />
            ))}
          </div>
        ) : (
          <EmptyState boxed>
            {D.loading ? "Syncing from contract…" : D.error ? "Could not reach the contract indexer." : q ? `No applications match “${query}”.` : "No images on-chain yet."}
          </EmptyState>
        )
      )}

      {/* table */}
      {(view === "ver" || (view === "reg" && regLayout === "list")) && (
      <div style={{ ...vCard, overflow: "hidden" }}>
        {/* ver · drill-down header strip (selected app + back to the rollup) */}
        {view === "ver" && appSel && (
          <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "10px 22px 10px 12px", background: "var(--v-canvas)", borderBottom: "var(--v-border)", flexWrap: "wrap" }}>
            <Button variant="small" onClick={() => { setAppSel(null); setQuery(""); setImgFilter(null); }}>← Back to applications</Button>
            <Identicon seed={appSel.applicationId || appSel.appHash} size={28} />
            <span style={{ fontFamily: "var(--font-display)", fontSize: 22, lineHeight: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }}>{appSel.name || "Unnamed application"}</span>
            {appSel.environment === "staging" && <StatusPill kind="staging" />}
            <span style={{ display: "inline-flex", alignItems: "baseline", gap: 6, fontFamily: "var(--font-mono)", fontSize: 12 }}>
              <span style={{ color: "var(--v-teal)" }}>app_id</span>
              <Mono copyable full={appSel.applicationId || appSel.appHash} size={12}>{shortHash(appSel.applicationId || appSel.appHash, 10)}</Mono>
            </span>
            {imgFilter && (
              <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--font-mono)", fontSize: 11.5, border: "1px solid var(--v-ink)", background: "var(--v-teal-tint)", padding: "2px 4px 2px 8px" }}>
                image {shortHash(imgFilter.id, 10)}
                <button onClick={() => setImgFilter(null)} title="Show all images" aria-label="Clear image filter" className="v-tint" style={{ border: "none", background: "transparent", cursor: "pointer", padding: 2, lineHeight: 0, color: "var(--v-ink)" }}>
                  <Icon.X size={9} />
                </button>
              </span>
            )}
            <CopyLinkButton hash={"#explorer/app/" + appSel.key} />
            <span style={{ marginLeft: "auto", fontFamily: "var(--font-mono)", fontSize: 12, whiteSpace: "nowrap" }}>
              {stream.loading ? "…" : `${fmtCount(stream.total)} verification${stream.total === 1 ? "" : "s"}${query.trim() ? " matching" : ""}`}
            </span>
          </div>
        )}

        {/* ver · apps rollup header */}
        {view === "ver" && !appSel && (
          <div className="tem-row-a" style={{ ...vLabel, display: "grid", gridTemplateColumns: ROLLUP_COLS, gap: 12, padding: "9px 22px", background: "var(--v-canvas)", borderBottom: "var(--v-border)" }}>
            <span>Application</span><span>app_id</span><span style={{ textAlign: "right" }}>Measurements</span><span style={{ textAlign: "right" }}>Verifications</span><span style={{ textAlign: "right" }}>Last verified</span>
          </div>
        )}

        {/* ver · stream header (log-style: timestamp leads) */}
        {view === "ver" && appSel && (
          <div className="tem-row-v" style={{ ...vLabel, display: "grid", gridTemplateColumns: STREAM_COLS, gap: 14, padding: "8px 22px", borderBottom: "var(--v-border)" }}>
            <span>Decision</span><span>Time</span><span>image_id</span><span>call_id</span><span>result_hash</span>
          </div>
        )}

        {/* empty states */}
        {view === "reg" && rows.length === 0 && (
          <EmptyState>
            {D.loading ? "Syncing from contract…" : D.error ? "Could not reach the contract indexer." : query.trim() ? `No records match “${query}”.` : "No measurements on-chain yet."}
          </EmptyState>
        )}
        {view === "ver" && !appSel && appRows.length === 0 && (
          <EmptyState>
            {D.loading ? "Syncing verification activity…" : D.error ? "Could not reach the verification index." : query.trim() ? `No applications match “${query}”.` : "No runtime decisions indexed yet."}
          </EmptyState>
        )}
        {view === "ver" && appSel && (stream.loading || stream.error || stream.items.length === 0) && (
          <EmptyState>
            {stream.loading ? "Loading verifications…" : stream.error ? "Could not load the verification stream." : query.trim() ? `No verifications match “${query}”.` : "No verifications recorded for this application yet."}
          </EmptyState>
        )}
        {view === "reg" && regLayout === "list" && groups.map((g, gi) => (
          <React.Fragment key={g.appId || UNGROUPED}>
            {/* group header */}
            <div style={{
              display: "flex", alignItems: "center", gap: 12, padding: "10px 22px 10px 14px", flexWrap: "wrap",
              borderTop: gi === 0 ? "none" : "var(--v-border)", borderBottom: "1px solid var(--v-ink)", background: "var(--v-canvas)",
            }}>
              {g.appId && <Identicon seed={g.appId} size={28} />}
              <span style={{ fontFamily: "var(--font-display)", fontSize: 22, lineHeight: 1, opacity: g.appId ? 1 : 0.7, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: 320 }}>{g.name}</span>
              {g.appId ? (
                <span style={{ display: "inline-flex", alignItems: "baseline", gap: 6, fontFamily: "var(--font-mono)", fontSize: 12 }}>
                  <span style={{ color: "var(--v-teal)" }}>app_id</span>
                  <Mono copyable full={g.appId} size={12}>{shortHash(g.appId)}</Mono>
                </span>
              ) : (
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.6 }}>no application_id</span>
              )}
              {g.appId && g.recs[0].dapp.desc && g.recs[0].dapp.desc !== "n/a" && (
                <span style={{ fontSize: 12.5, opacity: 0.7, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", flex: 1, minWidth: 0 }}>{g.recs[0].dapp.desc}</span>
              )}
              <span style={{ marginLeft: "auto", fontFamily: "var(--font-mono)", fontSize: 12 }}>{g.recs.length} record{g.recs.length === 1 ? "" : "s"}</span>
            </div>
            {/* group records */}
            {g.recs.map((r, ri) => (
              <div key={r.key} onClick={() => setSel(r)} className="tem-row-m v-wash" style={{
                display: "grid", gridTemplateColumns: "140px 90px 1fr 250px 180px 170px", gap: 16, padding: "12px 22px 12px 18px",
                borderTop: ri === 0 ? "none" : "1px solid var(--v-hair)",
                borderLeft: r.revoked ? "4px solid var(--v-danger)" : "4px solid transparent",
                cursor: "pointer", alignItems: "center",
              }}>
                <span style={{ display: "flex", flexWrap: "wrap", gap: 5 }}><StatusPill kind={r.revoked ? "revoked" : "registration"} />{r.environment === "staging" && <StatusPill kind="staging" />}</span>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.7 }}>{relTime(r.issued_at)}</span>
                <span style={{ minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                  {r.dapp.url && r.dapp.url !== "n/a" ? (
                    <a href={r.dapp.url} target="_blank" rel="noopener noreferrer" onClick={(e) => e.stopPropagation()} className="v-link" style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>
                      {r.dapp.url} <Icon.ArrowUpRight size={9} />
                    </a>
                  ) : (
                    <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.4 }}>n/a</span>
                  )}
                </span>
                <span style={{ display: "inline-flex", alignItems: "baseline", gap: 6, fontFamily: "var(--font-mono)", fontSize: 12, minWidth: 0, whiteSpace: "nowrap" }}>
                  <span style={{ color: "var(--v-teal)" }}>id</span>
                  <Mono copyable full={r.id} size={12} color={r.revoked ? "var(--v-danger)" : undefined}>{shortHash(r.id, 10)}</Mono>
                </span>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: verCount(r) > 0 ? "var(--v-ink)" : "var(--v-ink-40)", whiteSpace: "nowrap" }}>
                  {verCount(r) === "n/a" ? "Runtime data unavailable" : `${fmtCount(verCount(r))} runtime attestation${verCount(r) === 1 ? "" : "s"}`}
                </span>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--v-teal)", textAlign: "right", whiteSpace: "nowrap", display: "inline-flex", alignItems: "center", justifyContent: "flex-end", gap: 6 }}>
                  {attestationMeta(r.attestation_format).pill}{r.os_release ? " · " + osChipShort(r.os_release) : ""} <Icon.ArrowRight size={8} />
                </span>
              </div>
            ))}
          </React.Fragment>
        ))}
        {/* ver · apps rollup rows */}
        {view === "ver" && !appSel && appRows.map((a, i) => (
          <div key={a.key} onClick={() => openApp(a)} className="tem-row-a v-wash" style={{
            display: "grid", gridTemplateColumns: ROLLUP_COLS, gap: 12, padding: "14px 22px",
            borderTop: i === 0 ? "none" : "1px solid var(--v-hair)", cursor: "pointer", alignItems: "center",
          }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 12, minWidth: 0 }}>
              <Identicon seed={a.applicationId || a.appHash} size={28} />
              <span style={{ fontFamily: "var(--font-display)", fontSize: 22, lineHeight: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.name || "Unnamed application"}</span>
              {a.environment === "staging" && <StatusPill kind="staging" />}
            </span>
            <Mono copyable full={a.applicationId || a.appHash} color="var(--v-ink-78)" size={12}>{shortHash(a.applicationId || a.appHash, 10)}</Mono>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5, textAlign: "right" }}>{fmtCount(a.registrations)}</span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5, fontWeight: 500, color: a.verifications ? "var(--v-teal)" : "var(--v-ink-40)", textAlign: "right" }}>{a.verifications === null ? "Unavailable" : fmtCount(a.verifications)}</span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, opacity: 0.7, textAlign: "right" }}>{a.lastVerifiedAt ? relTime(Date.parse(a.lastVerifiedAt)) : "—"}</span>
          </div>
        ))}

        {/* ver · drill-down stream rows — rendered as a dense log: mono, tight
            leading, absolute timestamps, faint row rules */}
        {view === "ver" && appSel && !stream.loading && stream.items.map((r, i) => {
          const rejected = r.decision_status === "rejected";
          return (
            <div key={r.key} onClick={() => setSel(r)} className="tem-row-v v-wash" style={{
              display: "grid", gridTemplateColumns: STREAM_COLS, gap: 14, padding: "7px 22px",
              borderTop: i === 0 ? "none" : "1px solid var(--v-faint)",
              cursor: "pointer", alignItems: "center", fontFamily: "var(--font-mono)", fontSize: 11.5, lineHeight: 1.6,
            }}>
              <span style={{ justifySelf: "start", fontSize: 9.5, letterSpacing: "0.08em", textTransform: "uppercase", color: rejected ? "var(--v-danger)" : "var(--v-ink)", background: rejected ? "var(--v-danger-tint)" : "var(--v-teal-tint)", border: `1px solid ${rejected ? "var(--v-danger)" : "var(--v-ink)"}`, padding: "1px 7px", whiteSpace: "nowrap" }}>
                {rejected ? "rejected" : "verified"}
              </span>
              <span style={{ opacity: 0.7, whiteSpace: "nowrap" }}>{fmtDate(r.issued_at)}</span>
              <span>{shortHash(r.registration_id, 10)}</span>
              <span>{shortHash(r.call_id, 10)}</span>
              <span>{shortHash(r.result_hash, 10)}</span>
            </div>
          );
        })}

        {/* ver · load-more footer */}
        {view === "ver" && appSel && !stream.loading && stream.items.length > 0 && (
          <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 18, padding: "12px 22px", borderTop: "var(--v-border)", background: "var(--v-canvas)" }}>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>
              Showing {fmtCount(stream.items.length)} of {fmtCount(stream.total)}
            </span>
            {stream.nextBefore && (
              <Button variant="small" onClick={loadMore} disabled={stream.loadingMore} style={{ fontSize: 12, padding: "6px 16px" }}>
                {stream.loadingMore ? "Loading…" : "Load older"}
              </Button>
            )}
          </div>
        )}
      </div>
      )}
      {sel && (sel.type === 1
        ? <VerificationDrawer rec={sel} onClose={() => setSel(null)} onOpenRegistration={(parent) => setSel(parent)} />
        : <RecordDrawer rec={sel} onClose={() => setSel(null)} onOpenVerification={(v) => setSel(v)} onViewAllVerifications={viewImageStream} />)}
    </div>
  );
};
window.Explorer = Explorer;
