<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>

<?php
// =========================
// SAFETY HELPERS
// =========================
if (!function_exists('safe_prop')) {
  function safe_prop($src, array $keys, $default = '')
  {
    foreach ($keys as $k) {
      if (is_object($src) && isset($src->$k) && $src->$k !== '' && $src->$k !== null) return $src->$k;
      if (is_array($src)  && isset($src[$k]) && $src[$k] !== '' && $src[$k] !== null) return $src[$k];
    }
    return $default;
  }
}

$posts        = isset($posts) && is_array($posts) ? $posts : [];
$status_order = isset($status_order) ? $status_order : null;
$produk       = isset($produk) ? $produk : null;
$render_mode  = isset($render_mode) ? $render_mode : '';
$render_card  = ($render_mode === 'card');
$wrap_single  = isset($wrap_single) ? (bool)$wrap_single : false;
$operator_preload = isset($operator_preload) && is_array($operator_preload) ? $operator_preload : [];
$operator_detail_map = isset($operator_preload['details']) && is_array($operator_preload['details']) ? $operator_preload['details'] : [];
$operator_total_map = isset($operator_preload['totals']) && is_array($operator_preload['totals']) ? $operator_preload['totals'] : [];
$operator_payment_map = isset($operator_preload['payments']) && is_array($operator_preload['payments']) ? $operator_preload['payments'] : [];
$operator_progress_map = isset($operator_preload['progress']) && is_array($operator_preload['progress']) ? $operator_preload['progress'] : [];
$operator_proof_map = isset($operator_preload['proofs']) && is_array($operator_preload['proofs']) ? $operator_preload['proofs'] : [];

/* =========================================================
   ✅ PATCH FIX &amp; (Keterangan)
   - Data keterangan di DB kadang sudah berupa entity: "&amp;"
   - Kalau langsung htmlspecialchars() => jadi "&amp;amp;" dan tampil "&amp;"
   - Solusi: decode entity dulu, baru escape sekali
========================================================= */
if (!function_exists('pg_clean_text')) {
  function pg_clean_text($s, $default = '')
  {
    if ($s === null) return $default;
    $s = (string)$s;

    // decode entity: "baso &amp; ikan" -> "baso & ikan"
    $s = html_entity_decode($s, ENT_QUOTES, 'UTF-8');

    // rapihin spasi
    $s = preg_replace("/\s+/u", " ", $s);
    $s = trim($s);

    return ($s === '') ? $default : $s;
  }
}

$posts        = isset($posts) && is_array($posts) ? $posts : [];
$status_order = isset($status_order) ? $status_order : null;
$produk       = isset($produk) ? $produk : null;

// (BARU) URL suara notifikasi custom. Bisa di-override dari controller.
$notif_sound_url = isset($notif_sound_url) && $notif_sound_url ? $notif_sound_url : base_url('assets/sounds/ada_orderan_masuk.mp3');

// (BARU) URL refresh AJAX; jika punya endpoint khusus (mis. operator/ajax_order), kirim dari controller ke $refresh_url.
// Default: current_url() dengan query ?ajax=1 (view ini akan tetap mengembalikan HTML yang sama).
$refresh_url = isset($refresh_url) && $refresh_url ? $refresh_url : current_url().(strpos(current_url(), '?')===false ? '?ajax=1' : '&ajax=1');

// Fallback helper (agar tidak fatal saat preview)
if (!function_exists('dtimes'))          { function dtimes($a){ return htmlspecialchars((string)$a, ENT_QUOTES, 'UTF-8'); } }
if (!function_exists('encrypt_url'))     { function encrypt_url($a){ return $a; } }
if (!function_exists('bayar'))           { function bayar(){ return []; } }
if (!function_exists('detail_order'))    { function detail_order(){ return []; } }
if (!function_exists('jkategori'))       { function jkategori(){ return 0; } }
if (!function_exists('prosess_status'))  { function prosess_status($id,$st,$txt){ return '<span>'.$txt.'</span>'; } }
if (!function_exists('update_status'))   { function update_status($id,$st,$txt){ return '<button class="btn btn-info btn-sm">'.$txt.'</button>'; } }
if (!function_exists('juser'))           { function juser($id=0){ return '-'; } }
if (!function_exists('getDetailBahan'))  { function getDetailBahan(){ return null; } }
if (!function_exists('nama_produk'))     { function nama_produk($id=0){ return 'Produk'; } }
if (!function_exists('pg_status_meta')) {
  function pg_status_meta($st)
  {
    $meta = job_status_meta((int)$st);
    return [$meta['label'], 'btn-job-status', $meta['icon'], $meta['color']];
  }
}
if (!function_exists('pg_status_html')) {
  function pg_status_html($enc_detail, $st, $can_manage_progress, $cek_bahan = null, $nomor_order = '')
  {
    list($label, $class, $icon, $color) = pg_status_meta($st);
    if ($can_manage_progress) {
      $attrs = '';
      if ($cek_bahan !== null) {
        $attrs .= ' data-cek-bahan="' . (int)$cek_bahan . '"';
      }
      if ($nomor_order !== '') {
        $attrs .= ' data-no-order="' . htmlspecialchars((string)$nomor_order, ENT_QUOTES, 'UTF-8') . '"';
      }
      return '<button class="btn btn-icon-split btn-sm flat edit_baru ' . htmlspecialchars($class, ENT_QUOTES, 'UTF-8') . '" data-id="' . htmlspecialchars($enc_detail, ENT_QUOTES, 'UTF-8') . '" data-status="' . (int)$st . '" style="background-color:' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8') . ';border-color:' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8') . ';color:#fff"' . $attrs . '>
        <span class="icon text-white-50">
          <i class="fa fa-' . htmlspecialchars($icon, ENT_QUOTES, 'UTF-8') . '"></i>
        </span>
        <span class="text">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</span>
      </button>';
    }
    return '<span class="badge ' . htmlspecialchars($class, ENT_QUOTES, 'UTF-8') . '" style="background-color:' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8') . ';color:#fff">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</span>';
  }
}
?>

<?php if (!$render_card): ?>
  <!-- (BARU) Expose ke JS -->
  <script>
    window.NOTIF_SOUND_URL = <?= json_encode($notif_sound_url, JSON_UNESCAPED_SLASHES); ?>;
    window.REFRESH_URL     = <?= json_encode($refresh_url, JSON_UNESCAPED_SLASHES); ?>;
  </script>
<?php endif; ?>

