<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>GRN-{{grn_number}}</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }

    body {
      font-family: 'Segoe UI', Arial, sans-serif;
      background: #f4f5f7;
      padding: 20px;
      font-size: 13px;
      line-height: 1.5;
      color: #212529;
    }

    /* ── Outer page wrapper ── */
    .page-wrapper {
      max-width: 1200px;
      margin: 0 auto;
    }

    /* ── Top bar ── */
    .top-bar {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;
    }
    .breadcrumb {
      font-size: 12px;
      color: #6c757d;
    }
    .breadcrumb span { color: #4361ee; font-weight: 500; }
    .btn-back {
      border: 0.5px solid #dee2e6;
      border-radius: 6px;
      padding: 5px 12px;
      font-size: 12px;
      background: #fff;
      color: #495057;
      display: flex;
      align-items: center;
      gap: 4px;
    }

    /* ── Card ── */
    .card {
      background: #fff;
      border: 0.5px solid #dee2e6;
      border-radius: 12px;
      padding: 20px 24px;
      box-shadow: 0 1px 4px rgba(0,0,0,.06);
    }

    /* ── Header ── */
    .grn-header {
      position: relative;
      text-align: center;
      border-bottom: 2px solid #4361ee;
      padding-bottom: 12px;
      margin-bottom: 16px;
    }
    .grn-header h4 {
      font-weight: 700;
      font-size: 16px;
      letter-spacing: 1px;
      color: #1a1f36;
      margin-bottom: 2px;
      text-transform: uppercase;
    }
    .grn-header p {
      font-size: 12px;
      color: #6c757d;
    }
    .grn-meta {
      position: absolute;
      top: 0;
      right: 0;
      text-align: right;
      font-size: 12px;
    }
    .grn-meta span { color: #6c757d; }
    .grn-meta strong { color: #1a1f36; }

    /* ── 3-col info strip ── */
    .info-strip {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      gap: 10px;
      margin-bottom: 16px;
    }
    .info-card {
      border: 0.5px solid #dee2e6;
      border-radius: 8px;
      padding: 10px 12px;
      background: #f8f9fa;
    }
    .info-card-hd {
      font-size: 10px;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.7px;
      color: #6c757d;
      margin-bottom: 8px;
      display: flex;
      align-items: center;
      gap: 4px;
    }
    .info-card-hd svg { width: 12px; height: 12px; }
    .company-row {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-bottom: 8px;
    }
    .company-logo {
      height: 22px;
      max-width: 80px;
      object-fit: contain;
    }
    .logo-placeholder {
      width: 24px; height: 24px;
      background: #4361ee;
      border-radius: 4px;
      display: flex; align-items: center; justify-content: center;
      font-size: 9px; color: #fff; font-weight: 700; letter-spacing: 0.5px;
    }
    .company-name-label {
      font-size: 13px;
      font-weight: 600;
      color: #1a1f36;
    }
    .ic-addr { font-size: 11px; color: #6c757d; line-height: 1.5; margin-bottom: 3px; white-space: pre-line; }
    .ic-tag  { font-size: 11px; color: #6c757d; margin-bottom: 2px; }
    .ic-tag strong { color: #212529; }

    /* vendor kv */
    .kv { display: flex; gap: 6px; font-size: 11px; margin-bottom: 3px; align-items: flex-start; }
    .kv-label { color: #6c757d; min-width: 52px; flex-shrink: 0; }
    .kv-val   { color: #212529; font-weight: 500; word-break: break-all; }

    /* reference rows */
    .ref-row {
      display: flex;
      justify-content: space-between;
      font-size: 11px;
      padding: 4px 0;
      border-bottom: 0.5px dashed #dee2e6;
      gap: 8px;
    }
    .ref-row:last-child { border-bottom: none; }
    .ref-label { color: #6c757d; }
    .ref-val   { font-weight: 600; color: #212529; text-align: right; }
    .ref-na    { color: #adb5bd; font-style: italic; font-weight: 400; }

    /* ── Items Table ── */
    .section-title {
      font-weight: 600;
      font-size: 13px;
      margin-bottom: 8px;
      color: #1a1f36;
    }
    .table-wrap { overflow-x: auto; margin-bottom: 12px; }
    table { width: 100%; border-collapse: collapse; font-size: 12px; }
    th, td {
      border: 0.5px solid #dee2e6;
      padding: 7px 8px;
      vertical-align: middle;
    }
    th {
      background: #f8f9fa;
      font-weight: 600;
      font-size: 11px;
      text-transform: uppercase;
      letter-spacing: 0.4px;
      text-align: center;
      color: #6c757d;
      white-space: nowrap;
    }
    td.text-center { text-align: center; }
    td.text-right  { text-align: right; padding-right: 8px; }
    td.text-left   { text-align: left; }
    td.fw-500      { font-weight: 500; }

    /* input cells */
    .num-input {
      border: 0.5px solid #ced4da;
      border-radius: 4px;
      padding: 4px 6px;
      width: 80px;
      text-align: center;
      background: #fff;
      font-size: 12px;
      color: #212529;
    }
    .loc-input {
      border: 0.5px solid #ced4da;
      border-radius: 4px;
      padding: 4px 6px;
      width: 120px;
      background: #fff;
      font-size: 12px;
      color: #212529;
    }
    /* disabled state */
    .num-input:disabled, .loc-input:disabled {
      background: #f8f9fa;
      color: #6c757d;
    }

    /* tfoot */
    tfoot tr td {
      background: #f8f9fa;
      font-weight: 600;
    }

    /* ── Amount in words + Grand Total ── */
    .totals-row {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      border-top: 0.5px solid #dee2e6;
      padding-top: 12px;
      flex-wrap: wrap;
      gap: 10px;
      margin-bottom: 20px;
    }
    .words-box {
      font-size: 12px;
      color: #6c757d;
      max-width: 60%;
    }
    .words-box strong { color: #212529; }
    .grand-box {
      border: 0.5px solid #dee2e6;
      border-radius: 8px;
      padding: 10px 16px;
      background: #f8f9fa;
      text-align: right;
      min-width: 200px;
    }
    .grand-box .lbl { font-size: 11px; color: #6c757d; margin-bottom: 4px; }
    .grand-box .val { font-weight: 600; font-size: 20px; color: #1a1f36; }

    /* ── Signatory ── */
    .signatory {
      text-align: right;
      margin-bottom: 24px;
    }
    .signatory-inner {
      display: inline-block;
      text-align: center;
      border-top: 0.5px solid #dee2e6;
      padding-top: 8px;
      min-width: 180px;
    }
    .signatory-inner .co { font-size: 12px; color: #6c757d; margin-bottom: 2px; }
    .signatory-inner .auth { font-size: 12px; font-weight: 600; color: #212529; }

    /* ── Approval Workflow ── */
    .workflow-section {
      border-top: 0.5px solid #dee2e6;
      padding-top: 14px;
    }
    .workflow-hd {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-bottom: 14px;
    }
    .workflow-hd h6 {
      font-weight: 600;
      font-size: 13px;
      margin: 0;
      color: #1a1f36;
    }
    .badge-count {
      font-size: 10px;
      padding: 2px 7px;
      border-radius: 4px;
      background: #e9ecef;
      color: #6c757d;
      font-weight: 600;
    }
    .approvers-wrap { display: flex; flex-wrap: wrap; gap: 12px; }

    /* approver card */
    .approver-card {
      border: 0.5px solid #dee2e6;
      border-radius: 8px;
      padding: 12px;
      min-width: 200px;
      background: #fff;
    }
    .approver-card.is-clickable {
      border-color: #4361ee;
      background: #f0f4ff;
    }
    .approver-card.is-auto {
      border-color: #17a2b8;
      background: #e8f8fa;
    }
    .av-row { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 0; }
    .avatar {
      width: 34px; height: 34px;
      border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      color: #fff;
      font-weight: 600;
      font-size: 13px;
      flex-shrink: 0;
    }
    .av-name { font-weight: 600; font-size: 13px; color: #1a1f36; }
    .av-badges { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-top: 3px; }
    .av-role   { font-size: 11px; color: #6c757d; }
    .badge {
      font-size: 9px;
      padding: 2px 6px;
      border-radius: 4px;
      font-weight: 600;
      white-space: nowrap;
    }
    .b-success  { background: #d1f0da; color: #157347; }
    .b-danger   { background: #fde8e8; color: #b02a37; }
    .b-secondary{ background: #e9ecef; color: #6c757d; }
    .b-primary  { background: #dce7fd; color: #3451c7; }
    .b-info     { background: #d0f0f8; color: #0c7391; }
    .auto-note  { font-size: 10px; color: #17a2b8; margin-top: 4px; }
    .reject-note{ font-size: 10px; color: #dc3545; margin-top: 4px; }
    .action-btns {
      display: flex;
      gap: 8px;
      margin-top: 10px;
    }
    .btn-approve {
      flex: 1;
      border: 0.5px solid #28a745;
      border-radius: 6px;
      padding: 5px 10px;
      font-size: 12px;
      background: #d1f0da;
      color: #157347;
      cursor: pointer;
      display: flex; align-items: center; justify-content: center; gap: 4px;
    }
    .btn-reject {
      flex: 1;
      border: 0.5px solid #dc3545;
      border-radius: 6px;
      padding: 5px 10px;
      font-size: 12px;
      background: transparent;
      color: #dc3545;
      cursor: pointer;
      display: flex; align-items: center; justify-content: center; gap: 4px;
    }

    /* ── Bottom Buttons ── */
    .bottom-btns {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
      margin-top: 20px;
      padding-top: 12px;
      border-top: 0.5px solid #dee2e6;
    }
    .btn-outline {
      border: 0.5px solid #dee2e6;
      border-radius: 6px;
      padding: 6px 14px;
      font-size: 13px;
      background: #fff;
      color: #495057;
      cursor: pointer;
    }
    .btn-primary {
      border: none;
      border-radius: 6px;
      padding: 6px 16px;
      font-size: 13px;
      background: #4361ee;
      color: #fff;
      cursor: pointer;
      display: flex; align-items: center; gap: 6px;
    }
    .btn-primary:disabled, .btn-outline:disabled {
      opacity: 0.55;
      cursor: not-allowed;
    }

    /* ── Spinner ── */
    .spinner {
      display: none;
      width: 14px; height: 14px;
      border: 2px solid rgba(255,255,255,.4);
      border-top-color: #fff;
      border-radius: 50%;
      animation: spin .6s linear infinite;
    }
    @keyframes spin { to { transform: rotate(360deg); } }

    /* ── Modal overlay ── */
    .modal-overlay {
      display: none;
      position: fixed;
      inset: 0;
      background: rgba(0,0,0,.5);
      z-index: 9999;
      align-items: center;
      justify-content: center;
    }
    .modal-overlay.open { display: flex; }
    .modal-box {
      background: #fff;
      border-radius: 10px;
      width: 380px;
      max-width: 95vw;
      box-shadow: 0 8px 32px rgba(0,0,0,.18);
      overflow: hidden;
    }
    .modal-header {
      padding: 16px 20px 10px;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .modal-header h5 {
      font-weight: 700;
      font-size: 15px;
      display: flex;
      align-items: center;
      gap: 8px;
    }
    .modal-close {
      background: none;
      border: none;
      font-size: 18px;
      cursor: pointer;
      color: #6c757d;
      line-height: 1;
      padding: 0 4px;
    }
    .modal-body { padding: 10px 20px 12px; }
    .modal-av-row {
      display: flex;
      gap: 12px;
      align-items: center;
      margin-bottom: 12px;
    }
    .modal-av {
      width: 46px; height: 46px;
      border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      font-weight: 700; font-size: 16px; color: #fff; flex-shrink: 0;
    }
    .alert-admin {
      background: #dce7fd;
      color: #3451c7;
      border-radius: 6px;
      padding: 8px 12px;
      font-size: 12px;
      margin-bottom: 10px;
    }
    .modal-note { font-size: 12px; color: #6c757d; }
    .modal-footer {
      padding: 8px 20px 16px;
      display: flex;
      justify-content: flex-end;
      gap: 8px;
    }
    .modal-btn-cancel {
      border: 0.5px solid #dee2e6;
      border-radius: 6px;
      padding: 5px 14px;
      font-size: 13px;
      background: #f8f9fa;
      color: #495057;
      cursor: pointer;
    }
    .modal-btn-approve {
      border: none;
      border-radius: 6px;
      padding: 5px 20px;
      font-size: 13px;
      background: #28a745;
      color: #fff;
      cursor: pointer;
      display: flex; align-items: center; gap: 6px;
    }
    .modal-btn-reject {
      border: none;
      border-radius: 6px;
      padding: 5px 20px;
      font-size: 13px;
      background: #dc3545;
      color: #fff;
      cursor: pointer;
      display: flex; align-items: center; gap: 6px;
    }
    .form-label { font-size: 12px; font-weight: 600; margin-bottom: 4px; display: block; }
    .form-label span { color: #dc3545; }
    textarea.form-control {
      width: 100%;
      border: 0.5px solid #ced4da;
      border-radius: 6px;
      padding: 7px 10px;
      font-size: 12px;
      resize: vertical;
      font-family: inherit;
      color: #212529;
    }
    textarea.form-control:focus { outline: none; border-color: #4361ee; }
    .reject-hint { font-size: 11px; color: #6c757d; margin-top: 4px; }

    /* ── Terms ── */
    .terms-section {
      border-top: 0.5px solid #dee2e6;
      padding-top: 12px;
      margin-top: 16px;
    }
    .terms-title {
      font-weight: 600;
      font-size: 12px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      margin-bottom: 10px;
      color: #1a1f36;
    }
    .term-item { font-size: 12px; margin-bottom: 8px; color: #212529; }
    .term-item b { color: #1a1f36; }
    .term-desc { margin-left: 12px; color: #495057; }

    /* ── Footer ── */
    .grn-footer {
      margin-top: 20px;
      text-align: center;
      font-size: 10px;
      color: #6c757d;
      border-top: 0.5px solid #dee2e6;
      padding-top: 10px;
    }

    /* ── Print ── */
    @media print {
      body { background: #fff; padding: 0; }
      .card { box-shadow: none; border: none; }
      .top-bar, .bottom-btns, .modal-overlay { display: none !important; }
      .num-input, .loc-input { border: none; background: transparent; }
    }
  </style>
</head>
<body>

<div class="page-wrapper">

  <!-- TOP BAR -->
  <div class="top-bar">
    <div class="breadcrumb">
      Procurement &rsaquo; <span>Goods Receipt Note</span> &rsaquo; GRN View
    </div>
    <button class="btn-back" onclick="history.back()">
      &#8592; Back to List
    </button>
  </div>

  <div class="card">

    <!-- HEADER -->
    <div class="grn-header">
      <h4>Goods Receipt Note</h4>
      <p>Goods Receipt Note For Materials Received</p>
      <div class="grn-meta">
        <div><span>GRN No: </span><strong id="meta-grn-number">{{grn_number}}</strong></div>
        <div><span>Date: </span><span id="meta-grn-date">{{grn_date}}</span></div>
      </div>
    </div>

    <!-- INFO STRIP: FROM / VENDOR / REFERENCE -->
    <div class="info-strip">

      <!-- FROM -->
      <div class="info-card">
        <div class="info-card-hd">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 21h18M9 21V7l6-4v18M9 10h6"/></svg>
          From
        </div>
        <div class="company-row">
          {{#if logo_url}}
          <img src="{{logo_url}}" alt="Logo" class="company-logo" onerror="this.style.display='none'" />
          {{else}}
          <div class="logo-placeholder" id="logo-initials">{{company_initials}}</div>
          {{/if}}
          <span class="company-name-label" id="from-name">{{company_name}}</span>
        </div>
        <p class="ic-addr" id="from-address">{{company_address}}</p>
        <p class="ic-tag">GST: <strong id="from-gst">{{company_gst}}</strong></p>
        <p class="ic-tag" style="margin-bottom:0;">CIN: <strong id="from-cin">{{company_cin}}</strong></p>
      </div>

      <!-- VENDOR -->
      <div class="info-card">
        <div class="info-card-hd">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="1" y="3" width="15" height="13"/><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg>
          Vendor
        </div>
        <p style="font-size:13px;font-weight:600;color:#1a1f36;margin-bottom:6px;" id="vendor-name">{{vendor_name}}</p>
        {{#if vendor_contact_person}}
        <div class="kv"><span class="kv-label">Contact</span><span class="kv-val" id="vendor-contact">{{vendor_contact_person}}</span></div>
        {{/if}}
        <div class="kv"><span class="kv-label">Phone</span><span class="kv-val" id="vendor-phone">{{vendor_phone}}</span></div>
        {{#if vendor_email}}
        <div class="kv"><span class="kv-label">Email</span><span class="kv-val" id="vendor-email">{{vendor_email}}</span></div>
        {{/if}}
        {{#if vendor_gstin}}
        <div class="kv"><span class="kv-label">GSTIN</span><span class="kv-val" id="vendor-gstin">{{vendor_gstin}}</span></div>
        {{/if}}
        <div class="kv"><span class="kv-label">Address</span><span class="kv-val" id="vendor-address">{{vendor_full_address}}</span></div>
      </div>

      <!-- REFERENCE -->
      <div class="info-card">
        <div class="info-card-hd">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
          Reference Info
        </div>
        <div class="ref-row">
          <span class="ref-label">PO Reference</span>
          <span id="ref-po" class="ref-val">{{po_number}}</span>
        </div>
        <div class="ref-row">
          <span class="ref-label">Invoice No</span>
          <span id="ref-inv" class="ref-val">{{invoice_no}}</span>
        </div>
        <div class="ref-row">
          <span class="ref-label">Delivery Challan</span>
          <span id="ref-dc" class="ref-val">{{delivery_challan_no}}</span>
        </div>
        <div class="ref-row">
          <span class="ref-label">Gate Entry No</span>
          <span id="ref-ge" class="ref-val">{{gate_entry_no}}</span>
        </div>
        <div class="ref-row">
          <span class="ref-label">Vehicle No</span>
          <span id="ref-veh" class="ref-val">{{vehicle_number}}</span>
        </div>
      </div>

    </div><!-- /info-strip -->

    <!-- ITEMS TABLE -->
    <div class="section-title">Item Details</div>
    <div class="table-wrap">
      <table id="items-table">
        <thead>
          <tr>
            <th style="width:36px;">#</th>
            <th style="min-width:160px;text-align:left;">Item Name</th>
            <th style="min-width:88px;">Ordered</th>
            <th style="min-width:88px;">Received</th>
            <th style="min-width:88px;">Accepted</th>
            <th style="min-width:88px;">Rejected</th>
            <th style="min-width:110px;">Unit Price</th>
            <th style="min-width:110px;">Acc. Total</th>
            <th style="min-width:110px;">Rej. Price</th>
            <th style="min-width:110px;">Rej. Total</th>
            <th style="min-width:120px;">Grand Total</th>
            <th style="min-width:140px;">Store Location</th>
          </tr>
        </thead>
        <tbody id="items-tbody">
          <!-- Rows rendered by JS from GRN_DATA.items -->
        </tbody>
        <tfoot>
          <tr>
            <td colspan="2" class="text-right">Totals</td>
            <td class="text-center" id="ft-ordered">0</td>
            <td class="text-center" id="ft-received">0</td>
            <td class="text-center" id="ft-accepted">0</td>
            <td class="text-center" id="ft-rejected">0</td>
            <td class="text-center">—</td>
            <td class="text-right" id="ft-acc-total">₹0.00</td>
            <td class="text-center">—</td>
            <td class="text-right" id="ft-rej-total">₹0.00</td>
            <td class="text-right" id="ft-grand">₹0.00</td>
            <td></td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- AMOUNT IN WORDS + GRAND TOTAL -->
    <div class="totals-row">
      <div class="words-box">
        <strong>Amount in Words: </strong>
        <span id="amount-words">—</span>
      </div>
      <div class="grand-box">
        <div class="lbl">Grand Total</div>
        <div class="val" id="grand-total-display">₹0.00</div>
      </div>
    </div>

    <!-- AUTHORIZED SIGNATORY -->
    <div class="signatory">
      <div class="signatory-inner">
        <p class="co" id="sig-company">{{company_name}}</p>
        <p class="auth">Authorized Signatory</p>
      </div>
    </div>

    <!-- TERMS & CONDITIONS (optional) -->
    <div id="terms-section" class="terms-section" style="display:none;">
      <div class="terms-title">Terms &amp; Conditions :</div>
      <div id="terms-body"></div>
    </div>

    <!-- APPROVAL WORKFLOW -->
    <div class="workflow-section">
      <div class="workflow-hd">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#4361ee" stroke-width="2"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>
        <h6>Approval Workflow</h6>
        <span class="badge-count" id="workflow-count">0</span>
      </div>
      <div class="approvers-wrap" id="approvers-wrap">
        <!-- Rendered by JS -->
      </div>
    </div>

    <!-- BOTTOM BUTTONS -->
    <div class="bottom-btns">
      <button class="btn-outline" onclick="history.back()">Back to List</button>
      <button class="btn-primary" id="save-btn" onclick="saveChanges()" style="display:none;">
        <span class="spinner" id="save-spinner"></span>
        <span id="save-btn-text">&#128190; Save Changes</span>
      </button>
    </div>

    <!-- FOOTER -->
    <div class="grn-footer">
      <p>Generated on: <span id="footer-date"></span> | Created by: <span id="footer-created-by">{{created_by_name}}</span></p>
    </div>

  </div><!-- /card -->
</div><!-- /page-wrapper -->


<!-- ══ APPROVE MODAL ══ -->
<div class="modal-overlay" id="modal-approve">
  <div class="modal-box">
    <div class="modal-header">
      <h5 style="color:#28a745;">&#10003; Confirm Approval</h5>
      <button class="modal-close" onclick="closeModal('approve')">&times;</button>
    </div>
    <div class="modal-body">
      <div class="modal-av-row">
        <div class="modal-av" id="approve-av" style="background:#28a745;"></div>
        <div>
          <div style="font-weight:700;" id="approve-name"></div>
          <div style="font-size:12px;color:#6c757d;" id="approve-role"></div>
        </div>
      </div>
      <div class="alert-admin" id="approve-admin-note" style="display:none;">
        &#128081; Admin approval will auto-approve all remaining approvers.
      </div>
      <p class="modal-note">Are you sure you want to approve this GRN? This action will be recorded.</p>
    </div>
    <div class="modal-footer">
      <button class="modal-btn-cancel" onclick="closeModal('approve')">Cancel</button>
      <button class="modal-btn-approve" id="approve-confirm-btn" onclick="confirmApprove()">
        <span class="spinner" id="approve-spinner"></span>
        &#10003; Approve
      </button>
    </div>
  </div>
</div>

<!-- ══ REJECT MODAL ══ -->
<div class="modal-overlay" id="modal-reject">
  <div class="modal-box">
    <div class="modal-header">
      <h5 style="color:#dc3545;">&#10005; Confirm Rejection</h5>
      <button class="modal-close" onclick="closeModal('reject')">&times;</button>
    </div>
    <div class="modal-body">
      <div class="modal-av-row">
        <div class="modal-av" id="reject-av" style="background:#dc3545;"></div>
        <div>
          <div style="font-weight:700;" id="reject-name"></div>
          <div style="font-size:12px;color:#6c757d;" id="reject-role"></div>
        </div>
      </div>
      <label class="form-label">Rejection Reason <span>*</span></label>
      <textarea class="form-control" id="rejection-reason" rows="3" placeholder="Provide a reason for rejection..."></textarea>
      <p class="reject-hint">Note: Rejecting will reset all previous approvals.</p>
    </div>
    <div class="modal-footer">
      <button class="modal-btn-cancel" onclick="closeModal('reject')">Cancel</button>
      <button class="modal-btn-reject" id="reject-confirm-btn" onclick="confirmReject()">
        <span class="spinner" id="reject-spinner"></span>
        &#10005; Reject
      </button>
    </div>
  </div>
</div>


<script>
// ════════════════════════════════════════════════════
//  GRN_DATA  — replace this object with your backend
//  JSON (server-side render or fetch + hydrate)
// ════════════════════════════════════════════════════
const GRN_DATA = {
  grn_number: "GRN-2025-0041",
  grn_date: "2025-05-15",
  created_by_name: "Arjun Sharma",
  remarks: "",

  company: {
    name: "VIVEK BIO-PRODUCTS",
    initials: "VB",
    logo_url: "",
    address: "1-8-303/48/15, KRK House, P.G. Road,\nBegumpet, Hyderabad – 500003,\nTelangana, India.",
    gst: "36AFNPV7082B2Z1",
    cin: "U31909TG2016PTC112345"
  },

  vendor: {
    name: "Pharmex Supplies Pvt. Ltd.",
    contact_person: "Rajesh Kumar",
    phone: "+91 98765 43210",
    email: "rajesh@pharmex.in",
    gstin: "27AABCP1234F1Z5",
    full_address: "Mumbai, Maharashtra"
  },

  reference: {
    po_number: "PO-2025-0099",
    invoice_no: "INV-7823",
    delivery_challan_no: "DC-4561",
    gate_entry_no: "GE-112",
    vehicle_number: ""
  },

  items: [
    { id: 1, item_name: "Amoxicillin 500mg Capsules",  ordered_qty: 500,  received_qty: 500,  accepted_qty: 490, rejected_qty: 10, unit_price: 12.50, rejected_unit_price: 10.00, store_location: "Main Store" },
    { id: 2, item_name: "Paracetamol 650mg Tablets",   ordered_qty: 1000, received_qty: 1000, accepted_qty: 1000, rejected_qty: 0, unit_price: 3.20,  rejected_unit_price: 0.00,  store_location: "Cold Storage" },
    { id: 3, item_name: "Vitamin C 1000mg Sachets",    ordered_qty: 200,  received_qty: 200,  accepted_qty: 195, rejected_qty: 5,  unit_price: 45.00, rejected_unit_price: 40.00, store_location: "Main Store"  }
  ],

  terms: [
    { term: "Quality Inspection",   description: "All items must be inspected within 48 hours of receipt." },
    { term: "Rejection Policy",     description: "Rejected items must be returned within 7 working days." }
  ],

  workflow: {
    users: [
      { user_id: 101, first_name: "Arjun",  last_name: "Sharma", role: "Store Manager" },
      { user_id: 102, first_name: "Priya",  last_name: "Nair",   role: "Purchase Head" },
      { user_id: 103, first_name: "Vikram", last_name: "Reddy",  role: "CEO" }
    ],
    // Possible status values per user_id: "pending" | "approved" | "rejected" | "auto_approved"
    statuses: {
      101: { status: "approved", approved_at: "2025-05-15T10:30:00Z" },
      102: { status: "pending" },
      103: { status: "pending" }
    }
  }
};

// ════════════════════════════════════════════════════
//  Helpers
// ════════════════════════════════════════════════════
function fmtIndian(num) {
  const n = Number(num) || 0;
  const [int, dec] = n.toFixed(2).split(".");
  const last3 = int.slice(-3);
  const rest = int.slice(0, -3);
  const fmt = rest ? rest.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + "," + last3 : last3;
  return fmt + "." + dec;
}

function numberToWords(num) {
  const a = ["","ONE","TWO","THREE","FOUR","FIVE","SIX","SEVEN","EIGHT","NINE",
    "TEN","ELEVEN","TWELVE","THIRTEEN","FOURTEEN","FIFTEEN","SIXTEEN",
    "SEVENTEEN","EIGHTEEN","NINETEEN"];
  const b = ["","","TWENTY","THIRTY","FORTY","FIFTY","SIXTY","SEVENTY","EIGHTY","NINETY"];
  function inWords(n) {
    if (n < 20)       return a[n];
    if (n < 100)      return (b[Math.floor(n/10)] + " " + a[n%10]).trim();
    if (n < 1000)     return (a[Math.floor(n/100)] + " HUNDRED " + inWords(n%100)).trim();
    if (n < 100000)   return (inWords(Math.floor(n/1000)) + " THOUSAND " + inWords(n%1000)).trim();
    if (n < 10000000) return (inWords(Math.floor(n/100000)) + " LAKH " + inWords(n%100000)).trim();
    return (inWords(Math.floor(n/10000000)) + " CRORE " + inWords(n%10000000)).trim();
  }
  if (!num) return "ZERO";
  return inWords(Math.round(num)).trim();
}

function fmtDate(d) {
  if (!d) return "—";
  const dt = new Date(d);
  return dt.toLocaleDateString("en-IN", { day:"2-digit", month:"2-digit", year:"numeric" });
}

function isAdminRole(role) {
  return ["admin","ceo","superadmin"].includes((role||"").toLowerCase());
}

// ════════════════════════════════════════════════════
//  State
// ════════════════════════════════════════════════════
let items       = JSON.parse(JSON.stringify(GRN_DATA.items));
let origItems   = JSON.parse(JSON.stringify(GRN_DATA.items));
let approvalStatuses = JSON.parse(JSON.stringify(GRN_DATA.workflow.statuses));
let workflowUsers    = GRN_DATA.workflow.users;
let hasChanges  = false;
let selectedApprover = null;
let processing  = false;

// Compute derived values for each item
function computeItem(item) {
  item.total_price          = (item.accepted_qty || 0) * (item.unit_price || 0);
  item.rejected_total_price = (item.rejected_qty || 0) * (item.rejected_unit_price || 0);
  item.grand_total          = item.total_price + item.rejected_total_price;
  return item;
}
items.forEach(computeItem);
origItems.forEach(computeItem);

// ════════════════════════════════════════════════════
//  Approval helpers
// ════════════════════════════════════════════════════
function isFullyApproved() {
  return workflowUsers.length > 0 && workflowUsers.every(u => {
    const s = approvalStatuses[u.user_id]?.status;
    return s === "approved" || s === "auto_approved";
  });
}
function hasAnyRejection() {
  return Object.values(approvalStatuses).some(s => s.status === "rejected");
}
function isInputDisabled() { return isFullyApproved() || hasAnyRejection(); }

function isApproverClickable(user) {
  const s = approvalStatuses[user.user_id]?.status;
  if (s === "approved" || s === "auto_approved") return false;
  if (isFullyApproved()) return false;
  if (isAdminRole(user.role)) return true;
  const sorted = [...workflowUsers].sort((a,b) => (a.approval_order||0)-(b.approval_order||0));
  for (const wu of sorted) {
    const ws = approvalStatuses[wu.user_id]?.status;
    if (ws !== "approved") return wu.user_id === user.user_id;
  }
  return false;
}

// ════════════════════════════════════════════════════
//  Totals
// ════════════════════════════════════════════════════
function calcTotals() {
  return items.reduce((acc, item) => {
    acc.totalOrdered  += Number(item.ordered_qty)  || 0;
    acc.totalReceived += Number(item.received_qty) || 0;
    acc.totalAccepted += Number(item.accepted_qty) || 0;
    acc.totalRejected += Number(item.rejected_qty) || 0;
    acc.totalAcceptedValue += Number(item.total_price)          || 0;
    acc.totalRejectedValue += Number(item.rejected_total_price) || 0;
    acc.totalValue         += (Number(item.total_price)||0) + (Number(item.rejected_total_price)||0);
    return acc;
  }, { totalOrdered:0, totalReceived:0, totalAccepted:0, totalRejected:0,
       totalAcceptedValue:0, totalRejectedValue:0, totalValue:0 });
}

function updateTotals() {
  const t = calcTotals();
  document.getElementById("ft-ordered").textContent  = t.totalOrdered;
  document.getElementById("ft-received").textContent = t.totalReceived;
  document.getElementById("ft-accepted").textContent = t.totalAccepted;
  document.getElementById("ft-rejected").textContent = t.totalRejected;
  document.getElementById("ft-acc-total").textContent = "₹" + fmtIndian(t.totalAcceptedValue);
  document.getElementById("ft-rej-total").textContent = "₹" + fmtIndian(t.totalRejectedValue);
  document.getElementById("ft-grand").textContent     = "₹" + fmtIndian(t.totalValue);
  document.getElementById("grand-total-display").textContent = "₹ " + fmtIndian(t.totalValue);
  document.getElementById("amount-words").textContent =
    numberToWords(Math.floor(t.totalValue)) + " RUPEES ONLY";
}

// ════════════════════════════════════════════════════
//  Render items rows
// ════════════════════════════════════════════════════
function renderItems() {
  const tbody = document.getElementById("items-tbody");
  const disabled = isInputDisabled() ? "disabled" : "";
  tbody.innerHTML = items.map((item, i) => `
    <tr>
      <td class="text-center">${i+1}</td>
      <td class="text-left">${item.item_name || "—"}</td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.ordered_qty}" ${disabled}
          onchange="handleChange(${i},'ordered_qty',this.value)" min="0" />
      </td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.received_qty}" ${disabled}
          onchange="handleChange(${i},'received_qty',this.value)" min="0" />
      </td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.accepted_qty}" ${disabled}
          onchange="handleChange(${i},'accepted_qty',this.value)" min="0" />
      </td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.rejected_qty}" ${disabled}
          onchange="handleChange(${i},'rejected_qty',this.value)" min="0" />
      </td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.unit_price}" ${disabled}
          onchange="handleChange(${i},'unit_price',this.value)" min="0" step="0.01" />
      </td>
      <td class="text-right">₹${fmtIndian(item.total_price)}</td>
      <td style="padding:4px;">
        <input class="num-input" type="number" value="${item.rejected_unit_price}" ${disabled}
          onchange="handleChange(${i},'rejected_unit_price',this.value)" min="0" step="0.01" />
      </td>
      <td class="text-right">₹${fmtIndian(item.rejected_total_price)}</td>
      <td class="text-right fw-500">₹${fmtIndian(item.grand_total)}</td>
      <td style="padding:4px;">
        <input class="loc-input" type="text" value="${item.store_location||''}" ${disabled}
          onchange="handleChange(${i},'store_location',this.value)" placeholder="Store location" />
      </td>
    </tr>
  `).join("");
}

// ════════════════════════════════════════════════════
//  Render approvers
// ════════════════════════════════════════════════════
function renderApprovers() {
  const wrap = document.getElementById("approvers-wrap");
  document.getElementById("workflow-count").textContent = workflowUsers.length;
  wrap.innerHTML = workflowUsers.map(user => {
    const uid    = user.user_id;
    const aData  = approvalStatuses[uid] || { status: "pending" };
    const status = aData.status || "pending";
    const isAuto = status === "auto_approved";
    const displayStatus = isAuto ? "pending" : status;
    const clickable = isApproverClickable(user) && displayStatus === "pending";
    const isAdmin  = isAdminRole(user.role);
    const initials = (user.first_name[0]||"") + (user.last_name[0]||"");

    let avColor = "#6c757d", badgeHtml = "", avatarContent = "&#9203;";
    if (displayStatus === "approved") {
      avColor = "#28a745"; avatarContent = "&#10003;";
      badgeHtml = `<span class="badge b-success">Approved</span>`;
    } else if (displayStatus === "rejected") {
      avColor = "#dc3545"; avatarContent = "&#10005;";
      badgeHtml = `<span class="badge b-danger">Rejected</span>`;
    } else {
      if (isAuto) {
        avColor = "#17a2b8"; avatarContent = "&#10003;";
        badgeHtml = `<span class="badge b-info">Auto-Approved</span>`;
      } else {
        badgeHtml = `<span class="badge b-secondary">Pending</span>`;
      }
    }

    const autoNote = isAuto
      ? `<div class="auto-note">&#128081; Auto-approved by ${aData.super_approved_by||"Admin"}</div>` : "";
    const rejectNote = (displayStatus === "rejected" && aData.rejection_reason && !isAuto)
      ? `<div class="reject-note" title="${aData.rejection_reason}">&#128172; ${aData.rejection_reason.substring(0,45)}${aData.rejection_reason.length>45?"…":""}</div>` : "";

    const actionBtns = (clickable && displayStatus === "pending" && !isAuto) ? `
      <div class="action-btns">
        <button class="btn-approve" onclick="openApproveModal(${uid})">&#10003; Approve</button>
        <button class="btn-reject"  onclick="openRejectModal(${uid})">&#10005; Reject</button>
      </div>` : "";

    return `
      <div class="approver-card${clickable?" is-clickable":""}${isAuto?" is-auto":""}">
        <div class="av-row">
          <div class="avatar" style="background:${avColor};">${avatarContent}</div>
          <div style="flex:1;min-width:0;">
            <div class="av-name">${user.first_name} ${user.last_name}</div>
            <div class="av-badges">
              <span class="av-role">${user.role}</span>
              ${isAdmin ? `<span class="badge b-primary">Admin</span>` : ""}
              ${badgeHtml}
            </div>
            ${autoNote}
            ${rejectNote}
          </div>
        </div>
        ${actionBtns}
      </div>`;
  }).join("");
}

// ════════════════════════════════════════════════════
//  Handle item field change
// ════════════════════════════════════════════════════
function handleChange(index, field, value) {
  if (isInputDisabled()) return;
  const cur = { ...items[index] };
  const v = parseFloat(value) || 0;

  if (field === "ordered_qty")          { cur.ordered_qty = v; }
  else if (field === "received_qty")    { cur.received_qty = v; cur.rejected_qty = Math.max(0, v - (cur.accepted_qty||0)); }
  else if (field === "accepted_qty")    { cur.accepted_qty = v; cur.rejected_qty = Math.max(0, (cur.received_qty||0) - v); }
  else if (field === "rejected_qty")    { cur.rejected_qty = v; cur.accepted_qty = Math.max(0, (cur.received_qty||0) - v); }
  else if (field === "unit_price")      { cur.unit_price = v; }
  else if (field === "rejected_unit_price") { cur.rejected_unit_price = v; }
  else                                  { cur[field] = value; }

  computeItem(cur);
  items[index] = cur;
  hasChanges = JSON.stringify(items) !== JSON.stringify(origItems);
  updateTotals();
  renderItems();
  renderApprovers();
  document.getElementById("save-btn").style.display =
    (hasChanges && !isInputDisabled()) ? "flex" : "none";
}

// ════════════════════════════════════════════════════
//  Save changes (hook to your API endpoint)
// ════════════════════════════════════════════════════
function saveChanges() {
  if (!hasChanges || processing) return;
  processing = true;
  const spinner = document.getElementById("save-spinner");
  const btnText = document.getElementById("save-btn-text");
  spinner.style.display = "inline-block";
  btnText.textContent = "Saving…";

  // ── Replace this with your real API call ──────────────────
  // fetch(`/api/grn/${GRN_DATA.grn_number}/items/batch`, {
  //   method: "PUT",
  //   headers: { "Content-Type": "application/json" },
  //   credentials: "include",
  //   body: JSON.stringify({ items: items })
  // }).then(r => r.json()).then(data => { ... })
  // ─────────────────────────────────────────────────────────

  // Simulated async save
  setTimeout(() => {
    origItems = JSON.parse(JSON.stringify(items));
    hasChanges = false;
    processing = false;
    spinner.style.display = "none";
    btnText.textContent = "&#128190; Save Changes";
    document.getElementById("save-btn").style.display = "none";
    alert("GRN items saved successfully.");
  }, 800);
}

// ════════════════════════════════════════════════════
//  Modal logic
// ════════════════════════════════════════════════════
function openApproveModal(userId) {
  const user = workflowUsers.find(u => u.user_id === userId);
  if (!user) return;
  selectedApprover = user;
  const initials = (user.first_name[0]||"") + (user.last_name[0]||"");
  document.getElementById("approve-av").textContent   = initials;
  document.getElementById("approve-name").textContent = user.first_name + " " + user.last_name;
  document.getElementById("approve-role").textContent = user.role;
  document.getElementById("approve-admin-note").style.display =
    isAdminRole(user.role) ? "block" : "none";
  document.getElementById("modal-approve").classList.add("open");
}

function openRejectModal(userId) {
  const user = workflowUsers.find(u => u.user_id === userId);
  if (!user) return;
  selectedApprover = user;
  const initials = (user.first_name[0]||"") + (user.last_name[0]||"");
  document.getElementById("reject-av").textContent   = initials;
  document.getElementById("reject-name").textContent = user.first_name + " " + user.last_name;
  document.getElementById("reject-role").textContent = user.role;
  document.getElementById("rejection-reason").value  = "";
  document.getElementById("modal-reject").classList.add("open");
}

function closeModal(type) {
  if (processing) return;
  document.getElementById("modal-" + type).classList.remove("open");
  selectedApprover = null;
}

function confirmApprove() {
  if (!selectedApprover || processing) return;
  processing = true;
  const spinner = document.getElementById("approve-spinner");
  spinner.style.display = "inline-block";
  document.getElementById("approve-confirm-btn").disabled = true;

  // ── Replace with your real API call ───────────────────────
  // fetch(`/api/approvals/grn/${GRN_DATA.grn_number}/approve`, {
  //   method: "POST", credentials: "include",
  //   headers: { "Content-Type": "application/json" },
  //   body: JSON.stringify({ userId: selectedApprover.user_id })
  // }).then(...)
  // ─────────────────────────────────────────────────────────

  setTimeout(() => {
    approvalStatuses[selectedApprover.user_id] = { status: "approved", approved_at: new Date().toISOString() };
    // If admin/CEO → auto-approve remaining
    if (isAdminRole(selectedApprover.role)) {
      workflowUsers.forEach(u => {
        if (!approvalStatuses[u.user_id] || approvalStatuses[u.user_id].status === "pending") {
          approvalStatuses[u.user_id] = { status: "auto_approved", super_approved_by: selectedApprover.first_name + " " + selectedApprover.last_name };
        }
      });
    }
    processing = false;
    spinner.style.display = "none";
    document.getElementById("approve-confirm-btn").disabled = false;
    closeModal("approve");
    renderApprovers();
    renderItems();
    document.getElementById("save-btn").style.display = "none";
  }, 800);
}

function confirmReject() {
  if (!selectedApprover || processing) return;
  const reason = document.getElementById("rejection-reason").value.trim();
  if (!reason) { alert("Please provide a reason for rejection."); return; }
  processing = true;
  const spinner = document.getElementById("reject-spinner");
  spinner.style.display = "inline-block";
  document.getElementById("reject-confirm-btn").disabled = true;

  // ── Replace with your real API call ───────────────────────
  // fetch(`/api/approvals/grn/${GRN_DATA.grn_number}/reject`, { ... })
  // ─────────────────────────────────────────────────────────

  setTimeout(() => {
    approvalStatuses[selectedApprover.user_id] = { status: "rejected", rejection_reason: reason };
    processing = false;
    spinner.style.display = "none";
    document.getElementById("reject-confirm-btn").disabled = false;
    closeModal("reject");
    renderApprovers();
    renderItems();
  }, 800);
}

// Close modal on overlay click
document.getElementById("modal-approve").addEventListener("click", function(e) {
  if (e.target === this) closeModal("approve");
});
document.getElementById("modal-reject").addEventListener("click", function(e) {
  if (e.target === this) closeModal("reject");
});

// ════════════════════════════════════════════════════
//  Populate static fields from GRN_DATA
// ════════════════════════════════════════════════════
function populateStaticFields() {
  const d = GRN_DATA;
  const c = d.company;
  const v = d.vendor;
  const r = d.reference;

  // Header
  document.getElementById("meta-grn-number").textContent = d.grn_number;
  document.getElementById("meta-grn-date").textContent   = fmtDate(d.grn_date);

  // From
  document.getElementById("from-name").textContent    = c.name;
  document.getElementById("from-address").textContent = c.address;
  document.getElementById("from-gst").textContent     = c.gst;
  document.getElementById("from-cin").textContent     = c.cin;
  if (!c.logo_url) {
    const el = document.getElementById("logo-initials");
    if (el) el.textContent = c.initials || c.name.substring(0,2).toUpperCase();
  }

  // Vendor
  document.getElementById("vendor-name").textContent    = v.name    || "N/A";
  document.getElementById("vendor-phone").textContent   = v.phone   || "N/A";
  document.getElementById("vendor-address").textContent = v.full_address || "N/A";
  const vc = document.getElementById("vendor-contact");
  if (vc) vc.textContent = v.contact_person || "N/A";
  const ve = document.getElementById("vendor-email");
  if (ve) ve.textContent = v.email || "N/A";
  const vg = document.getElementById("vendor-gstin");
  if (vg) vg.textContent = v.gstin || "N/A";

  // Reference
  function setRef(id, val) {
    const el = document.getElementById(id);
    if (!el) return;
    if (val) { el.textContent = val; el.className = "ref-val"; }
    else      { el.textContent = "N/A"; el.className = "ref-na"; }
  }
  setRef("ref-po",  r.po_number);
  setRef("ref-inv", r.invoice_no);
  setRef("ref-dc",  r.delivery_challan_no);
  setRef("ref-ge",  r.gate_entry_no);
  setRef("ref-veh", r.vehicle_number);

  // Signatory
  document.getElementById("sig-company").textContent = c.name;

  // Footer
  document.getElementById("footer-date").textContent       = new Date().toLocaleDateString("en-IN");
  document.getElementById("footer-created-by").textContent = d.created_by_name || "—";

  // Terms
  if (d.terms && d.terms.length) {
    document.getElementById("terms-section").style.display = "block";
    document.getElementById("terms-body").innerHTML = d.terms.map((t, i) => `
      <div class="term-item">
        <b>${i+1}. ${t.term} :</b><br/>
        <span class="term-desc">${t.description}</span>
      </div>`).join("");
  }
}

// ════════════════════════════════════════════════════
//  Boot
// ════════════════════════════════════════════════════
populateStaticFields();
renderItems();
updateTotals();
renderApprovers();
</script>

</body>
</html>