@rel-time/mcp-server 1.2.8 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +728 -301
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -56,7 +56,7 @@ let LAST_INVOICE_PACK = null;
56
56
 
57
57
  const SERVER_INFO = {
58
58
  name: "rel-time-mcp-server",
59
- version: "1.2.8",
59
+ version: "1.2.9",
60
60
  };
61
61
 
62
62
  /**
@@ -506,7 +506,7 @@ function escapeHtml(str) {
506
506
  }
507
507
 
508
508
  /**
509
- * Generates a self-contained, interactive Rel-Time Superhighway Cryptographic Audit Trail HTML report.
509
+ * Generates a self-contained, institutional-grade Rel-Time Superhighway Cryptographic Audit Trail HTML report.
510
510
  */
511
511
  function generateAuditReportHtml(audit) {
512
512
  const generatedUtc = audit.generated_at_utc || new Date().toISOString();
@@ -518,99 +518,196 @@ function generateAuditReportHtml(audit) {
518
518
  const localCheck = audit.local_path_verification || null;
519
519
  const entries = Array.isArray(audit.audit_trail) ? audit.audit_trail : [];
520
520
 
521
+ const totalMatched = Math.max(1, Number(sum.matched_entries_count || entries.length || 1));
522
+ const settledCount = Number(sum.settled_on_bitcoin_count || 0);
523
+ const pendingCount = Number(sum.pending_finality_count || 0);
524
+ const standardCount = Number(modes.standard_count || 0);
525
+ const temporalCount = Number(modes.temporal_vdf_count || 0);
526
+ const biometricCount = Number(modes.biometric_passkey_count || 0);
527
+ const machineCount = Math.max(0, Number(sum.matched_entries_count || entries.length) - biometricCount);
528
+
529
+ const settledPct = Math.round((settledCount / totalMatched) * 100);
530
+ const standardPct = Math.round((standardCount / totalMatched) * 100);
531
+ const biometricPct = Math.round((biometricCount / totalMatched) * 100);
532
+
533
+ // Build Bitcoin Block Settlement Topology nodes from entries
534
+ const blockGroupsMap = new Map();
535
+ for (const e of entries) {
536
+ if (e.status === "settled" && e.block_height) {
537
+ const bh = String(e.block_height);
538
+ const cur = blockGroupsMap.get(bh) || {
539
+ block_height: bh,
540
+ count: 0,
541
+ txid: e.txid || null,
542
+ max_ticks: 0,
543
+ timestamp_utc: e.timestamp_utc || null,
544
+ };
545
+ cur.count++;
546
+ if (!cur.txid && e.txid) cur.txid = e.txid;
547
+ if (Number(e.vdf_ticks || 0) > cur.max_ticks) cur.max_ticks = Number(e.vdf_ticks || 0);
548
+ blockGroupsMap.set(bh, cur);
549
+ }
550
+ }
551
+ const sortedBlocks = Array.from(blockGroupsMap.values())
552
+ .sort((a, b) => Number(a.block_height) - Number(b.block_height))
553
+ .slice(-5);
554
+
555
+ const topologyNodesHtml = [
556
+ ...sortedBlocks.map(
557
+ (b) => `
558
+ <div class="topo-node">
559
+ <div class="topo-node-top">
560
+ <span class="dot dot-settled"></span>
561
+ <span class="mono topo-height">BLOCK #${escapeHtml(b.block_height)}</span>
562
+ </div>
563
+ <div class="topo-metric mono">${b.count} ${b.count === 1 ? "ANCHOR" : "ANCHORS"}</div>
564
+ <div class="topo-meta mono">
565
+ ${
566
+ b.txid
567
+ ? `<a href="https://mempool.space/tx/${escapeHtml(b.txid)}" target="_blank" rel="noopener">TX ${escapeHtml(
568
+ b.txid.slice(0, 8)
569
+ )}…${escapeHtml(b.txid.slice(-4))} ↗</a>`
570
+ : "SETTLED"
571
+ }
572
+ </div>
573
+ </div>`
574
+ ),
575
+ pendingCount > 0
576
+ ? `
577
+ <div class="topo-node topo-node-pending">
578
+ <div class="topo-node-top">
579
+ <span class="dot dot-pending"></span>
580
+ <span class="mono topo-height">VDF MEMPOOL QUEUE</span>
581
+ </div>
582
+ <div class="topo-metric mono">${pendingCount} PENDING</div>
583
+ <div class="topo-meta mono">NEXT EPOCH (~10m)</div>
584
+ </div>`
585
+ : "",
586
+ ]
587
+ .filter(Boolean)
588
+ .join(`<div class="topo-connector"></div>`);
589
+
521
590
  const signerRowsHtml = signers.length
522
591
  ? signers
523
- .map(
524
- (s, idx) => `
592
+ .map((s, idx) => {
593
+ const sharePct = Math.round((Number(s.anchor_count || 0) / totalMatched) * 100);
594
+ return `
525
595
  <tr>
526
- <td class="mono">#${idx + 1}</td>
596
+ <td class="mono muted">${String(idx + 1).padStart(2, "0")}</td>
527
597
  <td>
528
- <span class="badge badge-passkey">FIDO2 / WebAuthn Hardware Key</span>
529
- <div class="mono hash-full" style="margin-top:4px">${escapeHtml(s.signer_public_key)}</div>
598
+ <div class="signer-key-header">
599
+ <span class="tag tag-neutral">FIDO2 / COSE P-256</span>
600
+ <span class="mono muted">KEY ID: ${escapeHtml(s.signer_public_key.slice(0, 16).toUpperCase())}</span>
601
+ </div>
602
+ <div class="mono hash-full" style="margin-top:5px">${escapeHtml(s.signer_public_key)}</div>
530
603
  </td>
531
- <td class="mono" style="font-weight:700;color:#F5B041">${s.anchor_count}</td>
532
- <td class="mono" style="color:#2ECC71">${s.settled_count}</td>
533
- <td class="mono">${escapeHtml(s.latest_timestamp_utc || "—")}</td>
534
- </tr>`
535
- )
604
+ <td class="mono">
605
+ <div style="display:flex;align-items:center;gap:10px">
606
+ <span style="font-weight:700;color:var(--text);min-width:24px">${s.anchor_count}</span>
607
+ <div class="mini-bar-track"><div class="mini-bar-fill" style="width:${sharePct}%"></div></div>
608
+ <span class="muted" style="font-size:11px">${sharePct}%</span>
609
+ </div>
610
+ </td>
611
+ <td class="mono">${s.settled_count} / ${s.anchor_count}</td>
612
+ <td class="mono muted">${escapeHtml(s.latest_timestamp_utc || "—")}</td>
613
+ </tr>`;
614
+ })
536
615
  .join("")
537
- : `<tr><td colspan="5" style="text-align:center;color:#8892b0;padding:18px">No hardware Passkey signatures recorded yet in this window. Link a passkey with <code>reltime_link_passkey</code> and anchor with <code>biometric: true</code>.</td></tr>`;
616
+ : `<tr><td colspan="5" class="empty-cell">No hardware Passkey signatures recorded in this window. Link a FIDO2/WebAuthn hardware key with <code>reltime_link_passkey</code> and anchor with <code>biometric: true</code>.</td></tr>`;
538
617
 
539
618
  const localVerificationHtml = localCheck
540
619
  ? `
541
- <div class="section-card">
542
- <div class="section-header">
620
+ <section class="panel">
621
+ <div class="panel-header">
543
622
  <div>
544
- <h2>Local File &amp; Folder Integrity Audit</h2>
545
- <p class="section-sub">Target Path: <span class="mono">${escapeHtml(localCheck.target_path)}</span> · Zero-Knowledge Local SHA-256 Cross-Reference</p>
623
+ <div class="section-index">SECTION 01 // ZERO-KNOWLEDGE LOCAL FILE INTEGRITY MATRIX</div>
624
+ <h2>Local Directory Cross-Reference</h2>
625
+ <p class="section-sub">Target Path: <span class="mono" style="color:var(--text-secondary)">${escapeHtml(
626
+ localCheck.target_path
627
+ )}</span> · 0 Bytes Uploaded · Local SHA-256 vs. Bitcoin Ledger</p>
546
628
  </div>
547
- <span class="badge ${
548
- localCheck.summary.unanchored_or_modified_count === 0 ? "badge-settled" : "badge-warn"
629
+ <div class="status-pill ${
630
+ localCheck.summary.unanchored_or_modified_count === 0 ? "status-pill-ok" : "status-pill-alert"
549
631
  }">
550
- ${
632
+ <span class="dot ${
633
+ localCheck.summary.unanchored_or_modified_count === 0 ? "dot-settled" : "dot-alert"
634
+ }"></span>
635
+ <span>${
551
636
  localCheck.summary.unanchored_or_modified_count === 0
552
- ? `100% INTACT (${localCheck.summary.total_files_scanned} Verified)`
553
- : `${localCheck.summary.unanchored_or_modified_count} UNANCHORED / MODIFIED`
554
- }
555
- </span>
637
+ ? `INTEGRITY VERIFIED (${localCheck.summary.total_files_scanned}/${localCheck.summary.total_files_scanned})`
638
+ : `${localCheck.summary.unanchored_or_modified_count} UNANCHORED OR MODIFIED`
639
+ }</span>
640
+ </div>
556
641
  </div>
557
642
  <div class="table-wrap">
558
643
  <table>
559
644
  <thead>
560
645
  <tr>
561
- <th>File</th>
562
- <th>Size</th>
563
- <th>Local SHA-256 / Embedded Hash</th>
564
- <th>Integrity Status</th>
565
- <th>Mode / Signer</th>
566
- <th>Bitcoin Settlement</th>
567
- <th>Proof</th>
646
+ <th style="width:42px">#</th>
647
+ <th>Artifact / File Name</th>
648
+ <th>Bytes</th>
649
+ <th>Local SHA-256 Digest</th>
650
+ <th>Verification Status</th>
651
+ <th>Attestation / Mode</th>
652
+ <th>Timechain Settlement</th>
653
+ <th style="text-align:right">Receipt</th>
568
654
  </tr>
569
655
  </thead>
570
656
  <tbody>
571
657
  ${localCheck.files
572
- .map((f) => {
573
- const statusBadge =
658
+ .map((f, idx) => {
659
+ const statusTag =
574
660
  f.integrity_status === "VERIFIED_SETTLED"
575
- ? `<span class="badge badge-settled">✓ VERIFIED (BITCOIN SETTLED)</span>`
661
+ ? `<span class="status-cell"><span class="dot dot-settled"></span><span class="mono" style="color:var(--text)">VERIFIED · SETTLED</span></span>`
576
662
  : f.integrity_status === "VERIFIED_PENDING"
577
- ? `<span class="badge badge-pending">⏳ VERIFIED (PENDING BLOCK)</span>`
578
- : `<span class="badge badge-warn">⚠ UNANCHORED OR MODIFIED</span>`;
663
+ ? `<span class="status-cell"><span class="dot dot-pending"></span><span class="mono" style="color:var(--text-secondary)">VERIFIED · PENDING</span></span>`
664
+ : `<span class="status-cell"><span class="dot dot-alert"></span><span class="mono" style="color:var(--crimson)">UNANCHORED / MODIFIED</span></span>`;
665
+
579
666
  const signerText = f.signer_public_key
580
- ? `<span class="badge badge-passkey" title="${escapeHtml(f.signer_public_key)}">Passkey ${escapeHtml(
581
- f.signer_public_key.slice(0, 10)
582
- )}…</span>`
583
- : `<span class="mono" style="color:#94a3b8">${escapeHtml(f.anchor_mode || "—")}</span>`;
667
+ ? `<span class="tag tag-neutral" title="Passkey COSE: ${escapeHtml(
668
+ f.signer_public_key
669
+ )}">PASSKEY ${escapeHtml(f.signer_public_key.slice(0, 8).toUpperCase())}…</span>`
670
+ : f.anchor_mode
671
+ ? `<span class="tag tag-neutral">${escapeHtml(f.anchor_mode.toUpperCase())}</span>`
672
+ : `<span class="mono muted">—</span>`;
673
+
584
674
  const btcText = f.block_height