<style>
  :root{
    --radius: 8px;
    --radius-sm: 6px;
    --shadow: 0 2px 10px rgba(22, 28, 45, .08);
    --shadow-sm: 0 1px 4px rgba(22, 28, 45, .08);
    --line: rgba(140, 152, 164, .28);
    --muted: #111827;
    --accent: #4f46e5;
    --accent-2: #6366f1;
    --success: #16a34a;
    --danger: #dc2626;
    --warning: #f59e0b;
  }

  .cards-stack{ display:grid; gap:1rem; margin-top:.25rem !important; }

  .order-card{
    border:1px solid var(--line);
    border-radius: var(--radius);
    background:#fff;
    box-shadow: var(--shadow);
    overflow:hidden;
  }
  .order-header{
    display:flex; gap:.75rem 1rem; align-items:center; justify-content:space-between;
    padding:.95rem 1rem;
    background: #f8fafc;
    border-bottom:1px solid rgba(140,152,164,.18);
  }
  .order-meta{ display:flex; flex-wrap:wrap; gap:.5rem .75rem; align-items:center; }

  .chip{
    display:inline-flex; align-items:center; gap:.45rem;
    padding:.3rem .55rem; border-radius:var(--radius-sm); font-size:.8rem; line-height:1.2;
    border:1px solid var(--line); background:#fff; color:#111827; box-shadow: none;
  }
  .chip .dot{ width:.5rem; height:.5rem; border-radius:999px; background:var(--accent); box-shadow: 0 0 0 2px rgba(79,70,229,.15) inset; }
  .chip-muted{ color:var(--muted); background:#fafafa }
  .chip-kasir{ background:rgba(16,185,129,.08); border-color:rgba(16,185,129,.25); color:#065f46; }
  .chip-pay{ background:#f8fafc; border-color:rgba(148,163,184,.6); color:#0f172a; }
  .chip-pay.lunas{ background:rgba(34,197,94,.12); border-color:rgba(34,197,94,.35); color:#166534; }
  .chip-pay.belum{ background:rgba(245,158,11,.12); border-color:rgba(245,158,11,.35); color:#92400e; }

  .chip-order{ background:#111827; color:#fff; border-color:#111827; padding:.35rem .6rem; }
  .chip-order .dot{ background:#fff; box-shadow:0 0 0 2px rgba(255,255,255,.15) inset; }
  .chip-order .label{ opacity:.9; font-weight:600; letter-spacing:.01em; }
  .chip-order .order-code{ font-weight:800; font-size:1.05rem; letter-spacing:.03em; font-variant-numeric: tabular-nums; line-height:1.1; }
  .chip-order .sep{ opacity:.55; font-weight:700; margin:0 .25rem; }
  .chip-order .customer-name{ font-weight:700; opacity:.95; white-space:nowrap; font-size:1.05rem; line-height:1.1; }

  .order-actions{ display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; }

  .nested{ padding:.6rem 1rem 1rem 1rem; }
  .items-table{
    width:100%; border-collapse:separate !important; border-spacing:0;
    border:1px solid var(--line); border-radius: var(--radius-sm); overflow:hidden; background:#fff;
  }
  .items-table thead th{
    font-weight:600; font-size:.8rem; letter-spacing:.02em; background:#f8fafc; border-bottom:1px solid var(--line);
    padding:.6rem .7rem; white-space:nowrap;
  }
  .items-table tbody td{ padding:.55rem .7rem; font-size:.9rem; border-top:1px solid rgba(140,152,164,.18); vertical-align:top; }

  .check-cell{ text-align:center; vertical-align:middle !important; }
  .check-cell input[type="checkbox"]{ width:18px; height:18px; cursor:pointer; }
  .check-all{ transform: translateY(2px); }

  .w-100{width:100%} .text-right{text-align:right} .text-left{text-align:left} .mt-2{margin-top:.5rem}

  .btn-modern{
    --btn-bg: #111827; --btn-color: #fff; --btn-bd: transparent;
    display:inline-flex; align-items:center; gap:.5rem;
    padding:.5rem .75rem; border-radius:var(--radius-sm); border:1px solid var(--btn-bd);
    background: var(--btn-bg); color: var(--btn-color);
    font-weight:600; font-size:.85rem; letter-spacing:.01em;
    box-shadow: var(--shadow-sm); transition: box-shadow .2s ease, background .2s ease, color .2s ease, border-color .2s ease;
    line-height:1.1;
  }
  .btn-modern:hover{ box-shadow: 0 4px 12px rgba(22,28,45,.10); text-decoration:none; color:var(--btn-color); }
  .btn-wa    { --btn-bg: #111827; --btn-bd: #111827; }
  .btn-spk   { --btn-bg: #111827; --btn-bd: #111827; }
  .btn-ghost { --btn-bg: #111827; --btn-color:#fff; --btn-bd: #111827; }

  .update-item-menu{
    min-width: 320px;
    padding: .65rem .75rem;
  }
  .update-item-head{
    display:grid;
    grid-template-columns: 1fr auto;
    gap:.5rem;
    font-size:.75rem;
    font-weight:700;
    color:#111827;
    text-transform:uppercase;
    letter-spacing:.02em;
    margin-bottom:.35rem;
  }
  .update-item-row{
    display:grid;
    grid-template-columns: 1fr auto;
    gap:.6rem;
    align-items:center;
    padding:.35rem 0;
    border-top:1px solid rgba(140,152,164,.2);
  }
  .update-item-row:first-of-type{
    border-top:0;
  }
  .update-item-name{
    font-size:.85rem;
    color:#111827;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    max-width: 220px;
  }
  .update-item-btn .btn{
    margin:0 !important;
  }
  .update-item-empty{
    font-size:.85rem;
    color:#111827;
    padding:.25rem 0;
  }
  .status-item-actions{
    display:flex;
    align-items:center;
    gap:.4rem;
    flex-wrap:nowrap;
  }
  .status-item-actions.has-upload-proof{
    flex-direction:column;
    align-items:center;
    justify-content:center;
    gap:.25rem;
  }
  .bukti-progress-upload-label{
    display:block;
    color:#475569;
    font-size:.72rem;
    font-weight:700;
    line-height:1.1;
    text-align:center;
    white-space:nowrap;
  }
  .bukti-progress-upload-actions{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:.4rem;
  }
  .status-cell,
  .progres-cell{
    vertical-align: middle !important;
  }
  .progres-wrap{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    justify-content:center;
    gap:.35rem;
  }
  .bukti-preview{
    display:flex;
    align-items:center;
    flex-wrap:nowrap;
    gap:9px;
    width:100%;
    max-width:220px;
    margin-top:.35rem;
    padding:3px 4px 6px;
    overflow-x:auto;
    overflow-y:hidden;
    scrollbar-width:thin;
    scrollbar-color:#cbd5e1 transparent;
  }
  .bukti-preview::-webkit-scrollbar{ height:4px; }
  .bukti-preview::-webkit-scrollbar-thumb{
    border-radius:999px;
    background:#cbd5e1;
  }
  .items-table:not(.items-table-card) .progres-wrap{
    align-items:center;
    width:100%;
  }
  .items-table:not(.items-table-card) .status-item-actions{
    justify-content:center;
    width:100%;
  }
  .items-table:not(.items-table-card) .bukti-preview{
    width:max-content;
    min-width:0;
    margin:.35rem auto 0;
    justify-content:flex-start;
  }
  .bukti-thumb{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    position:relative;
    flex:0 0 34px;
    width:34px;
    height:34px;
    padding:2px;
    border:1px solid #3b82f6;
    border-radius:8px;
    background:#fff;
    box-shadow:0 2px 6px rgba(15,23,42,.12);
    text-decoration:none;
    z-index:1;
  }
  .bukti-thumb:not(:last-child)::after{
    content:"";
    position:absolute;
    left:100%;
    top:50%;
    width:9px;
    height:2px;
    background:#94a3b8;
    transform:translateY(-50%);
    z-index:0;
  }
  .bukti-thumb:hover{
    border-color:#1d4ed8;
    box-shadow:0 3px 9px rgba(37,99,235,.24);
  }
  .bukti-thumb img{
    display:block;
    width:100%;
    height:100%;
    object-fit:cover;
    border:0;
    border-radius:6px;
    background:#f8fafc;
  }
  .bukti-modal{
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.55);
    display:none;
    align-items:center;
    justify-content:center;
    z-index: 9999;
    padding: 1rem;
  }
  .bukti-modal.is-open{ display:flex; }
  .bukti-modal-content{
    background:#fff;
    border-radius: var(--radius);
    max-width: 90vw;
    max-height: 90vh;
    box-shadow: var(--shadow);
    overflow:hidden;
  }
  .bukti-modal-header{
    display:flex;
    align-items:center;
    justify-content:space-between;
    padding:.6rem .8rem;
    border-bottom:1px solid var(--line);
    font-weight:600;
    font-size:.9rem;
    color:#111827;
  }
  .bukti-modal-close{
    border:1px solid var(--line);
    background:#fff;
    border-radius:var(--radius-sm);
    padding:.25rem .5rem;
    font-size:.85rem;
    cursor:pointer;
  }
  .bukti-modal-body{
    padding:.6rem;
    background:#f8fafc;
  }
  .bukti-modal-stage{
    position:relative;
    display:flex;
    align-items:center;
    justify-content:center;
  }
  .bukti-gallery-modal .bukti-modal-stage{
    min-width:min(780px, 84vw);
    min-height:260px;
    touch-action:pan-y;
    user-select:none;
  }
  .bukti-modal-body img{
    display:block;
    max-width: 84vw;
    max-height: 76vh;
    width:auto;
    height:auto;
    margin:0 auto;
  }
  .bukti-modal-nav{
    position:absolute;
    top:50%;
    display:flex;
    align-items:center;
    justify-content:center;
    width:46px;
    height:46px;
    border:1px solid rgba(255,255,255,.55);
    border-radius:50%;
    background:rgba(15,23,42,.82);
    color:#fff;
    box-shadow:0 4px 12px rgba(15,23,42,.24);
    transform:translateY(-50%);
    cursor:pointer;
    z-index:3;
  }
  .bukti-modal-nav:hover:not(:disabled){
    background:#0f172a;
  }
  .bukti-modal-nav:disabled{
    opacity:.25;
    cursor:default;
  }
  .bukti-modal-prev{ left:12px; }
  .bukti-modal-next{ right:12px; }
  .bukti-modal-counter{
    position:absolute;
    right:12px;
    bottom:10px;
    padding:.25rem .55rem;
    border-radius:999px;
    background:rgba(15,23,42,.84);
    color:#fff;
    font-size:.76rem;
    font-weight:700;
    line-height:1.2;
    z-index:3;
  }
  .bukti-modal-counter.is-single,
  .bukti-modal-nav.is-hidden{ display:none; }
  .bukti-modal-meta{
    display:none;
    padding:.85rem 1rem .95rem;
    border-top:1px solid #334155;
    background:#0f172a;
  }
  .bukti-modal-meta.is-visible{ display:block; }
  .bukti-modal-caption{
    display:block;
    color:#fff;
    font-size:1.12rem;
    font-weight:700;
    line-height:1.35;
    letter-spacing:.01em;
  }
  .bukti-modal-time{
    display:block;
    margin-top:.3rem;
    color:#e2e8f0;
    font-size:.9rem;
    font-weight:600;
    line-height:1.3;
  }
  .bukti-upload-content{
    width:min(620px, 94vw);
  }
  .bukti-upload-help{
    margin:0 0 .65rem;
    color:#475569;
    font-size:.82rem;
  }
  .bukti-upload-list{
    display:flex;
    flex-direction:column;
    gap:.55rem;
    max-height:55vh;
    overflow:auto;
  }
  .bukti-upload-item{
    display:grid;
    grid-template-columns:32px minmax(0, 1fr);
    gap:.55rem;
    align-items:start;
    padding:.55rem;
    border:1px solid var(--line);
    border-radius:var(--radius-sm);
    background:#fff;
  }
  .bukti-upload-number{
    display:flex;
    align-items:center;
    justify-content:center;
    width:28px;
    height:28px;
    border-radius:50%;
    background:#eff6ff;
    color:#1d4ed8;
    font-weight:700;
    font-size:.78rem;
  }
  .bukti-upload-file{
    display:block;
    margin-bottom:.35rem;
    color:#334155;
    font-size:.75rem;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
  }
  .bukti-upload-caption-input{
    width:100%;
    height:36px;
    padding:.4rem .55rem;
    border:1px solid #cbd5e1;
    border-radius:var(--radius-sm);
    color:#111827;
    font-size:.82rem;
  }
  .bukti-upload-caption-input.is-invalid{
    border-color:#ef4444;
    box-shadow:0 0 0 2px rgba(239,68,68,.12);
  }
  .bukti-upload-actions{
    display:flex;
    justify-content:flex-end;
    gap:.5rem;
    padding:.65rem .8rem;
    border-top:1px solid var(--line);
    background:#fff;
  }
  .bukti-camera-wrap{
    width:100%;
    border:1px solid var(--line);
    border-radius:var(--radius-sm);
    overflow:hidden;
    background:#000;
  }
  #bukti-camera-video{
    display:block;
    width:100%;
    height:auto;
    max-height:68vh;
    background:#000;
  }
  .bukti-camera-actions{
    margin-top:.6rem;
    display:flex;
    justify-content:flex-end;
  }
  .btn-proof{
    display:inline-flex;
    align-items:center;
    gap:.35rem;
    padding:.35rem .55rem;
    border:1px solid var(--line);
    background:#fff;
    color:#111827;
    border-radius:var(--radius-sm);
    font-size:.8rem;
    font-weight:600;
    line-height:1.1;
    height: 38px;
  }
  .btn-proof:hover{
    box-shadow: var(--shadow-sm);
    text-decoration:none;
    color:#111827;
  }
  .btn-proof i{
    font-size:.85rem;
    line-height:1;
  }
  .btn-catatan-gallery{
    min-width:146px;
    max-width:220px;
    justify-content:center;
  }
  .btn-catatan-gallery span{
    max-width:100%;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  /* =========================================================
   PATCH: Samakan tombol UPDATE STATUS (hasil helper update_status)
   dengan gaya tombol .btn-modern (pill + shadow + hover)
   Target: elemen .btn / a.btn yang berada di dalam .btn-modernizer
  ========================================================= */
  .btn-modernizer{
    display:inline-flex;
    align-items:center;
  }

  .btn-modernizer .btn,
  .btn-modernizer a.btn{
    height: 38px !important;
    padding: 0 .95rem !important;   /* atas-bawah 0, kiri-kanan stabil */
    box-sizing: border-box !important;
  }

  .btn-modernizer .btn,
  .btn-modernizer a.btn{
    display:inline-flex !important;
    align-items:center !important;
    gap:.5rem !important;

    padding:.55rem .9rem !important;
    border-radius:var(--radius-sm) !important;

    font-weight:600 !important;
    font-size:.85rem !important;
    letter-spacing:.01em !important;
    line-height:1.1 !important;

    box-shadow: var(--shadow-sm) !important;
    border:1px solid transparent !important;

    transition: box-shadow .2s ease,
                background .2s ease,
                color .2s ease,
                border-color .2s ease;
  }

  .btn-modernizer .btn:hover,
  .btn-modernizer a.btn:hover{
    box-shadow: 0 4px 12px rgba(22,28,45,.10) !important;
    text-decoration:none;
  }

  /* Warna sesuai tipe bootstrap yang biasa dipakai helper */
  .btn-modernizer .btn.btn-info,
  .btn-modernizer a.btn.btn-info{
    background:#0ea5e9 !important;
    border-color:#0284c7 !important;
    color:#fff !important;
  }

  .btn-modernizer .btn.btn-warning,
  .btn-modernizer a.btn.btn-warning{
    background:#f59e0b !important;
    border-color:#d97706 !important;
    color:#fff !important;
  }

  .btn-modernizer .btn i,
  .btn-modernizer a.btn i{
    line-height:1 !important;
  }
  /* ======================= END PATCH ======================= */

  /* =========================================================
   PATCH: samakan warna icon di tombol UPDATE STATUS
   (hilangkan kotak gelap di belakang icon)
========================================================= */
.btn-modernizer .btn i,
.btn-modernizer a.btn i{
  background: transparent !important;
  color: inherit !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
}

/* Kalau icon dibungkus <span> atau punya class khusus, ini bantu juga */
.btn-modernizer .btn .icon,
.btn-modernizer a.btn .icon,
.btn-modernizer .btn span i,
.btn-modernizer a.btn span i{
  background: transparent !important;
  box-shadow: none !important;
}
/* ======================= END PATCH ======================= */

/* =========================================================
   PATCH: icon Update Status jadi putih (lebih kontras)
========================================================= */
.btn-modernizer .btn.btn-info i,
.btn-modernizer a.btn.btn-info i{
  color: #fff !important;
  opacity: 1 !important;
}
/* ======================= END PATCH ======================= */

/* =========================================================
   PATCH: rapatkan jarak icon & teks (samakan feel dgn Kirim WA)
========================================================= */
.btn-modernizer .btn,
.btn-modernizer a.btn{
  gap: .5rem !important;         /* default btn-modern */
}

.btn-modernizer .btn i,
.btn-modernizer a.btn i{
  margin-right: .45rem !important; /* kalau ada CSS lain bikin jauh */
}

/* kalau ternyata ikon dibungkus <span> */
.btn-modernizer .btn i + span,
.btn-modernizer a.btn i + span{
  margin-left: 0 !important;
}
/* ======================= END PATCH ======================= */

/* =========================================================
   PATCH: Tombol STATUS (kolom tabel) jadi pill modern
   Target: output prosess_status() yang biasanya berupa .btn/.badge
========================================================= */
.status-pillizer{
  display:inline-flex;
  align-items:center;
}

/* berlaku untuk tombol bootstrap dan badge jika dipakai */
  .status-pillizer .btn,
  .status-pillizer a.btn,
  .status-pillizer .badge,
  .status-pillizer a.badge{
  display:inline-flex !important;
  align-items:center !important;
  justify-content:flex-start !important;
  gap:.1rem !important;

  height: 38px !important;              /* samakan tinggi dengan tombol lain */
  min-width: 160px !important;          /* samakan lebar agar rapi */
  width: 140px !important;              /* paksa lebar konsisten */
  padding: 0 .95rem !important;         /* rapi & konsisten */
  box-sizing: border-box !important;
  text-align:left;

  border-radius:var(--radius-sm) !important;
  font-weight:700 !important;
  font-size:.85rem !important;
  letter-spacing:.01em !important;
  line-height:1.1 !important;

  box-shadow: var(--shadow-sm) !important;
  border:1px solid transparent !important;
  white-space:nowrap;
}

/* hover feel sama */
.status-pillizer .btn:hover,
.status-pillizer a.btn:hover{
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(22,28,45,.12) !important;
  text-decoration:none;
}

/* rapihkan icon: hilangkan kotak/warna aneh + buat putih */
.status-pillizer .btn i,
.status-pillizer a.btn i,
.status-pillizer .badge i,
.status-pillizer a.badge i{
  background: transparent !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
  line-height: 1 !important;
  color: inherit !important;
}

/* jarak icon & teks biar sama feel tombol WA */
.status-pillizer .btn i,
.status-pillizer a.btn i{
  margin-right: .1rem !important;
}

/* =========================================================
   PATCH (status-board/card):
   - Teks Isi Catatan & Status center
   - Tombol Finishing & Status sejajar
========================================================= */
.items-table.items-table-card td[data-label="Finishing"],
.items-table.items-table-card td[data-label="Status"]{
  vertical-align: middle !important;
}

.items-table.items-table-card td[data-label="Finishing"] .btn-modernizer,
.items-table.items-table-card td[data-label="Status"] .status-pillizer{
  width:100%;
  display:flex;
  align-items:center;
  justify-content:center;
}

.items-table.items-table-card .btn-modernizer .btn,
.items-table.items-table-card .btn-modernizer a.btn,
.items-table.items-table-card .status-pillizer .btn,
.items-table.items-table-card .status-pillizer a.btn,
.items-table.items-table-card .status-pillizer .badge,
.items-table.items-table-card .status-pillizer a.badge{
  min-width:146px !important;
  width:146px !important;
  height:38px !important;
  justify-content:center !important;
  text-align:center !important;
  padding-left:.6rem !important;
  padding-right:.6rem !important;
  line-height:1.05 !important;
}

.items-table.items-table-card .btn-modernizer .btn i,
.items-table.items-table-card .btn-modernizer a.btn i,
.items-table.items-table-card .status-pillizer .btn i,
.items-table.items-table-card .status-pillizer a.btn i{
  margin-right:.2rem !important;
}
.items-table.items-table-card td[data-label="Progres"]{
  vertical-align:middle !important;
}
.items-table.items-table-card td[data-label="Progres"] .progres-wrap{
  width:100%;
  align-items:center;
}
.items-table.items-table-card td[data-label="Progres"] .status-item-actions{
  width:100%;
  justify-content:center;
}

/* ===== Mapping warna status: samakan dengan status_board/index.php ===== */
.status-pillizer .btn.btn-sb-baru,
.status-pillizer a.btn.btn-sb-baru,
.status-pillizer .badge.badge-sb-baru,
.status-pillizer a.badge.badge-sb-baru,
.update-item-btn .btn.btn-sb-baru,
.update-item-btn a.btn.btn-sb-baru{
  background:#667085 !important;
  border-color:#667085 !important;
  color:#fff !important;
}

.status-pillizer .btn.btn-sb-desain,
.status-pillizer a.btn.btn-sb-desain,
.status-pillizer .badge.badge-sb-desain,
.status-pillizer a.badge.badge-sb-desain,
.update-item-btn .btn.btn-sb-desain,
.update-item-btn a.btn.btn-sb-desain{
  background:linear-gradient(145deg, #b100ff 0%, #da27ff 100%) !important;
  border-color:#b100ff !important;
  color:#fff !important;
}

.status-pillizer .btn.btn-sb-cetak,
.status-pillizer a.btn.btn-sb-cetak,
.status-pillizer .badge.badge-sb-cetak,
.status-pillizer a.badge.badge-sb-cetak,
.update-item-btn .btn.btn-sb-cetak,
.update-item-btn a.btn.btn-sb-cetak{
  background:linear-gradient(145deg, #2869f2 0%, #2d8dff 100%) !important;
  border-color:#2869f2 !important;
  color:#fff !important;
}

.status-pillizer .btn.btn-sb-selesai,
.status-pillizer a.btn.btn-sb-selesai,
.status-pillizer .badge.badge-sb-selesai,
.status-pillizer a.badge.badge-sb-selesai,
.update-item-btn .btn.btn-sb-selesai,
.update-item-btn a.btn.btn-sb-selesai{
  background:linear-gradient(145deg, #14a84c 0%, #1ccf60 100%) !important;
  border-color:#14a84c !important;
  color:#fff !important;
}

.status-pillizer .btn.btn-sb-diambil,
.status-pillizer a.btn.btn-sb-diambil,
.status-pillizer .badge.badge-sb-diambil,
.status-pillizer a.badge.badge-sb-diambil,
.update-item-btn .btn.btn-sb-diambil,
.update-item-btn a.btn.btn-sb-diambil{
  background:linear-gradient(145deg, #facc15 0%, #fde047 100%) !important;
  border-color:#facc15 !important;
  color:#111827 !important;
}

.status-pillizer .btn.btn-sb-dikirim,
.status-pillizer a.btn.btn-sb-dikirim,
.status-pillizer .badge.badge-sb-dikirim,
.status-pillizer a.badge.badge-sb-dikirim,
.update-item-btn .btn.btn-sb-dikirim,
.update-item-btn a.btn.btn-sb-dikirim{
  background:linear-gradient(145deg, #ec9b13 0%, #ffb22c 100%) !important;
  border-color:#ec9b13 !important;
  color:#111827 !important;
}

/* Ikon ikut warna teks status agar konsisten */
.status-pillizer .btn.btn-sb-baru i,
.status-pillizer .btn.btn-sb-desain i,
.status-pillizer .btn.btn-sb-cetak i,
.status-pillizer .btn.btn-sb-selesai i,
.status-pillizer .btn.btn-sb-diambil i,
.status-pillizer .btn.btn-sb-dikirim i,
.update-item-btn .btn.btn-sb-baru i,
.update-item-btn .btn.btn-sb-desain i,
.update-item-btn .btn.btn-sb-cetak i,
.update-item-btn .btn.btn-sb-selesai i,
.update-item-btn .btn.btn-sb-diambil i,
.update-item-btn .btn.btn-sb-dikirim i{
  color:inherit !important;
  opacity:1 !important;
}
/* ======================= END PATCH ======================= */

========================================================= */
.status-pillizer .btn i,
.status-pillizer a.btn i{
  background: transparent !important;
  color: inherit !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
}

/* Kalau icon dibungkus <span> atau punya class khusus, ini bantu juga */
.status-pillizer .btn .icon,
.status-pillizer a.btn .icon,
.status-pillizer .btn span i,
.status-pillizer a.btn span i{
  background: transparent !important;
  box-shadow: none !important;
}
/* ======================= END PATCH ======================= */




  .dropdown-menu.dropdown-menu-right{
    border-radius: var(--radius-sm);
    border:1px solid var(--line);
    box-shadow: var(--shadow);
    overflow:hidden;
  }
  .order-card.complaint-rework-card{
    border-color:#f59e0b;
    border-left:5px solid #ef4444;
    box-shadow:0 5px 18px rgba(239,68,68,.12);
  }
  .order-card.complaint-rework-card .order-header{
    background:linear-gradient(90deg,#fff7ed 0%,#fff 58%);
  }
  .chip-complaint-rework{
    border-color:#fecaca;
    background:#fee2e2;
    color:#b91c1c;
    font-weight:800;
    letter-spacing:.035em;
    text-transform:uppercase;
  }
  .chip-complaint-rework i{font-size:.75rem;}
  .dropdown-menu .dropdown-item{ font-size:.9rem; padding:.6rem .85rem; display:flex; align-items:center; gap:.55rem; }
  .dropdown-menu .dropdown-item i{ width:1.1rem; text-align:center; }
  .operator-printer-options{
    display:flex;
    flex-direction:column;
    gap:.55rem;
    text-align:left;
  }
  .operator-printer-option{
    width:100%;
    border:1px solid #d7dde6;
    background:#fff;
    border-radius:.35rem;
    padding:.7rem .85rem;
    text-align:left;
    cursor:pointer;
  }
  .operator-printer-option:hover{
    border-color:#17a2b8;
    background:#f4fbfd;
  }
  .operator-printer-option strong{
    color:#111827;
    font-size:.95rem;
    font-weight:700;
  }
  .operator-printer-option strong i{
    width:18px;
    color:#0ea5e9;
  }
  .operator-printer-option strong,
  .operator-printer-option small{
    display:block;
  }
  .operator-printer-option small{
    color:#6b7280;
    margin-top:.2rem;
  }

  @media (max-width: 768px){
    .order-header{flex-direction:column; align-items:flex-start; gap:.6rem;}
    .order-actions{width:100%; justify-content:flex-start; gap:.5rem; flex-wrap:wrap;}
    .items-table thead{display:none;}
    .items-table tbody tr{display:grid; grid-template-columns:1fr; padding:.35rem .5rem;}
    .items-table tbody td{ display:flex; justify-content:space-between; gap:1rem; border-top:1px dashed rgba(140,152,164,.25); }
    .items-table tbody td::before{ content: attr(data-label); font-weight:600; color:var(--muted); }
    .check-cell{ justify-content:center; }
    .items-table.items-table-card td[data-label="Progres"]::before{
      content:'';
      display:none;
    }
    .items-table.items-table-card td[data-label="Progres"]{
      flex-direction:column;
      align-items:flex-start;
      gap:.35rem;
    }
    .items-table.items-table-card td[data-label="Progres"] .progres-wrap{
      width:100%;
      align-items:flex-end;
      gap:.3rem;
    }
    .items-table.items-table-card td[data-label="Progres"] .status-item-actions{
      justify-content:flex-end;
    }
    .btn-catatan-gallery{
      width:100%;
      max-width:100%;
      min-width:0;
      height:36px;
      padding:.3rem .5rem;
      font-size:.78rem;
    }
  }

    /* ===== PATCH FINISHING: tampilkan sebagai chip biar rapi ===== */
  .fin-wrap{
    display:flex;
    flex-direction:column;
    gap:.35rem;
    align-items:flex-start;
    min-width:160px;
  }
  .fin-item{
    display:flex;
    align-items:center;
    gap:.45rem;
    max-width:100%;
  }
  .fin-pill{
    display:inline-flex;
    align-items:center;
    gap:.35rem;
    padding:.24rem .55rem;
    border-radius:var(--radius-sm);
    border:1px solid rgba(140,152,164,.30);
    background:#f8fafc;
    color:#111827;
    font-size:.82rem;
    line-height:1.2;
    max-width:130px;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
  }
  .fin-pill .dot{
    width:.42rem; height:.42rem;
    border-radius:999px;
    background: var(--accent);
    box-shadow: 0 0 0 2px rgba(79,70,229,.12) inset;
    flex:0 0 auto;
  }
  .fin-empty{
    color: var(--muted);
    font-size:.85rem;
  }
  .fin-img-btn{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    padding:0;
    width:30px;
    height:30px;
    border-radius:var(--radius-sm);
    border:1px solid rgba(140,152,164,.35);
    background:#f8fafc;
    text-decoration:none;
    overflow:hidden;
  }
  .fin-img-btn img{
    width:100%;
    height:100%;
    object-fit:cover;
    display:block;
  }
  .fin-img-btn:hover{
    text-decoration:none;
    box-shadow: var(--shadow-sm);
  }
  /* ===== END PATCH FINISHING ===== */


  /* Mini progress di THEAD (pengganti Select All) */
  .mini-prog{ display:flex; align-items:center; gap:.4rem; justify-content:flex-end; }
  .mini-outer{ width:100px; height:8px; border-radius:var(--radius-sm); background:#eef2ff; overflow:hidden; border:1px solid rgba(79,70,229,.25); }
  .mini-inner{ height:100%; width:0%; background: linear-gradient(135deg, var(--accent), var(--accent-2)); transition: width .25s ease; }
  .mini-text{ font-size:.8rem; font-weight:700; min-width:32px; text-align:right; }

  /* Tombol kecil sekali-klik untuk mengaktifkan suara */
  .sound-unlock-btn{
    position: fixed; right: 14px; bottom: 14px; z-index: 9999;
    background: #111827; color:#fff; border:1px solid rgba(0,0,0,.1);
    border-radius: var(--radius-sm); padding: 10px 14px; font-weight: 700;
    box-shadow: 0 4px 12px rgba(17,24,39,.14); cursor: pointer;
  }
  .sound-unlock-btn[hidden]{ display:none !important; }

  .operator-order-identity-mobile,
  .operator-mobile-progress{
    display:none;
  }

  @media (max-width: 767.98px){
    .cards-stack{
      gap:14px;
      margin-top:0 !important;
    }
    .order-card{
      border-color:#dfe5ed;
      border-radius:14px;
      box-shadow:0 7px 20px rgba(15,23,42,.07);
    }
    .order-header{
      display:block;
      padding:10px;
      background:#fff;
    }
    .order-meta{
      width:100%;
      gap:6px;
    }
    .operator-order-identity-desktop{
      display:none !important;
    }
    .operator-order-identity-mobile{
      width:100%;
      display:flex;
      align-items:center;
      gap:9px;
      min-width:0;
    }
    .operator-order-identity-mobile .order-code{
      flex:0 0 auto;
      padding:6px 9px;
      border-radius:6px;
      background:#07142f;
      color:#fff;
      font-size:15px;
      font-weight:800;
      line-height:1;
      letter-spacing:.025em;
      box-shadow:0 2px 5px rgba(7,20,47,.2);
    }
    .operator-order-identity-mobile .customer-name{
      min-width:0;
      overflow:hidden;
      color:#0f172a;
      font-size:15px;
      font-weight:800;
      line-height:1.15;
      text-overflow:ellipsis;
      white-space:nowrap;
    }
    .order-meta > .chip:not(.chip-order){
      padding:5px 7px;
      gap:5px;
      font-size:10.5px;
      border-radius:6px;
    }
    .operator-mobile-progress{
      margin-left:auto;
      display:inline-flex;
      align-items:center;
      gap:6px;
    }
    .operator-mobile-progress .mini-outer{
      width:46px;
      height:5px;
    }
    .operator-mobile-progress .mini-text{
      min-width:27px;
      font-size:10.5px;
    }
    .order-actions{
      width:100%;
      margin-top:8px;
      display:grid;
      grid-template-columns:repeat(3,minmax(0,1fr));
      gap:6px;
    }
    .order-actions > .btn-group,
    .order-actions > button,
    .order-actions > .btn-modernizer{
      width:100%;
      min-width:0;
    }
    .order-actions .btn-modern{
      width:100%;
      height:38px;
      min-height:38px;
      padding:0 5px;
      justify-content:center;
      gap:5px;
      border-radius:6px;
      font-size:11px;
      white-space:nowrap;
    }
    .order-actions .dropdown-toggle::after{
      display:none;
    }
    .nested{
      padding:0 8px 8px;
    }
    .items-table{
      border-radius:10px;
    }
    .items-table thead{
      display:none;
    }
    .items-table tbody tr{
      display:grid;
      grid-template-columns:22px minmax(36px,.9fr) minmax(40px,1fr) minmax(31px,.76fr) 20px minmax(36px,.86fr) 54px 26px 26px;
      grid-template-rows:auto auto;
      gap:6px 2px;
      padding:9px 6px;
      border-top:1px solid #e2e8f0;
    }
    .items-table tbody tr:first-child{
      border-top:0;
    }
    .items-table tbody td{
      min-width:0;
      padding:0;
      border:0;
      display:flex;
      flex-direction:column;
      align-items:flex-start;
      justify-content:flex-start;
      gap:2px;
      overflow:hidden;
      color:#334155;
      font-size:8.5px;
      line-height:1.18;
      overflow-wrap:anywhere;
    }
    .items-table tbody td::before{
      color:#475569;
      font-size:7.5px;
      font-weight:700;
      line-height:1;
    }
    .items-table td[data-label="QTY"]{grid-column:1;grid-row:1 / span 2;align-items:center;}
    .items-table td[data-label="Produk"]{grid-column:2;grid-row:1;}
    .items-table td[data-label="Bahan"]{grid-column:3;grid-row:1;}
    .items-table td[data-label="Ukuran"]{grid-column:4;grid-row:1;}
    .items-table td[data-label="Cek"]{grid-column:5;grid-row:1;align-items:center;}
    .items-table td[data-label="Operator"]{grid-column:6;grid-row:1;}
    .items-table td[data-label="Keterangan"]{grid-column:2 / 5;grid-row:2;}
    .items-table td[data-label="Finishing"]{grid-column:5 / 10;grid-row:2;}
    .items-table td[data-label="Status"]{
      grid-column:7;
      grid-row:1;
      width:100%;
      overflow:visible;
      align-items:stretch;
    }
    .items-table td[data-label="Progres"]{
      grid-column:8 / 10;
      grid-row:1;
      padding:0;
      overflow:visible;
      align-items:stretch !important;
    }
    .operator-qty-badge{
      width:20px;
      height:20px;
      border-radius:50%;
      display:inline-flex;
      align-items:center;
      justify-content:center;
      background:#eef2ff;
      color:#0f172a;
      font-size:8px;
      font-weight:800;
    }
    .items-table .check-cell input[type="checkbox"]{
      width:15px;
      height:15px;
      min-height:15px;
      margin:0;
    }
    .items-table .fin-wrap{
      min-width:0;
      max-width:100%;
      gap:3px;
    }
    .items-table .fin-pill{
      max-width:100%;
      padding:2px 4px;
      font-size:9px;
    }
    .items-table .status-pillizer{
      width:100%;
      min-width:0;
      display:block;
    }
    .items-table .status-pillizer .btn,
    .items-table .status-pillizer a.btn,
    .items-table .status-pillizer .badge,
    .items-table .status-pillizer a.badge{
      width:100% !important;
      min-width:0 !important;
      height:26px !important;
      min-height:26px !important;
      padding:0 2px !important;
      justify-content:center !important;
      overflow:hidden;
      border-radius:5px !important;
      font-size:7px !important;
      line-height:1 !important;
      text-overflow:ellipsis;
      white-space:nowrap !important;
      box-shadow:0 2px 5px rgba(15,23,42,.1) !important;
    }
    .items-table .status-pillizer .btn i,
    .items-table .status-pillizer a.btn i{
      display:none !important;
    }
    .items-table .status-pillizer .btn .icon,
    .items-table .status-pillizer a.btn .icon{
      display:none !important;
    }
    .items-table .status-pillizer .text{
      width:auto !important;
      min-width:0;
      max-width:100%;
      padding:0 !important;
      margin:0 !important;
      flex:1 1 auto;
      overflow:hidden;
      font-size:6.5px !important;
      letter-spacing:-.02em;
      text-overflow:ellipsis;
      white-space:nowrap;
    }
    .items-table td[data-label="Progres"]::before{
      display:block;
      content:'Bukti';
      color:#475569;
      font-size:7.5px;
      font-weight:700;
      line-height:1;
    }
    .items-table td[data-label="Progres"] .progres-wrap{
      width:100%;
      padding:0;
      box-sizing:border-box;
      align-items:stretch;
    }
    .items-table td[data-label="Progres"] .status-item-actions{
      width:100%;
      display:grid;
      grid-template-columns:repeat(2,minmax(0,1fr));
      gap:2px;
    }
    .items-table td[data-label="Progres"] .status-item-actions.has-upload-proof{
      display:flex;
      flex-direction:column;
      align-items:stretch;
      gap:2px;
    }
    .items-table td[data-label="Progres"] .bukti-progress-upload-label{
      font-size:6.5px;
      line-height:1;
      text-align:center;
    }
    .items-table td[data-label="Progres"] .bukti-progress-upload-actions{
      display:grid;
      grid-template-columns:repeat(2,minmax(0,1fr));
      gap:2px;
      width:100%;
    }
    .items-table .btn-proof{
      width:100%;
      min-width:0;
      height:26px;
      min-height:26px;
      padding:0;
      justify-content:center;
      border-color:#d8e0ea;
      border-radius:5px;
      background:#fff;
      color:#0f172a;
      box-shadow:0 2px 6px rgba(15,23,42,.06);
    }
    .items-table .btn-proof i{
      font-size:10px;
    }
    .items-table .btn-bukti-upload{
      border-color:#bfdbfe;
      background:#eff6ff;
      color:#1d4ed8;
    }
    .items-table .btn-proof:active{
      transform:scale(.97);
    }
    .items-table .btn-proof span{
      display:none;
    }
    .items-table .bukti-preview{
      max-width:100%;
    }
  }
</style>

<!-- (BARU) Bungkus untuk target refresh AJAX -->
<?php if (!$render_card || !$wrap_single): ?>
<div id="orders-wrap" data-refresh-url="<?= htmlspecialchars($refresh_url, ENT_QUOTES, 'UTF-8'); ?>">
  <div class="cards-stack">
<?php endif; ?>
    <?php
      if (count($posts) === 0) {
        echo '<div class="order-card"><div class="nested" style="color:#111827;">Data belum ada.</div></div>';
      }

      $ci = & get_instance();
      $has_bukti_table = $ci->db->table_exists('invoice_detail_bukti');
      $level = isset($ci->session->level) ? strtolower(trim((string)$ci->session->level)) : '';
      $idu = isset($ci->session->idu) ? (int)$ci->session->idu : 0;
      $allowed_levels = ['admin', 'owner', 'operator', 'desain', 'kasir', 'keuangan'];
      $can_manage_progress = ($idu > 0 && $level !== '' && in_array($level, $allowed_levels, true));

      foreach ($posts as $row) {
        $id_invoice   = isset($row['id_invoice'])   ? $row['id_invoice']   : 0;
        $id_transaksi = isset($row['id_transaksi']) ? $row['id_transaksi'] : '-';
        $is_complaint_rework = stripos((string)$id_transaksi, 'CMP-') === 0;
        $tgl_trx      = isset($row['tgl_trx'])      ? $row['tgl_trx']      : '';
        $tgl_ambil    = isset($row['tgl_ambil'])    ? $row['tgl_ambil']    : '';
        $nama_plg     = isset($row['nama'])         ? $row['nama']         : '-';
        $kasir_name   = isset($row['kasir'])        ? $row['kasir']        : '-';
        $no_hp        = isset($row['no_hp'])        ? $row['no_hp']        : '';

        $enc_inv    = encrypt_url($id_invoice);
        $url_pdf    = base_url() . 'operator/print_invoice/' . $enc_inv;
        $pdf   = '<a class="dropdown-item" href="'.$url_pdf.'" target="_blank"><i class="fa fa-file-pdf-o"></i> Cetak PDF</a>';
        $print = '<a class="dropdown-item operator-print-choice" href="#" data-token="'.$enc_inv.'"><i class="fa fa-print"></i> Print</a>';

        $detail = isset($operator_detail_map[(int)$id_invoice]) && is_array($operator_detail_map[(int)$id_invoice])
          ? $operator_detail_map[(int)$id_invoice]
          : [];
        if (empty($detail) && empty($operator_detail_map)) {
          try { $detail = detail_order($id_invoice, $status_order, $produk); } catch (\Throwable $e) { $detail = []; }
        }

        $total_info = isset($operator_total_map[(int)$id_invoice]) && is_array($operator_total_map[(int)$id_invoice])
          ? $operator_total_map[(int)$id_invoice]
          : [];
        $total_order = isset($total_info['total_order'])
          ? (int)$total_info['total_order']
          : (function_exists('sumOrder') ? (int) sumOrder($id_invoice) : (int) ($row['total_bayar'] ?? 0));
        $total_diskon = isset($total_info['total_diskon'])
          ? (int)$total_info['total_diskon']
          : (function_exists('totalDiskon') ? (int) totalDiskon($id_invoice) : 0);
        $total_tagihan = max(0, $total_order - $total_diskon);
        if (isset($operator_payment_map[(int)$id_invoice])) {
          $total_bayar = (int)$operator_payment_map[(int)$id_invoice];
        } else {
          $total_bayar = 0;
        }
        if (!isset($operator_payment_map[(int)$id_invoice]) && function_exists('sumPiutang')) {
          $sumPiutang = sumPiutang($id_invoice);
          if (is_array($sumPiutang) && isset($sumPiutang[0]['piutang'])) {
            $total_bayar = (int) $sumPiutang[0]['piutang'];
          }
        }
        $is_lunas = $total_tagihan > 0 ? ($total_bayar >= $total_tagihan) : false;
        $pay_label = $is_lunas ? 'Lunas' : 'Belum Lunas';
        $pay_class = $is_lunas ? 'lunas' : 'belum';

        // FIX SAFETY: Saat filter produk dipilih, jangan tampilkan invoice yang tidak punya item sesuai produk.
        if (!empty($produk) && (string)$produk !== '0' && empty($detail)) {
          continue;
        }


		$status_codes = [];
        if (!empty($detail)) {
          foreach ($detail as $__d) {
            $stt = 0;
            if (is_array($__d)) { $__d = (object)$__d; }
            if (isset($__d->status)) { $stt = (int)$__d->status; }
			$status_codes[] = $stt;
          }
        }
		$status_pekerjaan = job_status_slowest($status_codes);

        if ($status_pekerjaan === 5) {
          $surat_html = '<button class="btn-modern btn-ghost buat_surat" data-id="'.$enc_inv.'">
            <i class="fa fa-file-text"></i><span>Surat Jalan</span>
          </button>';
        } else {
          $surat_html = '';
        }

        $update_items = [];
        if (!empty($detail)) {
          foreach ($detail as $__d) {
            if (is_array($__d)) { $__d = (object)$__d; }
            $id_detail  = isset($__d->id_rincianinvoice) ? $__d->id_rincianinvoice : 0;
            $enc_detail = encrypt_url($id_detail);
            $id_produk  = isset($__d->id_produk) ? $__d->id_produk : 0;
            $stt        = isset($__d->status) ? (int)$__d->status : 0;
            $nama_produk_item = isset($__d->nama_produk) && $__d->nama_produk !== '' ? $__d->nama_produk : nama_produk($id_produk);
            $cek_bahan_item = isset($__d->cek_bahan) ? (int)$__d->cek_bahan : null;
            $item_name = htmlspecialchars($nama_produk_item, ENT_QUOTES, 'UTF-8');
            $btn = pg_status_html($enc_detail, $stt, $can_manage_progress, $cek_bahan_item, $id_transaksi);

            $update_items[] = '<div class="update-item-row"><div class="update-item-name">'.$item_name.'</div><div class="update-item-btn">'.$btn.'</div></div>';
          }
        }
        $update_items_html = !empty($update_items)
          ? implode('', $update_items)
          : '<div class="update-item-empty">Item tidak tersedia.</div>';

        $table_id  = 'items-'.$id_invoice;
        $mini_id   = 'minip-'.$id_invoice;  // mini bar (thead)
        $minit_id  = 'minit-'.$id_invoice;  // mini text (thead)
    ?>
      <div class="order-card<?= $is_complaint_rework?' complaint-rework-card':''; ?>" data-invoice="<?= (int)$id_invoice; ?>">
        <div class="order-header">
          <div class="order-meta">
            <span class="operator-order-identity-mobile">
              <span class="order-code"><?= htmlspecialchars($id_transaksi, ENT_QUOTES, 'UTF-8'); ?></span>
              <span class="customer-name"><?= htmlspecialchars($nama_plg, ENT_QUOTES, 'UTF-8'); ?></span>
            </span>
            <span class="chip chip-order operator-order-identity-desktop">
              <span class="dot"></span>
              <span class="label">No. Order</span>:
              <span class="order-code"><?= htmlspecialchars($id_transaksi, ENT_QUOTES, 'UTF-8'); ?></span>
              <span class="sep">•</span>
              <span class="customer-name"><?= htmlspecialchars($nama_plg, ENT_QUOTES, 'UTF-8'); ?></span>
            </span>
            <?php if ($is_complaint_rework): ?>
              <span class="chip chip-complaint-rework" title="Pekerjaan rework dari komplain pelanggan"><i class="fa fa-exclamation-circle"></i> Komplain · Rework</span>
            <?php endif; ?>

            <!--span class="chip chip-muted"><i class="fa fa-calendar"></i> <?= dtimes($tgl_trx); ?></span-->
            <span class="chip chip-muted"><i class="fa fa-calendar-check-o"></i> <?= dtimes($tgl_ambil); ?></span>
            <?php if (!$render_card): ?>
              <span class="chip chip-kasir"><i class="fa fa-id-badge"></i> <?= htmlspecialchars($kasir_name, ENT_QUOTES, 'UTF-8'); ?></span>
            <?php endif; ?>
            <span class="chip chip-pay <?= $pay_class; ?>"><i class="fa fa-credit-card"></i> <?= $pay_label; ?></span>
            <?php if (!$render_card): ?>
              <span class="operator-mobile-progress" title="Progres order ini">
                <span class="mini-outer"><span class="mini-inner" id="mobile-minip-<?= (int)$id_invoice; ?>"></span></span>
                <span class="mini-text" id="mobile-minit-<?= (int)$id_invoice; ?>">0%</span>
              </span>
            <?php endif; ?>
          </div>

          <?php if (!$render_card): ?>
            <div class="order-actions">
              <!-- CETAK SPK -->
              <div class="btn-group dropleft">
                <button type="button" class="btn-modern btn-spk dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                  <i class="fa fa-print"></i> Cetak SPK
                </button>
                <div class="dropdown-menu dropdown-menu-right">
                  <?= $pdf.$print; ?>
                </div>
              </div>

              <!-- KIRIM WA -->
              <button class="btn-modern btn-wa kirim_wa"
                      data-id="<?= $enc_inv; ?>"
                      data-nomor="<?= htmlspecialchars((string)$no_hp, ENT_QUOTES, 'UTF-8'); ?>"
                      data-trx="<?= htmlspecialchars((string)$id_transaksi, ENT_QUOTES, 'UTF-8'); ?>"
                      data-tgl="<?= htmlspecialchars((string)$tgl_trx, ENT_QUOTES, 'UTF-8'); ?>">
                <i class="fa fa-whatsapp"></i> Kirim WA
              </button>

              <!-- UPDATE STATUS (PER ITEM) -->
              <?php if ($can_manage_progress): ?>
                <div class="btn-group dropleft update-item-group">
                  <button type="button" class="btn-modern btn-ghost dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    <i class="fa fa-refresh"></i> Update Status
                  </button>
                  <div class="dropdown-menu dropdown-menu-right update-item-menu">
                    <div class="update-item-head">
                      <div class="update-item-col">Item Produk</div>
                      <div class="update-item-col">Status</div>
                    </div>
                    <?= $update_items_html; ?>
                  </div>
                </div>
              <?php endif; ?>

              <!-- SURAT JALAN (kondisional) -->
              <?= $surat_html; ?>
            </div>
          <?php endif; ?>
        </div>

        <div class="nested">
          <?php if (empty($detail)): ?>
            <div class="chip chip-muted">Detail item tidak tersedia.</div>
          <?php else: ?>
            <table class="items-table<?= $render_card ? ' items-table-card' : '' ?>" id="<?= $table_id; ?>" data-invoice="<?= (int)$id_invoice; ?>">
              <thead>
                <tr>
                  <th style="width:7%">QTY</th>
                  <th class="text-left" style="width:15%">Produk</th>
                  <th class="text-left" style="width:17%">Bahan</th>
                  <th class="text-left" style="width:9%">Ukuran</th>
                  <th class="text-left" style="width:10%">Keterangan</th>
                  <th class="text-left" style="width:18%">Finishing</th>

                  <?php if (!$render_card): ?>
                    <!-- KOLOM CEK (SEBELUM OPERATOR) -->
                    <th class="check-cell" style="width:5%">Cek</th>
                    <th class="text-left" style="width:12%">Operator</th>
                  <?php endif; ?>
                  <th class="text-left" style="width:12%">Status</th>

                  <!-- PENGGANTI CHECK ALL: Mini Progress -->
                  <th style="width:5%">
                    <?php if (!$render_card): ?>
                      <div class="mini-prog" title="Progres order ini">
                        <div class="mini-outer"><div class="mini-inner" id="<?= $mini_id; ?>"></div></div>
                        <div class="mini-text" id="<?= $minit_id; ?>">0%</div>
                      </div>
                    <?php endif; ?>
                  </th>
                </tr>
              </thead>
              <tbody>
              <?php
                $i = 0;
                foreach ($detail as $val) {
                  if (is_array($val)) { $val = (object)$val; }

                  $id_produk   = isset($val->id_produk) ? $val->id_produk : 0;
                  $jumlah      = isset($val->jumlah)    ? $val->jumlah    : 0;
                  $ukuran      = isset($val->ukuran)    ? $val->ukuran    : '';
                  $keterangan  = isset($val->keterangan)? $val->keterangan: '';
                  $id_bahan    = isset($val->id_bahan)  ? $val->id_bahan  : null;
                  $id_operator = isset($val->id_operator)? $val->id_operator: 0;
                  $st          = isset($val->status)    ? (int)$val->status: 0; // 0 = Baru
                  $id_detail   = isset($val->id_rincianinvoice) ? $val->id_rincianinvoice : 0;
                  $enc_detail  = encrypt_url($id_detail);
                  $cek_bahan_val = isset($val->cek_bahan) ? (int)$val->cek_bahan : null;
                  $status = pg_status_html($enc_detail, $st, $can_manage_progress, $cek_bahan_val, $id_transaksi);

                  $operator = isset($val->nama_operator) && $val->nama_operator !== '' ? $val->nama_operator : (!empty($id_operator) ? juser($id_operator) : '-');
                  $bukti_items = isset($operator_proof_map[(int)$id_detail]) && is_array($operator_proof_map[(int)$id_detail])
                    ? $operator_proof_map[(int)$id_detail]
                    : [];
                  if (empty($bukti_items) && empty($operator_detail_map) && $has_bukti_table && $id_detail) {
                    $caption_field = $ci->db->field_exists('keterangan', 'invoice_detail_bukti')
                      ? 'keterangan'
                      : "'' AS keterangan";
                    $bukti_rows = $ci->db
                      ->select("id, filename, {$caption_field}, created_at, updated_at", false)
                      ->where('id_rincianinvoice', $id_detail)
                      ->order_by('COALESCE(created_at, updated_at) ASC, id ASC', '', false)
                      ->get('invoice_detail_bukti')
                      ->result_array();
                    foreach ($bukti_rows as $bukti_row) {
                      $proof_time = !empty($bukti_row['created_at']) ? $bukti_row['created_at'] : $bukti_row['updated_at'];
                      $bukti_row['url'] = base_url('uploads/lampiran/progress/' . rawurlencode($bukti_row['filename']));
                      $bukti_row['uploaded_at_label'] = !empty($proof_time)
                        ? date('d/m/Y H:i:s', strtotime($proof_time)) . ' WIB'
                        : '-';
                      $bukti_items[] = $bukti_row;
                    }
                  }
                  if (empty($bukti_items) && !empty($val->bukti_file)) {
                    $bukti_items[] = [
                      'url' => base_url('uploads/lampiran/progress/' . rawurlencode((string)$val->bukti_file)),
                      'keterangan' => 'Bukti progres',
                      'uploaded_at_label' => '-',
                    ];
                  }
                  if (isset($val->nama_bahan) && $val->nama_bahan !== '') {
                    $bahan = $val->nama_bahan;
                  } else {
                    $bahanObj = getDetailBahan($id_bahan);
                    $bahan    = $bahanObj ? safe_prop($bahanObj, ['title','nama','name'], '-') : '-';
                  }
                  $nama_produk_val = isset($val->nama_produk) && $val->nama_produk !== '' ? $val->nama_produk : nama_produk($id_produk);
                  $catatan_gallery_items = [];
                  $finishingJson = null;
                  if (!empty($val->detail)) {
                    $finishingJson = @json_decode($val->detail);
                  }
                  if (is_object($finishingJson) && !empty($finishingJson->data)) {
                    foreach ($finishingJson->data as $f) {
                      $fTitle = trim((string) safe_prop($f, ['title','nama','name'], ''));
                      $fIsi   = trim((string) safe_prop($f, ['isi','value','val'], ''));
                      $catatan_text = '';
                      if ($fTitle !== '' && $fIsi !== '') $catatan_text = $fTitle . ': ' . $fIsi;
                      else if ($fTitle !== '')            $catatan_text = $fTitle;
                      else if ($fIsi !== '')              $catatan_text = $fIsi;
                      $catatan_text = preg_replace('/^\s*:\s*/', '', $catatan_text);
                      $catatan_text = preg_replace('/\s+/', ' ', $catatan_text);
                      $catatan_text = trim((string)$catatan_text);

                      $fGambarRaw = trim((string) safe_prop($f, ['gambar','image','img'], ''));
                      if ($fGambarRaw === '') {
                        continue;
                      }
                      $fGambarUrl = '';
                      if (preg_match('#^https?://#i', $fGambarRaw)) {
                        $fGambarUrl = $fGambarRaw;
                      } else {
                        $fGambarUrl = base_url(ltrim($fGambarRaw, '/'));
                      }
                      $catatan_gallery_items[] = [
                        'url'  => $fGambarUrl,
                        'text' => ($catatan_text !== '' ? $catatan_text : '-')
                      ];
                    }
                    if (!empty($catatan_gallery_items)) {
                      $unique_gallery_items = [];
                      foreach ($catatan_gallery_items as $gallery_item) {
                        $url_key = isset($gallery_item['url']) ? (string)$gallery_item['url'] : '';
                        if ($url_key === '' || isset($unique_gallery_items[$url_key])) {
                          continue;
                        }
                        $unique_gallery_items[$url_key] = $gallery_item;
                      }
                      $catatan_gallery_items = array_values($unique_gallery_items);
                    }
                  }

                  $finishing_html = '<span class="fin-empty">-</span>';
                  if ($render_card) {
                    if ((int)$id_detail > 0) {
                      $catatan_url = site_url('status-board/detail-catatan') . '?rid=' . (int)$id_detail;
                      $finishing_html = '<div class="btn-modernizer"><button type="button" class="btn btn-warning btn-sm btn-catatan-popup" data-url="' . htmlspecialchars($catatan_url, ENT_QUOTES, 'UTF-8') . '" title="Isi Catatan"><i class="fa fa-print"></i> Isi Catatan</button></div>';
                    }
                  } elseif (is_object($finishingJson) && !empty($finishingJson->data)) {
                    $tmp = [];
                    foreach ($finishingJson->data as $f) {
                      $fTitle = trim((string) safe_prop($f, ['title','nama','name'], ''));
                      $fIsi   = trim((string) safe_prop($f, ['isi','value','val'], ''));
                      $fGambarRaw = trim((string) safe_prop($f, ['gambar','image','img'], ''));

                      $fGambarUrl = '';
                      if ($fGambarRaw !== '') {
                        if (preg_match('#^https?://#i', $fGambarRaw)) {
                          $fGambarUrl = $fGambarRaw;
                        } else {
                          $fGambarUrl = base_url(ltrim($fGambarRaw, '/'));
                        }
                      }

                      // gabungkan rapi
                      $text = '';
                      if ($fTitle !== '' && $fIsi !== '') $text = $fTitle . ': ' . $fIsi;
                      else if ($fTitle !== '')           $text = $fTitle;
                      else if ($fIsi !== '')             $text = $fIsi;

                      // bersihin: buang ":" di depan & spasi berlebih
                      $text = preg_replace('/^\s*:\s*/', '', $text);
                      $text = preg_replace('/\s+/', ' ', $text);
                      $text = trim($text);

                      $labelText = $text !== '' ? $text : ($fGambarUrl !== '' ? 'Gambar finishing' : '');
                      $captionText = $text !== '' ? $text : pg_clean_text($keterangan, '');
                      if ($captionText === '-') {
                        $captionText = '';
                      }
                      if ($labelText !== '' || $fGambarUrl !== '') {
                        $item = '<div class="fin-item">';
                        if ($labelText !== '') {
                          $item .= '<span class="fin-pill"><span class="dot"></span>' . htmlspecialchars($labelText, ENT_QUOTES, 'UTF-8') . '</span>';
                        }
                        if ($fGambarUrl !== '') {
                          $safeUrl = htmlspecialchars($fGambarUrl, ENT_QUOTES, 'UTF-8');
                          $safeCaption = htmlspecialchars($captionText, ENT_QUOTES, 'UTF-8');
                          $item .= '<a href="' . $safeUrl . '" class="fin-img-btn bukti-open" title="Preview Gambar Finishing" data-caption="' . $safeCaption . '" data-time=""><img src="' . $safeUrl . '" alt="Gambar finishing"></a>';
                        }
                        $item .= '</div>';
                        $tmp[] = $item;
                      }
                    }

                    if (!empty($tmp)) {
                      $finishing_html = '<div class="fin-wrap">' . implode('', $tmp) . '</div>';
                    }
                  }


                  $cb_id = 'cek_'.$id_invoice.'_'.$i;
              ?>
                <!-- data-st untuk deteksi "Baru" -->
                <tr data-st="<?= (int)$st; ?>">
                  <td data-label="QTY"><span class="operator-qty-badge"><?= htmlspecialchars((string)$jumlah, ENT_QUOTES, 'UTF-8'); ?></span></td>
                  <td class="text-left" data-label="Produk"><?= htmlspecialchars($nama_produk_val, ENT_QUOTES, 'UTF-8'); ?></td>
                  <td class="text-left" data-label="Bahan"><?= htmlspecialchars($bahan, ENT_QUOTES, 'UTF-8'); ?></td>
                  <td class="text-left" data-label="Ukuran"><?= htmlspecialchars($ukuran, ENT_QUOTES, 'UTF-8'); ?></td>
                  <!-- ✅ PATCH FIX &amp; DI SINI -->
                  <td class="text-left" data-label="Keterangan">
                    <?= htmlspecialchars(pg_clean_text($keterangan, '-'), ENT_QUOTES, 'UTF-8'); ?>
                  </td>
                  <td class="text-left" data-label="Finishing"><?= $finishing_html; ?></td>

                  <?php if (!$render_card): ?>
                    <!-- Checkbox progres (SEBELUM OPERATOR) -->
                    <td class="check-cell" data-label="Cek">
                      <input type="checkbox"
                             id="<?= $cb_id; ?>"
                             class="item-status-check"
                             name="cek_item[<?= (int)$id_invoice; ?>][]"
                             value="<?= htmlspecialchars((string)$id_produk, ENT_QUOTES, 'UTF-8'); ?>|<?= $i; ?>"
                             data-invoice="<?= (int)$id_invoice; ?>"
                             data-index="<?= $i; ?>">
                    </td>

                    <td class="text-left" data-label="Operator"><?= htmlspecialchars($operator, ENT_QUOTES, 'UTF-8'); ?></td>
                  <?php endif; ?>
                  <td class="text-left status-cell" data-label="Status">
                    <span class="status-pillizer"><?= $status; ?></span>
                  </td>


                  <td class="text-left progres-cell" data-label="Progres">
                    <div class="progres-wrap">
                      <?php if ($render_card): ?>
                        <?php if (!empty($catatan_gallery_items)): ?>
                          <div class="status-item-actions">
                            <button type="button"
                                    class="btn-proof btn-catatan-gallery"
                                    data-product="<?= htmlspecialchars($nama_produk_val, ENT_QUOTES, 'UTF-8'); ?>"
                                    data-gallery="<?= htmlspecialchars(json_encode($catatan_gallery_items, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
                              <i class="fa fa-image"></i><span>Lihat Gambar (<?= count($catatan_gallery_items); ?>)</span>
                            </button>
                          </div>
                        <?php else: ?>
                          <span class="fin-empty">-</span>
                        <?php endif; ?>
                      <?php elseif ($can_manage_progress): ?>
                        <div class="status-item-actions has-upload-proof">
                          <span class="bukti-progress-upload-label">upload bukti progres</span>
                          <div class="bukti-progress-upload-actions">
                            <button type="button"
                                    class="btn-proof btn-bukti-camera"
                                    aria-label="Ambil foto bukti"
                                    title="Ambil foto bukti"
                                    data-id="<?= $enc_detail; ?>"
                                    data-mobile-input="bukti-camera-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                    data-preview="bukti-prev-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>">
                              <i class="fa fa-camera"></i><span>Camera</span>
                            </button>
                            <button type="button"
                                    class="btn-proof btn-bukti-upload"
                                    aria-label="Upload bukti"
                                    title="Upload bukti"
                                    data-id="<?= $enc_detail; ?>"
                                    data-input="bukti-upload-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                    data-preview="bukti-prev-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>">
                              <i class="fa fa-upload"></i><span>Upload</span>
                            </button>
                          </div>
                          <input type="file"
                                 id="bukti-upload-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                 class="bukti-input"
                                 data-id="<?= $enc_detail; ?>"
                                 data-preview="bukti-prev-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                 accept="image/*"
                                 multiple
                                 hidden>
                          <input type="file"
                                 id="bukti-camera-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                 class="bukti-camera-input"
                                 data-id="<?= $enc_detail; ?>"
                                 data-preview="bukti-prev-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>"
                                 accept="image/*"
                                 capture="environment"
                                 hidden>
                        </div>
                      <?php endif; ?>
                      <div class="bukti-preview" id="bukti-prev-<?= (int)$id_invoice; ?>-<?= (int)$i; ?>">
                        <?php if (!$render_card && !empty($bukti_items)): ?>
                          <?php foreach ($bukti_items as $bukti_item):
                            $proof_url = isset($bukti_item['url']) ? (string)$bukti_item['url'] : '';
                            $proof_caption = trim((string)($bukti_item['keterangan'] ?? ''));
                            $proof_caption = $proof_caption !== '' ? $proof_caption : 'Bukti progres';
                            $proof_time_label = trim((string)($bukti_item['uploaded_at_label'] ?? ''));
                            $proof_time_label = $proof_time_label !== '' ? $proof_time_label : '-';
                            if ($proof_url === '') continue;
                          ?>
                            <a class="bukti-thumb bukti-open"
                               href="<?= htmlspecialchars($proof_url, ENT_QUOTES, 'UTF-8'); ?>"
                               data-caption="<?= htmlspecialchars($proof_caption, ENT_QUOTES, 'UTF-8'); ?>"
                               data-time="<?= htmlspecialchars($proof_time_label, ENT_QUOTES, 'UTF-8'); ?>"
                               aria-label="Buka gambar bukti">
                              <img src="<?= htmlspecialchars($proof_url, ENT_QUOTES, 'UTF-8'); ?>" alt="Bukti progres">
                            </a>
                          <?php endforeach; ?>
                        <?php endif; ?>
                      </div>
                    </div>
                  </td>
                </tr>
              <?php $i++; } ?>
              </tbody>
            </table>
          <?php endif; ?>
        </div>
      </div>
    <?php } // end foreach ?>
  </div>

  <?php if (!$render_card || !$wrap_single): ?>
    <nav aria-label="Page navigation" class="mt-2">
      <?php
        if (isset($this->ajax_pagination) && method_exists($this->ajax_pagination, 'create_links')) {
          echo $this->ajax_pagination->create_links();
        }
      ?>
    </nav>
  </div>
  <?php endif; ?>

<div id="bukti-modal" class="bukti-modal<?= !$render_card ? ' bukti-gallery-modal' : ''; ?>" aria-hidden="true">
  <div class="bukti-modal-content" role="dialog" aria-modal="true" aria-label="Preview gambar">
    <div class="bukti-modal-header">
      <span>Preview Gambar</span>
      <button type="button" id="bukti-modal-close" class="bukti-modal-close">Tutup</button>
    </div>
    <div class="bukti-modal-body">
      <div id="bukti-modal-stage" class="bukti-modal-stage">
        <button type="button" id="bukti-modal-prev" class="bukti-modal-nav bukti-modal-prev is-hidden" aria-label="Gambar sebelumnya">
          <i class="fa fa-chevron-left" aria-hidden="true"></i>
        </button>
        <img id="bukti-modal-img" src="" alt="Preview gambar" draggable="false">
        <button type="button" id="bukti-modal-next" class="bukti-modal-nav bukti-modal-next is-hidden" aria-label="Gambar berikutnya">
          <i class="fa fa-chevron-right" aria-hidden="true"></i>
        </button>
        <span id="bukti-modal-counter" class="bukti-modal-counter is-single"></span>
      </div>
    </div>
    <div id="bukti-modal-meta" class="bukti-modal-meta">
      <span id="bukti-modal-caption" class="bukti-modal-caption"></span>
      <span id="bukti-modal-time" class="bukti-modal-time"></span>
    </div>
  </div>
</div>
<div id="bukti-upload-modal" class="bukti-modal" aria-hidden="true">
  <div class="bukti-modal-content bukti-upload-content" role="dialog" aria-modal="true" aria-label="Upload bukti progres">
    <div class="bukti-modal-header">
      <span>Upload Bukti Progres</span>
      <button type="button" id="bukti-upload-close" class="bukti-modal-close">Tutup</button>
    </div>
    <div class="bukti-modal-body">
      <p class="bukti-upload-help">Isi keterangan untuk setiap gambar. Waktu upload akan dicatat otomatis oleh sistem.</p>
      <div id="bukti-upload-list" class="bukti-upload-list"></div>
    </div>
    <div class="bukti-upload-actions">
      <button type="button" id="bukti-upload-cancel" class="btn-proof">Batal</button>
      <button type="button" id="bukti-upload-submit" class="btn-proof btn-bukti-upload">
        <i class="fa fa-upload"></i><span>Upload Semua</span>
      </button>
    </div>
  </div>
</div>
<div id="bukti-camera-modal" class="bukti-modal" aria-hidden="true">
  <div class="bukti-modal-content" role="dialog" aria-modal="true" aria-label="Ambil gambar kamera">
    <div class="bukti-modal-header">
      <span>Ambil Foto Camera</span>
      <button type="button" id="bukti-camera-close" class="bukti-modal-close">Tutup</button>
    </div>
    <div class="bukti-modal-body">
      <div class="bukti-camera-wrap">
        <video id="bukti-camera-video" autoplay playsinline muted></video>
      </div>
      <canvas id="bukti-camera-canvas" hidden></canvas>
      <div class="bukti-camera-actions">
        <button type="button" id="bukti-camera-capture" class="btn-proof">
          <i class="fa fa-camera"></i><span>Ambil Foto</span>
        </button>
      </div>
    </div>
  </div>
</div>

<?php if (!$render_card): ?>
<script>
  window.OPERATOR_PROGRESS_MAP = <?= json_encode($operator_progress_map, JSON_UNESCAPED_SLASHES); ?> || {};

  // ===== Util progres (ke DB via AJAX) =====
  function calcPct($table){
    const total   = $table.find('tbody .item-status-check').length;
    const checked = $table.find('tbody .item-status-check:checked').length;
    return total > 0 ? Math.round((checked/total)*100) : 0;
  }

  function getCheckedIndices($table){
    const arr = [];
    $table.find('tbody .item-status-check').each(function(){
      if (this.checked) arr.push(parseInt($(this).data('index'), 10));
    });
    return arr;
  }

  function applyIndicesToTable($table, indices){
    const set = new Set((indices || []).map(function(x){return String(x);})); 
    $table.find('tbody .item-status-check').each(function(){
      const idx = String($(this).data('index'));
      this.checked = set.has(idx);
    });
  }

  function renderProgress(inv, pct){
    const miniBar = document.getElementById('minip-'+inv);
    const miniTxt = document.getElementById('minit-'+inv);
    const mobileMiniBar = document.getElementById('mobile-minip-'+inv);
    const mobileMiniTxt = document.getElementById('mobile-minit-'+inv);
    if(miniBar){ miniBar.style.width = pct + '%'; miniBar.setAttribute('aria-valuenow', pct); }
    if(miniTxt){ miniTxt.textContent = pct + '%'; }
    if(mobileMiniBar){ mobileMiniBar.style.width = pct + '%'; mobileMiniBar.setAttribute('aria-valuenow', pct); }
    if(mobileMiniTxt){ mobileMiniTxt.textContent = pct + '%'; }
  }

  function fetchProgress($table){
    const inv = $table.data('invoice');
    if(!inv) return;
    const preload = window.OPERATOR_PROGRESS_MAP && Object.prototype.hasOwnProperty.call(window.OPERATOR_PROGRESS_MAP, String(inv))
      ? window.OPERATOR_PROGRESS_MAP[String(inv)]
      : null;
    if(preload){
      applyIndicesToTable($table, preload.indices || []);
      renderProgress(inv, parseInt(preload.pct || 0, 10));
      return;
    }
    if(window.OPERATOR_PROGRESS_MAP){
      renderProgress(inv, 0);
      return;
    }
    $.post(base_url + 'progress/get', {invoice: inv}, function(res){
      if(res && res.ok){
        applyIndicesToTable($table, res.indices || []);
        renderProgress(inv, parseInt(res.pct||0,10));
      } else {
        renderProgress(inv, 0);
      }
    }, 'json').fail(function(){
      renderProgress(inv, 0);
    });
  }

  function saveProgress($table){
    const inv   = $table.data('invoice');
    if(!inv) return;
    const idxs  = getCheckedIndices($table);
    const pct   = calcPct($table);

    $.post(base_url + 'progress/save', {invoice: inv, indices: idxs, pct: pct}, function(res){
      if(res && res.ok){
        window.OPERATOR_PROGRESS_MAP = window.OPERATOR_PROGRESS_MAP || {};
        window.OPERATOR_PROGRESS_MAP[String(inv)] = {
          indices: res.indices || idxs,
          pct: parseInt(res.pct || pct, 10)
        };
        renderProgress(inv, parseInt(res.pct||0,10));
      }
    }, 'json');
  }

  // Event: perubahan centang
  $(document).on('change', '.item-status-check', function(){
    const $table = $(this).closest('table.items-table');
    saveProgress($table);
  });

  // Inisialisasi: ambil progres dari DB
  $(function(){
    $('.items-table').each(function(){
      fetchProgress($(this));
    });
  });

  // ============================================================
  //  NOTIFIKASI SUARA untuk Transaksi Status "Baru"
  //  - Bunyi 1x per transaksi yang benar-benar baru (belum pernah diputar)
  //  - Menggunakan set invoice agar tidak dobel saat soft refresh
  // ============================================================

  (function(){
    // Simpan daftar invoice yang sudah pernah memicu notifikasi
    window.NOTIFIED_SET = window.NOTIFIED_SET || new Set();
    // Alias sesuai permintaan: seenInvoices
    window.seenInvoices = window.NOTIFIED_SET;

    // WebAudio fallback "beep"
    var AudioCtxCtor = window.AudioContext || window.webkitAudioContext;
    var audioCtx = AudioCtxCtor ? new AudioCtxCtor() : null;

    function beepOnce(durationMs){
      if(!audioCtx) return;
      var now = audioCtx.currentTime;
      var o = audioCtx.createOscillator();
      var g = audioCtx.createGain();
      o.type = 'sine';
      o.frequency.setValueAtTime(1100, now);
      g.gain.setValueAtTime(0.0001, now);
      g.gain.exponentialRampToValueAtTime(0.25, now + 0.02);
      g.gain.exponentialRampToValueAtTime(0.0001, now + (durationMs/1000));
      o.connect(g); g.connect(audioCtx.destination);
      o.start(now);
      o.stop(now + (durationMs/1000) + 0.05);
    }

    function playBeepTimes(times){
      times = Math.max(0, parseInt(times||0,10));
      if(times === 0) return;
      var gap = 220;
      var dur = 320;
      var count = 0;
      var i = setInterval(function(){
        beepOnce(dur);
        count++;
        if(count >= times) clearInterval(i);
      }, dur + gap);
    }

    // Pemutar audio custom (fallback ke beep jika gagal)
    function playCustomTimes(times){
      times = Math.max(0, parseInt(times||0,10));
      if(times === 0) return Promise.resolve();

      var url = (window.NOTIF_SOUND_URL || '').trim();
      if(!url) { playBeepTimes(times); return Promise.resolve(); }

      var audio = new Audio(url);
      audio.preload = 'auto';

      return new Promise(function(resolve){
        var count = 0;
        function playNext(){
          if(count >= times){ resolve(); return; }
          audio.currentTime = 0;
          var p = audio.play();
          if(p && typeof p.then === 'function'){
            p.then(function(){
              count++;
              audio.onended = playNext;
            }).catch(function(){
              playBeepTimes(times - count);
              resolve();
            });
          }else{
            playBeepTimes(times);
            resolve();
          }
        }
        playNext();
      });
    }

    function isOrderNew(orderCard){
      var rows = orderCard.querySelectorAll('table.items-table tbody tr[data-st]');
      for(var i=0;i<rows.length;i++){
        var st = parseInt(rows[i].getAttribute('data-st') || '0', 10);
        if(st === 0) return true; // 0 = Baru
      }
      return false;
    }

    function markInitialAndCountNew(){
      var cards = document.querySelectorAll('.order-card');
      var n = 0;
      cards.forEach(function(card){
        var inv = parseInt(card.getAttribute('data-invoice')||'0',10);
        if(!inv) return;
        if(isOrderNew(card) && !window.NOTIFIED_SET.has(inv)){
          n++;
          window.NOTIFIED_SET.add(inv);
        }
      });
      return n;
    }

    // Pertama kali halaman siap -> bunyikan untuk yang baru & tandai
    $(function(){
      var firstCount = markInitialAndCountNew();
      if(firstCount > 0){
        playCustomTimes(firstCount);
      }
    });

    // Observer: jika ada .order-card baru via DOM (mis. hasil AJAX ganti isi)
    var observer = new MutationObserver(function(mutations){
      var addCount = 0;
      mutations.forEach(function(m){
        m.addedNodes && m.addedNodes.forEach(function(node){
          if(!(node instanceof Element)) return;
          var consider = [];
          if(node.matches && node.matches('.order-card')){
            consider.push(node);
          }
          if(node.querySelectorAll){
            node.querySelectorAll('.order-card').forEach(function(c){ consider.push(c); });
          }
          consider.forEach(function(c){
            var inv = parseInt(c.getAttribute('data-invoice')||'0',10);
            if(inv && isOrderNew(c) && !window.NOTIFIED_SET.has(inv)){
              window.NOTIFIED_SET.add(inv);
              addCount++;
            }
          });
        });
      });
      if(addCount > 0){
        playCustomTimes(addCount);
      }
    });
    observer.observe(document.getElementById('orders-wrap'), {childList:true, subtree:true});
  })();

  // ============================================================
  //  SOFT REFRESH berkala (tetap seperti sebelumnya)
  //  - Interval tidak diubah (pertahankan yang lainnya)
  //  - Fungsi diekspos global agar bisa dipanggil setelah update status
  // ============================================================

  (function(){
    var intervalMs = 300000; // autoload ajax: 5 menit

    function refreshOrdersSoft(){
      if (document.hidden) return; // skip saat tab tidak aktif
      var url = (window.REFRESH_URL || '').trim();
      if(!url){ url = window.location.href; }

      $.get(url, function(html){
        var tmp = document.createElement('div');
        tmp.innerHTML = html;

        var newStack = tmp.querySelector('.cards-stack');
        if(!newStack){
          var wrap = tmp.querySelector('#orders-wrap .cards-stack');
          if(wrap) newStack = wrap;
        }
        if(!newStack) return;

        var $stack = $('.cards-stack');
        if(!$stack.length) return;

        $stack.html(newStack.innerHTML);

        // Re-init progress untuk tabel yang baru masuk
        $('.items-table').each(function(){
          fetchProgress($(this));
        });
      }, 'html');
    }

    // Ekspos ke global agar bisa dipanggil dari mana saja
    window.refreshOrdersSoft = refreshOrdersSoft;

    // Refresh berkala (tidak diubah)
    setInterval(refreshOrdersSoft, intervalMs);
  })();

  // ============================================================
  //  (BARU) Auto-reload setelah UPDATE STATUS transaksi (AJAX)
  //  - Mengandalkan hook global ajaxSuccess
  //  - Deteksi URL yang mengandung kata 'status'
  //  - Setelah sukses: trigger soft refresh (tanpa reset seenInvoices/NOTIFIED_SET)
  // ============================================================
  (function(){
    // jQuery global ajaxSuccess hook
    $(document).ajaxSuccess(function(event, xhr, settings){
      try{
        var url = (settings && settings.url) ? String(settings.url).toLowerCase() : '';
        if(!url) return;

        // Pola umum endpoint update status
        var isStatusUpdate =
          url.indexOf('status') !== -1 ||
          url.indexOf('update_status') !== -1 ||
          url.indexOf('proses_status') !== -1 ||
          url.indexOf('/status/') !== -1;

        if(isStatusUpdate){
          // Beri jeda singkat agar backend selesai commit -> baru refresh
          setTimeout(function(){
            if (typeof window.refreshOrdersSoft === 'function') {
              window.refreshOrdersSoft();
            }
          }, 200);
        }
      }catch(e){}
    });

    // Bila ada kode update status kustom non-jQuery,
    // Anda bisa memicu event manual ini setelah sukses:
    // $(document).trigger('status:updated')
    $(document).on('status:updated', function(){
      if (typeof window.refreshOrdersSoft === 'function') {
        window.refreshOrdersSoft();
      }
    });
  })();

  // ====== Pilih printer aktif untuk tombol Print operator ======
  (function(){
    function escOperatorPrinterText(value) {
      return String(value == null ? '' : value).replace(/[&<>"']/g, function(match) {
        return {
          '&': '&amp;',
          '<': '&lt;',
          '>': '&gt;',
          '"': '&quot;',
          "'": '&#039;'
        }[match];
      });
    }

    function isOperatorInvoicePrinter(printer) {
      var slug = String((printer && printer.slug) || '').toLowerCase();
      return slug === 'in' || slug === 'dotmatrix';
    }

    function operatorPrintUrl(token, printer) {
      var query = printer && printer.id ? '?printer_id=' + encodeURIComponent(printer.id) : '';
      if (isOperatorInvoicePrinter(printer)) {
        return base_url + 'operator/print_invoice_html/' + token + query;
      }
      return base_url + 'operator/print_spk_thermal_raw/' + token + query;
    }

    function openOperatorPrinter(token, printer) {
      if (!token || !printer) return;
      window.open(operatorPrintUrl(token, printer), '_blank');
    }

    function loadOperatorActivePrinters(callback) {
      $.ajax({
        type: 'GET',
        url: base_url + 'produk/active_printers',
        dataType: 'json',
        cache: false,
        data: { _: Date.now() },
        success: function(response) {
          window.operatorActivePrinters = response && $.isArray(response.printers) ? response.printers : [];
          callback(window.operatorActivePrinters);
        },
        error: function() {
          var printers = $.isArray(window.operatorActivePrinters) ? window.operatorActivePrinters : [];
          callback(printers);
        }
      });
    }

    function showOperatorPrinterOptions(token, printers) {
      var html = '<div class="operator-printer-options">';
      $.each(printers, function(idx, printer) {
        var shared = printer.shared_name || '';
        var paper = printer.ukuran_kertas ? 'Kertas ' + printer.ukuran_kertas : '';
        var position = printer.posisi ? ' - ' + printer.posisi : '';
        var label = isOperatorInvoicePrinter(printer) ? 'Cetak SPK' : 'Cetak struk SPK';
        var icon = isOperatorInvoicePrinter(printer) ? 'fa-file-text-o' : 'fa-print';

        html += '<button type="button" class="operator-printer-option" data-printer-id="' + escOperatorPrinterText(printer.id) + '">' +
          '<strong><i class="fa ' + icon + '"></i> ' + escOperatorPrinterText(printer.name || shared || 'Printer') + '</strong>' +
          '<small>' + escOperatorPrinterText(label) + (shared ? ' - ' + escOperatorPrinterText(shared) : '') + (paper ? ' - ' + escOperatorPrinterText(paper + position) : '') + '</small>' +
          '</button>';
      });
      html += '</div>';

      window.pendingOperatorPrintToken = token;

      if (typeof Swal === 'undefined') {
        openOperatorPrinter(token, printers[0]);
        return;
      }

      Swal.fire({
        title: 'Pilih printer aktif',
        html: html,
        showConfirmButton: false,
        showCloseButton: true,
        allowOutsideClick: false,
        width: 520
      });
    }

    $(document).off('click.operatorPrintChoice').on('click.operatorPrintChoice', '.operator-print-choice', function(e){
      e.preventDefault();
      var token = $(this).attr('data-token') || '';
      if (!token) return;

      loadOperatorActivePrinters(function(printers) {
        if (printers.length > 1) {
          showOperatorPrinterOptions(token, printers);
        } else if (printers.length === 1) {
          openOperatorPrinter(token, printers[0]);
        } else if (typeof Swal !== 'undefined') {
          Swal.fire('Printer belum aktif', 'Aktifkan minimal satu printer di Pengaturan printer.', 'warning');
        }
      });
    });

    $(document).off('click.operatorPrinterOption').on('click.operatorPrinterOption', '.operator-printer-option', function(){
      var printerId = String($(this).data('printer-id'));
      var token = window.pendingOperatorPrintToken || '';
      var printers = $.isArray(window.operatorActivePrinters) ? window.operatorActivePrinters : [];
      var selected = null;

      $.each(printers, function(idx, printer) {
        if (String(printer.id) === printerId) {
          selected = printer;
          return false;
        }
      });

      if (typeof Swal !== 'undefined') {
        Swal.close();
      }

      if (token && selected) {
        openOperatorPrinter(token, selected);
      }
    });
  })();

  // ====== Kode eksisting (tidak diubah) ======
  $(document).on('click','.buat_surat',function(e){
    e.preventDefault();
    var dataID = $(this).attr('data-id');
    var userEl = document.getElementById('user');
    var user   = userEl ? userEl.value : '';
    $.ajax({
      url: base_url + 'laporan/load_modal',
      method: 'POST',
      data: {id:dataID, user:user},
      success: function(data) {
        if (data==='error') {
          sweet('Peringatan!!!','Maaf Data telah direkap & tidak bisa di edit','warning','warning');
        } else {
		  $(".load-modal").html(data);
		  $("#surat_jalan").modal('show');
        }
      },
      error: function (xhr, ajaxOptions, thrownError) {
        sweet('Peringatan!!!', thrownError, 'warning','warning');
      }
    });
  });

  $(document).on('click', '.kirim_wa', function(e) {
    e.preventDefault();
    var id    = $(this).attr('data-id');
    var nomor = $(this).attr('data-nomor') || '';
    var trx   = $(this).attr('data-trx')   || '';
    var tgl   = $(this).attr('data-tgl')   || '';

    $('#WaLabel').html('Kirim ' + trx);
    $('#OpenModalWa').modal({backdrop: 'static', keyboard: false});

    $.ajax({
      url: base_url + 'whatsapp/get_form_wa',
      method: 'POST',
      dataType: 'html',
      data: {id:id, nomor:nomor, tgl:tgl},
      beforeSend: function(){ $('body').loading && $('body').loading(); },
      success: function(data) {
        $(".load-data-wa").html(data);
        $('body').loading && $('body').loading('stop');
      },
      error: function(xhr) {
        var err = xhr.responseText || 'Server error';
        sweet('Server!!!', err, 'error', 'danger');
        $('body').loading && $('body').loading('stop');
      }
    });
  });

  window.searchFilter = window.searchFilter || function(termOrInput, tableSelector) {
    try {
      var q = '';
      if (typeof termOrInput === 'string') q = termOrInput;
      else if (termOrInput && termOrInput.value !== undefined) q = termOrInput.value;
      else if (window.jQuery && termOrInput && termOrInput.jquery) q = termOrInput.val();
      q = (q || '').toString().toLowerCase();
      if (!window.jQuery) return;
      var $ = window.jQuery;
      var $table = tableSelector ? $(tableSelector) : $('.table:visible').first();
      if (!$table.length) return;
      $table.find('tbody tr').each(function () {
        var show = $(this).text().toLowerCase().indexOf(q) > -1;
        $(this).toggle(show);
      });
    } catch (err) { console.warn('searchFilter fallback warning:', err); }
  };

  var buktiGalleryState = {
    items: [],
    index: 0,
    touchStartX: null,
    touchStartY: null
  };

  function renderBuktiGalleryItem(index){
    var total = buktiGalleryState.items.length;
    if (!total) return;
    index = Math.max(0, Math.min(index, total - 1));
    buktiGalleryState.index = index;

    var item = buktiGalleryState.items[index] || {};
    var itemCaption = $.trim(item.caption || '');
    var itemTime = $.trim(item.timeLabel || '');
    $('#bukti-modal-img').attr('src', item.url || '');
    $('#bukti-modal-caption').text(itemCaption).toggle(itemCaption !== '');
    $('#bukti-modal-time').text(itemTime).toggle(itemTime !== '');
    $('#bukti-modal-meta').toggleClass('is-visible', itemCaption !== '' || itemTime !== '');
    $('#bukti-modal-counter')
      .text((index + 1) + ' / ' + total)
      .toggleClass('is-single', total <= 1);
    $('#bukti-modal-prev')
      .prop('disabled', index <= 0)
      .toggleClass('is-hidden', total <= 1);
    $('#bukti-modal-next')
      .prop('disabled', index >= total - 1)
      .toggleClass('is-hidden', total <= 1);

    if (index + 1 < total) {
      var preloadNext = new Image();
      preloadNext.src = buktiGalleryState.items[index + 1].url || '';
    }
  }

  function openBuktiModal(items, index){
    if (!items || !items.length) return;
    buktiGalleryState.items = items;
    buktiGalleryState.index = index || 0;
    buktiGalleryState.touchStartX = null;
    buktiGalleryState.touchStartY = null;
    renderBuktiGalleryItem(buktiGalleryState.index);
    $('#bukti-modal').addClass('is-open');
  }

  function moveBuktiGallery(step){
    if (!$('#bukti-modal').hasClass('is-open')) return;
    var nextIndex = buktiGalleryState.index + step;
    if (nextIndex < 0 || nextIndex >= buktiGalleryState.items.length) return;
    renderBuktiGalleryItem(nextIndex);
  }

  function closeBuktiModal(){
    $('#bukti-modal').removeClass('is-open');
    $('#bukti-modal-img').attr('src', '');
    $('#bukti-modal-caption, #bukti-modal-time').text('');
    $('#bukti-modal-meta').removeClass('is-visible');
    $('#bukti-modal-counter').text('').addClass('is-single');
    $('#bukti-modal-prev, #bukti-modal-next').prop('disabled', false).addClass('is-hidden');
    buktiGalleryState = { items: [], index: 0, touchStartX: null, touchStartY: null };
  }

  $(document).on('click', '.bukti-open', function(e){
    e.preventDefault();
    var $clicked = $(this);
    var $timeline = $clicked.closest('.bukti-preview');
    var $links = $timeline.length
      ? $timeline.find('.bukti-thumb.bukti-open')
      : $clicked;
    var items = [];
    $links.each(function(){
      items.push({
        url: $(this).attr('href') || '',
        caption: $(this).attr('data-caption') || '',
        timeLabel: $(this).attr('data-time') || ''
      });
    });
    var activeIndex = $links.index(this);
    openBuktiModal(items, activeIndex >= 0 ? activeIndex : 0);
  });

  $(document).on('click', '#bukti-modal-prev', function(e){
    e.preventDefault();
    e.stopPropagation();
    moveBuktiGallery(-1);
  });

  $(document).on('click', '#bukti-modal-next', function(e){
    e.preventDefault();
    e.stopPropagation();
    moveBuktiGallery(1);
  });

  $(document).on('touchstart', '#bukti-modal-stage', function(e){
    var touch = e.originalEvent.touches && e.originalEvent.touches[0];
    if (!touch) return;
    buktiGalleryState.touchStartX = touch.clientX;
    buktiGalleryState.touchStartY = touch.clientY;
  });

  $(document).on('touchend', '#bukti-modal-stage', function(e){
    var touch = e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
    if (!touch || buktiGalleryState.touchStartX === null || buktiGalleryState.touchStartY === null) return;
    var deltaX = touch.clientX - buktiGalleryState.touchStartX;
    var deltaY = touch.clientY - buktiGalleryState.touchStartY;
    buktiGalleryState.touchStartX = null;
    buktiGalleryState.touchStartY = null;
    if (Math.abs(deltaX) < 45 || Math.abs(deltaX) <= Math.abs(deltaY)) return;
    moveBuktiGallery(deltaX < 0 ? 1 : -1);
  });

  $(document).on('click', '#bukti-modal, #bukti-modal-close', function(e){
    if (e.target.id === 'bukti-modal' || e.target.id === 'bukti-modal-close') {
      closeBuktiModal();
    }
  });

  var buktiCameraState = {
    target: null,
    stream: null,
    uploading: false
  };
  var buktiUploadState = {
    files: [],
    encId: '',
    previewId: '',
    input: null
  };

  function escapeBuktiHtml(value){
    return $('<div>').text(value === null || value === undefined ? '' : String(value)).html();
  }

  function buktiProofHtml(proof){
    var url = proof && proof.url ? String(proof.url) : '';
    if (!url) return '';
    var caption = proof.keterangan ? String(proof.keterangan) : 'Bukti progres';
    var timeLabel = proof.uploaded_at_label ? String(proof.uploaded_at_label) : '-';
    var safeUrl = escapeBuktiHtml(url);
    var safeCaption = escapeBuktiHtml(caption);
    var safeTime = escapeBuktiHtml(timeLabel);

    return '<a class="bukti-thumb bukti-open" href="' + safeUrl + '"' +
      ' data-caption="' + safeCaption + '" data-time="' + safeTime + '" aria-label="Buka gambar bukti">' +
        '<img src="' + safeUrl + '" alt="Bukti progres">' +
      '</a>';
  }

  function openBuktiUploadModal(files, encId, previewId, input){
    buktiUploadState.files = files || [];
    buktiUploadState.encId = encId || '';
    buktiUploadState.previewId = previewId || '';
    buktiUploadState.input = input || null;

    var html = '';
    $.each(buktiUploadState.files, function(index, file){
      var filename = file && file.name ? file.name : ('Gambar ' + (index + 1));
      html += '<div class="bukti-upload-item" data-index="' + index + '">' +
        '<span class="bukti-upload-number">' + (index + 1) + '</span>' +
        '<div>' +
          '<span class="bukti-upload-file" title="' + escapeBuktiHtml(filename) + '">' + escapeBuktiHtml(filename) + '</span>' +
          '<input type="text" class="bukti-upload-caption-input" maxlength="255"' +
            ' placeholder="Contoh: Proses cetak" aria-label="Keterangan gambar ' + (index + 1) + '">' +
        '</div>' +
      '</div>';
    });
    $('#bukti-upload-list').html(html);
    $('#bukti-upload-modal').addClass('is-open');
    setTimeout(function(){
      $('#bukti-upload-list .bukti-upload-caption-input').first().trigger('focus');
    }, 50);
  }

  function closeBuktiUploadModal(){
    $('#bukti-upload-modal').removeClass('is-open');
    $('#bukti-upload-list').empty();
    if (buktiUploadState.input) {
      $(buktiUploadState.input).val('');
    }
    buktiUploadState = { files: [], encId: '', previewId: '', input: null };
  }

  $(document).on('click', '#bukti-upload-modal, #bukti-upload-close, #bukti-upload-cancel', function(e){
    if (e.target.id === 'bukti-upload-modal' || e.target.id === 'bukti-upload-close' || e.target.id === 'bukti-upload-cancel') {
      if (!buktiCameraState.uploading) closeBuktiUploadModal();
    }
  });

  function isBuktiMobileDevice(){
    var ua = (navigator.userAgent || navigator.vendor || window.opera || '').toLowerCase();
    if (/android|iphone|ipad|ipod|iemobile|opera mini|mobile/i.test(ua)) {
      return true;
    }
    if (window.matchMedia) {
      try {
        return window.matchMedia('(pointer:coarse)').matches;
      } catch (e) {}
    }
    return false;
  }

  function stopBuktiCameraStream(){
    if (buktiCameraState.stream && buktiCameraState.stream.getTracks) {
      $.each(buktiCameraState.stream.getTracks(), function(_, track){
        try { track.stop(); } catch (e) {}
      });
    }
    buktiCameraState.stream = null;
    var videoEl = document.getElementById('bukti-camera-video');
    if (videoEl) videoEl.srcObject = null;
  }

  function openBuktiCameraModal(){
    $('#bukti-camera-modal').addClass('is-open');
  }

  function closeBuktiCameraModal(){
    $('#bukti-camera-modal').removeClass('is-open');
    stopBuktiCameraStream();
  }

  $(document).on('click', '#bukti-camera-modal, #bukti-camera-close', function(e){
    if (e.target.id === 'bukti-camera-modal' || e.target.id === 'bukti-camera-close') {
      closeBuktiCameraModal();
      if (!buktiCameraState.uploading) {
        buktiCameraState.target = null;
      }
    }
  });

  $(document).on('keydown', function(e){
    if ($('#bukti-modal').hasClass('is-open') && e.key === 'ArrowLeft') {
      e.preventDefault();
      moveBuktiGallery(-1);
      return;
    }
    if ($('#bukti-modal').hasClass('is-open') && e.key === 'ArrowRight') {
      e.preventDefault();
      moveBuktiGallery(1);
      return;
    }
    if (e.key === 'Escape') {
      closeBuktiModal();
      closeBuktiCameraModal();
      if (!buktiCameraState.uploading) closeBuktiUploadModal();
      if (!buktiCameraState.uploading) {
        buktiCameraState.target = null;
      }
    }
  });

  $(document).on('click', '.btn-bukti-upload', function(){
    if (buktiCameraState.uploading) {
      if (typeof showNotif === 'function') {
        showNotif('bottom-right', 'Upload', 'Masih ada proses upload berjalan', 'warning');
      }
      return;
    }
    var inputId = $(this).attr('data-input');
    if (!inputId) return;
    var input = document.getElementById(inputId);
    if (input) input.click();
  });

  $(document).on('click', '.btn-bukti-camera', function(){
    if (buktiCameraState.uploading) {
      if (typeof showNotif === 'function') {
        showNotif('bottom-right', 'Camera', 'Masih ada proses upload berjalan', 'warning');
      }
      return;
    }

    var $btn = $(this);
    var encId = $btn.attr('data-id') || '';
    var previewId = $btn.attr('data-preview') || '';
    var mobileInputId = $btn.attr('data-mobile-input') || '';
    if (!encId) return;

    buktiCameraState.target = {
      encId: encId,
      previewId: previewId,
      $actions: $btn.closest('.status-item-actions')
    };

    if (isBuktiMobileDevice()) {
      if (!mobileInputId) return;
      var mobileInput = document.getElementById(mobileInputId);
      if (mobileInput) {
        mobileInput.click();
      }
      return;
    }

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      buktiCameraState.target = null;
      if (typeof sweet === 'function') {
        sweet('Peringatan!!!', 'Browser tidak mendukung webcam', 'warning', 'warning');
      }
      return;
    }

    var videoEl = document.getElementById('bukti-camera-video');
    if (!videoEl) {
      buktiCameraState.target = null;
      if (typeof sweet === 'function') {
        sweet('Peringatan!!!', 'Komponen camera tidak ditemukan', 'warning', 'warning');
      }
      return;
    }

    openBuktiCameraModal();
    navigator.mediaDevices.getUserMedia({
      video: { facingMode: 'environment' },
      audio: false
    }).then(function(stream){
      buktiCameraState.stream = stream;
      videoEl.srcObject = stream;
      if (videoEl.play) videoEl.play();
    }).catch(function(){
      closeBuktiCameraModal();
      buktiCameraState.target = null;
      if (typeof sweet === 'function') {
        sweet('Peringatan!!!', 'Tidak bisa mengakses camera', 'warning', 'warning');
      }
    });
  });

  function baseFileName(name){
    if (!name) return 'bukti-progress';
    return name.replace(/\.[^/.]+$/, '');
  }

  function prepareBuktiUploadFile(fileObj){
    var dfd = $.Deferred();
    if (!fileObj || !/^image\//i.test(fileObj.type || '') || typeof FileReader === 'undefined') {
      dfd.resolve({
        file: fileObj,
        filename: fileObj ? fileObj.name : 'bukti-progress.jpg'
      });
      return dfd.promise();
    }

    var reader = new FileReader();
    reader.onload = function(evt){
      var img = new Image();
      img.onload = function(){
        var maxSide = 1600;
        var ratio = Math.min(maxSide / img.width, maxSide / img.height, 1);
        var newW = Math.max(1, Math.round(img.width * ratio));
        var newH = Math.max(1, Math.round(img.height * ratio));

        var canvas = document.createElement('canvas');
        canvas.width = newW;
        canvas.height = newH;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, newW, newH);

        if (!canvas.toBlob) {
          dfd.resolve({ file: fileObj, filename: fileObj.name });
          return;
        }

        canvas.toBlob(function(blob){
          if (!blob || blob.size <= 0) {
            dfd.resolve({ file: fileObj, filename: fileObj.name });
            return;
          }

          var optimizedName = baseFileName(fileObj.name) + '.webp';
          var finalFile = blob;
          if (typeof File !== 'undefined') {
            try {
              finalFile = new File([blob], optimizedName, {
                type: 'image/webp',
                lastModified: Date.now()
              });
            } catch (e) {
              finalFile = blob;
            }
          }

          dfd.resolve({
            file: finalFile,
            filename: optimizedName
          });
        }, 'image/webp', 0.82);
      };

      img.onerror = function(){
        dfd.resolve({ file: fileObj, filename: fileObj.name });
      };

      img.src = evt.target.result;
    };

    reader.onerror = function(){
      dfd.resolve({ file: fileObj, filename: fileObj.name });
    };

    reader.readAsDataURL(fileObj);
    return dfd.promise();
  }

  function uploadBuktiProgressFile(file, encId, previewId, caption, doneCb, quietSuccess){
    if (!file || !encId) {
      if (typeof doneCb === 'function') doneCb(false, null);
      return;
    }

    buktiCameraState.uploading = true;
    prepareBuktiUploadFile(file).done(function(payload){
      var fd = new FormData();
      fd.append('id', encId);
      fd.append('keterangan', caption || 'Bukti progres');
      fd.append('lampiran', payload.file, payload.filename || file.name);
      var uploadOk = false;
      var uploadResponse = null;

      $.ajax({
        url: base_url + 'laporan/upload_bukti_progress',
        method: 'POST',
        data: fd,
        processData: false,
        contentType: false,
        dataType: 'json',
        beforeSend: function(){
          $('body').loading && $('body').loading();
        },
        success: function(res){
          uploadResponse = res;
          if (res && res.success) {
            uploadOk = true;
            if (previewId) {
              var $wrap = $('#' + previewId);
              if ($wrap.length) {
                $wrap.append(buktiProofHtml(res));
              }
            }

            if (!quietSuccess && typeof showNotif === 'function') {
              showNotif('bottom-right', 'Upload', 'Bukti progres tersimpan', 'success');
            }
          } else {
            var msg = (res && res.message) ? res.message : 'Upload gagal';
            if (typeof sweet === 'function') {
              sweet('Peringatan!!!', msg, 'warning', 'warning');
            }
          }
        },
        error: function(xhr){
          var msg = 'Upload gagal';
          if (xhr && xhr.responseJSON && xhr.responseJSON.message) {
            msg = xhr.responseJSON.message;
          } else if (xhr && xhr.responseText) {
            msg = xhr.responseText;
          }
          if (typeof sweet === 'function') {
            sweet('Peringatan!!!', msg, 'warning', 'warning');
          }
        },
        complete: function(){
          $('body').loading && $('body').loading('stop');
          buktiCameraState.uploading = false;
          if (typeof doneCb === 'function') doneCb(uploadOk, uploadResponse);
        }
      });
    }).fail(function(){
      if (typeof sweet === 'function') {
        sweet('Peringatan!!!', 'Gagal menyiapkan file gambar', 'warning', 'warning');
      }
      buktiCameraState.uploading = false;
      if (typeof doneCb === 'function') doneCb(false, null);
    });
  }

  $(document).on('change', '.bukti-input', function(){
    var $input = $(this);
    var files = this.files ? Array.prototype.slice.call(this.files) : [];
    files = files.filter(function(file){
      return file && /^image\//i.test(file.type || '');
    });
    if (!files.length) {
      $input.val('');
      return;
    }

    var encId = $input.attr('data-id');
    var previewId = $input.attr('data-preview');
    if (!encId) {
      $input.val('');
      return;
    }

    openBuktiUploadModal(files, encId, previewId, this);
  });

  $(document).on('click', '#bukti-upload-submit', function(){
    if (buktiCameraState.uploading || !buktiUploadState.files.length) return;

    var captions = [];
    var valid = true;
    $('#bukti-upload-list .bukti-upload-caption-input').each(function(){
      var caption = $.trim($(this).val() || '');
      $(this).toggleClass('is-invalid', caption === '');
      if (caption === '') valid = false;
      captions.push(caption);
    });
    if (!valid) {
      $('#bukti-upload-list .bukti-upload-caption-input.is-invalid').first().trigger('focus');
      if (typeof showNotif === 'function') {
        showNotif('bottom-right', 'Upload', 'Keterangan setiap gambar wajib diisi', 'warning');
      }
      return;
    }

    var files = buktiUploadState.files.slice();
    var encId = buktiUploadState.encId;
    var previewId = buktiUploadState.previewId;
    var index = 0;
    var successCount = 0;
    $('#bukti-upload-submit, #bukti-upload-cancel, #bukti-upload-close').prop('disabled', true);

    function uploadNext(){
      if (index >= files.length) {
        $('#bukti-upload-submit, #bukti-upload-cancel, #bukti-upload-close').prop('disabled', false);
        closeBuktiUploadModal();
        if (typeof showNotif === 'function') {
          var message = successCount === files.length
            ? successCount + ' bukti progres berhasil disimpan'
            : successCount + ' dari ' + files.length + ' bukti berhasil disimpan';
          showNotif('bottom-right', 'Upload', message, successCount ? 'success' : 'warning');
        }
        return;
      }

      var currentIndex = index;
      index++;
      uploadBuktiProgressFile(files[currentIndex], encId, previewId, captions[currentIndex], function(ok){
        if (ok) successCount++;
        uploadNext();
      }, true);
    }

    uploadNext();
  });

  $(document).on('change', '.bukti-camera-input', function(){
    var $input = $(this);
    var file = this.files && this.files[0] ? this.files[0] : null;
    if (!file) {
      buktiCameraState.target = null;
      return;
    }

    var encId = $input.attr('data-id');
    var previewId = $input.attr('data-preview');
    if (!encId) {
      $input.val('');
      buktiCameraState.target = null;
      return;
    }

    uploadBuktiProgressFile(file, encId, previewId, 'Foto camera', function(){
      $input.val('');
      buktiCameraState.target = null;
    });
  });

  $(document).on('click', '#bukti-camera-capture', function(){
    if (buktiCameraState.uploading) {
      if (typeof showNotif === 'function') {
        showNotif('bottom-right', 'Camera', 'Masih ada proses upload berjalan', 'warning');
      }
      return;
    }
    if (!buktiCameraState.target || !buktiCameraState.target.encId) {
      return;
    }

    var videoEl = document.getElementById('bukti-camera-video');
    var canvasEl = document.getElementById('bukti-camera-canvas');
    if (!videoEl || !canvasEl || !videoEl.videoWidth || !videoEl.videoHeight) {
      if (typeof sweet === 'function') {
        sweet('Peringatan!!!', 'Camera belum siap', 'warning', 'warning');
      }
      return;
    }

    canvasEl.width = videoEl.videoWidth;
    canvasEl.height = videoEl.videoHeight;
    var ctx = canvasEl.getContext('2d');
    ctx.drawImage(videoEl, 0, 0, canvasEl.width, canvasEl.height);

    canvasEl.toBlob(function(blob){
      if (!blob) {
        if (typeof sweet === 'function') {
          sweet('Peringatan!!!', 'Gagal mengambil foto', 'warning', 'warning');
        }
        return;
      }

      var fileObj = blob;
      if (typeof File !== 'undefined') {
        try {
          fileObj = new File([blob], 'bukti-camera.jpg', {
            type: 'image/jpeg',
            lastModified: Date.now()
          });
        } catch (e) {
          fileObj = blob;
        }
      }

      var target = buktiCameraState.target;
      closeBuktiCameraModal();
      uploadBuktiProgressFile(fileObj, target.encId, target.previewId, 'Foto camera', function(){
        buktiCameraState.target = null;
      });
    }, 'image/jpeg', 0.92);
  });
</script>
<?php endif; ?>

<?php if ($render_card): ?>
<script>
  function openBuktiModal(url){
    if (!url) return;
    var $modal = document.getElementById('bukti-modal');
    var img = document.getElementById('bukti-modal-img');
    if (img) img.src = url;
    if ($modal) $modal.classList.add('is-open');
  }

  function closeBuktiModal(){
    var $modal = document.getElementById('bukti-modal');
    var img = document.getElementById('bukti-modal-img');
    if (img) img.src = '';
    if ($modal) $modal.classList.remove('is-open');
  }

  document.addEventListener('click', function(e){
    var link = e.target.closest && e.target.closest('.bukti-open');
    if (link) {
      e.preventDefault();
      openBuktiModal(link.getAttribute('href'));
      return;
    }
    if (e.target && (e.target.id === 'bukti-modal' || e.target.id === 'bukti-modal-close')) {
      closeBuktiModal();
    }
  });

  document.addEventListener('keydown', function(e){
    if (e.key === 'Escape') closeBuktiModal();
  });
</script>
<?php endif; ?>
