← Files VeraARCHIVED FILE

modules/journal-sampling/assets/journal-sampling-review-widget.html

152 KB · Oct 2, 2026 · 00:29 UTC

↓ Download file

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Journal Sampling Review</title>
  <style>
    :root {
      color-scheme: light;
      --paper: #ffffff;
      --surface: #ffffff;
      --soft: #fafafa;
      --soft-strong: #f3f4f2;
      --ink: #1f2421;
      --text: #3f4541;
      --muted: #727972;
      --border: #e8eae7;
      --border-strong: #d8dcd7;
      --accent: #35463f;
      --accent-strong: #202a26;
      --accent-soft: #f3f6f4;
      --danger: #7b4b44;
      --danger-bg: #fbf7f6;
      --warning: #6f6247;
      --warning-bg: #fbfaf6;
      --ok: #4b6759;
      --ok-bg: #f7faf8;
      --info: #52646e;
      --info-bg: #f7fafb;
      --radius: 8px;
      --content: 1240px;
    }
    * { box-sizing: border-box; }
    html, body { margin: 0; max-width: 100%; background: var(--paper); }
    body {
      color: var(--text);
      font-family: "Aptos", "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      font-size: 1rem;
      line-height: 1.5;
      letter-spacing: 0;
      font-kerning: normal;
      text-rendering: optimizeLegibility;
    }
    button, input, textarea { font: inherit; letter-spacing: 0; }
    button, input, textarea, select { max-width: 100%; }
    .app { min-height: 100vh; padding: 1.5rem; background: var(--paper); }
    .shell { width: 100%; max-width: var(--content); min-width: 0; margin: 0 auto; }
    .topbar {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      gap: 1rem;
      padding-bottom: 1rem;
      margin-bottom: 1rem;
      border-bottom: 1px solid var(--border);
    }
    h1 { margin: 0 0 0.2rem; color: var(--ink); font-size: 1.25rem; font-weight: 650; line-height: 1.18; }
    .subtitle { margin: 0; color: var(--muted); font-size: 0.9rem; }
    .top-actions, .context-list, .tabs, .action-buttons, .empty-actions {
      display: flex;
      flex-wrap: wrap;
      gap: 0.45rem;
      min-width: 0;
    }
    .top-actions, .context-list, .tabs, .action-buttons { justify-content: flex-end; }
    .pill, .context-token, .status-token {
      display: inline-flex;
      align-items: center;
      min-width: 0;
      max-width: 100%;
      min-height: 1.7rem;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 0.2rem 0.55rem;
      background: var(--surface);
      color: var(--muted);
      font-size: 0.74rem;
      font-weight: 600;
      line-height: 1.2;
      white-space: normal;
      overflow-wrap: anywhere;
    }
    .summary {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(8.8rem, 1fr));
      gap: 0;
      margin-bottom: 1.1rem;
      border-top: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
    }
    .metric {
      min-width: 0;
      min-height: 3.9rem;
      border: 0;
      border-right: 1px solid var(--border);
      border-radius: 0;
      padding: 0.72rem 0.9rem 0.68rem 0;
      background: transparent;
    }
    .metric:last-child { border-right: 0; }
    .metric span { display: block; color: var(--muted); font-size: 0.74rem; font-weight: 560; }
    .metric strong {
      display: block;
      margin-top: 0.16rem;
      color: var(--ink);
      font-size: 1.2rem;
      font-weight: 650;
      line-height: 1.15;
      font-variant-numeric: tabular-nums;
    }
    .run-context, .review-actions {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 0.75rem;
      align-items: center;
      border: 0;
      border-bottom: 1px solid var(--border);
      border-radius: 0;
      padding: 0.78rem 0;
      margin-bottom: 1rem;
      background: transparent;
    }
    .run-context strong, .progress-meter strong {
      display: block;
      color: var(--ink);
      font-weight: 650;
      line-height: 1.25;
    }
    .run-context span, .progress-meter span {
      color: var(--muted);
      font-size: 0.84rem;
      line-height: 1.35;
      overflow-wrap: anywhere;
    }
    .review-store {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
      gap: 0;
      border-top: 1px solid var(--border);
      padding-top: 0.62rem;
      margin-top: 0.2rem;
    }
    .review-store__item {
      min-width: 0;
      border-right: 1px solid var(--border);
      padding: 0.16rem 0.7rem 0.12rem 0;
    }
    .review-store__item:last-child { border-right: 0; }
    .review-store__item span {
      display: block;
      color: var(--muted);
      font-size: 0.72rem;
      font-weight: 620;
      line-height: 1.2;
    }
    .review-store__item strong {
      display: block;
      margin-top: 0.12rem;
      color: var(--ink);
      font-size: 0.86rem;
      font-weight: 650;
      line-height: 1.25;
      overflow-wrap: anywhere;
      font-variant-numeric: tabular-nums;
    }
    .review-store__item.is-dirty strong { color: var(--warning); }
    .review-store__item.is-applied strong { color: var(--ok); }
    .review-store__item.is-empty strong { color: var(--muted); }
    .recovery-panel {
      grid-column: 1 / -1;
      display: none;
      grid-template-columns: minmax(9rem, 0.22fr) minmax(0, 1fr);
      gap: 0.6rem 0.9rem;
      align-items: start;
      border-top: 1px solid var(--border);
      padding-top: 0.68rem;
      color: var(--text);
    }
    .recovery-panel.is-visible { display: grid; }
    .recovery-panel.is-error { color: var(--danger); }
    .recovery-panel__title {
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .recovery-panel.is-error .recovery-panel__title { color: var(--danger); }
    .recovery-panel__body {
      display: grid;
      gap: 0.35rem;
      min-width: 0;
      color: var(--muted);
      font-size: 0.82rem;
      line-height: 1.35;
    }
    .recovery-panel__line {
      display: grid;
      grid-template-columns: minmax(5.5rem, 0.18fr) minmax(0, 1fr);
      gap: 0.45rem;
      min-width: 0;
    }
    .recovery-panel__line span:first-child {
      color: var(--ink);
      font-weight: 620;
    }
    .recovery-panel__line span:last-child {
      min-width: 0;
      overflow-wrap: anywhere;
    }
    .data-posture {
      display: grid;
      grid-template-columns: minmax(7.5rem, auto) minmax(0, 1fr);
      gap: 0.75rem;
      align-items: start;
      border-bottom: 1px solid var(--border);
      padding: 0 0 0.9rem;
      margin-bottom: 1rem;
    }
    .data-posture__title {
      display: grid;
      gap: 0.28rem;
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .data-posture__title small {
      max-width: 32ch;
      color: var(--muted);
      font-size: 0.7rem;
      font-weight: 450;
      line-height: 1.35;
    }
    .data-posture__grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(8.2rem, 1fr));
      gap: 0.45rem;
    }
    .data-posture__item {
      min-width: 0;
      border-left: 2px solid var(--border);
      padding-left: 0.55rem;
    }
    .data-posture__item span {
      display: block;
      color: var(--muted);
      font-size: 0.7rem;
      font-weight: 620;
      line-height: 1.2;
    }
    .data-posture__item strong {
      display: block;
      margin-top: 0.12rem;
      color: var(--text);
      font-size: 0.82rem;
      font-weight: 590;
      line-height: 1.25;
      overflow-wrap: anywhere;
    }
    .execution-provenance {
      display: none;
      border-bottom: 1px solid var(--border);
      padding: 0 0 0.9rem;
      margin: -0.2rem 0 1rem;
    }
    .execution-provenance.is-visible { display: grid; gap: 0.55rem; }
    .execution-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.75rem;
    }
    .execution-header h2 {
      margin: 0;
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .execution-header span {
      color: var(--muted);
      font-size: 0.74rem;
      font-weight: 620;
    }
    .execution-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
      gap: 0.5rem;
    }
    .execution-step {
      min-width: 0;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.68rem 0.75rem;
      background: var(--surface);
    }
    .execution-step__title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.5rem;
      color: var(--ink);
      font-size: 0.84rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .execution-badge {
      flex: 0 0 auto;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 0.1rem 0.42rem;
      color: var(--muted);
      font-size: 0.68rem;
      font-weight: 650;
    }
    .execution-badge.is-remote {
      border-color: rgba(176, 77, 67, 0.35);
      color: var(--danger);
      background: rgba(176, 77, 67, 0.08);
    }
    .execution-kv {
      display: grid;
      grid-template-columns: minmax(4.8rem, auto) minmax(0, 1fr);
      gap: 0.28rem 0.5rem;
      margin-top: 0.5rem;
      color: var(--text);
      font-size: 0.76rem;
      line-height: 1.3;
    }
    .execution-kv span:nth-child(odd) {
      color: var(--muted);
      font-weight: 620;
    }
    .execution-kv span:nth-child(even) {
      min-width: 0;
      overflow-wrap: anywhere;
    }
    .safeguards {
      display: none;
      border-bottom: 1px solid var(--border);
      padding: 0 0 0.9rem;
      margin: -0.2rem 0 1rem;
    }
    .safeguards.is-visible { display: grid; gap: 0.55rem; }
    .safeguards__header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.75rem;
    }
    .safeguards__header h2 {
      margin: 0;
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .safeguards__header span {
      color: var(--muted);
      font-size: 0.74rem;
      font-weight: 620;
    }
    .safeguards__grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
      gap: 0.45rem;
    }
    .safeguard {
      min-width: 0;
      border: 1px solid var(--border);
      border-left-width: 3px;
      border-radius: var(--radius);
      padding: 0.62rem 0.7rem;
      background: var(--surface);
    }
    .safeguard.is-ok { border-left-color: var(--ok); }
    .safeguard.is-check { border-left-color: var(--info); }
    .safeguard.is-warning { border-left-color: var(--warning); }
    .safeguard.is-danger { border-left-color: var(--danger); }
    .safeguard__top {
      display: flex;
      justify-content: space-between;
      gap: 0.5rem;
      align-items: start;
    }
    .safeguard__top strong {
      min-width: 0;
      color: var(--ink);
      font-size: 0.8rem;
      font-weight: 650;
      line-height: 1.25;
      overflow-wrap: anywhere;
    }
    .safeguard__badge {
      flex: 0 0 auto;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 0.1rem 0.38rem;
      color: var(--muted);
      font-size: 0.66rem;
      font-weight: 650;
      line-height: 1.15;
    }
    .safeguard.is-ok .safeguard__badge { color: var(--ok); }
    .safeguard.is-warning .safeguard__badge,
    .safeguard.is-danger .safeguard__badge { color: var(--danger); }
    .safeguard p {
      margin: 0.28rem 0 0;
      color: var(--muted);
      font-size: 0.76rem;
      line-height: 1.3;
      overflow-wrap: anywhere;
    }
    .progress-meter {
      display: grid;
      grid-template-columns: minmax(8rem, auto) minmax(7rem, 1fr) minmax(0, auto);
      gap: 0.45rem 0.7rem;
      align-items: center;
      min-width: 0;
    }
    .progress-rail {
      position: relative;
      width: 100%;
      min-width: 7rem;
      height: 0.28rem;
      border-radius: 999px;
      background: var(--border);
      overflow: hidden;
    }
    .progress-rail span {
      display: block;
      width: 0%;
      height: 100%;
      border-radius: inherit;
      background: var(--accent);
      transition: width 160ms ease;
    }
    .state-strip {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 0.8rem;
      align-items: center;
      border-bottom: 1px solid var(--border);
      padding: 0 0 0.9rem;
      margin-bottom: 0.85rem;
    }
    .state-filters {
      display: flex;
      flex-wrap: wrap;
      gap: 0.35rem;
      min-width: 0;
    }
    .state-chip {
      display: inline-grid;
      grid-template-columns: auto auto;
      gap: 0.38rem;
      align-items: center;
      min-height: 2rem;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.32rem 0.52rem;
      background: var(--surface);
      color: var(--text);
      cursor: pointer;
      font-size: 0.78rem;
      line-height: 1.2;
    }
    .state-chip:hover { background: var(--soft); }
    .state-chip[aria-pressed="true"] {
      border-color: var(--border-strong);
      background: var(--accent-soft);
      color: var(--accent-strong);
      font-weight: 620;
    }
    .state-chip strong {
      color: var(--ink);
      font-size: 0.82rem;
      font-variant-numeric: tabular-nums;
    }
    .state-final {
      display: grid;
      gap: 0.08rem;
      min-width: 8rem;
      border-left: 1px solid var(--border);
      padding-left: 0.78rem;
    }
    .state-final span {
      color: var(--muted);
      font-size: 0.7rem;
      font-weight: 620;
      line-height: 1.2;
    }
    .state-final strong {
      color: var(--ink);
      font-size: 0.86rem;
      font-weight: 650;
      line-height: 1.2;
    }
    .state-final.is-blocked strong, .state-final.is-partial_review_applied strong { color: var(--danger); }
    .state-final.is-final_ready strong { color: var(--ok); }
    .button, .tab, .decision-choice {
      max-width: 100%;
      min-width: 0;
      min-height: 2.15rem;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.42rem 0.64rem;
      background: var(--surface);
      color: var(--text);
      cursor: pointer;
      font-size: 0.86rem;
      line-height: 1.2;
      overflow-wrap: anywhere;
    }
    .button:hover, .tab:hover, .decision-choice:hover { background: var(--soft); }
    .button:disabled { cursor: not-allowed; opacity: 0.52; }
    .button.primary { border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 620; }
    .button.primary:hover { background: var(--accent-strong); }
    .status-message { min-width: 0; color: var(--muted); overflow-wrap: anywhere; }
    .status-message.is-error { color: var(--danger); }
    .status-message.is-ok { color: var(--ok); }
    .toolbar {
      display: grid;
      grid-template-columns: minmax(14rem, 1fr) auto;
      gap: 0.65rem;
      align-items: start;
      margin-bottom: 0.85rem;
    }
    .search {
      width: 100%;
      min-height: 2.45rem;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.54rem 0.7rem;
      background: var(--surface);
      color: var(--ink);
      outline: none;
    }
    .search::placeholder { color: var(--muted); }
    .tab[aria-pressed="true"], .decision-choice[aria-pressed="true"] {
      border-color: var(--border-strong);
      background: var(--accent-soft);
      color: var(--accent-strong);
      font-weight: 600;
    }
    .content {
      display: grid;
      grid-template-columns: minmax(20rem, 0.78fr) minmax(0, 1.22fr);
      gap: 0.85rem;
      align-items: start;
    }
    .panel {
      min-width: 0;
      overflow: hidden;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      background: var(--surface);
    }
    .panel-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 0.75rem;
      min-height: 2.8rem;
      border-bottom: 1px solid var(--border);
      padding: 0.68rem 0.85rem;
      background: var(--surface);
      color: var(--muted);
      font-size: 0.84rem;
    }
    .panel-header h2 {
      margin: 0;
      color: var(--ink);
      font-size: 0.9rem;
      font-weight: 650;
      line-height: 1.2;
    }
    .rows { max-height: min(720px, calc(100vh - 22rem)); overflow: auto; }
    .row {
      display: grid;
      grid-template-columns: minmax(6.75rem, 0.28fr) minmax(0, 1fr) minmax(7rem, 9rem);
      gap: 0.75rem;
      width: 100%;
      min-height: 4.15rem;
      border: 0;
      border-left: 2px solid transparent;
      border-bottom: 1px solid var(--border);
      padding: 0.7rem 0.82rem 0.7rem calc(0.82rem - 2px);
      background: var(--surface);
      color: var(--text);
      text-align: left;
      cursor: pointer;
    }
    .row:hover, .row.is-selected { background: var(--soft); }
    .row.is-selected { border-left-color: var(--accent); }
    .row > span {
      min-width: 0;
      max-width: 100%;
    }
    .row > span:last-child {
      display: flex;
      min-width: 0;
      max-width: 100%;
      flex-direction: column;
      align-items: flex-start;
    }
    .type { color: var(--muted); font-size: 0.78rem; line-height: 1.25; overflow-wrap: anywhere; }
    .title { color: var(--ink); font-weight: 650; line-height: 1.3; overflow-wrap: anywhere; word-break: break-word; }
    .row-support {
      display: block;
      margin-top: 0.22rem;
      color: var(--muted);
      font-size: 0.78rem;
      line-height: 1.35;
      overflow-wrap: anywhere;
      word-break: break-word;
    }
    .action {
      display: inline-flex;
      min-width: 0;
      max-width: 9rem;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 0.2rem 0.48rem;
      background: var(--surface);
      color: var(--warning);
      font-size: 0.72rem;
      font-weight: 600;
      line-height: 1.2;
      text-align: center;
      overflow-wrap: anywhere;
      white-space: normal;
    }
    .row-status {
      display: flex;
      flex-wrap: wrap;
      gap: 0.35rem;
      align-items: center;
      margin-top: 0.28rem;
      color: var(--muted);
      font-size: 0.76rem;
      line-height: 1.25;
    }
    .row-status::before {
      content: "";
      width: 0.42rem;
      height: 0.42rem;
      border-radius: 999px;
      background: var(--warning);
    }
    .row-status.is-ready::before, .row-status.is-accepted::before, .row-status.is-reviewed::before { background: var(--ok); }
    .row-status.is-needs_evidence::before, .row-status.is-rejected::before, .row-status.is-blocked::before { background: var(--danger); }
    .row-status.is-edited::before { background: var(--info); }
    .action--accept, .action--accepted { background: var(--surface); color: var(--ok); }
    .action--mark_unclear, .action--request_more_documents, .action--reject, .action--rejected, .action--needs_evidence {
      background: var(--surface);
      color: var(--danger);
    }
    .action--edit, .action--edited { background: var(--surface); color: var(--info); }
    .details { padding: 1rem; }
    .review-heading {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 0.8rem;
      align-items: start;
      padding-bottom: 0.85rem;
      border-bottom: 1px solid var(--border);
    }
    .review-heading > div { min-width: 0; }
    .review-heading h3 { margin: 0 0 0.25rem; color: var(--ink); font-size: 1.05rem; line-height: 1.25; overflow-wrap: anywhere; word-break: break-word; }
    .review-heading p { margin: 0; color: var(--muted); font-size: 0.86rem; line-height: 1.4; overflow-wrap: anywhere; word-break: break-word; }
    .details dl {
      display: grid;
      grid-template-columns: minmax(7.5rem, 0.32fr) minmax(0, 1fr);
      gap: 0.42rem 0.75rem;
      margin: 0.85rem 0;
    }
    .details dt { color: var(--muted); font-size: 0.8rem; line-height: 1.3; }
    .details dd { margin: 0; color: var(--text); overflow-wrap: anywhere; }
    .decision-box {
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.75rem;
      margin: 0.85rem 0;
      background: var(--surface);
    }
    .decision-grid { display: flex; flex-wrap: wrap; gap: 0.42rem; margin-bottom: 0.65rem; }
    .decision-impact {
      border: 1px solid var(--border);
      border-radius: var(--radius);
      margin-bottom: 0.72rem;
      background: var(--soft);
      overflow: hidden;
    }
    .decision-impact__title {
      padding: 0.56rem 0.68rem;
      border-bottom: 1px solid var(--border);
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .decision-impact__grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
      gap: 0;
    }
    .decision-impact__item {
      display: grid;
      gap: 0.16rem;
      min-width: 0;
      padding: 0.58rem 0.68rem;
      border-right: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
    }
    .decision-impact__item span {
      color: var(--muted);
      font-size: 0.72rem;
      font-weight: 620;
      line-height: 1.2;
    }
    .decision-impact__item strong {
      color: var(--text);
      font-size: 0.82rem;
      font-weight: 560;
      line-height: 1.3;
      overflow-wrap: anywhere;
    }
    .field { display: grid; gap: 0.25rem; margin-top: 0.55rem; }
    .field-label { color: var(--muted); font-size: 0.78rem; line-height: 1.25; }
    textarea {
      width: 100%;
      min-height: 5rem;
      resize: vertical;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.6rem 0.7rem;
      background: var(--surface);
      color: var(--ink);
      outline: none;
      overflow-wrap: anywhere;
    }
    .review-section { margin-top: 1rem; }
    .review-section h4 { margin: 0 0 0.48rem; color: var(--ink); font-size: 0.86rem; font-weight: 650; }
    .workflow-detail {
      min-width: 0;
      margin-top: 1rem;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      background: var(--surface);
      overflow: hidden;
    }
    .workflow-detail__header {
      display: grid;
      gap: 0.18rem;
      padding: 0.78rem 0.85rem;
      border-bottom: 1px solid var(--border);
      background: var(--surface);
    }
    .workflow-detail__header strong {
      color: var(--ink);
      font-size: 0.92rem;
      line-height: 1.25;
      overflow-wrap: anywhere;
      word-break: break-word;
    }
    .workflow-detail__header span {
      color: var(--muted);
      font-size: 0.8rem;
      line-height: 1.35;
      overflow-wrap: anywhere;
    }
    .workflow-detail__grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
      gap: 0;
    }
    .workflow-card {
      min-width: 0;
      padding: 0.86rem;
      border-right: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
      background: var(--surface);
    }
    .workflow-card h5 {
      margin: 0 0 0.55rem;
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 650;
      line-height: 1.25;
      overflow-wrap: anywhere;
      word-break: break-word;
    }
    .workflow-card--prose .kv div:nth-child(even),
    .workflow-card--draft .kv div:nth-child(even) {
      color: var(--ink);
      font-size: 0.98rem;
      line-height: 1.45;
    }
    .workflow-card--ledger .kv {
      grid-template-columns: minmax(5.5rem, 0.55fr) minmax(0, 1fr);
      gap: 0.32rem 0.65rem;
    }
    .workflow-card--finding {
      background: var(--surface);
    }
    .workflow-detail--claim-desk .workflow-card--prose,
    .workflow-detail--report-editor .workflow-card--draft,
    .workflow-detail--prompt-lab .workflow-card--draft {
      grid-column: span 2;
    }
    .workflow-detail--match-ledger .workflow-card--ledger,
    .workflow-detail--reconciliation-desk .workflow-card--ledger,
    .workflow-detail--sample-sheet .workflow-card--ledger {
      background: var(--surface);
    }
    .workflow-detail--intake-board .workflow-card--checklist,
    .workflow-detail--prompt-lab .workflow-card--checklist {
      background: var(--surface);
    }
    .evidence-columns {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
      gap: 0.65rem;
    }
    .evidence-pane, .evidence-card {
      min-width: 0;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 0.68rem;
      background: var(--surface);
    }
    .evidence-pane h5, .evidence-card strong {
      display: block;
      margin: 0 0 0.44rem;
      color: var(--ink);
      font-size: 0.8rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .kv {
      display: grid;
      grid-template-columns: 1fr;
      gap: 0.2rem;
    }
    .kv div:nth-child(odd) { color: var(--muted); font-size: 0.77rem; line-height: 1.25; }
    .kv div:nth-child(even) { min-width: 0; color: var(--text); overflow-wrap: anywhere; }
    .evidence-list { display: grid; gap: 0.5rem; }
    .artifact-strip {
      margin-top: 0.9rem;
      border: 1px solid var(--border);
      border-radius: var(--radius);
      background: var(--surface);
      overflow: hidden;
    }
    .artifact-header {
      display: flex;
      justify-content: space-between;
      gap: 0.75rem;
      align-items: center;
      min-height: 3rem;
      border-bottom: 1px solid var(--border);
      padding: 0.72rem 0.9rem;
      background: var(--surface);
    }
    .artifact-header h2 { margin: 0; color: var(--ink); font-size: 0.95rem; }
    .artifact-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
    .artifact-notes {
      display: grid;
      gap: 0.45rem;
      border-bottom: 1px solid var(--border);
      padding: 0.68rem 0.9rem;
      background: var(--soft);
    }
    .artifact-note {
      display: grid;
      grid-template-columns: minmax(5.8rem, 0.2fr) minmax(0, 1fr);
      gap: 0.55rem;
      align-items: start;
      color: var(--text);
      font-size: 0.8rem;
      line-height: 1.35;
    }
    .artifact-note strong {
      color: var(--ink);
      font-size: 0.78rem;
      font-weight: 650;
      line-height: 1.35;
    }
    .artifact-note span { min-width: 0; color: var(--muted); overflow-wrap: anywhere; }
    .artifact-item {
      min-width: 0;
      border-right: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
      padding: 0.78rem 0.9rem;
    }
    .artifact-item strong { display: block; color: var(--ink); font-size: 0.88rem; overflow-wrap: anywhere; }
    .artifact-item span { display: block; margin-top: 0.2rem; color: var(--muted); font-size: 0.78rem; overflow-wrap: anywhere; }
    .artifact-tags {
      display: flex;
      flex-wrap: wrap;
      gap: 0.28rem;
      margin-top: 0.55rem;
    }
    .artifact-tag {
      display: inline-flex;
      align-items: center;
      gap: 0.3rem;
      min-height: 1.45rem;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 0.16rem 0.45rem;
      background: var(--surface);
      color: var(--muted);
      font-size: 0.72rem;
      line-height: 1.2;
      overflow-wrap: anywhere;
    }
    .artifact-tag strong {
      display: inline;
      color: var(--ink);
      font-size: inherit;
      font-weight: 650;
    }
    .artifact-qa {
      margin-top: 0.62rem;
      border: 1px solid var(--border);
      border-radius: 0.42rem;
      background: var(--soft);
    }
    .artifact-qa summary {
      cursor: pointer;
      padding: 0.48rem 0.58rem;
      color: var(--ink);
      font-size: 0.76rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .artifact-qa-grid {
      display: grid;
      gap: 0.5rem;
      border-top: 1px solid var(--border);
      padding: 0.58rem;
    }
    .artifact-qa-section {
      display: grid;
      gap: 0.28rem;
      min-width: 0;
    }
    .artifact-qa-section strong {
      color: var(--ink);
      font-size: 0.74rem;
      font-weight: 650;
      line-height: 1.25;
    }
    .artifact-qa-section ul {
      display: grid;
      gap: 0.18rem;
      margin: 0;
      padding-left: 1rem;
      color: var(--muted);
      font-size: 0.74rem;
      line-height: 1.32;
      overflow-wrap: anywhere;
    }
    .empty, .empty-state { color: var(--muted); }
    .empty { padding: 1.25rem; }
    .empty-state { display: grid; gap: 0.85rem; padding: 1.25rem; min-height: 15rem; align-content: center; }
    .empty-state strong { color: var(--ink); font-size: 1rem; line-height: 1.25; }
    .empty-state p { max-width: 58ch; margin: 0; line-height: 1.45; }
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after { scroll-behavior: auto !important; transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
    }
    @media (max-width: 980px) {
      .content, .toolbar, .run-context, .data-posture, .execution-provenance, .safeguards, .review-actions, .state-strip { grid-template-columns: 1fr; }
      .top-actions, .context-list, .tabs, .action-buttons, .state-filters { justify-content: flex-start; }
      .state-final { border-left: 0; border-top: 1px solid var(--border); padding: 0.68rem 0 0; }
      .progress-meter { grid-template-columns: 1fr; }
    }
    @media (max-width: 760px) {
      .shell { display: flex; flex-direction: column; }
      .app { padding: 1rem; }
      .topbar { flex-direction: column; align-items: stretch; }
      .topbar { order: 1; }
      .summary { order: 2; }
      .run-context { order: 3; }
      .review-actions { order: 4; }
      .state-strip { order: 5; }
      .toolbar { order: 6; }
      .content { order: 7; }
      .artifact-strip { order: 8; }
      .data-posture { order: 9; }
      .execution-provenance { order: 10; }
      .safeguards { order: 11; }
      .summary, .data-posture__grid, .review-store, .artifact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .safeguards__grid { grid-template-columns: 1fr; }
      .metric { padding-right: 0.65rem; }
      .action-buttons > *, .tabs > *, .state-filters > * { flex: 1 1 100%; justify-content: center; }
      .row { grid-template-columns: 1fr; }
      .row .action { max-width: 100%; }
      .review-heading { grid-template-columns: 1fr; }
      .review-heading .status-token { justify-self: start; }
      .workflow-detail__grid { grid-template-columns: 1fr; }
      .workflow-detail--claim-desk .workflow-card--prose,
      .workflow-detail--report-editor .workflow-card--draft,
      .workflow-detail--prompt-lab .workflow-card--draft { grid-column: auto; }
      .decision-grid { display: grid; grid-template-columns: 1fr; }
      .decision-choice { width: 100%; }
      .decision-impact__grid { grid-template-columns: 1fr; }
      .details dl, .execution-kv, .recovery-panel__line, .workflow-card--ledger .kv, .kv { grid-template-columns: 1fr; }
    }
    @media (max-width: 430px) {
      .app { padding: 1rem 0.9rem; overflow-x: hidden; }
      .summary, .data-posture__grid, .safeguards__grid, .review-store, .artifact-grid { grid-template-columns: 1fr; }
      .metric { min-height: 3.2rem; border-right: 0; border-bottom: 1px solid var(--border); padding: 0.62rem 0; }
      .metric:last-child { border-bottom: 0; }
      .action-buttons > *, .tabs > *, .state-filters > * { flex-basis: 100%; justify-content: center; }
      .progress-rail { min-width: 0; }
      .execution-kv, .recovery-panel__line, .workflow-card--ledger .kv, .kv { grid-template-columns: 1fr; }
    }
    .shell > * { order: 0 !important; min-width: 0; }
    .technical-details { border-top: 1px solid var(--border); padding: 12px 0; }
    .technical-details > summary { cursor: pointer; padding: 8px; }
    @media (max-width: 600px) {
      .summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
      .summary .metric { padding: 10px; min-height: 0; }
      .tabs, .state-filters { flex-wrap: nowrap; overflow-x: auto; max-width: 100%; padding-bottom: 4px; }
      .tabs > *, .state-filters > * { flex: 0 0 auto; white-space: nowrap; }
    }
  </style>
</head>
<body>
  <main class="app">
    <div class="shell">
      <section class="topbar">
        <div>
          <h1 id="app-title">Journal Sampling Review</h1>
          <p class="subtitle" id="subtitle">Loading payload...</p>
        </div>
        <div class="top-actions">
          <span class="pill" id="status-pill">MCP widget</span>
          <span class="pill" id="decision-pill">0 reviewed</span>
        </div>
      </section>
      <section class="summary" id="summary"></section>
      <section class="state-strip" id="state-strip"></section>
      <section class="toolbar">
        <input id="search" class="search" type="search" placeholder="Search sample, journal row, mapping, extraction, artifact">
        <div class="tabs" id="tabs"></div>
      </section>
      <section class="content">
        <div class="panel">
          <div class="panel-header"><h2 id="queue-title">Review queue</h2><span id="count"></span></div>
          <div class="rows" id="rows"></div>
        </div>
        <div class="panel">
          <div class="panel-header"><h2 id="detail-title">Evidence and decision</h2></div>
          <div class="details" id="details"></div>
        </div>
      </section>
      <section class="artifact-strip" id="artifact-strip"></section>
      <section class="review-actions">
        <div class="progress-meter">
          <strong id="decision-progress">0 / 0 decided</strong>
          <div class="progress-rail" aria-hidden="true"><span id="decision-progress-fill"></span></div>
          <span class="status-message" id="save-status"></span>
        </div>
        <div class="action-buttons">
          <button class="button" id="use-recommended" type="button">Use recommended</button>
          <button class="button primary" id="save-decisions" type="button">Save decisions</button>
          <button class="button" id="apply-decisions" type="button">Apply decisions</button>
          <button class="button" id="copy-decisions" type="button">Copy JSON</button>
          <button class="button" id="download-decisions" type="button">Download JSON</button>
        </div>
        <div class="review-store" id="review-store"></div>
        <div class="recovery-panel" id="recovery-panel"></div>
      </section>
      <details class="technical-details"><summary id="technical-title">Technical details</summary>
      <section class="run-context" id="run-context"></section>
      <section class="data-posture" id="data-posture"></section>
      <section class="execution-provenance" id="execution-provenance"></section>
      <section class="safeguards" id="review-safeguards"></section>
      </details>

    </div>
  </main>
  <script>
    const CONFIG = {"schemaVersion":"1.0","plugin":"journal-sampling","title":"Journal Sampling Review","reviewTitle":"Journal Extraction And Sample Review","queueTitle":"Sample Rows","detailTitle":"Sample Rationale","detailMode":"sample-sheet","detailHelp":"Review extracted journal fields, sampling basis, and output trace.","detailGroups":[{"title":"Extracted Journal Row","variant":"ledger","fields":["movement_number","line_number","entry_date","account","line_desc","amount_signed","debit","credit","status"],"empty":"No journal row fields."},{"title":"Sampling Basis","variant":"checklist","fields":["method","reason","sample_size","population_size_after_filters","seed"],"empty":"See the sampling control for method and population."},{"title":"Output Trace","variant":"source","fields":["source_file","output_path","review_notes","status"],"empty":"No output trace."}],"panels":["Journal row","Sampling basis","Finding"],"localized":{"es":{"title":"Revisi\u00f3n de muestreo contable","reviewTitle":"Revisi\u00f3n de extracci\u00f3n y muestra","queueTitle":"L\u00edneas de la muestra","detailTitle":"Justificaci\u00f3n de la muestra","detailHelp":"Revise los campos extra\u00eddos, la base de muestreo y la trazabilidad de la salida.","search":"Buscar muestra, l\u00ednea contable, mapeo, extracci\u00f3n, salida"},"it":{"title":"Revisione campionamento contabile","reviewTitle":"Revisione estrazione e campione","queueTitle":"Righe campione","detailTitle":"Razionale campione","detailHelp":"Rivedi campi estratti, base di campionamento e tracciabilita output.","search":"Cerca campione, riga contabile, mapping, estrazione, output"},"fr":{"title":"Revue echantillonnage journal","reviewTitle":"Revue extraction et echantillon","queueTitle":"Lignes echantillon","detailTitle":"Rationale echantillon","detailHelp":"Revoyez les champs extraits, la base d'echantillonnage et la trace de sortie.","search":"Chercher echantillon, ligne, mapping, extraction, sortie"},"de":{"title":"Journal Sampling Review","reviewTitle":"Buchungsextraktion und Stichprobe pruefen","queueTitle":"Stichprobenzeilen","detailTitle":"Stichprobenbegruendung","detailHelp":"Extrahierte Buchungsfelder, Stichprobenbasis und Ausgabeprotokoll pruefen.","search":"Stichprobe, Buchungszeile, Mapping, Extraktion, Ausgabe suchen"}},"saveTool":"save_journal_sampling_decisions","applyTool":"apply_journal_sampling_decisions","widgetType":"journal_sampling_review","demo":{"review_type":"journal_sampling_review","items":[{"id":"sample-1","item_type":"sampled_entry","title":"Entry 812 - manual journal","source_path":"journal.xlsx","output_path":"audit_sample.csv","allowed_actions":["accept","edit","mark_unclear","skip"],"recommended_action":"accept","data":{"entry":"812","account":"Accruals","amount":"980.00","status":"selected","reason":"High-value manual journal.","target_artifact":"journal_sample.csv","target_id_field":"entry","target_record_id":"812","target_field":"review_notes","edit_hint":"Editing this sample updates review_notes in journal_sample.csv for entry 812."},"evidence":[{"kind":"sampling_basis","method":"risk-ranked sample"}]},{"id":"sample-2","item_type":"review_artifact","title":"Entry 944 - incomplete account mapping","source_path":"journal.xlsx","output_path":"journal_exceptions.csv","allowed_actions":["accept","edit","mark_unclear","request_more_documents","skip"],"recommended_action":"mark_unclear","data":{"entry":"944","account":"","amount":"410.00","status":"needs_evidence","method":"mapping exception review","reason":"The printed journal row has an amount but no readable account label.","requested_document":"Original journal export with account code for entry 944","target_artifact":"journal_exceptions.csv","target_id_field":"entry","target_record_id":"944","target_field":"review_notes","edit_hint":"Editing this exception updates review_notes in journal_exceptions.csv for entry 944."},"evidence":[{"kind":"extraction_exception","status":"needs_evidence","reason":"Account column was blank after deterministic extraction."}]}]},"injectLocalServer":false};
    const ACTION_LABELS = {
      accept: "Accept",
      reject: "Reject",
      edit: "Edit",
      mark_unclear: "Mark unclear",
      request_more_documents: "Request documents",
      skip: "Skip",
    };
    const ACTION_STATUSES = {
      accept: "accepted",
      reject: "rejected",
      edit: "edited",
      mark_unclear: "needs_evidence",
      request_more_documents: "needs_evidence",
      skip: "skipped",
    };
    const UI_TEXT = {"en":{"actions":{"accept":"Accept","reject":"Reject","edit":"Edit","mark_unclear":"Mark unclear","request_more_documents":"Request documents","skip":"Skip"},"statuses":{"accepted":"Accepted","rejected":"Rejected","edited":"Edited","needs_evidence":"Needs evidence","skipped":"Skipped","pending":"Pending","pending_review":"Pending review","partial_review":"Partial review","reviewed":"Reviewed","ready":"Ready","ready_for_review":"Ready for review","empty":"Empty","written":"Written","written_pending_review":"Written, pending review","final_ready":"Final ready","blocked":"Blocked","partial_review_applied":"Partially applied"},"metrics":{"items":"Items","issues":"Issues","evidence":"Evidence","artifacts":"Artifacts","reviewed":"Reviewed"},"buttons":{"useRecommended":"Use recommended","saveDecisions":"Save decisions","applyDecisions":"Apply decisions","copyJson":"Copy JSON","downloadJson":"Download JSON","previewSample":"Preview sample review","copyEmpty":"Copy empty decision JSON"},"fields":{"type":"Type","recommended":"Recommended","decision":"Decision","source":"Source","output":"Output","reviewerNote":"Reviewer note","editValue":"Edit value","requestedDocuments":"Requested documents"},"text":{"loadingPayload":"Loading payload...","mcpWidget":"MCP widget","reviewedSuffix":"decisions selected","decidedProgress":"{decided} / {total} decided","runLabel":"Run","noSourcePaths":"No source paths supplied","writesDecisions":"Writes ui_decisions.json","jsonFallback":"JSON fallback","decisionImpact":"Decision impact","currentAction":"Action","writeMode":"Write mode","writeTarget":"Write target","documentHint":"Document hint","reviewStore":"Review state","currentDecisions":"Current","savedDecisions":"Saved","appliedDecisions":"Applied","currentDecisionCount":"{count} current","savedDecisionCount":"{count} saved","appliedDecisionCount":"{count} applied","unsavedDecisionCount":"{count} unsaved","inSync":"In sync","recoveredDraftCount":"{count} recovered draft","fallbackActive":"JSON fallback active","fallbackBody":"Copy or download ui_decisions.json. Use the MCP or local-server review surface to persist and apply decisions.","applyRequiresMcp":"Apply requires the MCP or local-server review surface.","lastError":"Last error","recoveryAction":"Recovery","retryWithMcp":"Retry from the MCP or local-server review surface, or copy/download decision JSON for handoff.","toolLabel":"Tool","saveFailedTitle":"Save did not persist","applyFailedTitle":"Apply did not persist","mcpWriteMode":"MCP save/apply","copyOnlyMode":"Copy JSON only","noDecisionYet":"No decision selected","revisionOnly":"Revision file only until workflow apply updates a native artifact","notTargeted":"No direct artifact target","targetRecord":"record","targetField":"field","targetRecords":"records","all":"All","allStates":"All states","artifactState":"Artifact state","reviewQueue":"Review queue","evidenceDecision":"Evidence and decision","noPayloadTitle":"No review payload loaded","noPayloadBody":"This widget is waiting for an MCP render call with review_payload.json. Opening the HTML file directly does not include run data.","noFilterMatch":"No item matches the current filters.","noFields":"No fields.","detail":"Detail","reviewEvidence":"Review the evidence and capture the decision.","evidenceTrail":"Evidence trail","waitingTitle":"Waiting for review data","waitingBody":"Render this widget from the MCP tool to load review items, evidence, and outputs.","selectItem":"Select a review item.","readyDecision":"Ready for reviewer decision.","finalOutputs":"Final outputs","fileSingular":"file","filePlural":"files","output":"Output","outputsPending":"Outputs appear after the run writes final artifacts.","artifactRows":"Rows","artifactMinRows":"Min rows","artifactSheets":"Sheets","artifactHeaders":"Headers","artifactCells":"Cells","artifactText":"Text","artifactColumns":"Columns","artifactRecords":"Records","artifactQaDetails":"Verification details","artifactQaChecks":"QA checks","artifactRequiredText":"Required text","artifactRequiredColumns":"Required columns","artifactRequiredSheets":"Required sheets","artifactRequiredHeaders":"Required headers","artifactRequiredCells":"Required cells","artifactBytes":"bytes","artifactMore":"+{count} more","dataPosture":"Helper execution routes","dataPostureScope":"Optional routes used by helper execution. This does not describe or count the context sent by Codex to the model.","localFiles":"Files read by helpers","connectors":"Optional connectors","uploads":"Optional upload routes","remoteSql":"Helper remote SQL","hostedNotebook":"Helper hosted notebook","executionProvenance":"Execution provenance","executionPending":"Execution trace appears after run_intake.json records the local run.","traceStepSingular":"step","traceStepPlural":"steps","executionLocation":"Location","executionKind":"Kind","executionStatus":"Status","executionCommand":"Command","executionInputs":"Inputs","executionOutputs":"Outputs","localExecution":"Local","remoteExecution":"Remote","reviewSafeguards":"Review safeguards","safeguardsReady":"Ready","safeguardsCheck":"Check","safeguardsWarning":"Review","safeguardLocalExecution":"Helper-script execution","safeguardExternalRoute":"Optional routes beyond Codex","safeguardBoundedPayload":"Bounded payload","safeguardDecisionPersistence":"Decision persistence","safeguardFinalArtifacts":"Final artifacts","externalRouteUsed":"Route used and recorded","externalRouteNotUsed":"No optional route used","payloadItemsCount":"{count} items","finalArtifactsDeclared":"{count} outputs","finalArtifactsMissing":"No outputs declared","executionTraceMissing":"Trace missing","localExecutionDeclared":"Helper ran in local workspace","remoteExecutionDeclared":"Helper used an external path","persistenceAvailable":"Save/apply available","persistenceFallback":"Copy JSON only","notDeclared":"Not declared","noneValue":"None","blockers":"Blockers","caveats":"Caveats","nextActions":"Next actions","yes":"Yes","no":"No","editRequired":"Edit value required for {item}.","saving":"Saving...","savingApplying":"Saving and applying...","decisionsSaved":"Decisions saved.","decisionsApplied":"Decisions applied.","toolCopied":"Tool bridge unavailable. JSON copied.","toolCopiedApply":"Tool bridge unavailable. JSON copied; apply requires MCP.","jsonDownloaded":"JSON downloaded.","jsonCopied":"JSON copied.","emptyJsonCopied":"Empty decision JSON copied.","sampleLoaded":"Sample review loaded.","saveFailed":"Decision save failed.","applyFailed":"Decision apply failed."}},"es":{"actions":{"accept":"Aceptar","reject":"Rechazar","edit":"Editar","mark_unclear":"Marcar como incierto","request_more_documents":"Solicitar documentos","skip":"Omitir"},"statuses":{"accepted":"Aceptado","rejected":"Rechazado","edited":"Editado","needs_evidence":"Requiere evidencia","skipped":"Omitido","pending":"Pendiente","pending_review":"Pendiente de revisi\u00f3n","partial_review":"Revisi\u00f3n parcial","reviewed":"Revisado","ready":"Listo","ready_for_review":"Listo para revisi\u00f3n","empty":"Vac\u00edo","written":"Generado","written_pending_review":"Generado, pendiente de revisi\u00f3n","final_ready":"Versi\u00f3n final lista","blocked":"Bloqueado","partial_review_applied":"Aplicado parcialmente"},"metrics":{"items":"Elementos","issues":"Incidencias","evidence":"Evidencias","artifacts":"Artefactos","reviewed":"Revisados"},"buttons":{"useRecommended":"Usar recomendaciones","saveDecisions":"Guardar decisiones","applyDecisions":"Aplicar decisiones","copyJson":"Copiar JSON","downloadJson":"Descargar JSON","previewSample":"Ver revisi\u00f3n de ejemplo","copyEmpty":"Copiar JSON de decisiones vac\u00edo"},"fields":{"type":"Tipo","recommended":"Recomendado","decision":"Decisi\u00f3n","source":"Fuente","output":"Salida","reviewerNote":"Nota del revisor","editValue":"Valor editado","requestedDocuments":"Documentos solicitados"},"text":{"loadingPayload":"Cargando datos...","mcpWidget":"Widget MCP","reviewedSuffix":"decisiones seleccionadas","decidedProgress":"{decided} / {total} decididos","runLabel":"Ejecuci\u00f3n","noSourcePaths":"No se han indicado rutas de origen","writesDecisions":"Escribe ui_decisions.json","jsonFallback":"Modo alternativo JSON","decisionImpact":"Impacto de la decisi\u00f3n","currentAction":"Acci\u00f3n","writeMode":"Modo de escritura","writeTarget":"Destino de escritura","documentHint":"Documento sugerido","reviewStore":"Estado de la revisi\u00f3n","currentDecisions":"Actuales","savedDecisions":"Guardadas","appliedDecisions":"Aplicadas","currentDecisionCount":"{count} actuales","savedDecisionCount":"{count} guardadas","appliedDecisionCount":"{count} aplicadas","unsavedDecisionCount":"{count} sin guardar","inSync":"Sincronizado","recoveredDraftCount":"{count} borrador recuperado","fallbackActive":"Modo alternativo JSON activo","fallbackBody":"Copie o descargue ui_decisions.json. Use la superficie MCP o el servidor local para guardar y aplicar las decisiones.","applyRequiresMcp":"La aplicaci\u00f3n requiere la superficie MCP o el servidor local.","lastError":"\u00daltimo error","recoveryAction":"Recuperaci\u00f3n","retryWithMcp":"Vuelva a intentarlo desde la superficie MCP o el servidor local, o copie/descargue el JSON de decisiones para entregarlo.","toolLabel":"Herramienta","saveFailedTitle":"No se ha podido guardar","applyFailedTitle":"No se ha podido aplicar","mcpWriteMode":"Guardar/aplicar con MCP","copyOnlyMode":"Solo copiar JSON","noDecisionYet":"A\u00fan no se ha seleccionado ninguna decisi\u00f3n","revisionOnly":"Solo archivo de revisi\u00f3n hasta que el flujo de aplicaci\u00f3n actualice un artefacto nativo","notTargeted":"Sin destino de artefacto directo","targetRecord":"registro","targetField":"campo","targetRecords":"registros","all":"Todos","allStates":"Todos los estados","artifactState":"Estado del artefacto","reviewQueue":"Cola de revisi\u00f3n","evidenceDecision":"Evidencia y decisi\u00f3n","noPayloadTitle":"No hay datos de revisi\u00f3n cargados","noPayloadBody":"Este widget espera una llamada de renderizado MCP con review_payload.json. Abrir directamente el archivo HTML no incluye los datos de la ejecuci\u00f3n.","noFilterMatch":"Ning\u00fan elemento coincide con los filtros actuales.","noFields":"No hay campos.","detail":"Detalle","reviewEvidence":"Revise la evidencia y registre la decisi\u00f3n.","evidenceTrail":"Trazabilidad de la evidencia","waitingTitle":"Esperando datos de revisi\u00f3n","waitingBody":"Renderice este widget desde la herramienta MCP para cargar los elementos, las evidencias y las salidas.","selectItem":"Seleccione un elemento para revisar.","readyDecision":"Listo para la decisi\u00f3n del revisor.","finalOutputs":"Salidas finales","fileSingular":"archivo","filePlural":"archivos","output":"Salida","outputsPending":"Las salidas aparecer\u00e1n cuando la ejecuci\u00f3n genere los artefactos finales.","artifactRows":"Filas","artifactMinRows":"Filas m\u00ednimas","artifactSheets":"Hojas","artifactHeaders":"Encabezados","artifactCells":"Celdas","artifactText":"Texto","artifactColumns":"Columnas","artifactRecords":"Registros","artifactQaDetails":"Detalles de verificaci\u00f3n","artifactQaChecks":"Comprobaciones de calidad","artifactRequiredText":"Texto obligatorio","artifactRequiredColumns":"Columnas obligatorias","artifactRequiredSheets":"Hojas obligatorias","artifactRequiredHeaders":"Encabezados obligatorios","artifactRequiredCells":"Celdas obligatorias","artifactBytes":"bytes","artifactMore":"+{count} m\u00e1s","dataPosture":"Rutas de ejecuci\u00f3n auxiliares","dataPostureScope":"Rutas opcionales usadas por la ejecuci\u00f3n auxiliar. Esto no describe ni contabiliza el contexto que Codex env\u00eda al modelo.","localFiles":"Archivos le\u00eddos por los procesos auxiliares","connectors":"Conectores opcionales","uploads":"Rutas de carga opcionales","remoteSql":"SQL remoto auxiliar","hostedNotebook":"Cuaderno alojado auxiliar","executionProvenance":"Procedencia de la ejecuci\u00f3n","executionPending":"La traza de ejecuci\u00f3n aparecer\u00e1 cuando run_intake.json registre la ejecuci\u00f3n local.","traceStepSingular":"paso","traceStepPlural":"pasos","executionLocation":"Ubicaci\u00f3n","executionKind":"Tipo","executionStatus":"Estado","executionCommand":"Comando","executionInputs":"Entradas","executionOutputs":"Salidas","localExecution":"Local","remoteExecution":"Remota","reviewSafeguards":"Salvaguardas de revisi\u00f3n","safeguardsReady":"Listo","safeguardsCheck":"Comprobar","safeguardsWarning":"Revisar","safeguardLocalExecution":"Ejecuci\u00f3n de scripts auxiliares","safeguardExternalRoute":"Rutas opcionales fuera de Codex","safeguardBoundedPayload":"Datos acotados","safeguardDecisionPersistence":"Persistencia de decisiones","safeguardFinalArtifacts":"Artefactos finales","externalRouteUsed":"Ruta utilizada y registrada","externalRouteNotUsed":"No se ha usado ninguna ruta opcional","payloadItemsCount":"{count} elementos","finalArtifactsDeclared":"{count} salidas","finalArtifactsMissing":"No se han declarado salidas","executionTraceMissing":"Falta la traza","localExecutionDeclared":"El proceso auxiliar se ejecut\u00f3 en el espacio de trabajo local","remoteExecutionDeclared":"El proceso auxiliar utiliz\u00f3 una ruta externa","persistenceAvailable":"Guardado/aplicaci\u00f3n disponibles","persistenceFallback":"Solo copiar JSON","notDeclared":"No declarado","noneValue":"Ninguno","blockers":"Bloqueos","caveats":"Advertencias","nextActions":"Pr\u00f3ximas acciones","yes":"S\u00ed","no":"No","editRequired":"Se requiere un valor editado para {item}.","saving":"Guardando...","savingApplying":"Guardando y aplicando...","decisionsSaved":"Decisiones guardadas.","decisionsApplied":"Decisiones aplicadas.","toolCopied":"El puente de herramientas no est\u00e1 disponible. JSON copiado.","toolCopiedApply":"El puente de herramientas no est\u00e1 disponible. JSON copiado; la aplicaci\u00f3n requiere MCP.","jsonDownloaded":"JSON descargado.","jsonCopied":"JSON copiado.","emptyJsonCopied":"JSON de decisiones vac\u00edo copiado.","sampleLoaded":"Revisi\u00f3n de ejemplo cargada.","saveFailed":"No se han podido guardar las decisiones.","applyFailed":"No se han podido aplicar las decisiones."}},"it":{"actions":{"accept":"Accetta","reject":"Rifiuta","edit":"Modifica","mark_unclear":"Segna non chiaro","request_more_documents":"Richiedi documenti","skip":"Salta"},"statuses":{"accepted":"Accettato","rejected":"Rifiutato","edited":"Modificato","needs_evidence":"Serve evidenza","skipped":"Saltato","pending":"In attesa","pending_review":"Revisione in attesa","partial_review":"Revisione parziale","reviewed":"Rivisto","ready":"Pronto","ready_for_review":"Pronto per revisione","empty":"Vuoto","written":"Scritto","written_pending_review":"Scritto, revisione in attesa","final_ready":"Finale pronto","blocked":"Bloccato","partial_review_applied":"Applicato parzialmente"},"metrics":{"items":"Elementi","issues":"Rilievi","evidence":"Evidenze","artifacts":"Output","reviewed":"Rivisti"},"buttons":{"useRecommended":"Usa raccomandate","saveDecisions":"Salva decisioni","applyDecisions":"Applica decisioni","copyJson":"Copia JSON","downloadJson":"Scarica JSON","previewSample":"Apri esempio","copyEmpty":"Copia JSON vuoto"},"fields":{"type":"Tipo","recommended":"Raccomandato","decision":"Decisione","source":"Fonte","output":"Output","reviewerNote":"Nota revisore","editValue":"Valore modificato","requestedDocuments":"Documenti richiesti"},"text":{"loadingPayload":"Caricamento payload...","mcpWidget":"Widget MCP","reviewedSuffix":"decisioni selezionate","decidedProgress":"{decided} / {total} decisi","runLabel":"Run","noSourcePaths":"Nessun percorso sorgente fornito","writesDecisions":"Scrive ui_decisions.json","jsonFallback":"Fallback JSON","decisionImpact":"Impatto decisione","currentAction":"Azione","writeMode":"Scrittura","writeTarget":"Target scrittura","documentHint":"Documento suggerito","reviewStore":"Stato revisione","currentDecisions":"Correnti","savedDecisions":"Salvate","appliedDecisions":"Applicate","currentDecisionCount":"{count} correnti","savedDecisionCount":"{count} salvate","appliedDecisionCount":"{count} applicate","unsavedDecisionCount":"{count} non salvate","inSync":"Allineato","recoveredDraftCount":"{count} bozza recuperata","fallbackActive":"Fallback JSON attivo","fallbackBody":"Copia o scarica ui_decisions.json. Usa la superficie MCP o server locale per salvare e applicare decisioni.","applyRequiresMcp":"Applicare richiede la superficie MCP o server locale.","lastError":"Ultimo errore","recoveryAction":"Recupero","retryWithMcp":"Riprova dalla superficie MCP o server locale, oppure copia/scarica il JSON decisioni per handoff.","toolLabel":"Strumento","saveFailedTitle":"Salvataggio non persistito","applyFailedTitle":"Applicazione non persistita","mcpWriteMode":"Salva/applica MCP","copyOnlyMode":"Solo copia JSON","noDecisionYet":"Nessuna decisione","revisionOnly":"Solo file revisione finche il workflow aggiorna l'artefatto nativo","notTargeted":"Nessun target diretto","targetRecord":"record","targetField":"campo","targetRecords":"record","all":"Tutti","allStates":"Tutti gli stati","artifactState":"Stato output","reviewQueue":"Coda revisione","evidenceDecision":"Evidenza e decisione","noPayloadTitle":"Nessun payload di revisione caricato","noPayloadBody":"Il widget attende una chiamata MCP con review_payload.json. Aprire il file HTML direttamente non include i dati del run.","noFilterMatch":"Nessun elemento corrisponde ai filtri correnti.","noFields":"Nessun campo.","detail":"Dettaglio","reviewEvidence":"Rivedi l'evidenza e registra la decisione.","evidenceTrail":"Traccia evidenze","waitingTitle":"In attesa dei dati di revisione","waitingBody":"Apri il widget dallo strumento MCP per caricare elementi, evidenze e output.","selectItem":"Seleziona un elemento.","readyDecision":"Pronto per la decisione del revisore.","finalOutputs":"Output finali","fileSingular":"file","filePlural":"file","output":"Output","outputsPending":"Gli output appaiono dopo la scrittura degli artefatti finali.","artifactRows":"Righe","artifactMinRows":"Min righe","artifactSheets":"Fogli","artifactHeaders":"Intestazioni","artifactCells":"Celle","artifactText":"Testo","artifactColumns":"Colonne","artifactRecords":"Record","artifactQaDetails":"Dettagli verifica","artifactQaChecks":"Controlli QA","artifactRequiredText":"Testo richiesto","artifactRequiredColumns":"Colonne richieste","artifactRequiredSheets":"Fogli richiesti","artifactRequiredHeaders":"Intestazioni richieste","artifactRequiredCells":"Celle richieste","artifactBytes":"byte","artifactMore":"+{count} altri","dataPosture":"Percorsi dati dei processi di supporto","dataPostureScope":"Percorsi opzionali usati dai processi di supporto. Non descrive n\u00e9 conta il contesto inviato da Codex al modello.","localFiles":"File letti dai processi di supporto","connectors":"Connettori opzionali","uploads":"Percorsi di upload opzionali","remoteSql":"SQL remoto dei processi di supporto","hostedNotebook":"Notebook hosted dei processi di supporto","executionProvenance":"Provenienza esecuzione","executionPending":"La traccia di esecuzione appare dopo che run_intake.json registra il run locale.","traceStepSingular":"passo","traceStepPlural":"passi","executionLocation":"Luogo","executionKind":"Tipo","executionStatus":"Stato","executionCommand":"Comando","executionInputs":"Input","executionOutputs":"Output","localExecution":"Locale","remoteExecution":"Remoto","reviewSafeguards":"Garanzie revisione","safeguardsReady":"Pronto","safeguardsCheck":"Da verificare","safeguardsWarning":"Attenzione","safeguardLocalExecution":"Esecuzione degli script helper","safeguardExternalRoute":"Percorsi opzionali oltre Codex","safeguardBoundedPayload":"Payload limitato","safeguardDecisionPersistence":"Persistenza decisioni","safeguardFinalArtifacts":"Artefatti finali","externalRouteUsed":"Percorso usato e registrato","externalRouteNotUsed":"Nessun percorso opzionale usato","payloadItemsCount":"{count} elementi","finalArtifactsDeclared":"{count} output","finalArtifactsMissing":"Nessun output dichiarato","executionTraceMissing":"Traccia mancante","localExecutionDeclared":"Script eseguito nel workspace locale","remoteExecutionDeclared":"Script eseguito su un percorso esterno","persistenceAvailable":"Salva/applica disponibile","persistenceFallback":"Solo copia JSON","notDeclared":"Non dichiarato","noneValue":"Nessuno","blockers":"Blocchi","caveats":"Caveat","nextActions":"Azioni successive","yes":"S\u00ec","no":"No","editRequired":"Valore modificato richiesto per {item}.","saving":"Salvataggio...","savingApplying":"Salvataggio e applicazione...","decisionsSaved":"Decisioni salvate.","decisionsApplied":"Decisioni applicate.","toolCopied":"Bridge strumenti non disponibile. JSON copiato.","toolCopiedApply":"Bridge strumenti non disponibile. JSON copiato; applicare richiede MCP.","jsonDownloaded":"JSON scaricato.","jsonCopied":"JSON copiato.","emptyJsonCopied":"JSON vuoto copiato.","sampleLoaded":"Esempio caricato.","saveFailed":"Salvataggio decisioni non riuscito.","applyFailed":"Applicazione decisioni non riuscita."}},"fr":{"actions":{"accept":"Accepter","reject":"Rejeter","edit":"Modifier","mark_unclear":"Marquer incertain","request_more_documents":"Demander documents","skip":"Ignorer"},"statuses":{"accepted":"Accepte","rejected":"Rejete","edited":"Modifie","needs_evidence":"Justificatif requis","skipped":"Ignore","pending":"En attente","pending_review":"Revue en attente","partial_review":"Revue partielle","reviewed":"Revu","ready":"Pret","ready_for_review":"Pret pour revue","empty":"Vide","written":"Ecrit","written_pending_review":"Ecrit, revue en attente","final_ready":"Final pret","blocked":"Bloque","partial_review_applied":"Applique partiellement"},"metrics":{"items":"Elements","issues":"Points","evidence":"Justificatifs","artifacts":"Sorties","reviewed":"Revus"},"buttons":{"useRecommended":"Utiliser recommande","saveDecisions":"Enregistrer decisions","applyDecisions":"Appliquer decisions","copyJson":"Copier JSON","downloadJson":"Telecharger JSON","previewSample":"Voir exemple","copyEmpty":"Copier JSON vide"},"fields":{"type":"Type","recommended":"Recommande","decision":"Decision","source":"Source","output":"Sortie","reviewerNote":"Note du reviseur","editValue":"Valeur modifiee","requestedDocuments":"Documents demandes"},"text":{"loadingPayload":"Chargement du payload...","mcpWidget":"Widget MCP","reviewedSuffix":"d\u00e9cisions s\u00e9lectionn\u00e9es","decidedProgress":"{decided} / {total} decides","runLabel":"Run","noSourcePaths":"Aucun chemin source fourni","writesDecisions":"Ecrit ui_decisions.json","jsonFallback":"Fallback JSON","decisionImpact":"Impact decision","currentAction":"Action","writeMode":"Mode ecriture","writeTarget":"Cible ecriture","documentHint":"Document suggere","reviewStore":"Etat revue","currentDecisions":"Courantes","savedDecisions":"Enregistrees","appliedDecisions":"Appliquees","currentDecisionCount":"{count} courantes","savedDecisionCount":"{count} enregistrees","appliedDecisionCount":"{count} appliquees","unsavedDecisionCount":"{count} non enregistrees","inSync":"Synchronise","recoveredDraftCount":"{count} brouillon recupere","fallbackActive":"Fallback JSON actif","fallbackBody":"Copiez ou telechargez ui_decisions.json. Utilisez la surface MCP ou serveur local pour enregistrer et appliquer les decisions.","applyRequiresMcp":"L'application requiert la surface MCP ou serveur local.","lastError":"Derniere erreur","recoveryAction":"Recuperation","retryWithMcp":"Reessayez depuis la surface MCP ou serveur local, ou copiez/telechargez le JSON decisions pour handoff.","toolLabel":"Outil","saveFailedTitle":"Enregistrement non persiste","applyFailedTitle":"Application non persistee","mcpWriteMode":"Enregistrer/appliquer MCP","copyOnlyMode":"Copie JSON seule","noDecisionYet":"Aucune decision","revisionOnly":"Fichier de revision seul jusqu'a mise a jour native par le workflow","notTargeted":"Aucune cible directe","targetRecord":"enregistrement","targetField":"champ","targetRecords":"enregistrements","all":"Tous","allStates":"Tous statuts","artifactState":"Etat sortie","reviewQueue":"File de revue","evidenceDecision":"Justificatif et decision","noPayloadTitle":"Aucun payload de revue charge","noPayloadBody":"Ce widget attend un appel MCP avec review_payload.json. Ouvrir le HTML directement n'inclut pas les donnees du run.","noFilterMatch":"Aucun element ne correspond aux filtres.","noFields":"Aucun champ.","detail":"Detail","reviewEvidence":"Revoyez le justificatif et saisissez la decision.","evidenceTrail":"Trace justificative","waitingTitle":"En attente des donnees de revue","waitingBody":"Rendez ce widget depuis l'outil MCP pour charger les elements, justificatifs et sorties.","selectItem":"Selectionnez un element.","readyDecision":"Pret pour la decision du reviseur.","finalOutputs":"Sorties finales","fileSingular":"fichier","filePlural":"fichiers","output":"Sortie","outputsPending":"Les sorties apparaissent apres l'ecriture des artefacts finaux.","artifactRows":"Lignes","artifactMinRows":"Min lignes","artifactSheets":"Feuilles","artifactHeaders":"En-tetes","artifactCells":"Cellules","artifactText":"Texte","artifactColumns":"Colonnes","artifactRecords":"Enregistrements","artifactQaDetails":"Details verification","artifactQaChecks":"Controles QA","artifactRequiredText":"Texte requis","artifactRequiredColumns":"Colonnes requises","artifactRequiredSheets":"Feuilles requises","artifactRequiredHeaders":"En-tetes requis","artifactRequiredCells":"Cellules requises","artifactBytes":"octets","artifactMore":"+{count} autres","dataPosture":"Flux de donn\u00e9es des processus auxiliaires","dataPostureScope":"Flux optionnels utilis\u00e9s par les processus auxiliaires. Ceci ne d\u00e9crit ni ne compte le contexte envoy\u00e9 par Codex au mod\u00e8le.","localFiles":"Fichiers lus par les processus auxiliaires","connectors":"Connecteurs optionnels","uploads":"Flux de t\u00e9l\u00e9versement optionnels","remoteSql":"SQL distant des processus auxiliaires","hostedNotebook":"Notebook h\u00e9berg\u00e9 des processus auxiliaires","executionProvenance":"Provenance execution","executionPending":"La trace d'execution apparait apres l'enregistrement du run local dans run_intake.json.","traceStepSingular":"etape","traceStepPlural":"etapes","executionLocation":"Lieu","executionKind":"Type","executionStatus":"Statut","executionCommand":"Commande","executionInputs":"Entrees","executionOutputs":"Sorties","localExecution":"Locale","remoteExecution":"Distante","reviewSafeguards":"Garde-fous revue","safeguardsReady":"Pret","safeguardsCheck":"A verifier","safeguardsWarning":"Attention","safeguardLocalExecution":"Execution des scripts auxiliaires","safeguardExternalRoute":"Parcours optionnels hors de Codex","safeguardBoundedPayload":"Payload borne","safeguardDecisionPersistence":"Persistance decisions","safeguardFinalArtifacts":"Artefacts finaux","externalRouteUsed":"Parcours utilise et enregistre","externalRouteNotUsed":"Aucun parcours optionnel utilise","payloadItemsCount":"{count} elements","finalArtifactsDeclared":"{count} sorties","finalArtifactsMissing":"Aucune sortie declaree","executionTraceMissing":"Trace manquante","localExecutionDeclared":"Script execute dans le workspace local","remoteExecutionDeclared":"Script execute via un parcours externe","persistenceAvailable":"Enregistrement/application disponible","persistenceFallback":"Copie JSON seule","notDeclared":"Non declare","noneValue":"Aucun","blockers":"Blocages","caveats":"Caveats","nextActions":"Actions suivantes","yes":"Oui","no":"Non","editRequired":"Valeur modifiee requise pour {item}.","saving":"Enregistrement...","savingApplying":"Enregistrement et application...","decisionsSaved":"Decisions enregistrees.","decisionsApplied":"Decisions appliquees.","toolCopied":"Bridge outil indisponible. JSON copie.","toolCopiedApply":"Bridge outil indisponible. JSON copie; appliquer requiert MCP.","jsonDownloaded":"JSON telecharge.","jsonCopied":"JSON copie.","emptyJsonCopied":"JSON vide copie.","sampleLoaded":"Exemple charge.","saveFailed":"Echec d'enregistrement des decisions.","applyFailed":"Echec d'application des decisions."}},"de":{"actions":{"accept":"Akzeptieren","reject":"Ablehnen","edit":"Bearbeiten","mark_unclear":"Unklar markieren","request_more_documents":"Dokumente anfordern","skip":"Ueberspringen"},"statuses":{"accepted":"Akzeptiert","rejected":"Abgelehnt","edited":"Bearbeitet","needs_evidence":"Nachweis erforderlich","skipped":"Uebersprungen","pending":"Ausstehend","pending_review":"Review ausstehend","partial_review":"Teilreview","reviewed":"Geprueft","ready":"Bereit","ready_for_review":"Bereit fuer Review","empty":"Leer","written":"Geschrieben","written_pending_review":"Geschrieben, Review ausstehend","final_ready":"Final bereit","blocked":"Blockiert","partial_review_applied":"Teilweise angewendet"},"metrics":{"items":"Elemente","issues":"Punkte","evidence":"Nachweise","artifacts":"Ausgaben","reviewed":"Geprueft"},"buttons":{"useRecommended":"Empfehlungen nutzen","saveDecisions":"Entscheidungen speichern","applyDecisions":"Entscheidungen anwenden","copyJson":"JSON kopieren","downloadJson":"JSON herunterladen","previewSample":"Beispiel anzeigen","copyEmpty":"Leeres JSON kopieren"},"fields":{"type":"Typ","recommended":"Empfohlen","decision":"Entscheidung","source":"Quelle","output":"Ausgabe","reviewerNote":"Pruefernotiz","editValue":"Bearbeiteter Wert","requestedDocuments":"Angeforderte Dokumente"},"text":{"loadingPayload":"Payload wird geladen...","mcpWidget":"MCP-Widget","reviewedSuffix":"Entscheidungen ausgew\u00e4hlt","decidedProgress":"{decided} / {total} entschieden","runLabel":"Run","noSourcePaths":"Keine Quellpfade angegeben","writesDecisions":"Schreibt ui_decisions.json","jsonFallback":"JSON-Fallback","decisionImpact":"Entscheidungswirkung","currentAction":"Aktion","writeMode":"Schreibmodus","writeTarget":"Schreibziel","documentHint":"Dokumenthinweis","reviewStore":"Review-Stand","currentDecisions":"Aktuell","savedDecisions":"Gespeichert","appliedDecisions":"Angewendet","currentDecisionCount":"{count} aktuell","savedDecisionCount":"{count} gespeichert","appliedDecisionCount":"{count} angewendet","unsavedDecisionCount":"{count} ungespeichert","inSync":"Synchron","recoveredDraftCount":"{count} Entwurf wiederhergestellt","fallbackActive":"JSON-Fallback aktiv","fallbackBody":"Kopieren oder laden Sie ui_decisions.json herunter. Nutzen Sie die MCP- oder lokale Server-Reviewflaeche zum Speichern und Anwenden.","applyRequiresMcp":"Anwenden erfordert die MCP- oder lokale Server-Reviewflaeche.","lastError":"Letzter Fehler","recoveryAction":"Wiederherstellung","retryWithMcp":"Erneut ueber die MCP- oder lokale Server-Reviewflaeche versuchen, oder Entscheidungs-JSON fuer Handoff kopieren/herunterladen.","toolLabel":"Tool","saveFailedTitle":"Speichern nicht persistiert","applyFailedTitle":"Anwenden nicht persistiert","mcpWriteMode":"MCP speichern/anwenden","copyOnlyMode":"Nur JSON kopieren","noDecisionYet":"Keine Entscheidung","revisionOnly":"Nur Revisionsdatei, bis der Workflow ein natives Artefakt aktualisiert","notTargeted":"Kein direktes Artefaktziel","targetRecord":"Record","targetField":"Feld","targetRecords":"Records","all":"Alle","allStates":"Alle Status","artifactState":"Ausgabestatus","reviewQueue":"Review-Warteschlange","evidenceDecision":"Nachweis und Entscheidung","noPayloadTitle":"Kein Review-Payload geladen","noPayloadBody":"Dieses Widget wartet auf einen MCP-Renderaufruf mit review_payload.json. Direktes Oeffnen der HTML-Datei enthaelt keine Run-Daten.","noFilterMatch":"Kein Element entspricht den aktuellen Filtern.","noFields":"Keine Felder.","detail":"Detail","reviewEvidence":"Nachweis pruefen und Entscheidung erfassen.","evidenceTrail":"Nachweisverlauf","waitingTitle":"Warten auf Review-Daten","waitingBody":"Rendern Sie dieses Widget ueber das MCP-Tool, um Review-Elemente, Nachweise und Ausgaben zu laden.","selectItem":"Review-Element auswaehlen.","readyDecision":"Bereit fuer Prueferentscheidung.","finalOutputs":"Finale Ausgaben","fileSingular":"Datei","filePlural":"Dateien","output":"Ausgabe","outputsPending":"Ausgaben erscheinen, nachdem die finalen Artefakte geschrieben wurden.","artifactRows":"Zeilen","artifactMinRows":"Mindestzeilen","artifactSheets":"Blaetter","artifactHeaders":"Kopfzeilen","artifactCells":"Zellen","artifactText":"Text","artifactColumns":"Spalten","artifactRecords":"Records","artifactQaDetails":"Pruefdetails","artifactQaChecks":"QA-Pruefungen","artifactRequiredText":"Erforderlicher Text","artifactRequiredColumns":"Erforderliche Spalten","artifactRequiredSheets":"Erforderliche Blaetter","artifactRequiredHeaders":"Erforderliche Kopfzeilen","artifactRequiredCells":"Erforderliche Zellen","artifactBytes":"Bytes","artifactMore":"+{count} weitere","dataPosture":"Datenwege der Hilfsprozesse","dataPostureScope":"Optionale Wege der Hilfsprozesse. Dies beschreibt oder z\u00e4hlt nicht den von Codex an das Modell gesendeten Kontext.","localFiles":"Von Hilfsprozessen gelesene Dateien","connectors":"Optionale Konnektoren","uploads":"Optionale Upload-Wege","remoteSql":"Remote-SQL der Hilfsprozesse","hostedNotebook":"Gehostetes Notebook der Hilfsprozesse","executionProvenance":"Ausfuehrungsnachweis","executionPending":"Die Ausfuehrungsspur erscheint, nachdem run_intake.json den lokalen Run erfasst.","traceStepSingular":"Schritt","traceStepPlural":"Schritte","executionLocation":"Ort","executionKind":"Typ","executionStatus":"Status","executionCommand":"Befehl","executionInputs":"Eingaben","executionOutputs":"Ausgaben","localExecution":"Lokal","remoteExecution":"Remote","reviewSafeguards":"Review-Schutzmassnahmen","safeguardsReady":"Bereit","safeguardsCheck":"Pruefen","safeguardsWarning":"Achtung","safeguardLocalExecution":"Ausfuehrung der Hilfsskripte","safeguardExternalRoute":"Optionale Wege ausserhalb von Codex","safeguardBoundedPayload":"Begrenzter Payload","safeguardDecisionPersistence":"Entscheidungspersistenz","safeguardFinalArtifacts":"Finale Artefakte","externalRouteUsed":"Weg verwendet und erfasst","externalRouteNotUsed":"Kein optionaler Weg verwendet","payloadItemsCount":"{count} Elemente","finalArtifactsDeclared":"{count} Ausgaben","finalArtifactsMissing":"Keine Ausgaben deklariert","executionTraceMissing":"Spur fehlt","localExecutionDeclared":"Hilfsskript im lokalen Workspace","remoteExecutionDeclared":"Hilfsskript ueber externen Pfad","persistenceAvailable":"Speichern/Anwenden verfuegbar","persistenceFallback":"Nur JSON kopieren","notDeclared":"Nicht deklariert","noneValue":"Keine","blockers":"Blocker","caveats":"Hinweise","nextActions":"Naechste Schritte","yes":"Ja","no":"Nein","editRequired":"Bearbeiteter Wert fuer {item} erforderlich.","saving":"Speichern...","savingApplying":"Speichern und anwenden...","decisionsSaved":"Entscheidungen gespeichert.","decisionsApplied":"Entscheidungen angewendet.","toolCopied":"Tool-Bridge nicht verfuegbar. JSON kopiert.","toolCopiedApply":"Tool-Bridge nicht verfuegbar. JSON kopiert; Anwenden erfordert MCP.","jsonDownloaded":"JSON heruntergeladen.","jsonCopied":"JSON kopiert.","emptyJsonCopied":"Leeres JSON kopiert.","sampleLoaded":"Beispiel geladen.","saveFailed":"Speichern der Entscheidungen fehlgeschlagen.","applyFailed":"Anwenden der Entscheidungen fehlgeschlagen."}}};
    const GROUP_TEXT = {"es":{"Journal Entry":"Asiento contable","Support Document":"Documento justificativo","Finding":"Hallazgo","Claim":"Afirmaci\u00f3n","Citation / Source":"Cita / fuente","Source Support":"Respaldo de la fuente","Validation Finding":"Hallazgo de validaci\u00f3n","Client Document":"Documento del cliente","Required Evidence":"Evidencia requerida","Memo / Email Impact":"Impacto en informe / correo","Reconciliation Row":"L\u00ednea de conciliaci\u00f3n","Evidence":"Evidencia","Exception":"Excepci\u00f3n","Extracted Journal Row":"L\u00ednea contable extra\u00edda","Sampling Basis":"Base de muestreo","Output Trace":"Trazabilidad de salida","Bank Statement":"Extracto bancario","Match Result":"Resultado de conciliaci\u00f3n","Draft Section":"Secci\u00f3n del borrador","Source Table":"Tabla fuente","Revision Note":"Nota de revisi\u00f3n","Prompt Section":"Secci\u00f3n del prompt","Research Scope":"Alcance de la investigaci\u00f3n","Required Revision":"Revisi\u00f3n requerida","Plan Section":"Secci\u00f3n del plan","Accounting Support":"Respaldo contable","Tie-Out Finding":"Hallazgo de cuadre"},"it":{"Journal Entry":"Scrittura contabile","Support Document":"Documento di supporto","Finding":"Rilievo","Claim":"Claim","Citation / Source":"Citazione / fonte","Source Support":"Supporto fonte","Validation Finding":"Rilievo validazione","Client Document":"Documento cliente","Required Evidence":"Evidenza richiesta","Memo / Email Impact":"Impatto memo / email","Reconciliation Row":"Riga riconciliazione","Evidence":"Evidenza","Exception":"Eccezione","Extracted Journal Row":"Riga contabile estratta","Sampling Basis":"Base campionamento","See the sampling control for method and population.":"Metodo e popolazione sono nella voce Parametri campione.","Output Trace":"Traccia output","Bank Statement":"Estratto conto","Match Result":"Esito match","Draft Section":"Sezione bozza","No draft text.":"Nessun testo di bozza per questa voce.","No source table fields.":"Nessuna tabella fonte indicata per questa voce.","No revision note.":"Nessuna nota di revisione.","Source Table":"Tabella fonte","Revision Note":"Nota revisione","Prompt Section":"Sezione prompt","Research Scope":"Ambito ricerca","Required Revision":"Revisione richiesta","Plan Section":"Sezione piano","Accounting Support":"Supporto contabile","Tie-Out Finding":"Rilievo tie-out"},"fr":{"Journal Entry":"Ecriture comptable","Support Document":"Document justificatif","Finding":"Constat","Claim":"Assertion","Citation / Source":"Citation / source","Source Support":"Appui de la source","Validation Finding":"Constat de validation","Client Document":"Document client","Required Evidence":"Justificatif requis","Memo / Email Impact":"Impact memo / email","Reconciliation Row":"Ligne de rapprochement","Evidence":"Justificatif","Exception":"Exception","Extracted Journal Row":"Ligne d'ecriture extraite","Sampling Basis":"Base d'echantillonnage","Output Trace":"Trace de sortie","Bank Statement":"Releve bancaire","Match Result":"Resultat de rapprochement","Draft Section":"Section brouillon","Source Table":"Table source","Revision Note":"Note de revue","Prompt Section":"Section prompt","Research Scope":"Perimetre de recherche","Required Revision":"Revision requise","Plan Section":"Section du plan","Accounting Support":"Support comptable","Tie-Out Finding":"Constat de rapprochement"},"de":{"Journal Entry":"Buchung","Support Document":"Beleg","Finding":"Feststellung","Claim":"Aussage","Citation / Source":"Zitat / Quelle","Source Support":"Quellennachweis","Validation Finding":"Validierungsfeststellung","Client Document":"Mandantendokument","Required Evidence":"Erforderlicher Nachweis","Memo / Email Impact":"Memo-/E-Mail-Auswirkung","Reconciliation Row":"Abstimmungszeile","Evidence":"Nachweis","Exception":"Ausnahme","Extracted Journal Row":"Extrahierte Buchungszeile","Sampling Basis":"Stichprobenbasis","Output Trace":"Ausgabeprotokoll","Bank Statement":"Kontoauszug","Match Result":"Abstimmungsergebnis","Draft Section":"Entwurfsabschnitt","Source Table":"Quelltabelle","Revision Note":"Review-Notiz","Prompt Section":"Prompt-Abschnitt","Research Scope":"Rechercheumfang","Required Revision":"Erforderliche Ueberarbeitung","Plan Section":"Planabschnitt","Accounting Support":"Buchhaltungsnachweis","Tie-Out Finding":"Abgleichsfeststellung"}};
    const DEMO_PAYLOAD = {
      widget_type: CONFIG.widgetType,
      run_intake: {
        schema_version: "1.0",
        plugin: CONFIG.plugin,
        workflow: CONFIG.plugin,
        run_id: "sample-review",
        output_dir: "/tmp/" + CONFIG.plugin + "/sample",
        input_paths: ["input.xlsx", "evidence/"],
        language: "en",
        data_posture: {
          local_files_read: ["input.xlsx", "evidence/"],
          external_connectors_used: [],
          upload_paths_used: [],
          remote_sql_execution_used: false,
          hosted_notebook_execution_used: false,
        },
        execution_trace: [
          {
            step_id: CONFIG.plugin + "_sample_run",
            kind: "deterministic_review_session",
            status: "passed",
            execution_location: "local_codex_workspace",
            command: ["python", "plugins/" + CONFIG.plugin + "/scripts/review_session.py"],
            inputs: ["input.xlsx", "evidence/"],
            outputs: ["review_payload.json", "review_summary.md", "evidence_workbook.xlsx", "final_artifacts.json"],
          },
        ],
        status: "ready_for_review",
      },
      review_payload: {
        schema_version: "1.0",
        plugin: CONFIG.plugin,
        workflow: CONFIG.plugin,
        run_id: "sample-review",
        review_type: CONFIG.demo.review_type,
        status: "ready_for_review",
        items: CONFIG.demo.items,
        item_count: CONFIG.demo.items.length,
        summary: { result_row_count: CONFIG.demo.items.length, issue_count: CONFIG.demo.items.filter((item) => item.recommended_action !== "accept").length, artifact_count: 2 },
      },
      ui_decisions: { schema_version: "1.0", plugin: CONFIG.plugin, workflow: CONFIG.plugin, run_id: "sample-review", review_payload_path: "review_payload.json", decisions: [], decision_count: 0, status: "pending_review" },
      final_artifacts: { schema_version: "1.0", plugin: CONFIG.plugin, workflow: CONFIG.plugin, run_id: "sample-review", outputs: [
        { path: "review_payload.json", kind: "json", status: "written", row_count: CONFIG.demo.items.length, records_key: "items", required_columns: ["id", "item_type", "title"], qa_checks: ["json_parse", "row_count", "required_columns"] },
        { path: "review_summary.md", kind: "md", status: "written", required_text: [CONFIG.reviewTitle, "local_codex_workspace", "Sample payload is bounded for review."], qa_checks: ["nonempty_text", "required_text"] },
        { path: "evidence_workbook.xlsx", kind: "xlsx", status: "written", required_sheets: ["summary"], required_sheet_headers: { summary: ["item_id", "recommended_action", "status"] }, required_cells: { summary: { A1: "item_id", A2: CONFIG.demo.items[0]?.id || "sample-1", B1: "recommended_action", B2: CONFIG.demo.items[0]?.recommended_action || "accept" } }, qa_checks: ["office_zip", "workbook_xml", "required_sheets", "required_sheet_headers", "required_cells"] },
        { path: "ui_decisions.json", kind: "json", status: "pending_review", records_key: "decisions", min_rows: 1 },
      ], caveats: ["Sample payload is bounded for review."], next_actions: ["Save or apply decisions from the widget before treating outputs as final."], status: "written_pending_review" },
      decision_policy: { save_tool: CONFIG.saveTool, apply_tool: CONFIG.applyTool, can_persist: false, fallback: "copy_json" },
    };
    const FALLBACK = {
      widget_type: CONFIG.widgetType,
      run_intake: null,
      review_payload: { schema_version: "1.0", plugin: CONFIG.plugin, workflow: CONFIG.plugin, run_id: "preview", status: "empty", items: [], item_count: 0, summary: {} },
      ui_decisions: null,
      final_artifacts: null,
      decision_policy: { save_tool: CONFIG.saveTool, apply_tool: CONFIG.applyTool, can_persist: false, fallback: "copy_json" },
    };
    const state = { payload: FALLBACK, selectedType: "all", selectedState: "all", selectedId: null, query: "", decisions: {}, recovery: { savedDecisionCount: 0, draftDecisionCount: 0, lastIssue: null } };

    function pickPayload(raw) {
      if (!raw || typeof raw !== "object") return null;
      if (raw.widget_type === CONFIG.widgetType || raw.review_payload || raw.ui_decisions || raw.final_artifacts || raw.applied_decisions) return raw;
      for (const key of ["widget_payload", "_meta", "toolResponseMetadata", "mcp_tool_result", "call_tool_result", "structuredContent", "toolOutput"]) {
        const selected = pickPayload(raw[key]);
        if (selected) return selected;
      }
      return null;
    }
    function toolOutput() {
      if (new URLSearchParams(window.location.search).has("demo")) return DEMO_PAYLOAD;
      const host = window.openai || {};
      return pickPayload(host.toolResponseMetadata) || pickPayload(host.toolOutput) || pickPayload(host.structuredContent) || pickPayload(host) || FALLBACK;
    }
    function esc(value) {
      return String(value ?? "").replace(/[&<>"']/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[char]);
    }
    const IT_METADATA_LABELS = {"matched_pair": "Movimenti abbinati", "unmatched_bank": "Movimento bancario non abbinato", "unmatched_journal": "Registrazione non abbinata", "entry": "Registrazione", "counterparty": "Controparte", "amount": "Importo", "date": "Data", "description": "Descrizione", "status": "Stato", "reference": "Riferimento", "match_method": "Metodo di abbinamento", "bank_amount": "Importo bancario", "journal_amount": "Importo contabile", "difference": "Differenza", "source_path": "Documento di origine", "output_path": "Documento prodotto", "artifact": "Documento prodotto", "report_artifact": "Report", "chart_artifact": "Grafico", "evidence": "Evidenza", "account": "Conto", "currency": "Valuta", "debit": "Dare", "credit": "Avere", "invoice_number": "Numero fattura", "exact": "Esatto", "matched": "Abbinato", "unmatched": "Non abbinato", "sampling_control": "Parametri campione", "sampled_entry": "Riga estratta", "sample_artifact": "Campione", "review_artifact": "Tracciato", "entry_date": "Data registrazione", "movement_number": "Registrazione", "line_number": "Riga", "line_desc": "Descrizione", "amount_signed": "Importo con segno", "amount_abs": "Importo assoluto", "method": "Metodo", "sample_size": "Righe estratte", "requested_size": "Righe richieste", "population_size_after_filters": "Righe nella popolazione", "seed": "Seme casuale", "source_file": "File sorgente", "source_row": "Riga sorgente", "needs_review": "Da rivedere", "reported_increment": "Precisione importi", "filters": "Filtri", "population_proof": "Controlli sulla popolazione", "sampling_parameters": "Parametri di estrazione", "kind": "Tipo", "manual_review": "Da rivedere", "matched_support": "Documento abbinato", "support_type": "Tipo documento", "support_artifact_id": "Identificativo tecnico del documento", "support_match_status": "Abbinamento", "support_match_signals": "Elementi di confronto", "amount_found": "Importo nel documento", "date_found": "Data nel documento", "checks_run": "Controlli eseguiti", "mismatches": "Punti da chiarire", "review_notes": "Note di revisione", "evidence_facts": "Dati estratti dal documento", "professional_conclusion": "Conclusione professionale", "assurance_gate_status": "Stato dei controlli", "deterministic_checks": "Confronti automatici", "value": "Valore", "pending_review": "In attesa di revisione", "fatturapa_xml": "Fattura XML", "party_perimeter_requires_review": "Soggetto da confermare", "direction_requires_review": "Segno contabile da confermare", "missing_direction": "Confronto del segno non ancora concluso", "reconciliation_failed": "Confronto da completare", "semantic_review_withheld": "Giudizio professionale in attesa", "party_perimeter": "Soggetto", "report_section": "Sezione del report", "table_evidence": "Tabella di supporto", "review_issue": "Punto da rivedere", "section": "Sezione", "draft_text": "Testo della bozza", "codex_comment": "Testo attuale", "preview_rows": "Anteprima delle righe", "sheet_name": "Foglio", "source_table": "Tabella fonte", "metric": "Misura", "period": "Periodo", "reason": "Motivo", "blocker": "Impedimento", "proposed_fix": "Modifica proposta"};
    function humanize(value) {
      const key = String(value || "");
      if (activeLanguage() === "it" && IT_METADATA_LABELS[key]) return IT_METADATA_LABELS[key];
      return key.replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
    }
    function formatValue(value) {
      if (value == null || value === "") return "";
      if (typeof value === "boolean") return value ? uiText("yes", "Yes") : uiText("no", "No");
      if (typeof value === "number") return Number.isInteger(value) ? String(value) : value.toLocaleString(undefined, { maximumFractionDigits: 2 });
      if (typeof value === "object") return JSON.stringify(value);
      if (activeLanguage() === "it" && CONFIG.plugin === "check-entries") return String(value).split(/([,;])/).map((part) => IT_METADATA_LABELS[part] || part).join("");
      return String(value);
    }
    function reviewPayload() { return state.payload.review_payload || FALLBACK.review_payload; }
    function items() { return Array.isArray(reviewPayload().items) ? reviewPayload().items : []; }
    function normalizeLanguage(value) {
      const code = String(value || "").trim().toLowerCase().replace("_", "-").split("-")[0];
      return Object.prototype.hasOwnProperty.call(UI_TEXT, code) ? code : "en";
    }
    function activeLanguage() {
      const runIntake = state.payload.run_intake || {};
      const payload = reviewPayload();
      return normalizeLanguage(runIntake.language || runIntake.locale || payload.summary?.language || payload.language || "en");
    }
    function textGroup(group) {
      const lang = activeLanguage();
      return UI_TEXT[lang]?.[group] || UI_TEXT.en[group] || {};
    }
    function ui(group, key, fallback = "") {
      return textGroup(group)[key] || UI_TEXT.en[group]?.[key] || fallback || key;
    }
    function uiText(key, fallback = "") { return ui("text", key, fallback); }
    function workflowText(key, fallback = "") {
      const lang = activeLanguage();
      return CONFIG.localized?.[lang]?.[key] || CONFIG.localized?.en?.[key] || CONFIG[key] || fallback;
    }
    function groupTitle(group) {
      const lang = activeLanguage();
      return GROUP_TEXT[lang]?.[group.title] || group.title || uiText("detail", "Detail");
    }
    function groupEmpty(group) {
      const lang = activeLanguage();
      return GROUP_TEXT[lang]?.[group.empty] || group.empty || uiText("noFields", "No fields.");
    }
    function itemById(itemId) { return items().find((item) => item.id === itemId) || null; }
    function decisionFor(itemId) { const decision = state.decisions[itemId]; return decision && itemById(itemId) ? decision : null; }
    function validDecisionCount() { return Object.keys(state.decisions).filter((itemId) => decisionFor(itemId)).length; }
    function actionLabel(action) { return ui("actions", action, ACTION_LABELS[action] || humanize(action || "Review")); }
    function statusLabel(status) { return ui("statuses", status, humanize(status || "pending")); }
    function actionClass(value) { return String(value || "review").replace(/[^a-z0-9_-]/gi, "_"); }
    function statusFor(item) {
      const decision = decisionFor(item.id);
      if (decision?.action) return ACTION_STATUSES[decision.action] || decision.action;
      const status = item.data?.status || item.status || "pending";
      const statusText = String(status).toLowerCase();
      if (["ok", "matched", "supported", "classified", "selected", "relevant", "drafted"].includes(status)) return "ready";
      if (statusText.includes("missing") || statusText.includes("unmatched") || statusText.includes("mismatch") || statusText.includes("needs_evidence") || statusText.includes("blocked")) return "needs_evidence";
      if (["missing", "unmatched", "mismatch", "variance", "needs_evidence"].includes(status)) return "needs_evidence";
      return status;
    }
    function finalArtifacts() {
      return state.payload.final_artifacts && typeof state.payload.final_artifacts === "object" ? state.payload.final_artifacts : {};
    }
    function artifactState() {
      const artifacts = finalArtifacts();
      return artifacts.review_status || artifacts.status || state.payload.applied_decisions?.application_status || state.payload.ui_decisions?.status || reviewPayload().status || "pending_review";
    }
    function blockerItemIds() {
      return new Set((Array.isArray(finalArtifacts().blockers) ? finalArtifacts().blockers : [])
        .map((blocker) => blocker?.item_id)
        .filter(Boolean));
    }
    function reviewStateFor(item) {
      if (blockerItemIds().has(item.id)) return "blocked";
      const decision = decisionFor(item.id);
      if (!decision?.action) return statusFor(item) === "needs_evidence" ? "needs_evidence" : "pending";
      const status = ACTION_STATUSES[decision.action] || decision.action;
      if (["needs_evidence", "rejected"].includes(status)) return "needs_evidence";
      return "reviewed";
    }
    function reviewStateCounts() {
      const counts = { all: items().length, pending: 0, reviewed: 0, needs_evidence: 0, blocked: 0 };
      for (const item of items()) {
        const stateName = reviewStateFor(item);
        counts[stateName] = (counts[stateName] || 0) + 1;
      }
      return counts;
    }
    function supportLine(item) {
      const data = item.data || {};
      const parts = [data.source_title, data.citation, data.support, data.evidence, data.matched_pdf, data.bank_line, data.source_table, data.reason, data.review_notes, item.source_path || item.output_path].filter(Boolean);
      return parts.slice(0, 3).join(" · ");
    }
    function filteredItems() {
      const q = state.query.trim().toLowerCase();
      return items().filter((item) => {
        if (state.selectedType !== "all" && item.item_type !== state.selectedType) return false;
        if (state.selectedState !== "all" && reviewStateFor(item) !== state.selectedState) return false;
        return !q || JSON.stringify(item).toLowerCase().includes(q);
      });
    }
    function metric(label, value) { return `<article class="metric"><span>${esc(label)}</span><strong>${esc(value)}</strong></article>`; }
    function renderSummary() {
      const payload = reviewPayload();
      document.getElementById("technical-title").textContent = ({it: "Dettagli tecnici", en: "Technical details", fr: "Détails techniques", es: "Detalles técnicos", de: "Technische Details"})[activeLanguage()];
      const summary = payload.summary || {};
      const issueCount = summary.issue_count ?? items().filter((item) => item.recommended_action && item.recommended_action !== "accept").length;
      const artifactCount = artifactRecords().length;
      document.getElementById("subtitle").textContent = `${uiText("runLabel", "Run")} ${payload.run_id || "n/a"}`;
      document.getElementById("status-pill").textContent = statusLabel(payload.status || "ready_for_review");
      document.getElementById("summary").innerHTML = [
        metric(ui("metrics", "items", "Items"), items().length),
        metric(ui("metrics", "issues", "Issues"), issueCount),
        metric(ui("metrics", "evidence", "Evidence"), items().filter((item) => Array.isArray(item.evidence) && item.evidence.length).length),
        metric(ui("metrics", "artifacts", "Artifacts"), artifactCount),
        metric(uiText("reviewedSuffix", "Decisions selected"), `${validDecisionCount()} / ${items().length}`),
      ].join("");
    }
    function renderProgress() {
      const decided = validDecisionCount();
      const total = items().length;
      const percent = total ? Math.round((decided / total) * 100) : 0;
      document.getElementById("decision-pill").textContent = `${decided} ${uiText("reviewedSuffix", "reviewed")}`;
      document.getElementById("decision-progress").textContent = uiText("decidedProgress", "{decided} / {total} decided").replace("{decided}", decided).replace("{total}", total);
      document.getElementById("decision-progress-fill").style.width = `${percent}%`;
      document.getElementById("use-recommended").disabled = total === 0;
      document.getElementById("save-decisions").disabled = total === 0;
      document.getElementById("apply-decisions").disabled = total === 0;
      renderReviewStore();
      renderRecoveryPanel();
    }
    function countText(key, fallback, count) {
      return uiText(key, fallback).replace("{count}", count);
    }
    function normalizedDecisionRecord(decision) {
      if (!decision?.item_id || !decision?.action || !itemById(decision.item_id)) return null;
      return {
        item_id: String(decision.item_id),
        action: String(decision.action),
        reviewer_note: String(decision.reviewer_note || "").trim(),
        edit_value: String(decision.edit_value || "").trim(),
        requested_documents: Array.isArray(decision.requested_documents)
          ? decision.requested_documents.map((entry) => String(entry || "").trim()).filter(Boolean).sort()
          : [],
      };
    }
    function normalizedDecisionList(decisions) {
      return (Array.isArray(decisions) ? decisions : [])
        .map(normalizedDecisionRecord)
        .filter(Boolean)
        .sort((left, right) => left.item_id.localeCompare(right.item_id));
    }
    function decisionSignature(decisions) {
      return JSON.stringify(normalizedDecisionList(decisions));
    }
    function decisionSignatureByItem(decisions) {
      const signatures = new Map();
      for (const decision of normalizedDecisionList(decisions)) {
        signatures.set(decision.item_id, JSON.stringify(decision));
      }
      return signatures;
    }
    function changedDecisionCount(currentDecisions, baselineDecisions) {
      const baseline = decisionSignatureByItem(baselineDecisions);
      return normalizedDecisionList(currentDecisions).filter((decision) => baseline.get(decision.item_id) !== JSON.stringify(decision)).length;
    }
    function savedDecisionInputs() {
      return normalizedDecisionList(state.payload.ui_decisions?.decisions);
    }
    function appliedDecisionInputs() {
      return normalizedDecisionList(state.payload.applied_decisions?.decisions);
    }
    function reviewStoreItem(label, value, kind = "") {
      return `<div class="review-store__item${kind ? ` is-${esc(kind)}` : ""}"><span>${esc(label)}</span><strong>${esc(value)}</strong></div>`;
    }
    function renderReviewStore() {
      const node = document.getElementById("review-store");
      const current = collectDecisionInputs();
      const saved = savedDecisionInputs();
      const applied = appliedDecisionInputs();
      const currentSignature = decisionSignature(current);
      const savedSignature = decisionSignature(saved);
      const unsavedCount = currentSignature === savedSignature ? 0 : changedDecisionCount(current, saved);
      const hasUnsaved = unsavedCount > 0;
      const draftCount = state.recovery?.draftDecisionCount || 0;
      const cells = [
        reviewStoreItem(uiText("currentDecisions", "Current"), countText("currentDecisionCount", "{count} current", current.length), current.length ? "current" : "empty"),
        reviewStoreItem(uiText("savedDecisions", "Saved"), countText("savedDecisionCount", "{count} saved", saved.length), saved.length ? "saved" : "empty"),
        reviewStoreItem(uiText("appliedDecisions", "Applied"), countText("appliedDecisionCount", "{count} applied", applied.length), applied.length ? "applied" : "empty"),
        reviewStoreItem(uiText("reviewStore", "Review state"), hasUnsaved ? countText("unsavedDecisionCount", "{count} unsaved", unsavedCount) : uiText("inSync", "In sync"), hasUnsaved ? "dirty" : "applied"),
      ];
      if (draftCount) cells.push(reviewStoreItem(uiText("jsonFallback", "JSON fallback"), countText("recoveredDraftCount", "{count} recovered draft", draftCount), "dirty"));
      node.innerHTML = cells.join("");
    }
    function canPersistThroughBridge() {
      return Boolean(state.payload.decision_policy?.can_persist) && typeof window.openai?.callTool === "function";
    }
    function recoveryLine(label, value) {
      if (!value) return "";
      return `<div class="recovery-panel__line"><span>${esc(label)}</span><span>${esc(value)}</span></div>`;
    }
    function setRecoveryIssue(kind, title, body, toolName = "", errorMessage = "") {
      state.recovery.lastIssue = { kind, title, body, toolName, errorMessage };
      renderRecoveryPanel();
    }
    function clearRecoveryIssue() {
      if (!state.recovery) state.recovery = {};
      state.recovery.lastIssue = null;
      renderRecoveryPanel();
    }
    function renderRecoveryPanel() {
      const node = document.getElementById("recovery-panel");
      if (!node) return;
      const issue = state.recovery?.lastIssue || null;
      const fallbackActive = items().length > 0 && !canPersistThroughBridge();
      if (!issue && !fallbackActive) {
        node.className = "recovery-panel";
        node.innerHTML = "";
        return;
      }
      const title = issue?.title || uiText("fallbackActive", "JSON fallback active");
      const body = issue?.body || uiText("fallbackBody", "Copy or download ui_decisions.json. Use the MCP or local-server review surface to persist and apply decisions.");
      const tool = issue?.toolName || state.payload.decision_policy?.save_tool || CONFIG.saveTool;
      const error = issue?.errorMessage || "";
      const lines = [
        recoveryLine(uiText("recoveryAction", "Recovery"), body),
        recoveryLine(uiText("toolLabel", "Tool"), tool),
        recoveryLine(uiText("lastError", "Last error"), error),
      ].filter(Boolean).join("");
      node.className = `recovery-panel is-visible${issue?.kind === "error" ? " is-error" : ""}`;
      node.innerHTML = `<div class="recovery-panel__title">${esc(title)}</div><div class="recovery-panel__body">${lines}</div>`;
    }
    function postureValue(value, fallback) {
      if (Array.isArray(value)) return value.length ? listSummary(value, 3) : fallback;
      if (typeof value === "boolean") return uiText(value ? "yes" : "no", value ? "Yes" : "No");
      if (value === null || value === undefined || value === "") return fallback;
      return String(value);
    }
    function remoteSqlValue(posture, fallback) {
      if (typeof posture.remote_sql_execution_used === "boolean") return postureValue(posture.remote_sql_execution_used, fallback);
      if (posture.remote_sql_execution_used) return postureValue(posture.remote_sql_execution_used, fallback);
      const notes = Array.isArray(posture.notes) ? posture.notes.join(" ").toLowerCase() : "";
      if (notes.includes("remote sql") && notes.includes("no external")) return uiText("no", "No");
      return fallback;
    }
    function hostedNotebookValue(posture, fallback) {
      if (typeof posture.hosted_notebook_execution_used === "boolean") return postureValue(posture.hosted_notebook_execution_used, fallback);
      if (posture.hosted_notebook_execution_used) return postureValue(posture.hosted_notebook_execution_used, fallback);
      const notes = Array.isArray(posture.notes) ? posture.notes.join(" ").toLowerCase() : "";
      if (notes.includes("hosted notebook") && notes.includes("no external")) return uiText("no", "No");
      return fallback;
    }
    function postureItem(label, value) {
      return `<div class="data-posture__item"><span>${esc(label)}</span><strong>${esc(value)}</strong></div>`;
    }
    function renderDataPosture() {
      const node = document.getElementById("data-posture");
      const posture = state.payload.run_intake?.data_posture;
      if (!posture || typeof posture !== "object" || Array.isArray(posture)) {
        node.innerHTML = "";
        node.style.display = "none";
        return;
      }
      const none = uiText("noneValue", "None");
      const missing = uiText("notDeclared", "Not declared");
      const cells = [
        postureItem(uiText("localFiles", "Files read by helpers"), postureValue(posture.local_files_read, missing)),
        postureItem(uiText("connectors", "Optional connectors"), postureValue(posture.external_connectors_used, none)),
        postureItem(uiText("uploads", "Optional upload routes"), postureValue(posture.upload_paths_used, none)),
        postureItem(uiText("remoteSql", "Helper remote SQL"), remoteSqlValue(posture, missing)),
        postureItem(uiText("hostedNotebook", "Helper hosted notebook"), hostedNotebookValue(posture, missing)),
      ];
      node.style.display = "";
      const scope = uiText("dataPostureScope", "Optional routes used by helper execution. This does not describe or count the context sent by Codex to the model.");
      node.innerHTML = `<div class="data-posture__title">${esc(uiText("dataPosture", "Helper execution routes"))}<small>${esc(scope)}</small></div><div class="data-posture__grid">${cells.join("")}</div>`;
    }
    function traceEntries() {
      const trace = state.payload.run_intake?.execution_trace;
      return Array.isArray(trace) ? trace.filter((step) => step && typeof step === "object").slice(-4) : [];
    }
    function traceValue(value, fallback = "") {
      if (Array.isArray(value)) return value.length ? listSummary(value, 4) : fallback;
      if (value && typeof value === "object") {
        const locator = value.path || value.uri || value.id || value.name || "";
        return locator ? String(locator) : JSON.stringify(value);
      }
      if (value === null || value === undefined || value === "") return fallback;
      return String(value);
    }
    function traceCommandValue(value) {
      if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ");
      return traceValue(value, "");
    }
    function isRemoteExecutionLocation(value) {
      return ["external_connector", "hosted_notebook", "remote_warehouse"].includes(String(value || ""));
    }
    function traceStepHtml(step) {
      const location = traceValue(step.execution_location, uiText("notDeclared", "Not declared"));
      const remote = isRemoteExecutionLocation(step.execution_location);
      const badge = remote ? uiText("remoteExecution", "Remote") : uiText("localExecution", "Local");
      const rows = [
        [uiText("executionLocation", "Location"), location],
        [uiText("executionKind", "Kind"), traceValue(step.kind, "")],
        [uiText("executionStatus", "Status"), traceValue(step.status, "")],
        [uiText("executionCommand", "Command"), traceCommandValue(step.command)],
        [uiText("executionInputs", "Inputs"), traceValue(step.inputs, "")],
        [uiText("executionOutputs", "Outputs"), traceValue(step.outputs, "")],
      ].filter(([, value]) => value);
      return `<div class="execution-step"><div class="execution-step__title"><span>${esc(traceValue(step.step_id, step.kind || "step"))}</span><span class="execution-badge${remote ? " is-remote" : ""}">${esc(badge)}</span></div><div class="execution-kv">${rows.map(([label, value]) => `<span>${esc(label)}</span><span>${esc(value)}</span>`).join("")}</div></div>`;
    }
    function renderExecutionProvenance() {
      const node = document.getElementById("execution-provenance");
      if (!node) return;
      const trace = traceEntries();
      if (!trace.length) {
        node.className = "execution-provenance";
        node.innerHTML = "";
        return;
      }
      const countLabel = `${trace.length} ${esc(trace.length === 1 ? uiText("traceStepSingular", "step") : uiText("traceStepPlural", "steps"))}`;
      node.className = "execution-provenance is-visible";
      node.innerHTML = `<div class="execution-header"><h2>${esc(uiText("executionProvenance", "Execution provenance"))}</h2><span>${countLabel}</span></div><div class="execution-grid">${trace.map(traceStepHtml).join("")}</div>`;
    }
    function replaceCountText(key, fallback, count) {
      return uiText(key, fallback).replace("{count}", count);
    }
    function postureUsesExternal(value) {
      if (Array.isArray(value)) return value.length > 0;
      if (typeof value === "boolean") return value;
      if (value && typeof value === "object") return Object.keys(value).length > 0;
      const text = String(value || "").trim().toLowerCase();
      return Boolean(text && !["false", "no", "none", "0"].includes(text));
    }
    function externalExecutionUsed() {
      const posture = state.payload.run_intake?.data_posture || {};
      return postureUsesExternal(posture.external_connectors_used)
        || postureUsesExternal(posture.external_routes_used)
        || postureUsesExternal(posture.upload_paths_used)
        || postureUsesExternal(posture.remote_sql_execution_used)
        || postureUsesExternal(posture.hosted_notebook_execution_used)
        || traceEntries().some((step) => isRemoteExecutionLocation(step.execution_location));
    }
    function safeguardBadge(kind) {
      if (kind === "ok") return uiText("safeguardsReady", "Ready");
      if (kind === "danger" || kind === "warning") return uiText("safeguardsWarning", "Review");
      return uiText("safeguardsCheck", "Check");
    }
    function safeguardItemHtml(label, value, kind = "check") {
      return `<article class="safeguard is-${esc(kind)}"><div class="safeguard__top"><strong>${esc(label)}</strong><span class="safeguard__badge">${esc(safeguardBadge(kind))}</span></div><p>${esc(value)}</p></article>`;
    }
    function safeguardRecords() {
      const trace = traceEntries();
      const hasRemoteTrace = trace.some((step) => isRemoteExecutionLocation(step.execution_location));
      const externalUsed = externalExecutionUsed();
      const payload = reviewPayload();
      const declaredCount = Number(payload.item_count);
      const actualCount = items().length;
      const countMismatch = Number.isFinite(declaredCount) && declaredCount !== actualCount;
      const outputCount = artifactRecords().length;
      return [
        {
          label: uiText("safeguardLocalExecution", "Helper-script execution"),
          value: trace.length
            ? (hasRemoteTrace ? uiText("remoteExecutionDeclared", "Helper used an external path") : uiText("localExecutionDeclared", "Helper ran in local workspace"))
            : uiText("executionTraceMissing", "Trace missing"),
          kind: trace.length ? (hasRemoteTrace ? "check" : "ok") : "warning",
        },
        {
          label: uiText("safeguardExternalRoute", "Optional routes beyond Codex"),
          value: externalUsed
            ? uiText("externalRouteUsed", "Route used and recorded")
            : uiText("externalRouteNotUsed", "No optional route used"),
          kind: externalUsed ? "check" : "ok",
        },
        {
          label: uiText("safeguardBoundedPayload", "Bounded payload"),
          value: replaceCountText("payloadItemsCount", "{count} items", actualCount),
          kind: countMismatch ? "danger" : "ok",
        },
        {
          label: uiText("safeguardDecisionPersistence", "Decision persistence"),
          value: canPersistThroughBridge() ? uiText("persistenceAvailable", "Save/apply available") : uiText("persistenceFallback", "Copy JSON only"),
          kind: canPersistThroughBridge() ? "ok" : "check",
        },
        {
          label: uiText("safeguardFinalArtifacts", "Final artifacts"),
          value: outputCount ? replaceCountText("finalArtifactsDeclared", "{count} outputs", outputCount) : uiText("finalArtifactsMissing", "No outputs declared"),
          kind: outputCount ? "ok" : "warning",
        },
      ];
    }
    function renderReviewSafeguards() {
      const node = document.getElementById("review-safeguards");
      if (!node) return;
      if (!items().length) {
        node.className = "safeguards";
        node.innerHTML = "";
        return;
      }
      const records = safeguardRecords();
      const needsReview = records.some((record) => ["danger", "warning"].includes(record.kind));
      const summary = needsReview ? uiText("safeguardsWarning", "Review") : uiText("safeguardsReady", "Ready");
      node.className = "safeguards is-visible";
      node.innerHTML = `<div class="safeguards__header"><h2>${esc(uiText("reviewSafeguards", "Review safeguards"))}</h2><span>${esc(summary)}</span></div><div class="safeguards__grid">${records.map((record) => safeguardItemHtml(record.label, record.value, record.kind)).join("")}</div>`;
    }
    function renderContext() {
      const payload = reviewPayload();
      const runIntake = state.payload.run_intake || {};
      const sourcePaths = Array.isArray(payload.source_paths) ? payload.source_paths : runIntake.input_paths || [];
      const canPersist = Boolean(state.payload.decision_policy?.can_persist);
      document.getElementById("run-context").innerHTML = `<div><strong>${esc(workflowText("reviewTitle", CONFIG.reviewTitle))}</strong><span>${esc(sourcePaths.length ? sourcePaths.join(" · ") : uiText("noSourcePaths", "No source paths supplied"))}</span></div><div class="context-list"><span class="context-token">${esc(runIntake.language || payload.summary?.language || "en")}</span><span class="context-token">${canPersist ? uiText("writesDecisions", "Writes ui_decisions.json") : uiText("jsonFallback", "JSON fallback")}</span></div>`;
    }
    function renderTabs() {
      const counts = new Map([["all", items().length]]);
      for (const item of items()) counts.set(item.item_type, (counts.get(item.item_type) || 0) + 1);
      document.getElementById("tabs").innerHTML = Array.from(counts.entries()).map(([type, count]) => `<button class="tab" data-type="${esc(type)}" aria-pressed="${type === state.selectedType}">${esc(type === "all" ? uiText("all", "All") : humanize(type))} (${count})</button>`).join("");
    }
    function stateChip(key, label, count) {
      return `<button class="state-chip is-${esc(actionClass(key))}" data-state-filter="${esc(key)}" aria-pressed="${key === state.selectedState}"><span>${esc(label)}</span><strong>${esc(count)}</strong></button>`;
    }
    function renderStateStrip() {
      const node = document.getElementById("state-strip");
      const counts = reviewStateCounts();
      const chips = [
        stateChip("all", uiText("allStates", "All states"), counts.all),
        stateChip("pending", statusLabel("pending"), counts.pending),
        stateChip("reviewed", statusLabel("reviewed"), counts.reviewed),
        stateChip("needs_evidence", statusLabel("needs_evidence"), counts.needs_evidence),
        stateChip("blocked", statusLabel("blocked"), counts.blocked),
      ].join("");
      const currentArtifactState = artifactState();
      node.innerHTML = `<div class="state-filters">${chips}</div><div class="state-final is-${esc(actionClass(currentArtifactState))}"><span>${esc(uiText("artifactState", "Artifact state"))}</span><strong>${esc(statusLabel(currentArtifactState))}</strong></div>`;
    }
    function rowHtml(item) {
      const decision = decisionFor(item.id);
      const action = decision?.action || item.recommended_action || "review";
      const status = statusFor(item);
      const stateName = reviewStateFor(item);
      return `<button class="row row--${esc(actionClass(stateName))}${item.id === state.selectedId ? " is-selected" : ""}" data-id="${esc(item.id)}"><span class="type">${esc(humanize(item.item_type))}</span><span><span class="title">${esc(item.title)}</span><span class="row-support">${esc(supportLine(item))}</span></span><span><span class="action action--${esc(actionClass(action))}">${esc(actionLabel(action))}</span><span class="row-status is-${esc(actionClass(stateName))}">${esc(statusLabel(stateName))}</span></span></button>`;
    }
    function emptyQueueHtml() {
      return `<div class="empty-state"><strong>${esc(uiText("noPayloadTitle", "No review payload loaded"))}</strong><p>${esc(uiText("noPayloadBody", "This widget is waiting for an MCP render call with review_payload.json. Opening the HTML file directly does not include run data."))}</p><div class="empty-actions"><button class="button primary" type="button" data-load-demo="true">${esc(ui("buttons", "previewSample", "Preview sample review"))}</button><button class="button" type="button" id="copy-empty-contract">${esc(ui("buttons", "copyEmpty", "Copy empty decision JSON"))}</button></div></div>`;
    }
    function renderRows() {
      const rows = filteredItems();
      document.getElementById("count").textContent = `${rows.length} / ${items().length}`;
      document.getElementById("rows").innerHTML = rows.length ? rows.map(rowHtml).join("") : (items().length ? `<div class="empty">${esc(uiText("noFilterMatch", "No item matches the current filters."))}</div>` : emptyQueueHtml());
      if (!state.selectedId && rows[0]) state.selectedId = rows[0].id;
      if (state.selectedId && !rows.some((item) => item.id === state.selectedId)) state.selectedId = rows[0]?.id || null;
      renderDetails();
      renderSummary();
      renderProgress();
      renderStateStrip();
    }
    const PANEL_KEYS = [
      ["claim", "prompt", "section", "entry", "document", "account", "counterparty", "amount", "status", "fiscal_year"],
      ["citation", "source_title", "source_url", "support", "evidence", "matched_pdf", "bank_line", "source_table", "requested_document"],
      ["severity", "reason", "finding", "mismatches", "review_notes", "status", "variance", "blocker"],
    ];
    function entriesFor(record, keys) {
      if (!record || typeof record !== "object" || Array.isArray(record)) return [];
      return keys.filter((key) => Object.prototype.hasOwnProperty.call(record, key)).map((key) => [key, record[key]]).filter(([, value]) => value != null && value !== "");
    }
    function evidenceValueHtml(value) {
      if (typeof value === "string" && value.length < 100000 && /^[{[]/.test(value.trim())) {
        try { const parsed = JSON.parse(value); if (parsed && typeof parsed === "object") value = parsed; } catch (_) {}
      }
      if (value && typeof value === "object") {
        const label = ({it: "Dettagli tecnici", en: "Technical details", fr: "Détails techniques", es: "Detalles técnicos", de: "Technische Details"})[activeLanguage()];
        return `<details><summary>${esc(label)}</summary><pre style="white-space:pre-wrap;overflow-wrap:anywhere">${esc(JSON.stringify(value, null, 2))}</pre></details>`;
      }
      return esc(formatValue(value));
    }
    function kvHtml(record, keys) {
      const entries = entriesFor(record, keys);
      if (!entries.length) return `<div class="empty">${esc(uiText("noFields", "No fields."))}</div>`;
      return `<div class="kv">${entries.map(([key, value]) => `<div>${esc(humanize(key))}</div><div>${CONFIG.plugin === "report-builder" && key === "preview_rows" ? sourcePreviewHtml(value) : evidenceValueHtml(value)}</div>`).join("")}</div>`;
    }
    function valueForField(item, field) {
      const data = item.data || {};
      const roots = [data, item, ...(Array.isArray(item.evidence) ? item.evidence : [])];
      for (const root of roots) {
        if (!root || typeof root !== "object") continue;
        if (!Object.prototype.hasOwnProperty.call(root, field)) continue;
        const value = root[field];
        if (CONFIG.plugin === "report-builder" && field === "preview_rows" && Array.isArray(value)) return value;
        if (value == null || value === "") continue;
        if (Array.isArray(value)) return value.map(formatValue).join(", ");
        if (typeof value === "object") return JSON.stringify(value);
        return value;
      }
      return "";
    }
    function groupEntries(item, group) {
      return (group.fields || [])
        .map((field) => [field, valueForField(item, field)])
        .filter(([, value]) => value != null && value !== "");
    }
    function sourcePreviewHtml(rows) {
      if (!Array.isArray(rows) || !rows.length || !rows.every(row => row && typeof row === "object" && !Array.isArray(row))) return evidenceValueHtml(rows);
      const columns = [...new Set(rows.flatMap(row => Object.keys(row)))];
      return `<div style="overflow-x:auto"><table><thead><tr>${columns.map(key => `<th>${esc(key)}</th>`).join("")}</tr></thead><tbody>${rows.map(row => `<tr>${columns.map(key => `<td>${esc(row[key] ?? "")}</td>`).join("")}</tr>`).join("")}</tbody></table></div>`;
    }
    function workflowCardHtml(item, group) {
      const entries = groupEntries(item, group);
      const variant = group.variant || "default";
      const body = entries.length
        ? `<div class="kv">${entries.map(([key, value]) => `<div>${esc(humanize(key))}</div><div>${CONFIG.plugin === "report-builder" && key === "preview_rows" ? sourcePreviewHtml(value) : evidenceValueHtml(value)}</div>`).join("")}</div>`
        : `<div class="empty">${esc(groupEmpty(group))}</div>`;
      return `<section class="workflow-card workflow-card--${esc(variant)}"><h5>${esc(groupTitle(group))}</h5>${body}</section>`;
    }
    function workflowDetailHtml(item) {
      const groups = Array.isArray(CONFIG.detailGroups) && CONFIG.detailGroups.length
        ? CONFIG.detailGroups
        : CONFIG.panels.map((title, index) => ({ title, variant: "default", fields: PANEL_KEYS[index] || [] }));
      return `<div class="workflow-detail workflow-detail--${esc(CONFIG.detailMode || "review")}"><div class="workflow-detail__header"><strong>${esc(workflowText("reviewTitle", CONFIG.reviewTitle))}</strong><span>${esc(workflowText("detailHelp", uiText("reviewEvidence", "Review the evidence and capture the decision.")))}</span></div><div class="workflow-detail__grid">${groups.map((group) => workflowCardHtml(item, group)).join("")}</div></div>`;
    }
    function evidenceHtml(item) {
      const evidence = Array.isArray(item.evidence) ? item.evidence : [];
      if (!evidence.length) return "";
      return `<div class="review-section"><h4>${esc(uiText("evidenceTrail", "Evidence trail"))}</h4><div class="evidence-list">${evidence.map((entry) => `<div class="evidence-card"><strong>${esc(humanize(entry?.kind || "evidence"))}</strong>${kvHtml(entry || {}, Object.keys(entry || {}))}</div>`).join("")}</div></div>`;
    }
    function explicitRoots(item) {
      return [item.data || {}, item, ...(Array.isArray(item.evidence) ? item.evidence : [])];
    }
    function flatTextValues(value) {
      if (value == null || value === "") return [];
      if (Array.isArray(value)) return value.flatMap(flatTextValues);
      if (typeof value === "object") {
        const candidate = value.title || value.name || value.document || value.path || value.source_path || value.file || value.id || value.reason || "";
        return candidate ? [String(candidate)] : [];
      }
      return [String(value)];
    }
    function collectExplicitValues(item, keys, limit = 4) {
      const seen = new Set();
      const values = [];
      for (const root of explicitRoots(item)) {
        if (!root || typeof root !== "object" || Array.isArray(root)) continue;
        for (const key of keys) {
          if (!Object.prototype.hasOwnProperty.call(root, key)) continue;
          for (const value of flatTextValues(root[key])) {
            const normalized = value.trim();
            if (!normalized || seen.has(normalized)) continue;
            seen.add(normalized);
            values.push(normalized);
            if (values.length >= limit) return values;
          }
        }
      }
      return values;
    }
    function requestedDocumentHints(item) {
      return collectExplicitValues(item, [
        "requested_document",
        "requested_documents",
        "missing_document",
        "missing_documents",
        "required_document",
        "required_documents",
        "support_document",
        "support_documents",
        "source_document",
        "source_documents",
      ]);
    }
    function editTargetSummary(item) {
      const data = item.data || {};
      if (data.edit_hint) return String(data.edit_hint);
      const artifact = data.target_artifact || item.output_path || "";
      const field = data.target_field || "";
      const recordId = data.target_record_id || "";
      const idField = data.target_id_field || "";
      const recordsKey = data.target_records_key || "";
      if (!artifact) return uiText("revisionOnly", "Revision file only until workflow apply updates a native artifact");
      const details = [];
      if (field) details.push(`${uiText("targetField", "field")}: ${field}`);
      if (recordId) details.push(`${idField || uiText("targetRecord", "record")}: ${recordId}`);
      if (recordsKey) details.push(`${uiText("targetRecords", "records")}: ${recordsKey}`);
      return `${artifact}${details.length ? " (" + details.join(", ") + ")" : ""}`;
    }
    function decisionImpactItem(label, value) {
      return `<div class="decision-impact__item"><span>${esc(label)}</span><strong>${esc(value)}</strong></div>`;
    }
    function decisionImpactHtml(item, action) {
      const canPersist = canPersistThroughBridge();
      const rows = [
        decisionImpactItem(uiText("currentAction", "Action"), action ? actionLabel(action) : uiText("noDecisionYet", "No decision selected")),
        decisionImpactItem(uiText("writeMode", "Write mode"), canPersist ? uiText("mcpWriteMode", "MCP save/apply") : uiText("copyOnlyMode", "Copy JSON only")),
      ];
      const targetSummary = editTargetSummary(item);
      const hasExplicitTarget = Boolean(item.data?.target_artifact || item.data?.target_field || item.data?.edit_hint);
      if (action === "edit" || hasExplicitTarget) {
        rows.push(decisionImpactItem(uiText("writeTarget", "Write target"), targetSummary || uiText("notTargeted", "No direct artifact target")));
      }
      const docs = requestedDocumentHints(item);
      if (action === "request_more_documents" || docs.length) {
        rows.push(decisionImpactItem(uiText("documentHint", "Document hint"), docs.length ? docs.join(", ") : uiText("noneValue", "None")));
      }
      return `<div class="decision-impact"><div class="decision-impact__title">${esc(uiText("decisionImpact", "Decision impact"))}</div><div class="decision-impact__grid">${rows.join("")}</div></div>`;
    }
    function decisionControlsHtml(item) {
      const decision = decisionFor(item.id);
      const action = decision?.action || "";
      const note = decision?.reviewer_note || "";
      const editValue = decision?.edit_value || "";
      const docs = Array.isArray(decision?.requested_documents) ? decision.requested_documents.join("\n") : "";
      const buttons = (item.allowed_actions || []).map((candidate) => `<button class="decision-choice" type="button" data-decision-action="${esc(candidate)}" aria-pressed="${candidate === action}">${esc(actionLabel(candidate))}${candidate === item.recommended_action ? " *" : ""}</button>`).join("");
      return `<section class="decision-box"><div class="decision-grid">${buttons}</div>${decisionImpactHtml(item, action)}<label class="field"><span class="field-label">${esc(ui("fields", "reviewerNote", "Reviewer note"))}</span><textarea data-decision-field="reviewer_note">${esc(note)}</textarea></label>${action === "edit" ? `<label class="field"><span class="field-label">${esc(ui("fields", "editValue", "Edit value"))}</span><textarea data-decision-field="edit_value">${esc(editValue)}</textarea></label>` : ""}${action === "request_more_documents" ? `<label class="field"><span class="field-label">${esc(ui("fields", "requestedDocuments", "Requested documents"))}</span><textarea data-decision-field="requested_documents">${esc(docs)}</textarea></label>` : ""}</section>`;
    }
    function detailsHtml(item) {
      if (!item) return items().length ? `<div class="empty">${esc(uiText("selectItem", "Select a review item."))}</div>` : `<div class="empty-state"><strong>${esc(uiText("waitingTitle", "Waiting for review data"))}</strong><p>${esc(uiText("waitingBody", "Render this widget from the MCP tool to load review items, evidence, and outputs."))}</p></div>`;
      const decision = decisionFor(item.id);
      const fields = [[ui("fields", "type", "Type"), humanize(item.item_type)], [ui("fields", "recommended", "Recommended"), actionLabel(item.recommended_action || "")], [ui("fields", "decision", "Decision"), decision ? actionLabel(decision.action) : ""], [ui("fields", "source", "Source"), item.source_path || ""], [ui("fields", "output", "Output"), item.output_path || ""]].filter(([, value]) => value);
      const status = statusFor(item);
      return `<section class="review-heading"><div><h3>${esc(item.title)}</h3><p>${esc(supportLine(item) || uiText("readyDecision", "Ready for reviewer decision."))}</p></div><span class="status-token">${esc(statusLabel(status))}</span></section><dl>${fields.map(([key, value]) => `<dt>${esc(key)}</dt><dd>${esc(value)}</dd>`).join("")}</dl>${outputLinkHtml(item.source_path, true)}${outputLinkHtml(item.output_path)}${decisionControlsHtml(item)}${workflowDetailHtml(item)}${evidenceHtml(item)}`;
    }
    function renderDetails() { document.getElementById("details").innerHTML = detailsHtml(itemById(state.selectedId)); }
    function artifactRecords() {
      const finalOutputs = Array.isArray(state.payload.final_artifacts?.outputs) ? state.payload.final_artifacts.outputs : [];
      if (finalOutputs.length) return finalOutputs;
      return items().filter((item) => String(item.item_type || "").includes("artifact") || item.output_path).map((item) => ({ path: item.output_path || item.title, kind: String(item.output_path || "file").split(".").pop(), status: item.data?.exists === false ? "missing" : "written" })).slice(0, 8);
    }
    function artifactMetaText(record) {
      const parts = [statusLabel(record.status || "written"), record.kind || "file"];
      if (record.size_bytes != null && record.size_bytes !== "") {
        parts.push(`${formatValue(record.size_bytes)} ${uiText("artifactBytes", "bytes")}`);
      }
      return parts.join(" · ");
    }
    function compactListValue(value) {
      if (value == null || value === "") return "";
      if (typeof value === "object") {
        if (value.action || value.followup_context || value.requested_documents) {
          return blockerSummary(value);
        }
        const candidate = value.title || value.reason || value.message || value.item_id || value.path || value.status || "";
        return candidate ? String(candidate) : JSON.stringify(value);
      }
      return formatValue(value);
    }
    function contextSummary(context, limit = 4) {
      if (!context || typeof context !== "object" || Array.isArray(context)) return "";
      const entries = Object.entries(context)
        .map(([key, value]) => {
          const formatted = formatValue(value);
          return formatted ? `${humanize(key)}: ${formatted}` : "";
        })
        .filter(Boolean);
      if (!entries.length) return "";
      const visible = entries.slice(0, limit).join("; ");
      const overflow = entries.length - limit;
      if (overflow <= 0) return visible;
      return `${visible}; ${uiText("artifactMore", "+{count} more").replace("{count}", overflow)}`;
    }
    function blockerSummary(value) {
      const head = value.title || value.item_id || statusLabel(value.status || value.action || "blocked");
      const parts = [head];
      const docs = listSummary(value.requested_documents, 2);
      if (docs) parts.push(`${ui("fields", "requestedDocuments", "Requested documents")}: ${docs}`);
      const context = contextSummary(value.followup_context, 4);
      if (context) parts.push(context);
      if (value.reviewer_note) parts.push(value.reviewer_note);
      return parts.filter(Boolean).join(" | ");
    }
    function listSummary(value, limit = 4) {
      const values = Array.isArray(value) ? value : [value];
      const entries = values.map(compactListValue).filter(Boolean);
      if (!entries.length) return "";
      const visible = entries.slice(0, limit).join(", ");
      const overflow = entries.length - limit;
      if (overflow <= 0) return visible;
      return `${visible}, ${uiText("artifactMore", "+{count} more").replace("{count}", overflow)}`;
    }
    function artifactTagHtml(label, value) {
      const summary = listSummary(value);
      if (!summary) return "";
      return `<span class="artifact-tag"><strong>${esc(label)}</strong>${esc(summary)}</span>`;
    }
    function sheetHeaderSummary(value) {
      if (!value || typeof value !== "object" || Array.isArray(value)) return "";
      return Object.entries(value).map(([sheet, headers]) => {
        const headerText = listSummary(Array.isArray(headers) ? headers : [headers], 3);
        return headerText ? `${sheet}: ${headerText}` : sheet;
      });
    }
    function cellSummary(value) {
      if (!value || typeof value !== "object" || Array.isArray(value)) return "";
      return Object.entries(value).map(([sheet, cells]) => {
        if (!cells || typeof cells !== "object" || Array.isArray(cells)) return sheet;
        const cellText = listSummary(Object.entries(cells).map(([cell, expected]) => `${cell}=${compactListValue(expected)}`), 3);
        return cellText ? `${sheet}: ${cellText}` : sheet;
      });
    }
    function artifactTagsHtml(record) {
      const tags = [
        record.row_count != null && record.row_count !== "" ? artifactTagHtml(uiText("artifactRows", "Rows"), record.row_count) : "",
        record.min_rows != null && record.min_rows !== "" ? artifactTagHtml(uiText("artifactMinRows", "Min rows"), record.min_rows) : "",
        artifactTagHtml(uiText("artifactSheets", "Sheets"), record.required_sheets),
        artifactTagHtml(uiText("artifactHeaders", "Headers"), sheetHeaderSummary(record.required_sheet_headers)),
        artifactTagHtml(uiText("artifactCells", "Cells"), cellSummary(record.required_cells)),
        artifactTagHtml(uiText("artifactText", "Text"), record.required_text),
        artifactTagHtml(uiText("artifactColumns", "Columns"), record.required_columns),
        artifactTagHtml(uiText("artifactRecords", "Records"), record.records_key),
      ].filter(Boolean);
      return tags.length ? `<div class="artifact-tags">${tags.join("")}</div>` : "";
    }
    function artifactDetailEntries(value) {
      if (value == null || value === "") return [];
      if (Array.isArray(value)) return value.map(compactListValue).filter(Boolean);
      if (typeof value === "object") {
        return Object.entries(value).map(([key, nested]) => {
          if (nested && typeof nested === "object" && !Array.isArray(nested)) {
            const nestedSummary = listSummary(Object.entries(nested).map(([nestedKey, nestedValue]) => `${nestedKey}=${compactListValue(nestedValue)}`), 8);
            return nestedSummary ? `${humanize(key)}: ${nestedSummary}` : humanize(key);
          }
          const nestedSummary = listSummary(nested, 8);
          return nestedSummary ? `${humanize(key)}: ${nestedSummary}` : humanize(key);
        }).filter(Boolean);
      }
      const single = compactListValue(value);
      return single ? [single] : [];
    }
    function artifactQaSectionHtml(label, value) {
      const entries = artifactDetailEntries(value);
      if (!entries.length) return "";
      const visible = entries.slice(0, 12);
      const overflow = entries.length - visible.length;
      const rows = visible.map((entry) => `<li>${esc(entry)}</li>`);
      if (overflow > 0) rows.push(`<li>${esc(uiText("artifactMore", "+{count} more").replace("{count}", overflow))}</li>`);
      return `<div class="artifact-qa-section"><strong>${esc(label)}</strong><ul>${rows.join("")}</ul></div>`;
    }
    function artifactQaHtml(record) {
      const sections = [
        artifactQaSectionHtml(uiText("artifactQaChecks", "QA checks"), record.qa_checks),
        artifactQaSectionHtml(uiText("artifactRequiredText", "Required text"), record.required_text),
        artifactQaSectionHtml(uiText("artifactRequiredColumns", "Required columns"), record.required_columns),
        artifactQaSectionHtml(uiText("artifactRequiredSheets", "Required sheets"), record.required_sheets),
        artifactQaSectionHtml(uiText("artifactRequiredHeaders", "Required headers"), record.required_sheet_headers),
        artifactQaSectionHtml(uiText("artifactRequiredCells", "Required cells"), record.required_cells),
      ].filter(Boolean);
      if (!sections.length) return "";
      return `<details class="artifact-qa"><summary>${esc(uiText("artifactQaDetails", "Verification details"))}</summary><div class="artifact-qa-grid">${sections.join("")}</div></details>`;
    }
    function artifactNoteHtml(label, values) {
      const summary = listSummary(values, 3);
      if (!summary) return "";
      return `<div class="artifact-note"><strong>${esc(label)}</strong><span>${esc(summary)}</span></div>`;
    }
    function artifactNotesHtml() {
      const artifacts = state.payload.final_artifacts || {};
      const notes = [
        artifactNoteHtml(uiText("blockers", "Blockers"), artifacts.blockers),
        artifactNoteHtml(uiText("caveats", "Caveats"), artifacts.caveats),
        artifactNoteHtml(uiText("nextActions", "Next actions"), artifacts.next_actions),
      ].filter(Boolean);
      return notes.length ? `<div class="artifact-notes">${notes.join("")}</div>` : "";
    }
    function outputLinkHtml(path, source = false) {
      if (!path) return "";
      const downloadable = !source && typeof window.localReviewDownloadOutput === "function";
      const label = activeLanguage() === "it" ? (downloadable ? "Scarica documento" : "Copia percorso") : (downloadable ? "Download file" : "Copy path");
      return `<button class="button" type="button" data-output-path="${esc(path)}" data-copy-only="${source}">${esc(label)}</button><span role="status" class="output-link-status"></span>`;
    }
    async function handleOutputLink(event) {
      const button = event.target.closest("button[data-output-path]");
      if (!button) return;
      const message = button.nextElementSibling;
      try {
        if (button.dataset.copyOnly !== "true" && typeof window.localReviewDownloadOutput === "function") await window.localReviewDownloadOutput(button.dataset.outputPath);
        else await navigator.clipboard.writeText(button.dataset.outputPath);
        const downloaded = button.dataset.copyOnly !== "true" && typeof window.localReviewDownloadOutput === "function";
        message.textContent = activeLanguage() === "it" ? (downloaded ? "Documento scaricato." : "Percorso copiato.") : (downloaded ? "File downloaded." : "Path copied.");
      } catch (error) { message.textContent = error.message || String(error); }
    }
    function artifactRecordHtml(record) {
      return `<div class="artifact-item"><strong>${esc(record.path || record.title || uiText("output", "Output"))}</strong><span>${esc(artifactMetaText(record))}</span>${artifactTagsHtml(record)}${artifactQaHtml(record)}${outputLinkHtml(record.path)}</div>`;
    }
    function renderArtifacts() {
      const records = artifactRecords();
      const node = document.getElementById("artifact-strip");
      if (!records.length && !items().length) { node.innerHTML = ""; node.style.display = "none"; return; }
      node.style.display = "";
      node.innerHTML = `<div class="artifact-header"><h2>${esc(uiText("finalOutputs", "Final outputs"))}</h2><span>${records.length} ${esc(records.length === 1 ? uiText("fileSingular", "file") : uiText("filePlural", "files"))}</span></div>${artifactNotesHtml()}<div class="artifact-grid">${records.length ? records.map(artifactRecordHtml).join("") : `<div class="empty">${esc(uiText("outputsPending", "Outputs appear after the run writes final artifacts."))}</div>`}</div>`;
    }
    function ensureDecision(item, action = null) {
      if (!item) return null;
      const current = state.decisions[item.id] || {};
      const nextAction = action || current.action || item.recommended_action || item.allowed_actions?.[0] || "mark_unclear";
      const requestedDocuments = Array.isArray(current.requested_documents) && current.requested_documents.length
        ? current.requested_documents
        : (nextAction === "request_more_documents" ? requestedDocumentHints(item) : []);
      state.decisions[item.id] = { item_id: item.id, action: nextAction, reviewer_note: current.reviewer_note || "", edit_value: current.edit_value ?? (CONFIG.plugin === "report-builder" && nextAction === "edit" ? String(item.data?.[item.data?.target_field] ?? "") : ""), requested_documents: requestedDocuments };
      return state.decisions[item.id];
    }
    function setDecisionAction(item, action) { if (!item || !action) return; ensureDecision(item, action); persistWidgetState(); renderRows(); }
    function setDecisionField(item, field, value) {
      const decision = ensureDecision(item);
      if (!decision) return;
      if (field === "requested_documents") decision.requested_documents = String(value || "").split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
      else decision[field] = String(value || "");
      persistWidgetState();
      renderRows();
    }
    function collectDecisionInputs() {
      return Object.values(state.decisions).filter((decision) => decision?.item_id && decision?.action && itemById(decision.item_id)).map((decision) => {
        const payload = { item_id: decision.item_id, action: decision.action };
        if (decision.reviewer_note) payload.reviewer_note = decision.reviewer_note.trim();
        if (decision.edit_value) payload.edit_value = decision.edit_value.trim();
        if (Array.isArray(decision.requested_documents) && decision.requested_documents.length) payload.requested_documents = decision.requested_documents;
        return payload;
      });
    }
    function validateDecisionInputs(decisions) {
      for (const decision of decisions) {
        if (decision.action === "edit" && !decision.edit_value) throw new Error(uiText("editRequired", "Edit value required for {item}.").replace("{item}", itemById(decision.item_id)?.title || decision.item_id));
      }
    }
    function fallbackUiDecisions() {
      const payload = reviewPayload();
      const now = new Date().toISOString();
      const decisions = collectDecisionInputs().map((decision) => {
        const item = itemById(decision.item_id);
        return { item_id: decision.item_id, item_type: item?.item_type || "", title: item?.title || "", action: decision.action, status: ACTION_STATUSES[decision.action] || "reviewed", decided_at: now, ...(decision.reviewer_note ? { reviewer_note: decision.reviewer_note } : {}), ...(decision.edit_value ? { edit_value: decision.edit_value } : {}), ...(decision.requested_documents?.length ? { requested_documents: decision.requested_documents } : {}) };
      });
      return { schema_version: payload.schema_version || "1.0", plugin: payload.plugin || CONFIG.plugin, workflow: payload.workflow || CONFIG.plugin, run_id: payload.run_id || "preview", decided_at: decisions.length ? now : null, decision_source: "mcp_widget_export", review_payload_path: state.payload.ui_decisions?.review_payload_path || "review_payload.json", decisions, decision_count: decisions.length, item_count: items().length, status: decisions.length === 0 ? "pending_review" : decisions.length === items().length ? "reviewed" : "partial_review" };
    }
    function saveToolArgs() {
      return {
        run_intake: state.payload.run_intake || null,
        review_payload: reviewPayload(),
        ui_decisions: state.payload.ui_decisions || null,
        decisions: collectDecisionInputs(),
        decision_source: "mcp_widget",
      };
    }
    function applyToolArgs() {
      return {
        run_intake: state.payload.run_intake || null,
        review_payload: reviewPayload(),
        ui_decisions: state.payload.ui_decisions || null,
        final_artifacts: state.payload.final_artifacts || null,
        decisions: collectDecisionInputs(),
        decision_source: "mcp_widget",
      };
    }
    function parseToolResult(result) {
      const privatePayload = pickPayload(result);
      if (privatePayload) return privatePayload;
      if (result?.structuredContent) return result.structuredContent;
      if (result?.ui_decisions || result?.ok != null) return result;
      const text = Array.isArray(result?.content) ? result.content.find((entry) => entry?.text)?.text : null;
      if (text) {
        try { return JSON.parse(text); } catch { return { ok: false, error: text }; }
      }
      return result || {};
    }
    async function copyText(text) {
      if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(text); return; }
      const textarea = document.createElement("textarea");
      textarea.value = text; textarea.setAttribute("readonly", ""); textarea.style.position = "fixed"; textarea.style.opacity = "0";
      document.body.appendChild(textarea); textarea.select(); document.execCommand("copy"); textarea.remove();
    }
    async function copyDecisionJson() { await copyText(`${JSON.stringify(fallbackUiDecisions(), null, 2)}\n`); }
    function setSaveStatus(message, kind = "") {
      const node = document.getElementById("save-status");
      node.textContent = message || "";
      node.className = `status-message${kind ? ` is-${kind}` : ""}`;
    }
    async function saveCurrentDecisions() {
      const saveTool = state.payload.decision_policy?.save_tool || CONFIG.saveTool;
      if (typeof window.openai?.callTool !== "function") {
        await copyDecisionJson();
        setRecoveryIssue("fallback", uiText("fallbackActive", "JSON fallback active"), uiText("fallbackBody", "Copy or download ui_decisions.json. Use the MCP or local-server review surface to persist and apply decisions."), saveTool);
        return { ok: true, copied: true, message: uiText("toolCopied", "Tool bridge unavailable. JSON copied.") };
      }
      const result = parseToolResult(await window.openai.callTool(saveTool, saveToolArgs()));
      if (!result?.ok) throw new Error(result?.error || uiText("saveFailed", "Decision save failed."));
      if (result.ui_decisions) state.payload.ui_decisions = result.ui_decisions;
      return result;
    }
    async function handleSaveDecisions() {
      const decisions = collectDecisionInputs();
      try { validateDecisionInputs(decisions); } catch (error) { setSaveStatus(error.message || String(error), "error"); return; }
      setSaveStatus(uiText("saving", "Saving..."));
      try {
        const result = await saveCurrentDecisions();
        if (!result.copied) clearRecoveryIssue();
        setSaveStatus(result.message || uiText("decisionsSaved", "Decisions saved."), "ok");
        renderProgress();
      } catch (error) {
        setRecoveryIssue("error", uiText("saveFailedTitle", "Save did not persist"), uiText("retryWithMcp", "Retry from the MCP or local-server review surface, or copy/download decision JSON for handoff."), state.payload.decision_policy?.save_tool || CONFIG.saveTool, error.message || String(error));
        setSaveStatus(error.message || String(error), "error");
      }
    }
    async function handleApplyDecisions() {
      const decisions = collectDecisionInputs();
      try { validateDecisionInputs(decisions); } catch (error) { setSaveStatus(error.message || String(error), "error"); return; }
      if (typeof window.openai?.callTool !== "function") {
        try {
          await copyDecisionJson();
          setRecoveryIssue("fallback", uiText("applyFailedTitle", "Apply did not persist"), uiText("applyRequiresMcp", "Apply requires the MCP or local-server review surface."), state.payload.decision_policy?.apply_tool || CONFIG.applyTool);
          setSaveStatus(uiText("toolCopiedApply", "Tool bridge unavailable. JSON copied; apply requires MCP."), "ok");
        } catch (error) {
          setRecoveryIssue("error", uiText("applyFailedTitle", "Apply did not persist"), uiText("retryWithMcp", "Retry from the MCP or local-server review surface, or copy/download decision JSON for handoff."), state.payload.decision_policy?.apply_tool || CONFIG.applyTool, error.message || String(error));
          setSaveStatus(error.message || String(error), "error");
        }
        return;
      }
      setSaveStatus(uiText("savingApplying", "Saving and applying..."));
      try {
        await saveCurrentDecisions();
        const applyTool = state.payload.decision_policy?.apply_tool || CONFIG.applyTool;
        const result = parseToolResult(await window.openai.callTool(applyTool, applyToolArgs()));
        if (!result?.ok) throw new Error(result?.error || uiText("applyFailed", "Decision apply failed."));
        if (result.final_artifacts) state.payload.final_artifacts = result.final_artifacts;
        if (result.applied_decisions) state.payload.applied_decisions = result.applied_decisions;
        clearRecoveryIssue();
        setSaveStatus(result.message || uiText("decisionsApplied", "Decisions applied."), "ok");
        render();
      } catch (error) {
        setRecoveryIssue("error", uiText("applyFailedTitle", "Apply did not persist"), uiText("retryWithMcp", "Retry from the MCP or local-server review surface, or copy/download decision JSON for handoff."), state.payload.decision_policy?.apply_tool || CONFIG.applyTool, error.message || String(error));
        setSaveStatus(error.message || String(error), "error");
      }
    }
    function downloadDecisionJson() {
      const blob = new Blob([`${JSON.stringify(fallbackUiDecisions(), null, 2)}\n`], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const anchor = document.createElement("a");
      anchor.href = url; anchor.download = "ui_decisions.json"; document.body.appendChild(anchor); anchor.click(); anchor.remove(); URL.revokeObjectURL(url);
      setSaveStatus(uiText("jsonDownloaded", "JSON downloaded."), "ok");
    }
    function applyRecommendedToVisible() { for (const item of filteredItems()) ensureDecision(item, item.recommended_action || item.allowed_actions?.[0] || "mark_unclear"); persistWidgetState(); renderRows(); }
    function persistWidgetState() {
      try { window.openai?.setWidgetState?.({ run_id: reviewPayload().run_id || null, decisions: state.decisions }); } catch { }
    }
    function loadInitialDecisions() {
      const current = {};
      let savedDecisionCount = 0;
      for (const decision of (Array.isArray(state.payload.ui_decisions?.decisions) ? state.payload.ui_decisions.decisions : [])) {
        if (decision?.item_id && decision?.action && itemById(decision.item_id)) {
          current[decision.item_id] = { item_id: decision.item_id, action: decision.action, reviewer_note: decision.reviewer_note || "", edit_value: decision.edit_value || "", requested_documents: Array.isArray(decision.requested_documents) ? decision.requested_documents : [] };
          savedDecisionCount += 1;
        }
      }
      const widgetState = window.openai?.widgetState;
      let draftDecisionCount = 0;
      if (widgetState?.run_id === reviewPayload().run_id && widgetState.decisions && typeof widgetState.decisions === "object") {
        for (const [itemId, decision] of Object.entries(widgetState.decisions)) if (itemById(itemId) && decision?.action) {
          current[itemId] = decision;
          draftDecisionCount += 1;
        }
      }
      state.decisions = current;
      state.recovery = { savedDecisionCount, draftDecisionCount };
    }
    function setButtonText(id, text) {
      const button = document.getElementById(id);
      if (button) button.textContent = text;
    }
    function renderChrome() {
      const lang = activeLanguage();
      const title = workflowText("title", CONFIG.title);
      document.documentElement.lang = lang;
      document.title = title;
      document.getElementById("app-title").textContent = title;
      document.getElementById("status-pill").textContent = uiText("mcpWidget", "MCP widget");
      setButtonText("use-recommended", ui("buttons", "useRecommended", "Use recommended"));
      setButtonText("save-decisions", ui("buttons", "saveDecisions", "Save decisions"));
      setButtonText("apply-decisions", ui("buttons", "applyDecisions", "Apply decisions"));
      setButtonText("copy-decisions", ui("buttons", "copyJson", "Copy JSON"));
      setButtonText("download-decisions", ui("buttons", "downloadJson", "Download JSON"));
      document.getElementById("search").placeholder = workflowText("search", "Search sample, journal row, mapping, extraction, artifact");
      document.getElementById("queue-title").textContent = workflowText("queueTitle", uiText("reviewQueue", "Review queue"));
      document.getElementById("detail-title").textContent = workflowText("detailTitle", uiText("evidenceDecision", "Evidence and decision"));
    }
    function loadDemoPayload() { state.payload = DEMO_PAYLOAD; state.selectedType = "all"; state.selectedState = "all"; state.selectedId = null; state.query = ""; document.getElementById("search").value = ""; loadInitialDecisions(); setSaveStatus(uiText("sampleLoaded", "Sample review loaded."), "ok"); render(); }
    function render() {
      renderChrome();
      renderSummary(); renderContext(); renderDataPosture(); renderExecutionProvenance(); renderReviewSafeguards(); renderTabs(); renderRows(); renderProgress(); renderArtifacts();
    }
    document.getElementById("artifact-strip").addEventListener("click", handleOutputLink);
    document.getElementById("details").addEventListener("click", handleOutputLink);
    document.getElementById("search").addEventListener("input", (event) => { state.query = event.target.value; renderRows(); });
    document.getElementById("tabs").addEventListener("click", (event) => { const button = event.target.closest("button[data-type]"); if (!button) return; state.selectedType = button.dataset.type; state.selectedId = null; render(); });
    document.getElementById("state-strip").addEventListener("click", (event) => { const button = event.target.closest("button[data-state-filter]"); if (!button) return; state.selectedState = button.dataset.stateFilter; state.selectedId = null; render(); });
    document.getElementById("rows").addEventListener("click", (event) => {
      const demoButton = event.target.closest("button[data-load-demo]"); if (demoButton) { loadDemoPayload(); return; }
      const emptyButton = event.target.closest("#copy-empty-contract"); if (emptyButton) { copyDecisionJson().then(() => setSaveStatus(uiText("emptyJsonCopied", "Empty decision JSON copied."), "ok")).catch((error) => setSaveStatus(error.message || String(error), "error")); return; }
      const button = event.target.closest("button[data-id]"); if (!button) return; state.selectedId = button.dataset.id; renderRows();
    });
    document.getElementById("details").addEventListener("click", (event) => { const button = event.target.closest("button[data-decision-action]"); if (!button) return; setDecisionAction(itemById(state.selectedId), button.dataset.decisionAction); });
    document.getElementById("details").addEventListener("input", (event) => { const field = event.target.closest("[data-decision-field]"); if (!field) return; setDecisionField(itemById(state.selectedId), field.dataset.decisionField, field.value); });
    document.getElementById("use-recommended").addEventListener("click", applyRecommendedToVisible);
    document.getElementById("save-decisions").addEventListener("click", handleSaveDecisions);
    document.getElementById("apply-decisions").addEventListener("click", handleApplyDecisions);
    document.getElementById("copy-decisions").addEventListener("click", () => copyDecisionJson().then(() => setSaveStatus(uiText("jsonCopied", "JSON copied."), "ok")).catch((error) => setSaveStatus(error.message || String(error), "error")));
    document.getElementById("download-decisions").addEventListener("click", downloadDecisionJson);
    window.addEventListener("message", (event) => {
      if (event?.data?.method !== "ui/notifications/tool-result") return;
      const nextPayload = pickPayload(event.data.params);
      if (!nextPayload || (nextPayload.widget_type !== CONFIG.widgetType && !nextPayload.review_payload)) return;
      state.payload = nextPayload;
      loadInitialDecisions();
      render();
    });
    state.payload = toolOutput();
    loadInitialDecisions();
    render();
  </script>
</body>
</html>

SHA-256: 138d57073a3a9648ed1431737e882d4476c77a23b767d2f67a43dbde7e4d22fb