585
- ? `<span class="mono" style="color:#2ECC71">Block #${escapeHtml(f.block_height)}</span>`
675
+ ? `<span class="mono" style="color:var(--text)">BLOCK #${escapeHtml(f.block_height)}</span>`
586
676
  : f.integrity_status === "VERIFIED_PENDING"
587
- ? `<span class="mono" style="color:#F5B041">Awaiting Next Block</span>`
588
- : `—`;
677
+ ? `<span class="mono muted">MEMPOOL QUEUE</span>`
678
+ : `<span class="mono muted">—</span>`;
679
+
589
680
  const verifyLink = f.verify_url
590
- ? `<a class="btn-link" href="${escapeHtml(f.verify_url)}" target="_blank" rel="noopener">Verify ↗</a>`
591
- : `—`;
681
+ ? `<a class="action-link" href="${escapeHtml(f.verify_url)}" target="_blank" rel="noopener">VERIFY ↗</a>`
682
+ : `<span class="mono muted">—</span>`;
683
+
592
684
  return `
593
685
  <tr>
594
- <td style="font-weight:600;color:#f8fafc">${escapeHtml(f.file_name)}${
595
- f.is_stamped_copy ? ` <span class="badge badge-mode">Stamped Copy</span>` : ""
596
- }</td>
597
- <td class="mono">${escapeHtml(f.size_human)}</td>
598
- <td class="mono hash-cell" title="${escapeHtml(f.local_sha256)}">${escapeHtml(
686
+ <td class="mono muted">${String(idx + 1).padStart(2, "0")}</td>
687
+ <td>
688
+ <span style="font-weight:600;color:var(--text)">${escapeHtml(f.file_name)}</span>
689
+ ${f.is_stamped_copy ? `<span class="tag tag-subtle" style="margin-left:8px">STAMPED COPY</span>` : ""}
690
+ </td>
691
+ <td class="mono muted">${escapeHtml(f.size_human)}</td>
692
+ <td class="mono" style="color:var(--text-secondary)" title="${escapeHtml(f.local_sha256)}">${escapeHtml(
599
693
  f.local_sha256.slice(0, 16)
600
- )}…${escapeHtml(f.local_sha256.slice(-8))}</td>
601
- <td>${statusBadge}</td>
694
+ )}…${escapeHtml(f.local_sha256.slice(-10))}</td>
695
+ <td>${statusTag}</td>
602
696
  <td>${signerText}</td>
603
697
  <td>${btcText}</td>
604
- <td>${verifyLink}</td>
698
+ <td style="text-align:right">${verifyLink}</td>
605
699
  </tr>`;
606
700
  })
607
701
  .join("")}
608
702
  </tbody>
609
703
  </table>
610
704
  </div>
611
- </div>`
705
+ </section>`
612
706
  : "";
613
707
 
708
+ const ledgerSectionNum = localCheck ? "03" : "02";
709
+ const signerSectionNum = localCheck ? "02" : "01";
710
+
614
711
  const ledgerRowsHtml = entries.length
615
712
  ? entries
616
713
  .map((e, idx) => {
@@ -626,34 +723,34 @@ function generateAuditReportHtml(audit) {
626
723
  .join(" ");
627
724
 
628
725
  const statusHtml = isSettled
629
- ? `<span class="badge badge-settled">✓ SETTLED</span>`
630
- : `<span class="badge badge-pending">⏳ PENDING FINALITY</span>`;
726
+ ? `<span class="status-cell"><span class="dot dot-settled"></span><span class="mono" style="color:var(--text)">SETTLED</span></span>`
727
+ : `<span class="status-cell"><span class="dot dot-pending"></span><span class="mono muted">PENDING</span></span>`;
631
728
 
632
729
  const modeHtml = `
633
- <span class="badge badge-mode">${escapeHtml(modeType.toUpperCase())}</span>
730
+ <span class="tag tag-neutral">${escapeHtml(modeType.toUpperCase())}</span>
634
731
  ${
635
732
  isBiometric
636
- ? `<span class="badge badge-passkey" title="Signed by Passkey: ${escapeHtml(
733
+ ? `<span class="tag tag-subtle" title="Passkey COSE: ${escapeHtml(
637
734
  e.signer_public_key
638
- )}">🔐 Passkey ${escapeHtml(e.signer_public_key.slice(0, 8))}…</span>`
735
+ )}">PK:${escapeHtml(e.signer_public_key.slice(0, 8).toUpperCase())}</span>`
639
736
  : ""
640
737
  }
641
738
  `;
642
739
 
643
740
  const btcHtml = isSettled
644
741
  ? `
645
- <div class="mono" style="color:#2ECC71;font-weight:600">Block #${escapeHtml(e.block_height || "—")}</div>
742
+ <div class="mono" style="color:var(--text);font-weight:600">BLOCK #${escapeHtml(e.block_height || "—")}</div>
646
743
  ${
647
744
  e.txid
648
745
  ? `<a class="mono tx-link" href="https://mempool.space/tx/${escapeHtml(
649
746
  e.txid
650
- )}" target="_blank" rel="noopener" title="${escapeHtml(e.txid)}">TX: ${escapeHtml(
747
+ )}" target="_blank" rel="noopener" title="${escapeHtml(e.txid)}">TX ${escapeHtml(
651
748
  e.txid.slice(0, 10)
652
749
  )}…${escapeHtml(e.txid.slice(-6))} ↗</a>`
653
750
  : ""
654
751
  }
655
752
  `
656
- : `<span class="mono" style="color:#94a3b8">Queued in VDF Batch</span>`;
753
+ : `<span class="mono muted">AWAITING BLOCK</span>`;
657
754
 
658
755
  return `
659
756
  <tr class="ledger-row ${filterClasses}" data-search="${escapeHtml(
@@ -661,367 +758,682 @@ function generateAuditReportHtml(audit) {
661
758
  e.txid || ""
662
759
  } ${e.block_height || ""} ${modeType}`.toLowerCase()
663
760
  )}">
664
- <td class="mono" style="color:#64748b">#${idx + 1}</td>
665
- <td class="mono">${escapeHtml(e.timestamp_utc || "—")}</td>
761
+ <td class="mono muted">${String(idx + 1).padStart(2, "0")}</td>
762
+ <td class="mono muted">${escapeHtml((e.timestamp_utc || "—").replace(".000Z", "Z"))}</td>
666
763
  <td>${statusHtml}</td>
667
764
  <td>${modeHtml}</td>
668
- <td class="mono hash-cell" title="Client Hash: ${escapeHtml(e.client_hash)}${
765
+ <td class="mono" style="color:var(--text-secondary)" title="Client Hash: ${escapeHtml(e.client_hash)}${
669
766
  e.original_file_hash ? ` | Original File SHA-256: ${escapeHtml(e.original_file_hash)}` : ""
670
767
  }">
671
- <div>${escapeHtml(e.client_hash.slice(0, 14))}…${escapeHtml(e.client_hash.slice(-8))}</div>
768
+ <div>${escapeHtml(e.client_hash.slice(0, 14))}…${escapeHtml(e.client_hash.slice(-10))}</div>
672
769
  ${
673
770
  e.original_file_hash
674
- ? `<div style="font-size:11px;color:#94a3b8">File: ${escapeHtml(
675
- e.original_file_hash.slice(0, 10)
771
+ ? `<div class="muted" style="font-size:10.5px;margin-top:2px">FILE: ${escapeHtml(
772
+ e.original_file_hash.slice(0, 12)
676
773
  )}…</div>`
677
774
  : ""
678
775
  }
679
776
  </td>
680
- <td class="mono hash-cell" title="T_index: ${escapeHtml(e.t_index)} | Solar Ticks: ${escapeHtml(
777
+ <td class="mono" style="color:var(--text-secondary)" title="T_index: ${escapeHtml(e.t_index)} | Solar Ticks: ${escapeHtml(
681
778
  e.vdf_ticks
682
779
  )}">
683
- <div>${escapeHtml(e.t_index.slice(0, 12))}…${escapeHtml(e.t_index.slice(-6))}</div>
684
- <div style="font-size:11px;color:#F5B041">Ticks: ${ Number(e.vdf_ticks || 0).toLocaleString() }</div>
780
+ <div>${escapeHtml(e.t_index.slice(0, 14))}…${escapeHtml(e.t_index.slice(-8))}</div>
781
+ <div class="muted" style="font-size:10.5px;margin-top:2px">VDF TICKS: ${Number(
782
+ e.vdf_ticks || 0
783
+ ).toLocaleString()}</div>
685
784
  </td>
686
785
  <td>${btcHtml}</td>
687
- <td>
688
- <a class="btn-link" href="${escapeHtml(e.verify_url)}" target="_blank" rel="noopener">Verify ↗</a>
786
+ <td style="text-align:right">
787
+ <a class="action-link" href="${escapeHtml(e.verify_url)}" target="_blank" rel="noopener">VERIFY ↗</a>
689
788
  </td>
690
789
  </tr>`;
691
790
  })
692
791
  .join("")
693
- : `<tr><td colspan="8" style="text-align:center;color:#8892b0;padding:24px">No ledger entries matched the current filter.</td></tr>`;
792
+ : `<tr><td colspan="8" class="empty-cell">No ledger entries matched the active filter criteria.</td></tr>`;
694
793
 
695
794
  return `<!DOCTYPE html>
696
- <html lang="en">
795
+ <html lang="en" data-theme="dark">
697
796
  <head>
698
797
  <meta charset="UTF-8" />
699
798
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
700
- <title>Rel-Time Superhighway — Cryptographic Audit Trail</title>
799
+ <title>Rel-Time Superhighway // Forensic Timechain Audit Report</title>
701
800
  <style>
702
801
  :root {
703
- --bg: #07090e;
704
- --card: #0f1420;
705
- --card-border: #1e293b;
706
- --gold: #f5b041;
707
- --gold-dim: rgba(245, 176, 65, 0.14);
708
- --green: #2ecc71;
709
- --green-dim: rgba(46, 204, 113, 0.14);
710
- --blue: #38bdf8;
711
- --blue-dim: rgba(56, 189, 248, 0.14);
712
- --purple: #c084fc;
713
- --purple-dim: rgba(192, 132, 252, 0.15);
714
- --red: #f87171;
715
- --red-dim: rgba(248, 113, 113, 0.15);
716
- --text: #f8fafc;
717
- --muted: #94a3b8;
802
+ --bg: #050506;
803
+ --grid-line: rgba(255, 255, 255, 0.015);
804
+ --panel: #0a0a0c;
805
+ --panel-alt: #0e0e12;
806
+ --border: #1e1e24;
807
+ --border-strong: #2e2e38;
808
+ --text: #f4f4f5;
809
+ --text-secondary: #d4d4d8;
810
+ --muted: #71717a;
811
+ --amber: #f59e0b;
812
+ --emerald: #10b981;
813
+ --crimson: #ef4444;
814
+ --track-bg: #18181d;
815
+ --bar-primary: #e4e4e7;
816
+ --bar-muted: #3f3f46;
817
+ --tag-bg: #141418;
818
+ --tab-active-bg: #18181f;
819
+ --row-hover: rgba(255, 255, 255, 0.015);
820
+ --btn-primary-fg: #050506;
821
+ }
822
+ html[data-theme="light"] {
823
+ --bg: #f4f4f6;
824
+ --grid-line: rgba(0, 0, 0, 0.03);
825
+ --panel: #ffffff;
826
+ --panel-alt: #f8f8fa;
827
+ --border: #e4e4e7;
828
+ --border-strong: #d4d4d8;
829
+ --text: #09090b;
830
+ --text-secondary: #3f3f46;
831
+ --muted: #71717a;
832
+ --amber: #d97706;
833
+ --emerald: #059669;
834
+ --crimson: #dc2626;
835
+ --track-bg: #e4e4e7;
836
+ --bar-primary: #18181b;
837
+ --bar-muted: #a1a1aa;
838
+ --tag-bg: #f4f4f5;
839
+ --tab-active-bg: #f4f4f5;
840
+ --row-hover: rgba(0, 0, 0, 0.02);
841
+ --btn-primary-fg: #ffffff;
718
842
  }
719
843
  * { box-sizing: border-box; }
720
844
  body {
721
845
  margin: 0;
722
- padding: 32px 24px 64px;
723
- background: radial-gradient(circle at top right, #131c31 0%, var(--bg) 55%);
846
+ padding: 28px 24px 64px;
847
+ background-color: var(--bg);
848
+ background-image:
849
+ linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
850
+ linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
851
+ background-size: 32px 32px;
724
852
  color: var(--text);
725
853
  font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, sans-serif;
726
- line-height: 1.5;
854
+ font-size: 13px;
855
+ line-height: 1.45;
856
+ -webkit-font-smoothing: antialiased;
857
+ transition: background-color 0.15s ease, color 0.15s ease;
727
858
  }
728
- .container { max-width: 1340px; margin: 0 auto; }
729
- .topbar {
859
+ .container { max-width: 1360px; margin: 0 auto; }
860
+ .mono {
861
+ font-family: "JetBrains Mono", "SF Mono", "Fira Code", Menlo, Consolas, monospace;
862
+ font-variant-numeric: tabular-nums;
863
+ font-size: 12px;
864
+ }
865
+ .muted { color: var(--muted); }
866
+
867
+ /* Masthead */
868
+ .masthead {
869
+ background: var(--panel);
870
+ border: 1px solid var(--border);
871
+ border-top: 2px solid var(--amber);
872
+ padding: 22px 26px;
730
873
  display: flex;
731
874
  flex-wrap: wrap;
732
875
  justify-content: space-between;
733
- align-items: center;
734
- gap: 16px;
735
- padding: 24px 28px;
736
- background: linear-gradient(135deg, rgba(15,20,32,0.96), rgba(20,28,46,0.92));
737
- border: 1px solid rgba(245, 176, 65, 0.35);
738
- border-radius: 16px;
739
- box-shadow: 0 18px 40px rgba(0,0,0,0.45);
740
- margin-bottom: 24px;
741
- }
742
- .brand-eyebrow {
743
- font-size: 11px;
744
- letter-spacing: 0.18em;
876
+ align-items: flex-start;
877
+ gap: 20px;
878
+ margin-bottom: 16px;
879
+ }
880
+ .eyebrow {
881
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
882
+ font-size: 10.5px;
883
+ letter-spacing: 0.16em;
745
884
  text-transform: uppercase;
746
- color: var(--gold);
747
- font-weight: 700;
748
- margin-bottom: 4px;
885
+ color: var(--amber);
886
+ margin-bottom: 6px;
749
887
  }
750
888
  h1 {
751
889
  margin: 0;
752
- font-size: 26px;
753
- font-weight: 800;
890
+ font-size: 22px;
891
+ font-weight: 700;
754
892
  letter-spacing: -0.02em;
893
+ color: var(--text);
755
894
  }
756
- .meta-line {
757
- font-size: 13px;
895
+ .masthead-meta {
896
+ margin-top: 10px;
897
+ display: flex;
898
+ flex-wrap: wrap;
899
+ gap: 18px;
900
+ font-size: 11.5px;
758
901
  color: var(--muted);
759
- margin-top: 4px;
902
+ }
903
+ .masthead-meta span strong {
904
+ color: var(--text-secondary);
905
+ font-weight: 600;
760
906
  }
761
907
  .actions-bar {
762
908
  display: flex;
763
- gap: 10px;
909
+ flex-wrap: wrap;
910
+ gap: 8px;
764
911
  align-items: center;
765
912
  }
766
- .btn {
767
- background: var(--gold);
768
- color: #07090e;
769
- border: none;
770
- padding: 10px 16px;
771
- border-radius: 8px;
913
+ .btn-primary {
914
+ background: var(--text);
915
+ color: var(--btn-primary-fg);
916
+ border: 1px solid var(--text);
917
+ padding: 9px 14px;
918
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
919
+ font-size: 11px;
772
920
  font-weight: 700;
773
- font-size: 13px;
921
+ letter-spacing: 0.06em;
922
+ text-transform: uppercase;
774
923
  cursor: pointer;
775
924
  text-decoration: none;
776
- display: inline-flex;
777
- align-items: center;
778
- gap: 6px;
779
925
  }
780
- .btn-outline {
926
+ .btn-primary:hover {
927
+ background: var(--amber);
928
+ border-color: var(--amber);
929
+ color: #050506;
930
+ }
931
+ .btn-secondary {
781
932
  background: transparent;
782
- color: var(--text);
783
- border: 1px solid var(--card-border);
784
- padding: 10px 16px;
785
- border-radius: 8px;
933
+ color: var(--text-secondary);
934
+ border: 1px solid var(--border-strong);
935
+ padding: 9px 14px;
936
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
937
+ font-size: 11px;
786
938
  font-weight: 600;
787
- font-size: 13px;
939
+ letter-spacing: 0.06em;
940
+ text-transform: uppercase;
788
941
  cursor: pointer;
789
942
  text-decoration: none;
790
943
  }
791
- .kpi-grid {
944
+ .btn-secondary:hover {
945
+ border-color: var(--text-secondary);
946
+ color: var(--text);
947
+ }
948
+
949
+ /* Flush Architectural Telemetry Strip */
950
+ .telemetry-strip {
792
951
  display: grid;
793
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
794
- gap: 16px;
795
- margin-bottom: 24px;
952
+ grid-template-columns: repeat(6, 1fr);
953
+ background: var(--panel);
954
+ border: 1px solid var(--border);
955
+ margin-bottom: 16px;
796
956
  }
797
- .kpi-card {
798
- background: var(--card);
799
- border: 1px solid var(--card-border);
800
- border-radius: 14px;
801
- padding: 18px 20px;
957
+ @media (max-width: 1100px) {
958
+ .telemetry-strip { grid-template-columns: repeat(3, 1fr); }
802
959
  }
803
- .kpi-label {
804
- font-size: 11px;
960
+ @media (max-width: 640px) {
961
+ .telemetry-strip { grid-template-columns: repeat(2, 1fr); }
962
+ }
963
+ .telemetry-cell {
964
+ padding: 16px 20px;
965
+ border-right: 1px solid var(--border);
966
+ border-bottom: 1px solid var(--border);
967
+ }
968
+ .telemetry-cell:last-child { border-right: none; }
969
+ .telemetry-label {
970
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
971
+ font-size: 10px;
805
972
  text-transform: uppercase;
806
- letter-spacing: 0.1em;
973
+ letter-spacing: 0.12em;
807
974
  color: var(--muted);
808
- margin-bottom: 6px;
975
+ margin-bottom: 8px;
809
976
  }
810
- .kpi-value {
811
- font-size: 26px;
812
- font-weight: 800;
977
+ .telemetry-val {
813
978
  font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
979
+ font-size: 24px;
980
+ font-weight: 700;
981
+ color: var(--text);
982
+ letter-spacing: -0.02em;
814
983
  }
815
- .kpi-sub {
816
- font-size: 12px;
984
+ .telemetry-sub {
985
+ font-size: 11px;
817
986
  color: var(--muted);
818
987
  margin-top: 4px;
819
988
  }
820
- .section-card {
821
- background: var(--card);
822
- border: 1px solid var(--card-border);
823
- border-radius: 16px;
824
- padding: 22px 24px;
825
- margin-bottom: 24px;
989
+
990
+ /* Visualization Grid (2 Columns) */
991
+ .viz-grid {
992
+ display: grid;
993
+ grid-template-columns: 1fr 1.25fr;
994
+ gap: 16px;
995
+ margin-bottom: 16px;
996
+ }
997
+ @media (max-width: 980px) {
998
+ .viz-grid { grid-template-columns: 1fr; }
999
+ }
1000
+ .panel {
1001
+ background: var(--panel);
1002
+ border: 1px solid var(--border);
1003
+ padding: 20px 24px;
1004
+ margin-bottom: 16px;
826
1005
  }
827
- .section-header {
1006
+ .viz-grid .panel { margin-bottom: 0; }
1007
+ .panel-header {
828
1008
  display: flex;
829
1009
  flex-wrap: wrap;
830
1010
  justify-content: space-between;
831
- align-items: center;
1011
+ align-items: flex-start;
832
1012
  gap: 12px;
1013
+ padding-bottom: 14px;
1014
+ border-bottom: 1px solid var(--border);
833
1015
  margin-bottom: 16px;
834
1016
  }
1017
+ .section-index {
1018
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1019
+ font-size: 10px;
1020
+ letter-spacing: 0.14em;
1021
+ text-transform: uppercase;
1022
+ color: var(--muted);
1023
+ margin-bottom: 3px;
1024
+ }
835
1025
  h2 {
836
1026
  margin: 0;
837
- font-size: 18px;
1027
+ font-size: 15px;
838
1028
  font-weight: 700;
1029
+ letter-spacing: -0.01em;
1030
+ color: var(--text);
839
1031
  }
840
1032
  .section-sub {
841
1033
  margin: 3px 0 0;
842
- font-size: 13px;
1034
+ font-size: 12px;
843
1035
  color: var(--muted);
844
1036
  }
1037
+
1038
+ /* Distribution Bars */
1039
+ .dist-row {
1040
+ margin-bottom: 14px;
1041
+ }
1042
+ .dist-row:last-child { margin-bottom: 0; }
1043
+ .dist-header {
1044
+ display: flex;
1045
+ justify-content: space-between;
1046
+ font-size: 11.5px;
1047
+ margin-bottom: 6px;
1048
+ }
1049
+ .dist-track {
1050
+ height: 6px;
1051
+ width: 100%;
1052
+ background: var(--track-bg);
1053
+ display: flex;
1054
+ overflow: hidden;
1055
+ }
1056
+ .dist-seg-primary { background: var(--bar-primary); height: 100%; }
1057
+ .dist-seg-emerald { background: var(--emerald); height: 100%; }
1058
+ .dist-seg-amber { background: var(--amber); height: 100%; }
1059
+ .dist-seg-muted { background: var(--bar-muted); height: 100%; }
1060
+
1061
+ /* Bitcoin Topology Strip */
1062
+ .topo-chain {
1063
+ display: flex;
1064
+ align-items: stretch;
1065
+ gap: 0;
1066
+ overflow-x: auto;
1067
+ padding: 6px 0 4px;
1068
+ }
1069
+ .topo-node {
1070
+ flex: 1;
1071
+ min-width: 135px;
1072
+ background: var(--panel-alt);
1073
+ border: 1px solid var(--border-strong);
1074
+ padding: 12px 14px;
1075
+ }
1076
+ .topo-node-pending {
1077
+ border-style: dashed;
1078
+ border-color: rgba(245, 158, 11, 0.55);
1079
+ }
1080
+ .topo-node-top {
1081
+ display: flex;
1082
+ align-items: center;
1083
+ gap: 6px;
1084
+ margin-bottom: 8px;
1085
+ }
1086
+ .topo-height {
1087
+ font-size: 11px;
1088
+ font-weight: 700;
1089
+ color: var(--text);
1090
+ }
1091
+ .topo-metric {
1092
+ font-size: 14px;
1093
+ font-weight: 700;
1094
+ color: var(--text-secondary);
1095
+ margin-bottom: 4px;
1096
+ }
1097
+ .topo-meta {
1098
+ font-size: 10.5px;
1099
+ color: var(--muted);
1100
+ }
1101
+ .topo-meta a {
1102
+ color: var(--muted);
1103
+ text-decoration: none;
1104
+ border-bottom: 1px dotted var(--muted);
1105
+ }
1106
+ .topo-meta a:hover { color: var(--text); border-bottom-color: var(--text); }
1107
+ .topo-connector {
1108
+ width: 18px;
1109
+ min-width: 18px;
1110
+ display: flex;
1111
+ align-items: center;
1112
+ justify-content: center;
1113
+ position: relative;
1114
+ }
1115
+ .topo-connector::before {
1116
+ content: "";
1117
+ width: 100%;
1118
+ height: 1px;
1119
+ background: var(--border-strong);
1120
+ }
1121
+
1122
+ /* Status Dots & Tags */
1123
+ .status-cell {
1124
+ display: inline-flex;
1125
+ align-items: center;
1126
+ gap: 7px;
1127
+ white-space: nowrap;
1128
+ }
1129
+ .dot {
1130
+ width: 6px;
1131
+ height: 6px;
1132
+ border-radius: 50%;
1133
+ display: inline-block;
1134
+ flex-shrink: 0;
1135
+ }
1136
+ .dot-settled { background: var(--emerald); }
1137
+ .dot-pending { background: var(--amber); }
1138
+ .dot-alert { background: var(--crimson); }
1139
+
1140
+ .status-pill {
1141
+ display: inline-flex;
1142
+ align-items: center;
1143
+ gap: 8px;
1144
+ padding: 5px 10px;
1145
+ border: 1px solid var(--border-strong);
1146
+ background: var(--panel-alt);
1147
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1148
+ font-size: 11px;
1149
+ font-weight: 600;
1150
+ }
1151
+ .status-pill-ok { border-color: rgba(16, 185, 129, 0.4); color: var(--text); }
1152
+ .status-pill-alert { border-color: rgba(239, 68, 68, 0.5); color: var(--crimson); }
1153
+
1154
+ .tag {
1155
+ display: inline-block;
1156
+ padding: 2px 6px;
1157
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1158
+ font-size: 10px;
1159
+ font-weight: 600;
1160
+ letter-spacing: 0.04em;
1161
+ white-space: nowrap;
1162
+ }
1163
+ .tag-neutral {
1164
+ background: var(--tag-bg);
1165
+ border: 1px solid var(--border-strong);
1166
+ color: var(--text-secondary);
1167
+ }
1168
+ .tag-subtle {
1169
+ background: transparent;
1170
+ border: 1px solid var(--border);
1171
+ color: var(--muted);
1172
+ }
1173
+
1174
+ .mini-bar-track {
1175
+ width: 72px;
1176
+ height: 4px;
1177
+ background: var(--track-bg);
1178
+ overflow: hidden;
1179
+ }
1180
+ .mini-bar-fill {
1181
+ height: 100%;
1182
+ background: var(--text-secondary);
1183
+ }
1184
+
1185
+ /* Filter Bar */
845
1186
  .filter-bar {
846
1187
  display: flex;
847
1188
  flex-wrap: wrap;
848
- gap: 8px;
1189
+ justify-content: space-between;
1190
+ gap: 10px;
849
1191
  align-items: center;
850
- margin-bottom: 16px;
1192
+ margin-bottom: 14px;
851
1193
  }
852
1194
  .search-input {
853
- background: #07090e;
854
- border: 1px solid var(--card-border);
1195
+ background: var(--bg);
1196
+ border: 1px solid var(--border-strong);
855
1197
  color: var(--text);
856
- padding: 8px 12px;
857
- border-radius: 8px;
858
- font-size: 13px;
859
- min-width: 260px;
1198
+ padding: 7px 12px;
1199
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1200
+ font-size: 11.5px;
1201
+ min-width: 290px;
1202
+ outline: none;
1203
+ }
1204
+ .search-input:focus { border-color: var(--text-secondary); }
1205
+ .tab-group {
1206
+ display: inline-flex;
1207
+ border: 1px solid var(--border-strong);
1208
+ background: var(--bg);
860
1209
  }
861
- .filter-pill {
862
- background: #07090e;
863
- border: 1px solid var(--card-border);
1210
+ .filter-tab {
1211
+ background: transparent;
1212
+ border: none;
1213
+ border-right: 1px solid var(--border);
864
1214
  color: var(--muted);
865
- padding: 6px 12px;
866
- border-radius: 999px;
867
- font-size: 12px;
1215
+ padding: 6px 11px;
1216
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1217
+ font-size: 10.5px;
868
1218
  font-weight: 600;
1219
+ text-transform: uppercase;
1220
+ letter-spacing: 0.05em;
869
1221
  cursor: pointer;
870
1222
  }
871
- .filter-pill.active {
872
- background: var(--gold-dim);
873
- border-color: var(--gold);
874
- color: var(--gold);
875
- }
876
- .table-wrap {
877
- overflow-x: auto;
1223
+ .filter-tab:last-child { border-right: none; }
1224
+ .filter-tab:hover { color: var(--text-secondary); }
1225
+ .filter-tab.active {
1226
+ background: var(--tab-active-bg);
1227
+ color: var(--text);
1228
+ box-shadow: inset 0 -2px 0 var(--amber);
878
1229
  }
1230
+
1231
+ /* Tables */
1232
+ .table-wrap { overflow-x: auto; }
879
1233
  table {
880
1234
  width: 100%;
881
1235
  border-collapse: collapse;
882
- font-size: 13px;
883
1236
  }
884
1237
  th {
885
1238
  text-align: left;
886
- padding: 11px 12px;
887
- font-size: 11px;
1239
+ padding: 10px 12px;
1240
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1241
+ font-size: 10px;
1242
+ font-weight: 600;
888
1243
  text-transform: uppercase;
889
- letter-spacing: 0.08em;
1244
+ letter-spacing: 0.1em;
890
1245
  color: var(--muted);
891
- border-bottom: 1px solid var(--card-border);
1246
+ background: var(--bg);
1247
+ border-top: 1px solid var(--border);
1248
+ border-bottom: 1px solid var(--border);
892
1249
  white-space: nowrap;
893
1250
  }
894
1251
  td {
895
- padding: 12px;
896
- border-bottom: 1px solid rgba(30, 41, 59, 0.65);
1252
+ padding: 11px 12px;
1253
+ border-bottom: 1px solid var(--border);
897
1254
  vertical-align: middle;
898
1255
  }
899
- tr:hover td {
900
- background: rgba(255, 255, 255, 0.02);
901
- }
902
- .mono {
903
- font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
904
- font-size: 12px;
905
- }
1256
+ tr:hover td { background: var(--row-hover); }
906
1257
  .hash-full {
907
1258
  word-break: break-all;
908
- color: #cbd5e1;
909
- font-size: 11.5px;
910
- }
911
- .badge {
912
- display: inline-block;
913
- padding: 3px 9px;
914
- border-radius: 999px;
1259
+ color: var(--text-secondary);
915
1260
  font-size: 11px;
916
- font-weight: 700;
917
- letter-spacing: 0.03em;
918
- white-space: nowrap;
919
1261
  }
920
- .badge-settled { background: var(--green-dim); color: var(--green); border: 1px solid rgba(46,204,113,0.35); }
921
- .badge-pending { background: var(--gold-dim); color: var(--gold); border: 1px solid rgba(245,176,65,0.35); }
922
- .badge-mode { background: var(--blue-dim); color: var(--blue); border: 1px solid rgba(56,189,248,0.3); }
923
- .badge-passkey { background: var(--purple-dim); color: var(--purple); border: 1px solid rgba(192,132,252,0.35); }
924
- .badge-warn { background: var(--red-dim); color: var(--red); border: 1px solid rgba(248,113,113,0.35); }
925
- .btn-link {
926
- color: var(--gold);
1262
+ .signer-key-header {
1263
+ display: flex;
1264
+ align-items: center;
1265
+ gap: 8px;
1266
+ }
1267
+ .action-link {
1268
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1269
+ font-size: 10.5px;
1270
+ font-weight: 600;
1271
+ color: var(--text-secondary);
927
1272
  text-decoration: none;
928
- font-weight: 700;
929
- font-size: 12px;
930
- padding: 5px 10px;
931
- border: 1px solid rgba(245,176,65,0.35);
932
- border-radius: 6px;
933
- background: var(--gold-dim);
1273
+ padding: 4px 8px;
1274
+ border: 1px solid var(--border-strong);
1275
+ background: var(--bg);
934
1276
  white-space: nowrap;
935
1277
  }
1278
+ .action-link:hover {
1279
+ border-color: var(--amber);
1280
+ color: var(--amber);
1281
+ }
936
1282
  .tx-link {
937
- color: #94a3b8;
1283
+ color: var(--muted);
938
1284
  text-decoration: none;
939
- font-size: 11px;
1285
+ font-size: 10.5px;
940
1286
  display: inline-block;
941
1287
  margin-top: 2px;
942
1288
  }
943
- .tx-link:hover { color: var(--gold); }
1289
+ .tx-link:hover { color: var(--text); }
1290
+ .empty-cell {
1291
+ text-align: center;
1292
+ color: var(--muted);
1293
+ padding: 24px;
1294
+ font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
1295
+ font-size: 11.5px;
1296
+ }
944
1297
  @media print {
945
- body { background: #07090e !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; padding: 12px; }
1298
+ body { background: var(--bg) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; padding: 10px; }
946
1299
  .no-print { display: none !important; }
947
1300
  }
948
1301
  </style>
949
1302
  </head>
950
1303
  <body>
951
1304
  <div class="container">
952
- <div class="topbar">
1305
+ <header class="masthead">
953
1306
  <div>
954
- <div class="brand-eyebrow">Rel-Time Sovereign Provenance Protocol · Audit Trail</div>
955
- <h1>Cryptographic Data Integrity &amp; Timechain Audit Report</h1>
956
- <div class="meta-line">
957
- Generated: <span class="mono">${escapeHtml(generatedUtc)}</span> ·
958
- Account Tier: <strong style="color:#F5B041">${escapeHtml(acct.tier || "Active")}</strong> ·
959
- Key: <span class="mono">${escapeHtml(acct.masked_api_key || "rel_key_***")}</span>
1307
+ <div class="eyebrow">REL-TIME SOVEREIGN PROVENANCE PROTOCOL // FORENSIC AUDIT LEDGER</div>
1308
+ <h1>Cryptographic Data Integrity &amp; Timechain Settlement Report</h1>
1309
+ <div class="masthead-meta mono">
1310
+ <span>GENERATED UTC: <strong>${escapeHtml(generatedUtc)}</strong></span>
1311
+ <span>SLA TIER: <strong>${escapeHtml(acct.tier || "Active")}</strong></span>
1312
+ <span>CREDENTIAL: <strong>${escapeHtml(acct.masked_api_key || "rel_key_***")}</strong></span>
960
1313
  </div>
961
1314
  </div>
962
1315
  <div class="actions-bar no-print">
963
- <a class="btn-outline" href="https://rel-time.com/verify" target="_blank" rel="noopener">Open Verifier ↗</a>
964
- <button class="btn" onclick="window.print()">Print / Save PDF Audit Certificate</button>
1316
+ <button id="themeToggleBtn" class="btn-secondary" onclick="toggleTheme()">[ ☀ LIGHT MODE ]</button>
1317
+ <a class="btn-secondary" href="https://rel-time.com/verify" target="_blank" rel="noopener">[ OPEN VERIFIER ↗ ]</a>
1318
+ <button class="btn-primary" onclick="window.print()">[ EXPORT PDF CERTIFICATE ]</button>
965
1319
  </div>
966
- </div>
1320
+ </header>
967
1321
 
968
- <div class="kpi-grid">
969
- <div class="kpi-card">
970
- <div class="kpi-label">Audited Anchors</div>
971
- <div class="kpi-value" style="color:#f8fafc">${Number(sum.matched_entries_count || 0).toLocaleString()}</div>
972
- <div class="kpi-sub">Lifetime Account Total: ${Number(acct.lifetime_anchors || 0).toLocaleString()}</div>
1322
+ <div class="telemetry-strip">
1323
+ <div class="telemetry-cell">
1324
+ <div class="telemetry-label">Audited Scope</div>
1325
+ <div class="telemetry-val">${Number(sum.matched_entries_count || 0).toLocaleString()}</div>
1326
+ <div class="telemetry-sub mono">LIFETIME: ${Number(acct.lifetime_anchors || 0).toLocaleString()}</div>
973
1327
  </div>
974
- <div class="kpi-card">
975
- <div class="kpi-label">Bitcoin Finality</div>
976
- <div class="kpi-value" style="color:#2ECC71">${Number(sum.settled_on_bitcoin_count || 0).toLocaleString()}</div>
977
- <div class="kpi-sub">${escapeHtml(sum.settlement_rate_pct || "0%")} Settled · ${Number(
978
- sum.pending_finality_count || 0
979
- )} Pending</div>
1328
+ <div class="telemetry-cell">
1329
+ <div class="telemetry-label">Timechain Finality</div>
1330
+ <div class="telemetry-val">${settledCount.toLocaleString()} <span style="font-size:14px;color:var(--muted)">/ ${Number(
1331
+ sum.matched_entries_count || 0
1332
+ )}</span></div>
1333
+ <div class="telemetry-sub mono">${escapeHtml(sum.settlement_rate_pct || "0%")} SETTLED · ${pendingCount} QUEUED</div>
980
1334
  </div>
981
- <div class="kpi-card">
982
- <div class="kpi-label">Bitcoin Blocks &amp; TXs</div>
983
- <div class="kpi-value" style="color:#F5B041">${Number(btc.unique_blocks_count || 0)}</div>
984
- <div class="kpi-sub">${Number(btc.unique_txids_count || 0)} Unique OP_RETURN TXIDs${
985
- btc.latest_settled_block ? ` · Latest #${escapeHtml(btc.latest_settled_block)}` : ""
1335
+ <div class="telemetry-cell">
1336
+ <div class="telemetry-label">Bitcoin Blocks</div>
1337
+ <div class="telemetry-val">${Number(btc.unique_blocks_count || 0)}</div>
1338
+ <div class="telemetry-sub mono">${Number(btc.unique_txids_count || 0)} OP_RETURN TXS${
1339
+ btc.latest_settled_block ? ` · #${escapeHtml(btc.latest_settled_block)}` : ""
986
1340
  }</div>
987
1341
  </div>
988
- <div class="kpi-card">
989
- <div class="kpi-label">Hashing Modes</div>
990
- <div class="kpi-value" style="color:#38bdf8">${Number(modes.standard_count || 0)} / ${Number(
991
- modes.temporal_vdf_count || 0
992
- )}</div>
993
- <div class="kpi-sub">Standard Integrity / Temporal VDF</div>
1342
+ <div class="telemetry-cell">
1343
+ <div class="telemetry-label">Mode Split</div>
1344
+ <div class="telemetry-val">${standardCount} <span style="font-size:14px;color:var(--muted)">:</span> ${temporalCount}</div>
1345
+ <div class="telemetry-sub mono">STANDARD : TEMPORAL VDF</div>
994
1346
  </div>
995
- <div class="kpi-card">
996
- <div class="kpi-label">Hardware Passkey Signers</div>
997
- <div class="kpi-value" style="color:#c084fc">${signers.length}</div>
998
- <div class="kpi-sub">${Number(modes.biometric_passkey_count || 0)} Biometric-Attested Anchors</div>
1347
+ <div class="telemetry-cell">
1348
+ <div class="telemetry-label">Passkey Authorities</div>
1349
+ <div class="telemetry-val">${signers.length}</div>
1350
+ <div class="telemetry-sub mono">${biometricCount} BIOMETRIC SIGNATURES</div>
999
1351
  </div>
1000
- <div class="kpi-card">
1001
- <div class="kpi-label">Available Fuel</div>
1002
- <div class="kpi-value" style="color:#F5B041">${Number(acct.hash_credits_remaining || 0).toLocaleString()}</div>
1003
- <div class="kpi-sub">Remaining Hash Credits</div>
1352
+ <div class="telemetry-cell">
1353
+ <div class="telemetry-label">Available Fuel</div>
1354
+ <div class="telemetry-val" style="color:var(--amber)">${Number(
1355
+ acct.hash_credits_remaining || 0
1356
+ ).toLocaleString()}</div>
1357
+ <div class="telemetry-sub mono">HASH CREDITS REMAINING</div>
1358
+ </div>
1359
+ </div>
1360
+
1361
+ <div class="viz-grid">
1362
+ <div class="panel">
1363
+ <div class="panel-header" style="margin-bottom:14px;padding-bottom:10px">
1364
+ <div>
1365
+ <div class="section-index">TELEMETRY // DISTRIBUTION METRICS</div>
1366
+ <h2>Pipeline &amp; Attestation Ratios</h2>
1367
+ </div>
1368
+ </div>
1369
+ <div class="dist-row">
1370
+ <div class="dist-header mono">
1371
+ <span>BITCOIN FINALITY (${settledPct}% SETTLED)</span>
1372
+ <span class="muted">${settledCount} SETTLED / ${pendingCount} PENDING</span>
1373
+ </div>
1374
+ <div class="dist-track">
1375
+ <div class="dist-seg-emerald" style="width:${settledPct}%"></div>
1376
+ <div class="dist-seg-amber" style="width:${100 - settledPct}%"></div>
1377
+ </div>
1378
+ </div>
1379
+ <div class="dist-row">
1380
+ <div class="dist-header mono">
1381
+ <span>HASHING ARCHITECTURE (${standardPct}% STANDARD)</span>
1382
+ <span class="muted">${standardCount} INTEGRITY / ${temporalCount} TEMPORAL VDF</span>
1383
+ </div>
1384
+ <div class="dist-track">
1385
+ <div class="dist-seg-primary" style="width:${standardPct}%"></div>
1386
+ <div class="dist-seg-muted" style="width:${100 - standardPct}%"></div>
1387
+ </div>
1388
+ </div>
1389
+ <div class="dist-row">
1390
+ <div class="dist-header mono">
1391
+ <span>HARDWARE PASSKEY ATTESTATION (${biometricPct}%)</span>
1392
+ <span class="muted">${biometricCount} FIDO2 SIGNED / ${machineCount} MACHINE</span>
1393
+ </div>
1394
+ <div class="dist-track">
1395
+ <div class="dist-seg-primary" style="width:${biometricPct}%"></div>
1396
+ <div class="dist-seg-muted" style="width:${100 - biometricPct}%"></div>
1397
+ </div>
1398
+ </div>
1399
+ </div>
1400
+
1401
+ <div class="panel">
1402
+ <div class="panel-header" style="margin-bottom:14px;padding-bottom:10px">
1403
+ <div>
1404
+ <div class="section-index">TIMECHAIN TOPOLOGY // MERKLE BATCH ANCHORS</div>
1405
+ <h2>Bitcoin Block Settlement Sequence</h2>
1406
+ </div>
1407
+ <span class="mono muted" style="font-size:11px">SHA-256 MERKLE ROOT ➔ OP_RETURN</span>
1408
+ </div>
1409
+ <div class="topo-chain">
1410
+ ${
1411
+ topologyNodesHtml ||
1412
+ `<div class="empty-cell" style="width:100%;padding:16px">No settled Bitcoin blocks in current filter window.</div>`
1413
+ }
1414
+ </div>
1004
1415
  </div>
1005
1416
  </div>
1006
1417
 
1007
1418
  ${localVerificationHtml}
1008
1419
 
1009
- <div class="section-card">
1010
- <div class="section-header">
1420
+ <section class="panel">
1421
+ <div class="panel-header">
1011
1422
  <div>
1012
- <h2>Corporate Hardware Passkey Signers (WebAuthn / FIDO2 COSE Keys)</h2>
1013
- <p class="section-sub">Hardware Secure Enclave &amp; YubiKey public keys that have attested files under this corporate account</p>
1423
+ <div class="section-index">SECTION ${signerSectionNum} // CORPORATE HARDWARE PASSKEY REGISTRY</div>
1424
+ <h2>Authorized WebAuthn / FIDO2 Signer Authorities</h2>
1425
+ <p class="section-sub">Non-exportable Secure Enclave &amp; YubiKey COSE public keys recorded across this corporate credential</p>
1014
1426
  </div>
1015
1427
  </div>
1016
1428
  <div class="table-wrap">
1017
1429
  <table>
1018
1430
  <thead>
1019
1431
  <tr>
1020
- <th>#</th>
1432
+ <th style="width:42px">#</th>
1021
1433
  <th>Hardware Signer Public Key (COSE Hex)</th>
1022
- <th>Signed Anchors</th>
1023
- <th>Bitcoin Settled</th>
1024
- <th>Latest Signature (UTC)</th>
1434
+ <th style="width:200px">Attested Volume</th>
1435
+ <th style="width:130px">Finality Ratio</th>
1436
+ <th style="width:190px">Latest Attestation (UTC)</th>
1025
1437
  </tr>
1026
1438
  </thead>
1027
1439
  <tbody>
@@ -1029,46 +1441,39 @@ function generateAuditReportHtml(audit) {
1029
1441
  </tbody>
1030
1442
  </table>
1031
1443
  </div>
1032
- </div>
1444
+ </section>
1033
1445
 
1034
- <div class="section-card">
1035
- <div class="section-header">
1446
+ <section class="panel">
1447
+ <div class="panel-header">
1036
1448
  <div>
1037
- <h2>Chronological Timechain Audit Ledger</h2>
1038
- <p class="section-sub">Complete record of SHA-256 data integrity hashes, VDF thermodynamic proofs (T_index), and Bitcoin Merkle settlements</p>
1449
+ <div class="section-index">SECTION ${ledgerSectionNum} // CHRONOLOGICAL TIMECHAIN LEDGER</div>
1450
+ <h2>Cryptographic Anchor &amp; VDF Sequence Log</h2>
1451
+ <p class="section-sub">Immutable record of SHA-256 payload digests, VDF thermodynamic proofs (T_index), and Bitcoin Merkle settlements</p>
1039
1452
  </div>
1040
1453
  </div>
1041
1454
  <div class="filter-bar no-print">
1042
- <input id="searchInput" class="search-input" type="text" placeholder="Filter by SHA-256 hash, T_index, Passkey, TXID, or Block #..." oninput="filterLedger()" />
1043
- <button class="filter-pill active" onclick="setPill(this, 'all')">All (${entries.length})</button>
1044
- <button class="filter-pill" onclick="setPill(this, 'status-settled')">Settled (${Number(
1045
- sum.settled_on_bitcoin_count || 0
1046
- )})</button>
1047
- <button class="filter-pill" onclick="setPill(this, 'status-pending')">Pending (${Number(
1048
- sum.pending_finality_count || 0
1049
- )})</button>
1050
- <button class="filter-pill" onclick="setPill(this, 'mode-biometric')">Biometric Passkey (${Number(
1051
- modes.biometric_passkey_count || 0
1052
- )})</button>
1053
- <button class="filter-pill" onclick="setPill(this, 'mode-temporal')">Temporal VDF (${Number(
1054
- modes.temporal_vdf_count || 0
1055
- )})</button>
1056
- <button class="filter-pill" onclick="setPill(this, 'mode-standard')">Standard (${Number(
1057
- modes.standard_count || 0
1058
- )})</button>
1455
+ <div class="tab-group">
1456
+ <button class="filter-tab active" onclick="setPill(this, 'all')">All (${entries.length})</button>
1457
+ <button class="filter-tab" onclick="setPill(this, 'status-settled')">Settled (${settledCount})</button>
1458
+ <button class="filter-tab" onclick="setPill(this, 'status-pending')">Pending (${pendingCount})</button>
1459
+ <button class="filter-tab" onclick="setPill(this, 'mode-biometric')">Passkey (${biometricCount})</button>
1460
+ <button class="filter-tab" onclick="setPill(this, 'mode-temporal')">Temporal VDF (${temporalCount})</button>
1461
+ <button class="filter-tab" onclick="setPill(this, 'mode-standard')">Standard (${standardCount})</button>
1462
+ </div>
1463
+ <input id="searchInput" class="search-input" type="text" placeholder="QUERY SHA-256 / T_INDEX / PASSKEY / TXID / BLOCK..." oninput="filterLedger()" />
1059
1464
  </div>
1060
1465
  <div class="table-wrap">
1061
1466
  <table>
1062
1467
  <thead>
1063
1468
  <tr>
1064
- <th>#</th>
1469
+ <th style="width:42px">#</th>
1065
1470
  <th>Timestamp (UTC)</th>
1066
- <th>Status</th>
1067
- <th>Mode &amp; Signer</th>
1068
- <th>Client / File SHA-256</th>
1069
- <th>Thermodynamic Proof (T_index)</th>
1471
+ <th>Finality</th>
1472
+ <th>Mode / Authority</th>
1473
+ <th>Client / File SHA-256 Digest</th>
1474
+ <th>Thermodynamic Proof (T_Index)</th>
1070
1475
  <th>Bitcoin Settlement</th>
1071
- <th>Verify</th>
1476
+ <th style="text-align:right">Proof</th>
1072
1477
  </tr>
1073
1478
  </thead>
1074
1479
  <tbody id="ledgerBody">
@@ -1076,14 +1481,36 @@ function generateAuditReportHtml(audit) {
1076
1481
  </tbody>
1077
1482
  </table>
1078
1483
  </div>
1079
- </div>
1484
+ </section>
1080
1485
  </div>
1081
1486
 
1082
1487
  <script>
1083
1488
  let currentFilter = 'all';
1489
+ function applyTheme(theme) {
1490
+ const root = document.documentElement;
1491
+ const btn = document.getElementById('themeToggleBtn');
1492
+ if (theme === 'light') {
1493
+ root.setAttribute('data-theme', 'light');
1494
+ if (btn) btn.textContent = '[ ☾ DARK MODE ]';
1495
+ } else {
1496
+ root.setAttribute('data-theme', 'dark');
1497
+ if (btn) btn.textContent = '[ ☀ LIGHT MODE ]';
1498
+ }
1499
+ try { localStorage.setItem('reltime_audit_theme', theme); } catch (e) {}
1500
+ }
1501
+ function toggleTheme() {
1502
+ const current = document.documentElement.getAttribute('data-theme') || 'dark';
1503
+ applyTheme(current === 'dark' ? 'light' : 'dark');
1504
+ }
1505
+ (function initTheme() {
1506
+ try {
1507
+ const saved = localStorage.getItem('reltime_audit_theme');
1508
+ if (saved === 'light' || saved === 'dark') applyTheme(saved);
1509
+ } catch (e) {}
1510
+ })();
1084
1511
  function setPill(btn, filter) {
1085
1512
  currentFilter = filter;
1086
- document.querySelectorAll('.filter-pill').forEach(el => el.classList.remove('active'));
1513
+ document.querySelectorAll('.filter-tab').forEach(el => el.classList.remove('active'));
1087
1514
  btn.classList.add('active');
1088
1515
  filterLedger();
1089
1516
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rel-time/mcp-server",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "Official Model Context Protocol (MCP) server for Rel-Time (rel-time.com) — Zero-Knowledge Bitcoin & VDF Provenance, Local File Hashing, and Sun-Stamp Generation for Claude, Cursor, Windsurf, and Antigravity.",
5
5
  "main": "index.js",
6
6
  "bin": {