<?php $this->start('body');
    $t       = $this->data['tender'] ?? [];
    $hist    = $this->data['stage_history'] ?? [];
    $bidders = $this->data['bidders'] ?? [];
    $result  = $this->data['result'] ?? null;
    $stages  = $this->data['stages'] ?? [];

    $curIdx  = array_search($t['tender_stage'], $stages, true);
    $stageChip = [
        'PREP'=>'#94A3B8','SUBMISSION'=>'#7A8BA1','FOLLOW_UP'=>'#D4A574','OPENING'=>'#7A9E7E',
        'NEGOTIATIONS'=>'#D4A574','AWARDED'=>'#166534','CONTRACT_SIGNING'=>'#166534','EXECUTION'=>'#334155',
    ];
    $stCol = $stageChip[$t['tender_stage']] ?? '#94A3B8';
    $statusChip = ['OPEN'=>'#7A8BA1','WON'=>'#166534','LOST'=>'#C48579','CANCELLED'=>'#94A3B8','WITHDRAWN'=>'#94A3B8'];
    $stsCol = $statusChip[$t['tender_status']] ?? '#94A3B8';
    // Projects are auto-created by the Exec on approval of TENDER_CONTRACT — see Tenders::onContractApproved.
    // The manual "Create project" button is retired; kept in the model as a fallback for edge cases (Admin only).

    // Requirements panel data
    $docTypes    = $this->data['doc_types']    ?? [];
    $requiredIds = array_flip($this->data['required_ids'] ?? []);
    $catLabels   = [
        'SUBMISSION'       => 'Submission Documents',
        'FOLLOW_UP'        => 'Follow-up Documents',
        'NEGOTIATION'      => 'Negotiation Documents',
        'RESULT'           => 'Result / Award Documents',
        'BID_OPENING'      => 'Bid-opening Documents',
        'CONTRACT_SIGNING' => 'Contract-signing Documents',
        'EXPENSE'          => 'Expense Documents',
        'PRICING_INTERNAL' => 'Pricing (internal)',
        'TENDER_PACK'      => 'Tender Pack',
    ];
    $catOrder = ['SUBMISSION','FOLLOW_UP','BID_OPENING','NEGOTIATION','RESULT','CONTRACT_SIGNING','EXPENSE','TENDER_PACK','PRICING_INTERNAL'];
    $totalReq = count($this->data['required_ids'] ?? []);
    $totalStat = 0;
    foreach ($docTypes as $rows) foreach ($rows as $dt) if ((int)$dt['is_statutory'] === 1 && isset($requiredIds[(int)$dt['c0d']])) $totalStat++;
?>

<div class="d-flex align-items-center justify-content-between mb-3">
    <div>
        <h5 class="mb-0" style="font-weight:600;color:#334155;"><i class="fas fa-file-signature me-2" style="color:#7A8BA1;"></i><?= htmlspecialchars($t['tender_no']); ?> · <?= htmlspecialchars($t['tender_title']); ?></h5>
        <div class="text-muted small mt-1" style="color:#64748B;"><?= htmlspecialchars($t['buyer_name']); ?><?php if (!empty($t['customer_display'])): ?> · customer: <?= htmlspecialchars((string)$t['customer_display']); ?><?php endif; ?> · <?= htmlspecialchars($t['source_type']); ?></div>
    </div>
    <div class="d-flex align-items-center gap-2">
        <span class="badge" style="background:<?= $stCol; ?>;color:#fff;font-size:.72rem;padding:.35rem .7rem;"><?= ucfirst(strtolower(str_replace('_',' ',$t['tender_stage']))); ?></span>
        <span class="badge" style="background:<?= $stsCol; ?>;color:#fff;font-size:.72rem;padding:.35rem .7rem;"><?= $t['tender_status']; ?></span>
        <?php if (UserGroups::can('Tenders','edit')): ?><a href="<?= PROOT; ?>Tenders/edit/<?= (int)$t['c0d']; ?>" class="btn btn-sm" style="background:#F8FAFC;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-edit me-1" style="color:#7A8BA1;"></i>Edit</a><?php endif; ?>
        <a href="<?= PROOT; ?>Tenders" class="btn btn-sm" style="background:#F8FAFC;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-arrow-left me-1"></i>Back</a>
    </div>
</div>

<?php if (!empty($t['linked_project_id'])): ?>
<div class="alert py-2 mb-3" style="background:#DCFCE7;border:1px solid #86EFAC;color:#166534;font-size:.86rem;">
    <i class="fas fa-check-circle me-1"></i>
    <strong>Linked to project <?= htmlspecialchars((string)$t['project_no']); ?></strong>
    · CRM status: <?= htmlspecialchars((string)$t['crm_status']); ?>
    <?php if ($t['crm_status'] === 'PENDING'): ?> · <a href="<?= PROOT; ?>Onboarding" style="color:#166534;font-weight:600;">Complete onboarding checklist →</a><?php endif; ?>
</div>
<?php endif; ?>

<?php
    // Cross-tab CTA: WON+AWARDED (or later) with no contract terms yet → nudge FM to the Contract signing tab.
    $awardedIdx  = array_search('AWARDED', $stages, true);
    $signingIdx  = array_search('CONTRACT_SIGNING', $stages, true);
    $termsRow    = $this->data['contract_terms'] ?? null;
    $apprRow     = $this->data['contract_approval'] ?? null;
    $needsTerms  = ($t['tender_status'] === 'WON')
                   && ($curIdx >= $awardedIdx)
                   && $termsRow === null
                   && UserGroups::can('Tenders','saveContractTermsAj');
    $awaitingApproval = ($termsRow !== null) && (($apprRow['status'] ?? '') === 'IN_PROGRESS');
?>
<?php if ($needsTerms): ?>
<div class="alert py-2 mb-3 d-flex align-items-center justify-content-between" style="background:#FEF3C7;border:1px solid #F59E0B;color:#78350F;font-size:.86rem;">
    <div>
        <i class="fas fa-clipboard-list me-1"></i>
        <strong>Contract terms needed.</strong>
        This tender is Awarded/Won — Finance Manager must capture the contract terms before the approval chain can start.
    </div>
    <a href="#tab-contract" class="btn btn-sm" data-bs-toggle="tab"
       style="background:#F59E0B;border-color:#F59E0B;color:#fff;font-weight:600;">
        <i class="fas fa-arrow-right me-1"></i> Enter contract terms
    </a>
</div>
<?php elseif ($awaitingApproval): ?>
<div class="alert py-2 mb-3" style="background:#F8FAFC;border:1px solid #7A8BA1;color:#334155;font-size:.86rem;">
    <i class="fas fa-hourglass-half me-1"></i>
    Contract terms captured — approval chain in progress. Track it on the
    <a href="#tab-contract" data-bs-toggle="tab" style="color:#334155;font-weight:600;">Contract signing tab</a>.
</div>
<?php endif; ?>

<!-- ── Advance-stage toolbar (persistent) ─────────────────────────────── -->
<?php if (UserGroups::can('Tenders','advanceStageAj') && $t['tender_status'] === 'OPEN' && $curIdx < count($stages) - 1): ?>
<div class="card border-0 shadow-sm mb-3" style="background:#F8FAFC;">
    <div class="card-body p-2 d-flex align-items-center gap-2 flex-wrap">
        <span style="color:#64748B;font-size:.82rem;"><i class="fas fa-arrow-right me-1" style="color:#7A8BA1;"></i>Current stage <strong style="color:#334155;"><?= ucfirst(strtolower(str_replace('_',' ', $t['tender_stage']))); ?></strong>. Advance to:</span>
        <select id="new_stage" class="form-select form-select-sm" style="max-width:220px;">
            <?php for ($i = $curIdx + 1; $i < count($stages); $i++): ?>
                <option value="<?= $stages[$i]; ?>"><?= ucfirst(strtolower(str_replace('_',' ', $stages[$i]))); ?></option>
            <?php endfor; ?>
        </select>
        <input type="text" id="stage_notes" placeholder="Optional notes" class="form-control form-control-sm" style="flex:1;min-width:200px;">
        <button type="button" id="btn_advance" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-check me-1"></i>Advance</button>
    </div>
</div>
<?php endif; ?>

<!-- ── KPIs ─────────────────────────────────────────────────────────────── -->
<div class="row g-3 mb-3">
    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="border-left:4px solid #7A8BA1 !important;background:#F8FAFC;"><div class="card-body p-3">
        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;" title="Buyer's own budget estimate on the RFP">Buyer estimate</div>
        <div style="font-weight:700;font-size:1.3rem;color:#334155;">TZS <?= number_format((float)$t['estimated_value']); ?></div>
        <div class="small" style="color:#94A3B8;font-size:.68rem;">pre-bid</div>
    </div></div></div>
    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="border-left:4px solid #D4A574 !important;background:#F8FAFC;"><div class="card-body p-3">
        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;" title="The amount we submitted as our priced bid">Our bid</div>
        <div style="font-weight:700;font-size:1.3rem;color:#334155;">TZS <?= number_format((float)$t['submission_amount']); ?></div>
        <div class="small" style="color:#94A3B8;font-size:.68rem;">submitted</div>
    </div></div></div>
    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="border-left:4px solid #7A8BA1 !important;background:#F8FAFC;"><div class="card-body p-3">
        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Deadline</div>
        <div style="font-weight:700;font-size:1rem;color:#334155;"><?= htmlspecialchars((string)($t['deadline_date'] ?? '—')); ?></div>
        <div class="text-muted small" style="color:#64748B;font-size:.72rem;"><?= htmlspecialchars((string)($t['deadline_time'] ?? '')); ?></div>
    </div></div></div>
    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="background:#F8FAFC;"><div class="card-body p-3">
        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Bidders</div>
        <div style="font-weight:700;font-size:1.3rem;color:#334155;"><?= count($bidders); ?></div>
    </div></div></div>
</div>

<!-- ── Stage-based tabs (free navigation, current stage highlighted) ──── -->
<?php
    $subFilled = !empty($t['submission_amount']) || !empty($t['submission_date']) || !empty($t['submission_method']);
    // Which tab-pane id maps to each stage (some panes are shared / stubs for now)
    $stageTab = [
        'PREP'             => 'tab-prep',
        'SUBMISSION'       => 'tab-submission',
        'FOLLOW_UP'        => 'tab-followup',
        'OPENING'          => 'tab-opening',
        'NEGOTIATIONS'     => 'tab-negotiations',
        'AWARDED'          => 'tab-awarded',
        'CONTRACT_SIGNING' => 'tab-contract',
        'EXECUTION'        => 'tab-execution',
    ];
    $currentTabId = $stageTab[$t['tender_stage']] ?? 'tab-details';
    // Small style helper: current stage tab shows a coloured underline + bold weight
    $tabStyle = function (string $tabId) use ($currentTabId, $stCol) {
        return $tabId === $currentTabId
            ? "color:#334155;font-weight:600;border-bottom:3px solid $stCol;"
            : "color:#334155;";
    };
    $tabRibbon = function (string $stage) use ($t) {
        // Return a tiny ▸ hint if this stage is BEFORE the current stage (done), or ● for future (upcoming)
        static $stages = null;
        if ($stages === null) $stages = Tenders::STAGES;
        $idx = array_search($stage, $stages, true);
        $cur = array_search($t['tender_stage'], $stages, true);
        if ($idx < $cur)  return '<i class="fas fa-check ms-1" style="color:#7A9E7E;font-size:.6rem;"></i>';
        if ($idx === $cur) return '<i class="fas fa-circle ms-1" style="color:#D4A574;font-size:.55rem;"></i>';
        return '';
    };
?>
<ul class="nav nav-tabs mb-2" role="tablist" style="flex-wrap:wrap;">
    <li class="nav-item"><a class="nav-link active"  data-bs-toggle="tab" href="#tab-details"      style="<?= $tabStyle('tab-details'); ?>"><i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>Details</a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-prep"          style="<?= $tabStyle('tab-prep'); ?>">Prep<?= $totalReq > 0 ? ' <span style="color:#94A3B8;font-size:.72rem;">(' . $totalReq . ')</span>' : ''; ?><?= $tabRibbon('PREP'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-items"        style="color:#334155;"><i class="fas fa-list-ul me-1" style="color:#7A8BA1;"></i>Items<?php $tItems = $this->data['tender_items'] ?? []; if (!empty($tItems)): ?> <span style="color:#94A3B8;font-size:.72rem;">(<?= count($tItems); ?>)</span><?php endif; ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-pricing"      style="color:#334155;">Pricing<?php $pv = $this->data['pricing_versions'] ?? []; if (!empty($pv)): ?> <span style="color:#94A3B8;font-size:.72rem;">(v<?= count($pv); ?>)</span><?php endif; $pc = $this->data['pricing_current'] ?? null; if ($pc && $pc['status'] === 'APPROVED'): ?> <i class="fas fa-check ms-1" style="color:#7A9E7E;font-size:.68rem;"></i><?php endif; ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-submission"   style="<?= $tabStyle('tab-submission'); ?>">Submission<?= $subFilled ? ' <i class="fas fa-check ms-1" style="color:#7A9E7E;font-size:.68rem;"></i>' : $tabRibbon('SUBMISSION'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-followup"     style="<?= $tabStyle('tab-followup'); ?>">Follow up<?= $tabRibbon('FOLLOW_UP'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-opening"      style="<?= $tabStyle('tab-opening'); ?>">Opening<?= count($bidders) > 0 ? ' <span style="color:#94A3B8;font-size:.72rem;">(' . count($bidders) . ')</span>' : ''; ?><?= $tabRibbon('OPENING'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-negotiations" style="<?= $tabStyle('tab-negotiations'); ?>">Negotiations<?= $tabRibbon('NEGOTIATIONS'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-awarded"      style="<?= $tabStyle('tab-awarded'); ?>">Awarded<?= $result ? ' <i class="fas fa-flag-checkered ms-1" style="color:#166534;font-size:.68rem;"></i>' : $tabRibbon('AWARDED'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-contract"     style="<?= $tabStyle('tab-contract'); ?>">Contract signing<?= $tabRibbon('CONTRACT_SIGNING'); ?></a></li>
    <li class="nav-item"><a class="nav-link"         data-bs-toggle="tab" href="#tab-execution"    style="<?= $tabStyle('tab-execution'); ?>">Execution<?= !empty($t['linked_project_id']) ? ' <i class="fas fa-link ms-1" style="color:#166534;font-size:.68rem;"></i>' : $tabRibbon('EXECUTION'); ?></a></li>
    <li class="nav-item ms-auto"><a class="nav-link" data-bs-toggle="tab" href="#tab-history"      style="color:#94A3B8;"><i class="fas fa-history me-1"></i>History (<?= count($hist); ?>)</a></li>
</ul>

<div class="tab-content">
    <!-- Details ── -->
    <div class="tab-pane fade show active" id="tab-details">
        <?php $canEditDetails = UserGroups::can('Tenders','saveDetailsAj'); ?>
        <div class="card border-0 shadow-sm">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                <strong style="color:#334155;font-size:.9rem;"><i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>Tender details</strong>
                <?php if ($canEditDetails): ?>
                    <button type="button" id="btn_edit_details" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-pencil-alt me-1"></i>Edit details</button>
                <?php endif; ?>
            </div>
            <div class="card-body p-3">
                <dl class="row mb-0" style="font-size:.86rem;color:#334155;">
                    <dt class="col-md-3" style="color:#64748B;">Source</dt><dd class="col-md-9"><?= htmlspecialchars($t['source_type']); ?><?php if (!empty($t['source_ref'])): ?> · ref <?= htmlspecialchars((string)$t['source_ref']); ?><?php endif; ?><?php if (!empty($t['source_url'])): ?> · <a href="<?= htmlspecialchars($t['source_url']); ?>" target="_blank" style="color:#7A8BA1;">link</a><?php endif; ?></dd>
                    <dt class="col-md-3" style="color:#64748B;">Industry</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['tender_industry']) ?: '—'; ?></dd>
                    <dt class="col-md-3" style="color:#64748B;">Type</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['project_type']); ?><span class="small ms-2" style="color:#94A3B8;font-size:.68rem;">(locked · set at intake)</span></dd>
                    <dt class="col-md-3" style="color:#64748B;">Region / District</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['region']) ?: '—'; ?><?php if (!empty($t['district'])): ?> · <?= htmlspecialchars($t['district']); ?><?php endif; ?></dd>
                    <dt class="col-md-3" style="color:#64748B;">Received</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['date_received']); ?></dd>
                    <dt class="col-md-3" style="color:#64748B;">Submission method</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['submission_method']) ?: '—'; ?></dd>
                    <?php if (!empty($t['tender_description'])): ?>
                        <dt class="col-md-3" style="color:#64748B;">Description</dt><dd class="col-md-9"><?= nl2br(htmlspecialchars((string)$t['tender_description'])); ?></dd>
                    <?php endif; ?>
                    <dt class="col-md-3" style="color:#64748B;">Created</dt><dd class="col-md-9"><?= htmlspecialchars((string)$t['created_on']); ?> by <?= htmlspecialchars((string)$t['created_by_name']); ?></dd>
                </dl>
            </div>
        </div>

    </div>

    <!-- Requirements ── -->
    <div class="tab-pane fade" id="tab-prep">
        <div class="card border-0 shadow-sm">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                <div><strong style="color:#334155;"><i class="fas fa-clipboard-list me-2" style="color:#7A8BA1;"></i>Required Documents For This Tender</strong>
                    <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">Tick each document this tender requires. Statutory docs (compliance) are marked <i class="fas fa-star" style="color:#D4A574;"></i>.</div>
                </div>
                <div id="req_summary" class="small" style="color:#64748B;"><?= $totalReq; ?> selected · <?= $totalStat; ?> statutory</div>
            </div>

            <?php if (UserGroups::can('Tenders','setRequirementsAj')): ?>
            <div class="card-body p-2 d-flex align-items-center gap-2 flex-wrap" style="background:#F8FAFC;border-bottom:1px solid #E2E8F0;">
                <input type="text" id="req_search" placeholder="Search document types…" class="form-control form-control-sm" style="max-width:280px;">
                <div class="ms-auto d-flex gap-2">
                    <?php if (UserGroups::can('Tenders','applyStatutoryDefaultsAj')): ?>
                        <button type="button" id="btn_stat_defaults" class="btn btn-sm" style="background:#F1F5F9;border:1px solid #E2E8F0;color:#334155;font-weight:600;"><i class="fas fa-magic me-1" style="color:#D4A574;"></i>Apply statutory defaults</button>
                    <?php endif; ?>
                    <?php if (UserGroups::can('Tenders','clearRequirementsAj')): ?>
                        <button type="button" id="btn_clear_reqs" class="btn btn-sm" style="background:#F8FAFC;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-times me-1" style="color:#C48579;"></i>Clear all</button>
                    <?php endif; ?>
                    <button type="button" id="btn_save_reqs" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save requirements</button>
                </div>
            </div>
            <?php endif; ?>

            <div class="card-body p-3">
                <?php foreach ($catOrder as $cat):
                    if (empty($docTypes[$cat])) continue;
                    $rows = $docTypes[$cat];
                    $selInCat = 0; $statInCat = 0;
                    foreach ($rows as $dt) {
                        if (isset($requiredIds[(int)$dt['c0d']])) $selInCat++;
                        if ((int)$dt['is_statutory'] === 1) $statInCat++;
                    }
                ?>
                    <div class="req-cat mb-3">
                        <div class="d-flex align-items-center justify-content-between mb-2 pb-1" style="border-bottom:1px solid #E2E8F0;">
                            <strong style="color:#334155;font-size:.9rem;"><?= htmlspecialchars($catLabels[$cat] ?? $cat); ?></strong>
                            <span class="req-cat-count small" style="color:#64748B;font-size:.72rem;" data-cat="<?= htmlspecialchars($cat); ?>"><?= $selInCat; ?> / <?= count($rows); ?> selected<?= $statInCat > 0 ? ' · ' . $statInCat . ' statutory' : ''; ?></span>
                        </div>
                        <div class="row g-2">
                            <?php foreach ($rows as $dt):
                                $sel = isset($requiredIds[(int)$dt['c0d']]);
                                $stat = (int)$dt['is_statutory'] === 1;
                            ?>
                                <div class="col-md-3 req-item" data-label="<?= htmlspecialchars(strtolower($dt['type_label'])); ?>">
                                    <label class="w-100 p-2 d-flex align-items-start gap-2" style="background:<?= $sel ? '#F1F5F9' : '#fff'; ?>;border:1px solid #E2E8F0;border-radius:3px;cursor:<?= UserGroups::can('Tenders','setRequirementsAj') ? 'pointer' : 'default'; ?>;">
                                        <input type="checkbox" class="form-check-input mt-1 chk-req" value="<?= (int)$dt['c0d']; ?>" data-cat="<?= htmlspecialchars($cat); ?>" data-statutory="<?= $stat ? 1 : 0; ?>" <?= $sel ? 'checked' : ''; ?> <?= UserGroups::can('Tenders','setRequirementsAj') ? '' : 'disabled'; ?>>
                                        <span>
                                            <span style="color:#334155;font-weight:500;font-size:.82rem;line-height:1.2;"><?= htmlspecialchars($dt['type_label']); ?><?php if ($stat): ?> <i class="fas fa-star ms-1" style="color:#D4A574;font-size:.68rem;" title="Statutory / compliance"></i><?php endif; ?></span>
                                            <?php if (!empty($dt['notes'])): ?><span class="d-block text-muted small" style="color:#94A3B8;font-size:.7rem;line-height:1.2;"><?= htmlspecialchars($dt['notes']); ?></span><?php endif; ?>
                                            <span class="d-block small" style="color:#94A3B8;font-size:.65rem;font-family:monospace;"><?= htmlspecialchars($dt['type_code']); ?></span>
                                        </span>
                                    </label>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    </div>
                <?php endforeach; ?>
                <?php if (empty($docTypes)): ?><div class="text-center py-4" style="color:#94A3B8;">No document types configured.</div><?php endif; ?>
            </div>
        </div>
    </div>

    <!-- Items ── buyer's list (Slice 8L, Vue 3 Options API root) -->
    <div class="tab-pane fade" id="tab-items">
        <?php
            $canWriteItems = UserGroups::can('Tenders','itemsAddAj');
            $tItemsBoot    = $this->data['tender_items']              ?? [];
            $tKindDefault  = $this->data['tender_items_default_kind'] ?? 'GOOD';
        ?>

        <?php /* ────── Slice 8S-10 · Services-only "as-bid" spec card ──────
                Only renders for services tenders — Goods/Works/Consultancy
                tenders skip this entirely and see the unchanged Items tab. */ ?>
        <?php if (($t['project_type'] ?? '') === 'services'):
            $spec        = $this->data['service_spec']           ?? [];
            $specEq      = $this->data['service_spec_equipment'] ?? [];
            $canEditSpec = !empty($this->data['service_spec_can_edit']);
            $vSel   = function ($k, $v) use ($spec) { $cur = (string)($spec[$k] ?? ''); return $cur === $v ? ' selected' : ''; };
            $vChk   = function ($k) use ($spec) { return !empty($spec[$k]) ? ' checked' : ''; };
            $vVal   = function ($k) use ($spec) { return htmlspecialchars((string)($spec[$k] ?? '')); };
            $vNum   = function ($k) use ($spec) { $v = $spec[$k] ?? ''; return $v === '' || $v === null ? '' : htmlspecialchars((string)$v); };
        ?>
        <div class="card border-0 shadow-sm mb-3 ts-spec-card" style="border-left:3px solid #7A8BA1 !important;">
            <div class="card-header d-flex align-items-center justify-content-between" style="background:#F8FAFC;border-bottom:1px solid #E2E8F0;">
                <div>
                    <strong style="color:#334155;font-size:.9rem;"><i class="fas fa-clipboard-check me-2" style="color:#7A8BA1;"></i>Services bid-time answers</strong>
                    <div class="small mt-1" style="color:#64748B;font-size:.72rem;">CRM captures these during bid preparation. On Won → convert, they pre-populate a DRAFT Service Contract so PC never re-types.</div>
                </div>
                <div class="d-flex align-items-center gap-2">
                    <?php if (UserGroups::can('Tenders','walkthroughManualPdf')): ?>
                        <a href="<?= PROOT; ?>Tenders/walkthroughManualPdf/<?= (int)$t['c0d']; ?>" target="_blank" class="btn btn-sm" style="background:#F1F5F9;border:1px solid #E2E8F0;color:#334155;font-weight:500;" title="Open the Services walkthrough manual for this tender in a new tab (PDF)"><i class="fas fa-book me-1" style="color:#7A8BA1;"></i>Walkthrough manual</a>
                    <?php endif; ?>
                    <?php if ($canEditSpec): ?>
                        <button type="button" id="ts_spec_save" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save answers</button>
                    <?php else: ?>
                        <span class="badge" style="background:#F1F5F9;color:#64748B;border:1px solid #E2E8F0;font-size:.66rem;text-transform:capitalize;">Read-only · Admin / CRM edit</span>
                    <?php endif; ?>
                </div>
            </div>
            <div class="card-body p-3">
                <form id="ts_spec_form" onsubmit="return false;" <?= $canEditSpec ? '' : 'inert'; ?>>
                    <input type="hidden" name="tender_id" value="<?= (int)$t['c0d']; ?>">

                    <div class="row g-3">
                        <!-- Q1 · Sites -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">1</span>Sites</div>
                                <div class="row g-2">
                                    <div class="col-4"><label class="ts-lbl">No. of sites</label>
                                        <input type="number" min="0" name="no_of_sites" value="<?= $vNum('no_of_sites'); ?>" class="form-control form-control-sm"></div>
                                    <div class="col-8"><label class="ts-lbl">Notes</label>
                                        <input type="text" name="sites_notes" value="<?= $vVal('sites_notes'); ?>" placeholder="e.g. 45 BTS across Dar / Coast / Morogoro" class="form-control form-control-sm"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q2 · Equipment breakdown -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head d-flex align-items-center justify-content-between">
                                    <div><span class="ts-q-num">2</span>Equipment (per type)</div>
                                    <?php if ($canEditSpec): ?>
                                        <button type="button" id="ts_eq_add" class="btn btn-sm" style="background:transparent;border:1px dashed #7A8BA1;color:#7A8BA1;padding:.15rem .45rem;font-size:.72rem;"><i class="fas fa-plus me-1"></i>Add row</button>
                                    <?php endif; ?>
                                </div>
                                <div id="ts_eq_rows">
                                    <?php if (empty($specEq)): ?>
                                        <div class="text-muted small ts-eq-empty" style="color:#94A3B8;font-size:.74rem;">No equipment rows yet. Click "Add row" to capture a type / size / count.</div>
                                    <?php else: foreach ($specEq as $r): ?>
                                        <div class="row g-1 ts-eq-row mb-1">
                                            <div class="col-4"><input type="text" class="form-control form-control-sm ts-eq-type" placeholder="Type (GEN, AC, UPS…)" value="<?= htmlspecialchars((string)($r['type'] ?? '')); ?>"></div>
                                            <div class="col-5"><input type="text" class="form-control form-control-sm ts-eq-size" placeholder="Size / rating"      value="<?= htmlspecialchars((string)($r['size'] ?? '')); ?>"></div>
                                            <div class="col-2"><input type="number" min="0" class="form-control form-control-sm ts-eq-count text-end" placeholder="Qty" value="<?= (int)($r['count'] ?? 0); ?>"></div>
                                            <?php if ($canEditSpec): ?>
                                                <div class="col-1 d-flex align-items-center"><button type="button" class="btn btn-sm ts-eq-del" style="background:transparent;border:none;color:#C48579;padding:0;"><i class="fas fa-times"></i></button></div>
                                            <?php endif; ?>
                                        </div>
                                    <?php endforeach; endif; ?>
                                </div>
                                <input type="hidden" name="equipment_json" id="ts_eq_json" value="<?= htmlspecialchars((string)($spec['equipment_json'] ?? '')); ?>">
                            </div>
                        </div>

                        <!-- Q3 · PM structure -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">3</span>PM structure</div>
                                <div class="row g-2">
                                    <div class="col-6"><label class="ts-lbl">Cadence</label>
                                        <select name="pm_cadence" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="MONTHLY"<?= $vSel('pm_cadence','MONTHLY'); ?>>Monthly</option>
                                            <option value="QUARTERLY"<?= $vSel('pm_cadence','QUARTERLY'); ?>>Quarterly</option>
                                            <option value="SEMI_ANNUAL"<?= $vSel('pm_cadence','SEMI_ANNUAL'); ?>>Semi-annual</option>
                                            <option value="ANNUAL"<?= $vSel('pm_cadence','ANNUAL'); ?>>Annual</option>
                                            <option value="ADHOC"<?= $vSel('pm_cadence','ADHOC'); ?>>Adhoc</option>
                                        </select>
                                    </div>
                                    <div class="col-6"><label class="ts-lbl">How is PM paid?</label>
                                        <select name="pm_payment_structure" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="MONTHLY_RETAINER"<?= $vSel('pm_payment_structure','MONTHLY_RETAINER'); ?>>Monthly retainer</option>
                                            <option value="PER_EVENT"<?= $vSel('pm_payment_structure','PER_EVENT'); ?>>Per event</option>
                                            <option value="BUNDLED_WITH_CALLOUTS"<?= $vSel('pm_payment_structure','BUNDLED_WITH_CALLOUTS'); ?>>Bundled with callouts</option>
                                        </select>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Q4 · Callout structure -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head">
                                    <span class="ts-q-num">4</span>Callouts
                                    <label class="ms-2 form-check-label" style="font-weight:400;font-size:.78rem;color:#64748B;">
                                        <input type="checkbox" class="form-check-input" name="has_callouts" value="1"<?= $vChk('has_callouts'); ?>>
                                        included in scope
                                    </label>
                                </div>
                                <div class="row g-2">
                                    <div class="col-6"><label class="ts-lbl">Payment structure</label>
                                        <select name="callout_payment_structure" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="PER_CALLOUT_FEE"<?= $vSel('callout_payment_structure','PER_CALLOUT_FEE'); ?>>Per-callout fee</option>
                                            <option value="T_AND_M"<?= $vSel('callout_payment_structure','T_AND_M'); ?>>Time &amp; materials</option>
                                            <option value="BUNDLED"<?= $vSel('callout_payment_structure','BUNDLED'); ?>>Bundled (with PM)</option>
                                            <option value="FREE_QUOTA_PLUS_FEE"<?= $vSel('callout_payment_structure','FREE_QUOTA_PLUS_FEE'); ?>>Free quota + fee beyond</option>
                                        </select>
                                    </div>
                                    <div class="col-3"><label class="ts-lbl">Fee (TZS)</label>
                                        <input type="number" step="0.01" name="callout_fee" value="<?= $vNum('callout_fee'); ?>" class="form-control form-control-sm text-end"></div>
                                    <div class="col-3"><label class="ts-lbl">Emerg. multiplier</label>
                                        <input type="number" step="0.01" name="emergency_multiplier" value="<?= $vNum('emergency_multiplier'); ?>" placeholder="e.g. 2.00" class="form-control form-control-sm text-end"></div>
                                    <div class="col-6"><label class="ts-lbl">Free callouts / month</label>
                                        <input type="number" min="0" name="free_callouts_per_month" value="<?= $vNum('free_callouts_per_month'); ?>" class="form-control form-control-sm text-end"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q5 · SLA -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">5</span>SLA response (hours)</div>
                                <div class="row g-2">
                                    <div class="col-4"><label class="ts-lbl">Emergency</label>
                                        <input type="number" min="0" name="sla_emergency_hrs" value="<?= $vNum('sla_emergency_hrs'); ?>" class="form-control form-control-sm text-end"></div>
                                    <div class="col-4"><label class="ts-lbl">Urgent</label>
                                        <input type="number" min="0" name="sla_urgent_hrs" value="<?= $vNum('sla_urgent_hrs'); ?>" class="form-control form-control-sm text-end"></div>
                                    <div class="col-4"><label class="ts-lbl">Routine</label>
                                        <input type="number" min="0" name="sla_routine_hrs" value="<?= $vNum('sla_routine_hrs'); ?>" class="form-control form-control-sm text-end"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q6 · Spare policy -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">6</span>Spare policy</div>
                                <div class="row g-2">
                                    <div class="col-4"><label class="ts-lbl">Who owns spares?</label>
                                        <select name="spare_policy" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="COMPANY"<?= $vSel('spare_policy','COMPANY'); ?>>Company</option>
                                            <option value="CLIENT"<?= $vSel('spare_policy','CLIENT'); ?>>Client</option>
                                            <option value="CONSIGNMENT"<?= $vSel('spare_policy','CONSIGNMENT'); ?>>Consignment</option>
                                            <option value="FIXED_PACK"<?= $vSel('spare_policy','FIXED_PACK'); ?>>Fixed pack</option>
                                        </select>
                                    </div>
                                    <div class="col-8"><label class="ts-lbl">Notes</label>
                                        <input type="text" name="spare_policy_notes" value="<?= $vVal('spare_policy_notes'); ?>" class="form-control form-control-sm"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q7 · Service pack -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head">
                                    <span class="ts-q-num">7</span>Service pack
                                    <label class="ms-2 form-check-label" style="font-weight:400;font-size:.78rem;color:#64748B;">
                                        <input type="checkbox" class="form-check-input" name="client_supplied_pack" value="1"<?= $vChk('client_supplied_pack'); ?>>
                                        client-supplied
                                    </label>
                                </div>
                                <div><label class="ts-lbl">Parts list agreed with client (per interval)</label>
                                    <textarea name="service_pack_notes" class="form-control form-control-sm" rows="2" placeholder="e.g. 1× oil filter + 1× air filter per quarter"><?= $vVal('service_pack_notes'); ?></textarea>
                                </div>
                            </div>
                        </div>

                        <!-- Q8 · Invoicing -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">8</span>Invoicing &amp; payment</div>
                                <div class="row g-2">
                                    <div class="col-8"><label class="ts-lbl">Cadence</label>
                                        <select name="invoicing_cadence" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="MONTHLY_RETAINER"<?= $vSel('invoicing_cadence','MONTHLY_RETAINER'); ?>>Monthly retainer</option>
                                            <option value="PER_EVENT"<?= $vSel('invoicing_cadence','PER_EVENT'); ?>>Per event</option>
                                            <option value="MILESTONE"<?= $vSel('invoicing_cadence','MILESTONE'); ?>>Milestone</option>
                                            <option value="CONSUMPTION"<?= $vSel('invoicing_cadence','CONSUMPTION'); ?>>Consumption</option>
                                        </select>
                                    </div>
                                    <div class="col-4"><label class="ts-lbl">Terms (days)</label>
                                        <input type="number" min="0" name="payment_terms_days" value="<?= $vNum('payment_terms_days'); ?>" class="form-control form-control-sm text-end"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q9 · Pricing model -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><span class="ts-q-num">9</span>Pricing model</div>
                                <div class="row g-2">
                                    <div class="col-4"><label class="ts-lbl">Labour / hr (TZS)</label>
                                        <input type="number" step="0.01" name="labour_rate_per_hr" value="<?= $vNum('labour_rate_per_hr'); ?>" class="form-control form-control-sm text-end"></div>
                                    <div class="col-4"><label class="ts-lbl">Mileage / km (TZS)</label>
                                        <input type="number" step="0.01" name="mileage_rate_per_km" value="<?= $vNum('mileage_rate_per_km'); ?>" class="form-control form-control-sm text-end"></div>
                                    <div class="col-4"><label class="ts-lbl">Parts markup %</label>
                                        <input type="number" step="0.01" name="parts_markup_pct" value="<?= $vNum('parts_markup_pct'); ?>" class="form-control form-control-sm text-end"></div>
                                </div>
                            </div>
                        </div>

                        <!-- Q10 · Part replacement SOP -->
                        <div class="col-md-6">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head">
                                    <span class="ts-q-num">10</span>Part replacement SOP
                                    <label class="ms-2 form-check-label" style="font-weight:400;font-size:.78rem;color:#64748B;">
                                        <input type="checkbox" class="form-check-input" name="part_replacement_sop_agreed" value="1"<?= $vChk('part_replacement_sop_agreed'); ?>>
                                        SOP agreed with client
                                    </label>
                                </div>
                                <div><label class="ts-lbl">Adhoc replacement process notes</label>
                                    <textarea name="part_replacement_notes" class="form-control form-control-sm" rows="2" placeholder="e.g. photo + quote → PM approval → replace within 48h"><?= $vVal('part_replacement_notes'); ?></textarea>
                                </div>
                            </div>
                        </div>

                        <!-- General notes -->
                        <div class="col-12">
                            <div class="ts-spec-q">
                                <div class="ts-spec-q-head"><i class="fas fa-comment me-1" style="color:#7A8BA1;"></i>General notes</div>
                                <textarea name="general_notes" class="form-control form-control-sm" rows="2" placeholder="Anything else worth noting for the bid → contract handover"><?= $vVal('general_notes'); ?></textarea>
                            </div>
                        </div>
                    </div>
                </form>
            </div>
        </div>

        <style>
            .ts-spec-card .ts-spec-q { background:#fff;border:1px solid #E2E8F0;border-radius:4px;padding:.65rem .75rem; }
            .ts-spec-card .ts-spec-q-head { color:#334155;font-weight:600;font-size:.82rem;margin-bottom:.4rem;display:flex;align-items:center; }
            .ts-spec-card .ts-q-num { display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:#7A8BA1;color:#fff;font-size:.66rem;margin-right:.4rem;font-weight:700; }
            .ts-spec-card .ts-lbl { display:block;color:#64748B;font-size:.7rem;text-transform:capitalize;margin-bottom:.15rem; }
            .ts-spec-card .ts-eq-row input { font-size:.78rem; }
        </style>

        <script>
        (function(){
            var $form = $('#ts_spec_form'); if (!$form.length) return;
            var canEdit = <?= $canEditSpec ? 'true' : 'false'; ?>;

            // ── Equipment rows: add/remove + serialise on save
            function serialiseEq(){
                var rows = [];
                $('#ts_eq_rows .ts-eq-row').each(function(){
                    var t = $(this).find('.ts-eq-type').val() || '';
                    var s = $(this).find('.ts-eq-size').val() || '';
                    var c = parseInt($(this).find('.ts-eq-count').val() || '0', 10);
                    if (!t && !c) return;
                    rows.push({type: t.trim(), size: (s || '').trim(), count: isNaN(c) ? 0 : Math.max(0, c)});
                });
                $('#ts_eq_json').val(JSON.stringify(rows));
            }
            if (canEdit){
                $('#ts_eq_add').on('click', function(){
                    $('#ts_eq_rows .ts-eq-empty').remove();
                    var html = ''
                      + '<div class="row g-1 ts-eq-row mb-1">'
                      + '<div class="col-4"><input type="text" class="form-control form-control-sm ts-eq-type" placeholder="Type (GEN, AC, UPS…)"></div>'
                      + '<div class="col-5"><input type="text" class="form-control form-control-sm ts-eq-size" placeholder="Size / rating"></div>'
                      + '<div class="col-2"><input type="number" min="0" class="form-control form-control-sm ts-eq-count text-end" placeholder="Qty"></div>'
                      + '<div class="col-1 d-flex align-items-center"><button type="button" class="btn btn-sm ts-eq-del" style="background:transparent;border:none;color:#C48579;padding:0;"><i class="fas fa-times"></i></button></div>'
                      + '</div>';
                    $('#ts_eq_rows').append(html);
                });
                $('#ts_eq_rows').on('click', '.ts-eq-del', function(){ $(this).closest('.ts-eq-row').remove(); });
            }

            // ── Save
            $('#ts_spec_save').on('click', function(){
                serialiseEq();
                var $btn = $(this).prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-1"></i>Saving…');
                $.post('<?= PROOT; ?>Tenders/saveServiceSpecAj', $form.serialize(), function(res){
                    $btn.prop('disabled', false).html('<i class="fas fa-save me-1"></i>Save answers');
                    if (res && res.ok) {
                        if (typeof rsToast === 'function') rsToast('Answers saved.', 'success');
                        else if (window.jQuery && window.$.confirm) $.alert({title:'Saved', content:'Answers saved.'});
                    } else {
                        var msg = (res && res.msg) || 'Could not save.';
                        if (window.jQuery && window.$.confirm) $.alert({title:'Save failed', content: msg, type:'red'});
                        else alert(msg);
                    }
                }, 'json').fail(function(){
                    $btn.prop('disabled', false).html('<i class="fas fa-save me-1"></i>Save answers');
                    if (window.jQuery && window.$.confirm) $.alert({title:'Network error', content:'Save request failed.', type:'red'});
                });
            });
        })();
        </script>
        <?php endif; /* end services-only spec card */ ?>

        <div id="ti_app_root" v-cloak>
            <div class="card border-0 shadow-sm mb-3" style="background:#F8FAFC;">
                <div class="card-body p-2 d-flex align-items-center gap-2 flex-wrap">
                    <span style="color:#64748B;font-size:.82rem;"><i class="fas fa-list-ul me-1" style="color:#7A8BA1;"></i>Buyer's item list <span style="color:#94A3B8;">·</span> what this tender asks for</span>
                    <span class="badge" style="background:#F1F5F9;color:#334155;border:1px solid #E2E8F0;font-size:.66rem;text-transform:capitalize;">{{ items.length }} line(s)</span>
                    <div class="ms-auto d-flex gap-2">
                        <button v-if="canWrite" type="button" @click="openBulk" class="btn btn-sm" style="background:#F1F5F9;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-file-import me-1" style="color:#7A8BA1;"></i>Bulk paste</button>
                        <button v-if="canWrite" type="button" @click="beginAdd" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus me-1"></i>Add line</button>
                    </div>
                </div>
            </div>

            <div v-if="!items.length && !adding" class="card border-0 shadow-sm" style="background:#F8FAFC;"><div class="card-body p-4 text-center" style="color:#64748B;">
                <i class="fas fa-list-ul" style="font-size:2rem;color:#94A3B8;"></i>
                <div class="mt-2" style="font-size:.9rem;">No items captured yet. Add the first line — this is the buyer's specification.</div>
            </div></div>

            <div v-else class="card border-0 shadow-sm">
                <div class="table-responsive">
                    <table class="table table-sm mb-0 align-middle">
                        <thead style="background:#F1F5F9;">
                            <tr>
                                <th style="width:2.5rem;color:#334155;">#</th>
                                <th style="width:8%;color:#334155;">Item ref</th>
                                <th style="color:#334155;">Description</th>
                                <th style="width:6rem;color:#334155;" class="text-end">Qty</th>
                                <th style="width:5rem;color:#334155;">UOM</th>
                                <th style="width:7rem;color:#334155;">Kind</th>
                                <th style="width:6rem;"></th>
                            </tr>
                        </thead>
                        <tbody>
                            <template v-for="(it, idx) in items" :key="it.c0d">
                                <tr v-if="editingId !== it.c0d">
                                    <td class="text-muted small" style="color:#64748B;">{{ it.line_no }}</td>
                                    <td style="font-family:monospace;color:#334155;font-size:.78rem;">{{ it.item_ref || '—' }}</td>
                                    <td style="color:#334155;font-size:.86rem;">
                                        <div>{{ it.description }}</div>
                                        <div v-if="it.spec_notes" class="small" style="color:#64748B;font-size:.7rem;line-height:1.3;">{{ it.spec_notes }}</div>
                                    </td>
                                    <td class="text-end" style="color:#334155;">{{ fmtQty(it.qty) }}</td>
                                    <td style="color:#334155;font-size:.8rem;">{{ it.uom || '—' }}</td>
                                    <td><span class="badge" :style="kindStyle(it.line_kind)">{{ kindLabel(it.line_kind) }}</span></td>
                                    <td class="text-end">
                                        <button v-if="canWrite" type="button" @click="beginEdit(it)" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.2rem;" title="Edit"><i class="fas fa-pencil-alt"></i></button>
                                        <button v-if="canWrite" type="button" @click="remove(it)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;padding:.2rem;" title="Remove"><i class="fas fa-times"></i></button>
                                    </td>
                                </tr>
                                <tr v-else style="background:#FFFBEB;">
                                    <td class="text-muted small">{{ it.line_no }}</td>
                                    <td><input type="text" v-model="draft.item_ref" class="form-control form-control-sm" placeholder="ref"></td>
                                    <td>
                                        <input type="text" v-model="draft.description" class="form-control form-control-sm mb-1" placeholder="Description">
                                        <input type="text" v-model="draft.spec_notes"  class="form-control form-control-sm" placeholder="Spec notes (optional)" style="font-size:.72rem;">
                                    </td>
                                    <td><input type="number" step="0.0001" v-model.number="draft.qty" class="form-control form-control-sm text-end"></td>
                                    <td><input type="text" v-model="draft.uom" class="form-control form-control-sm" placeholder="ea"></td>
                                    <td>
                                        <select v-model="draft.line_kind" class="form-select form-select-sm">
                                            <option v-for="k in KINDS" :key="k" :value="k">{{ kindLabel(k) }}</option>
                                        </select>
                                    </td>
                                    <td class="text-end">
                                        <button type="button" @click="saveEdit" :disabled="busy" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;padding:.2rem .5rem;"><i class="fas fa-check"></i></button>
                                        <button type="button" @click="cancelEdit"  class="btn btn-sm" style="background:transparent;border:none;color:#64748B;padding:.2rem;"><i class="fas fa-times"></i></button>
                                    </td>
                                </tr>
                            </template>

                            <tr v-if="adding" style="background:#EAF2E8;">
                                <td class="text-muted small">new</td>
                                <td><input type="text" v-model="draft.item_ref" class="form-control form-control-sm" placeholder="ref"></td>
                                <td>
                                    <input type="text" v-model="draft.description" class="form-control form-control-sm mb-1" placeholder="Description" @keyup.enter="saveNew">
                                    <input type="text" v-model="draft.spec_notes"  class="form-control form-control-sm" placeholder="Spec notes (optional)" style="font-size:.72rem;">
                                </td>
                                <td><input type="number" step="0.0001" v-model.number="draft.qty" class="form-control form-control-sm text-end"></td>
                                <td><input type="text" v-model="draft.uom" class="form-control form-control-sm" placeholder="ea"></td>
                                <td>
                                    <select v-model="draft.line_kind" class="form-select form-select-sm">
                                        <option v-for="k in KINDS" :key="k" :value="k">{{ kindLabel(k) }}</option>
                                    </select>
                                </td>
                                <td class="text-end">
                                    <button type="button" @click="saveNew" :disabled="busy" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;padding:.2rem .5rem;"><i class="fas fa-check"></i></button>
                                    <button type="button" @click="cancelAdd" class="btn btn-sm" style="background:transparent;border:none;color:#64748B;padding:.2rem;"><i class="fas fa-times"></i></button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <!-- Pricing ── BOQ builder + version approval (Slice 4 · Vue-rewritten Slice 8M) -->
    <div class="tab-pane fade" id="tab-pricing">
        <?php
            $pvAll     = $this->data['pricing_versions']         ?? [];
            $pvCur     = $this->data['pricing_current']          ?? null;
            $pvSecs    = $this->data['pricing_sections']         ?? [];
            $pvLines   = $this->data['pricing_lines_by_section'] ?? [];
            $tItems    = $this->data['tender_items']             ?? [];
            // Prefixed with $pv_ to avoid collision with $canSubmit / $canApply used in the Contract-Signing tab
            // block further down the page (those overwrite as booleans and blow up the pricing Vue init JS).
            $pv_canCreateVer = UserGroups::can('Tenders','pricingCreateVersionAj') ? 'true' : 'false';
            $pv_canSubmit    = UserGroups::can('Tenders','pricingSubmitAj') ? 'true' : 'false';
            $pv_canApply     = UserGroups::can('Tenders','pricingApplyAj') ? 'true' : 'false';
            $pv_canSeed      = UserGroups::can('Tenders','pricingSeedFromItemsAj') ? 'true' : 'false';
        ?>

        <!-- Always-visible explanation (outside Vue so it renders even if Vue fails). Collapsed by default. -->
        <div class="card border-0 shadow-sm mb-3" style="background:#FDF7EC;border-left:3px solid #D4A574 !important;">
            <button type="button" class="btn w-100 text-start d-flex align-items-center justify-content-between collapsed" data-bs-toggle="collapse" data-bs-target="#pv_help_body" aria-expanded="false" aria-controls="pv_help_body" style="background:transparent;border:none;padding:.6rem 1rem;color:#8B6914;">
                <strong style="font-size:.86rem;"><i class="fas fa-lightbulb me-1"></i>What is a Pricing Version? <span style="color:#94A3B8;font-weight:400;font-size:.74rem;font-style:italic;">click to expand</span></strong>
                <i class="fas fa-chevron-down" style="font-size:.7rem;transition:transform .2s;"></i>
            </button>
            <div id="pv_help_body" class="collapse">
                <div class="card-body p-3 pt-0" style="font-size:.82rem;color:#334155;">
                    <div style="line-height:1.5;">
                        A pricing version is <strong>your priced bid</strong> — a snapshot of the BOQ with your unit costs, markups, and totals. Each revision is saved as a separate version so the history is auditable.
                    </div>
                    <div class="mt-2 d-flex flex-wrap gap-3" style="font-size:.76rem;color:#64748B;">
                        <span><span class="badge me-1" style="background:#94A3B8;color:#fff;font-size:.7rem;text-transform:capitalize;font-weight:500;">Draft</span>editable</span>
                        <span><span class="badge me-1" style="background:#D4A574;color:#fff;font-size:.7rem;text-transform:capitalize;font-weight:500;">Submitted</span>locked, awaiting PM → FM → Exec</span>
                        <span><span class="badge me-1" style="background:#7A9E7E;color:#fff;font-size:.7rem;text-transform:capitalize;font-weight:500;">Approved</span>locked, becomes the bid amount</span>
                    </div>
                    <div class="mt-2" style="font-size:.76rem;color:#64748B;">
                        <i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>
                        <strong>Where to edit:</strong> switch versions via the dropdown just below. Only DRAFT is editable. To revise an APPROVED version, click "New draft" — it clones the current version so you can adjust and resubmit.
                    </div>
                    <div class="mt-2" style="font-size:.76rem;color:#64748B;">
                        <i class="fas fa-arrow-right me-1" style="color:#7A9E7E;"></i>
                        <strong>How items flow to pricing:</strong> the buyer's list on the <a href="#tab-items" data-bs-toggle="tab" style="color:#7A8BA1;">Items tab</a> gets copied into a new pricing section (cost=0, markup=default) via the <em>"Seed pricing from tender items"</em> button in Version settings — or, on an empty pricing tab, via the <em>"Start draft &amp; seed"</em> button. Re-seeding is idempotent (duplicates skipped by ref+description).
                    </div>
                    <?php if (UserGroups::can('PricingDefaults','index')): ?>
                    <div class="mt-2" style="font-size:.76rem;color:#64748B;">
                        <i class="fas fa-sliders-h me-1" style="color:#B87A5A;"></i>
                        <strong>Defaults come from:</strong> the <a href="<?= PROOT; ?>PricingDefaults" style="color:#B87A5A;font-weight:600;">Pricing Defaults</a> settings page (VAT, markup, contingency, currency). Change them there once and every new draft picks them up.
                    </div>
                    <?php endif; ?>
                </div>
            </div>
        </div>
        <style>
            /* Rotate the chevron when the collapse is open */
            [data-bs-target="#pv_help_body"]:not(.collapsed) .fa-chevron-down { transform: rotate(180deg); }
            /* Muted "click to expand" hint disappears once opened */
            [data-bs-target="#pv_help_body"]:not(.collapsed) span[style*="click to expand"] { display: none; }
        </style>

        <div id="pv_app_root" v-cloak>
            <!-- Version selector + toolbar -->
            <div class="card border-0 shadow-sm mb-3" style="background:#F8FAFC;">
                <div class="card-body p-2 d-flex align-items-center gap-2 flex-wrap">
                    <span style="color:#64748B;font-size:.82rem;"><i class="fas fa-code-branch me-1" style="color:#7A8BA1;"></i>Pick a version to view / edit:</span>
                    <span v-if="!versions.length" style="color:#94A3B8;font-size:.82rem;font-style:italic;">none yet — start a draft below</span>
                    <select v-else v-model.number="currentVersionId" @change="switchVersion" class="form-select form-select-sm" style="max-width:320px;">
                        <option v-for="pv in versions" :key="pv.c0d" :value="pv.c0d">v{{ pv.version_no }} · {{ pv.version_label }} · {{ pv.status }}</option>
                    </select>
                    <span v-if="version" class="badge" :style="statusBadge(version.status)">{{ (version.status || '').toLowerCase() }}</span>
                    <span v-if="version && version.status !== 'DRAFT'" class="small" style="color:#94A3B8;font-size:.72rem;font-style:italic;"><i class="fas fa-lock me-1"></i>locked — click "New draft" to revise</span>

                    <div class="ms-auto d-flex gap-2">
                        <button v-if="canCreateVer && (!version || version.status !== 'DRAFT')" type="button" @click="createDraft" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus me-1"></i>New draft <span v-if="version">(clone from v{{ version.version_no }})</span></button>
                        <div v-if="version" class="d-flex flex-wrap gap-1 justify-content-end">
                            <div class="btn-group btn-group-sm" role="group" title="Client-facing exports">
                                <a :href="PROOT + 'Tenders/pricingXlsx/' + version.c0d + '?audience=client'" class="btn btn-sm" style="background:#EAF2E8;border:1px solid #7A9E7E;color:#3F5C43;font-weight:600;" title="Client-facing Excel — respects BOQ visibility, hides overhead breakdown"><i class="fas fa-file-excel me-1"></i>Client xlsx</a>
                                <button type="button" @click="previewPricingPdf('client')" class="btn btn-sm" style="background:#EAF2E8;border:1px solid #7A9E7E;color:#3F5C43;font-weight:600;" title="Client-facing PDF — preview in modal, warm palette + Roboto Condensed"><i class="fas fa-file-pdf me-1"></i>PDF</button>
                            </div>
                            <div class="btn-group btn-group-sm" role="group" title="Internal audit exports">
                                <a :href="PROOT + 'Tenders/pricingXlsx/' + version.c0d + '?audience=internal'" class="btn btn-sm" style="background:#F5EAE1;border:1px solid #B87A5A;color:#8B4C2C;font-weight:600;" title="Internal Excel — direct cost + all overheads + true margin"><i class="fas fa-file-invoice me-1"></i>Internal xlsx</a>
                                <button type="button" @click="previewPricingPdf('internal')" class="btn btn-sm" style="background:#F5EAE1;border:1px solid #B87A5A;color:#8B4C2C;font-weight:600;" title="Internal PDF — preview in modal, full breakdown landscape"><i class="fas fa-file-pdf me-1"></i>PDF</button>
                            </div>
                        </div>
                        <button v-if="version && version.status === 'DRAFT' && canSubmit" type="button" @click="submitForApproval" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"><i class="fas fa-paper-plane me-1"></i>Submit for approval</button>
                        <button v-if="version && version.status === 'APPROVED' && canApply" type="button" @click="applyToTender" class="btn btn-sm" style="background:#166534;border-color:#166534;color:#fff;font-weight:600;"><i class="fas fa-arrow-right me-1"></i>Apply as bid amount</button>
                    </div>
                </div>
            </div>

            <div v-if="!version" class="card border-0 shadow-sm" style="background:#F8FAFC;"><div class="card-body p-4 text-center" style="color:#64748B;">
                <i class="fas fa-calculator" style="font-size:2.5rem;color:#94A3B8;"></i>
                <div class="mt-2" style="font-size:1rem;color:#334155;font-weight:600;">No pricing yet — start your first draft</div>
                <div class="small mt-2 mx-auto" style="font-size:.8rem;color:#64748B;max-width:520px;">
                    A pricing draft is where you build the priced BOQ. You can start blank, or auto-seed the buyer's items you captured on the Items tab as the starting BOQ.
                </div>
                <div class="d-flex gap-2 justify-content-center flex-wrap mt-3">
                    <button v-if="canCreateVer && canSeed && hasTenderItems" type="button" @click="createDraftAndSeed" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;padding:.4rem 1rem;">
                        <i class="fas fa-file-import me-1"></i>Start draft &amp; seed {{ tenderItemCount }} item(s) from Items tab
                    </button>
                    <button v-if="canCreateVer" type="button" @click="createDraft" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;padding:.4rem 1rem;">
                        <i class="fas fa-plus me-1"></i>Start blank draft
                    </button>
                </div>
                <div v-if="!hasTenderItems" class="small mt-2" style="color:#94A3B8;font-size:.72rem;">
                    <i class="fas fa-lightbulb me-1" style="color:#D4A574;"></i>Tip: capture the buyer's items on the <a href="#tab-items" data-bs-toggle="tab" style="color:#7A8BA1;">Items tab</a> first — you can then seed the pricing draft directly from them.
                </div>
            </div></div>

            <template v-else>
                <!-- Totals strip -->
                <div class="row g-3 mb-3">
                    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="background:#F8FAFC;border-left:4px solid #7A8BA1 !important;"><div class="card-body p-3">
                        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Cost total <span style="color:#94A3B8;font-weight:400;">(internal true cost)</span></div>
                        <div style="font-weight:700;font-size:1.2rem;color:#334155;">{{ version.currency }} {{ fmt0(version.sum_cost) }}</div>
                        <div class="small" style="color:#64748B;font-size:.68rem;">items cost + overhead pool</div>
                    </div></div></div>
                    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="background:#F8FAFC;border-left:4px solid #166534 !important;"><div class="card-body p-3">
                        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Bid price ({{ version.pricing_mode === 'LUMPSUM' ? 'lumpsum' : 'sell' }}) <span style="color:#94A3B8;font-weight:400;">(client sees)</span></div>
                        <div style="font-weight:700;font-size:1.2rem;color:#166534;">{{ version.currency }} {{ fmt0(version.sum_price) }}</div>
                        <div v-if="version.pricing_mode === 'LUMPSUM'" class="small" style="color:#3F5C43;font-size:.7rem;"><i class="fas fa-tag me-1"></i>lumpsum</div>
                        <div v-else class="small" style="color:#64748B;font-size:.68rem;">items sell + prelims + distributed overhead</div>
                    </div></div></div>
                    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="background:#F8FAFC;border-left:4px solid #7A9E7E !important;"><div class="card-body p-3">
                        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Margin (true / client)</div>
                        <div style="font-weight:700;font-size:1.2rem;color:#334155;">{{ fmt2(version.margin_pct) }}% <span style="color:#B87A5A;font-size:.86rem;">/</span> <span style="color:#3F5C43;font-size:.86rem;">{{ fmt2(clientMarginPct) }}%</span></div>
                        <div class="small" style="color:#64748B;font-size:.7rem;">true = after overheads · client = pre-overhead</div>
                    </div></div></div>
                    <div class="col-md-3"><div class="card border-0 shadow-sm h-100" style="background:#F8FAFC;"><div class="card-body p-3">
                        <div style="text-transform:capitalize;letter-spacing:.2px;font-size:.7rem;color:#64748B;font-weight:600;">Overheads · Sections / Lines</div>
                        <div style="font-weight:700;font-size:1.2rem;color:#334155;">{{ version.currency }} {{ fmt0(version.sum_overhead) }}</div>
                        <div class="small" style="color:#64748B;font-size:.7rem;">{{ overheads.length }} pool line(s) · {{ sections.length }} sec / {{ totalLineCount }} items · VAT {{ fmt1(version.vat_pct) }}%</div>
                    </div></div></div>
                </div>

                <!-- Version settings (DRAFT only) -->
                <div v-if="version.status === 'DRAFT'" class="card border-0 shadow-sm mb-3" style="background:#F8FAFC;">
                    <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                        <strong style="color:#334155;font-size:.86rem;"><i class="fas fa-cog me-1" style="color:#7A8BA1;"></i>Version settings</strong>
                        <div class="d-flex align-items-center gap-2">
                            <span style="color:#64748B;font-size:.72rem;">Pricing mode:</span>
                            <div class="btn-group btn-group-sm" role="group">
                                <button type="button" @click="setMode('PER_ITEM')" :style="modeButtonStyle('PER_ITEM')"><i class="fas fa-list-ol me-1"></i>Per-item BOQ</button>
                                <button type="button" @click="setMode('LUMPSUM')"  :style="modeButtonStyle('LUMPSUM')"><i class="fas fa-tag me-1"></i>Lumpsum</button>
                            </div>
                        </div>
                    </div>
                    <div class="card-body p-2">
                        <div class="row g-2">
                            <div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Label</label>
                                <input type="text" v-model="headerDraft.version_label" class="form-control form-control-sm"></div>
                            <div class="col-md-2"><label class="form-label" style="color:#334155;font-size:.72rem;">VAT %</label>
                                <input type="number" step="0.01" v-model.number="headerDraft.vat_pct" class="form-control form-control-sm"></div>
                            <div class="col-md-2"><label class="form-label" style="color:#334155;font-size:.72rem;">Contingency %</label>
                                <input type="number" step="0.01" v-model.number="headerDraft.contingency_pct" class="form-control form-control-sm"></div>
                            <div class="col-md-2"><label class="form-label" style="color:#334155;font-size:.72rem;">Prelims ({{ version.currency }})</label>
                                <input type="number" step="0.01" v-model.number="headerDraft.prelims_amount" :disabled="headerDraft.pricing_mode === 'LUMPSUM'" class="form-control form-control-sm"></div>
                            <div class="col-md-2"><label class="form-label" style="color:#334155;font-size:.72rem;">Default markup %</label>
                                <input type="number" step="0.01" v-model.number="headerDraft.default_markup_pct" class="form-control form-control-sm">
                                <div class="small mt-1" style="color:#64748B;font-size:.66rem;line-height:1.2;">
                                    <i class="fas fa-exchange-alt me-1" style="color:#7A8BA1;"></i>&asymp; <strong style="color:#3F5C43;">{{ fmt1(markupToMargin(headerDraft.default_markup_pct)) }}% margin</strong>
                                </div>
                            </div>

                            <!-- Slice 8S: procurement mode (Goods-oriented) + client BOQ visibility -->
                            <div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Goods procurement mode</label>
                                <select v-model="headerDraft.procurement_mode" class="form-select form-select-sm">
                                    <option value="LOCAL">Local purchase</option>
                                    <option value="IMPORT">Import</option>
                                    <option value="MIXED">Mixed (local + import)</option>
                                    <option value="NA">N/A · non-goods</option>
                                </select>
                                <div class="small mt-1" style="color:#94A3B8;font-size:.66rem;">Drives the default overhead template (freight/duty for Import, transport/labour for Local).</div>
                            </div>
                            <div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Client BOQ visibility</label>
                                <select v-model="headerDraft.client_boq_visibility" class="form-select form-select-sm">
                                    <option value="ITEMS_AND_SECTIONS">Sections + items (full BOQ)</option>
                                    <option value="ITEMS_ONLY">Items only (flat list)</option>
                                    <option value="LUMPSUM_ONLY">Lumpsum only (no BOQ)</option>
                                </select>
                                <div class="small mt-1" style="color:#94A3B8;font-size:.66rem;">Controls what the client-facing Excel shows. Internal export always shows everything.</div>
                            </div>

                            <!-- LUMPSUM-only fields -->
                            <template v-if="headerDraft.pricing_mode === 'LUMPSUM'">
                                <div class="col-12 mt-1 pt-2" style="border-top:1px dashed #E2E8F0;">
                                    <div class="small mb-2" style="color:#3F5C43;background:#EAF2E8;border-left:3px solid #7A9E7E;padding:.4rem .6rem;font-size:.76rem;">
                                        <i class="fas fa-tag me-1"></i>Lumpsum mode: the buyer sees ONE bid amount. Sections and lines below become your internal cost breakdown — buyer never sees them.
                                    </div>
                                </div>
                                <div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Bid price · lumpsum ({{ version.currency }})</label>
                                    <input type="number" step="0.01" v-model.number="headerDraft.lumpsum_amount" class="form-control form-control-sm" style="font-weight:600;color:#166534;"></div>
                                <div class="col-md-8"><label class="form-label" style="color:#334155;font-size:.72rem;">Lumpsum notes (visible to buyer, optional)</label>
                                    <input type="text" v-model="headerDraft.lumpsum_notes" placeholder="e.g. All-inclusive fixed price for full scope of works." class="form-control form-control-sm"></div>
                            </template>

                            <div class="col-12 d-flex align-items-center justify-content-between">
                                <button v-if="canSeed && hasTenderItems && sections.length <= 1" type="button" @click="seedFromItems" class="btn btn-sm" style="background:#EAF2E8;border:1px solid #7A9E7E;color:#3F5C43;font-weight:600;"><i class="fas fa-file-import me-1"></i>Seed <span v-if="headerDraft.pricing_mode === 'LUMPSUM'">cost breakdown</span><span v-else>pricing</span> from tender items ({{ tenderItemCount }})</button>
                                <span v-else></span>
                                <button type="button" @click="saveHeader" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save settings</button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Slice 8S · Overhead pool card (distinct from tender_items) -->
                <div class="card border-0 shadow-sm mb-3" style="background:#FDF7EC;border-left:3px solid #B87A5A !important;">
                    <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                        <div>
                            <strong style="color:#334155;font-size:.9rem;"><i class="fas fa-layer-group me-1" style="color:#B87A5A;"></i>Overhead pool <span class="badge" style="background:#F5EAE1;color:#8B4C2C;border:1px solid #B87A5A;font-size:.7rem;text-transform:capitalize;font-weight:500;">Internal · off-BOQ</span></strong>
                            <div class="small" style="color:#64748B;font-size:.72rem;line-height:1.4;">Manpower, transport, equipment, freight, admin — the stuff behind the items. Each row picks a display mode:
                                <span style="color:#3F5C43;"><strong>Prelims</strong> shows on the client's BOQ as its own line</span>,
                                <span style="color:#334155;"><strong>Distributed</strong> is baked into item prices (spread pro-rata)</span>,
                                <span style="color:#8B4C2C;"><strong>Internal only</strong> is hidden from the client and eats your margin silently</span>.
                            </div>
                        </div>
                        <div v-if="isDraft" class="d-flex gap-1 flex-wrap justify-content-end">
                            <button type="button" @click="loadOverheadTemplate('GOODS_LOCAL')"  class="btn btn-sm" style="background:#F1F5F9;border:1px solid #E2E8F0;color:#334155;font-size:.72rem;padding:.3rem .55rem;text-transform:capitalize;"><i class="fas fa-truck me-1" style="color:#7A9E7E;"></i>Quick-load local</button>
                            <button type="button" @click="loadOverheadTemplate('GOODS_IMPORT')" class="btn btn-sm" style="background:#F1F5F9;border:1px solid #E2E8F0;color:#334155;font-size:.72rem;padding:.3rem .55rem;text-transform:capitalize;"><i class="fas fa-ship me-1" style="color:#7A8BA1;"></i>Quick-load import</button>
                        </div>
                    </div>
                    <div class="table-responsive">
                        <table class="table table-sm mb-0 align-middle" style="background:#fff;">
                            <thead style="background:#F1F5F9;">
                                <tr>
                                    <th style="width:2.5rem;color:#334155;">#</th>
                                    <th style="width:12rem;color:#334155;">Category</th>
                                    <th style="color:#334155;">Label</th>
                                    <th style="width:15rem;color:#334155;">Display mode</th>
                                    <th class="text-end" style="width:10rem;color:#334155;">Amount ({{ version.currency }})</th>
                                    <th style="width:5rem;"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="(oh, idx) in overheads" :key="oh.c0d">
                                    <td class="text-muted small" style="color:#64748B;">{{ oh.line_no }}</td>
                                    <td>
                                        <select v-model="oh.category" :disabled="!isDraft" class="form-select form-select-sm" style="font-size:.74rem;">
                                            <option v-for="c in OH_CATEGORIES" :key="c" :value="c">{{ categoryLabel(c) }}</option>
                                        </select>
                                    </td>
                                    <td><input type="text" v-model="oh.label" :disabled="!isDraft" class="form-control form-control-sm" placeholder="e.g. Loading crew · 3 casuals × 2 days"></td>
                                    <td>
                                        <select v-model="oh.display_mode" :disabled="!isDraft" class="form-select form-select-sm" style="font-size:.74rem;" :style="modeSelectStyle(oh.display_mode)">
                                            <option value="PRELIMS_LINE">Prelims (client-visible)</option>
                                            <option value="DISTRIBUTED">Distributed (baked into items)</option>
                                            <option value="INTERNAL_ONLY">Internal only (hidden)</option>
                                        </select>
                                    </td>
                                    <td><input type="number" step="0.01" v-model.number="oh.amount" :disabled="!isDraft" class="form-control form-control-sm text-end"></td>
                                    <td class="text-end">
                                        <template v-if="isDraft">
                                            <button type="button" @click="saveOverhead(oh)"   class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.2rem;" title="Save"><i class="fas fa-check"></i></button>
                                            <button type="button" @click="deleteOverhead(oh)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;padding:.2rem;" title="Remove"><i class="fas fa-times"></i></button>
                                        </template>
                                    </td>
                                </tr>
                                <tr v-if="isDraft" style="background:#EAF2E8;">
                                    <td></td>
                                    <td>
                                        <select v-model="newOverhead.category" class="form-select form-select-sm" style="font-size:.74rem;">
                                            <option v-for="c in OH_CATEGORIES" :key="c" :value="c">{{ categoryLabel(c) }}</option>
                                        </select>
                                    </td>
                                    <td><input type="text" v-model="newOverhead.label" class="form-control form-control-sm" placeholder="Label" @keyup.enter="addOverhead"></td>
                                    <td>
                                        <select v-model="newOverhead.display_mode" class="form-select form-select-sm" style="font-size:.74rem;" :style="modeSelectStyle(newOverhead.display_mode)">
                                            <option value="PRELIMS_LINE">Prelims (client-visible)</option>
                                            <option value="DISTRIBUTED">Distributed (baked into items)</option>
                                            <option value="INTERNAL_ONLY">Internal only (hidden)</option>
                                        </select>
                                    </td>
                                    <td><input type="number" step="0.01" v-model.number="newOverhead.amount" class="form-control form-control-sm text-end"></td>
                                    <td class="text-end"><button type="button" @click="addOverhead" class="btn btn-sm" style="background:#B87A5A;border-color:#B87A5A;color:#fff;padding:.2rem .5rem;"><i class="fas fa-plus"></i></button></td>
                                </tr>
                                <tr v-if="!overheads.length && !isDraft">
                                    <td colspan="6" class="text-center py-3" style="color:#94A3B8;">No overhead lines.</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>

                <!-- Sections + lines -->
                <div v-if="distributedTotal > 0" class="small mb-2" style="color:#3F5C43;background:#EAF2E8;border-left:3px solid #7A9E7E;padding:.5rem .7rem;font-size:.76rem;">
                    <i class="fas fa-arrow-right me-1"></i><strong>Distribution active:</strong> {{ version.currency }} {{ fmt0(distributedTotal) }} of overhead is being spread pro-rata across items. Each row shows the raw line price <span style="text-decoration:line-through;color:#94A3B8;">crossed out</span> above the client-facing (distributed) price in green — that's what the client's BOQ actually shows.
                </div>
                <div v-for="sec in sections" :key="sec.c0d" class="card border-0 shadow-sm mb-3">
                    <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                        <div>
                            <strong style="color:#334155;font-size:.9rem;">{{ sec.section_no }}. {{ sec.section_name }}</strong>
                            <div v-if="sec.notes" class="text-muted small" style="color:#64748B;font-size:.7rem;">{{ sec.notes }}</div>
                        </div>
                        <div class="d-flex align-items-center gap-3">
                            <div class="text-end small" style="color:#64748B;">
                                <div><strong style="color:#334155;">Cost</strong> {{ fmt0(sec.sum_cost) }}</div>
                                <div><strong style="color:#166534;">Sell</strong> {{ fmt0(sec.sum_price) }}</div>
                                <div style="font-size:.66rem;color:#94A3B8;font-style:italic;line-height:1.1;">items only · pre-overhead</div>
                            </div>
                            <button v-if="isDraft" type="button" @click="deleteSection(sec)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;" title="Delete section"><i class="fas fa-times"></i></button>
                        </div>
                    </div>
                    <div class="table-responsive">
                        <table class="table table-sm mb-0 align-middle">
                            <thead style="background:#F1F5F9;">
                                <tr>
                                    <th style="width:3rem;color:#334155;">#</th>
                                    <th style="width:6rem;color:#334155;">Item ref</th>
                                    <th style="color:#334155;">Description</th>
                                    <th class="text-end" style="color:#334155;width:5rem;">Qty</th>
                                    <th style="color:#334155;width:4rem;">UOM</th>
                                    <th class="text-end" style="color:#334155;width:7rem;">Unit cost</th>
                                    <th class="text-end" style="color:#334155;width:5rem;" title="Markup % — added on top of unit_cost. Sell = cost × (1 + markup/100). Different from margin %.">Mark %</th>
                                    <th class="text-end" style="color:#334155;width:7rem;">Unit price</th>
                                    <th class="text-end" style="color:#334155;width:8rem;">Line price</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="ln in linesFor(sec.c0d)" :key="ln.c0d">
                                    <td class="text-muted small" style="color:#64748B;">{{ ln.line_no }}</td>
                                    <td><input type="text" v-model="ln.item_ref"    :disabled="!isDraft" class="form-control form-control-sm"></td>
                                    <td><input type="text" v-model="ln.description" :disabled="!isDraft" class="form-control form-control-sm"></td>
                                    <td><input type="number" step="0.0001" v-model.number="ln.qty" :disabled="!isDraft" class="form-control form-control-sm text-end"></td>
                                    <td><input type="text" v-model="ln.uom" :disabled="!isDraft" class="form-control form-control-sm"></td>
                                    <td><input type="number" step="0.01" v-model.number="ln.unit_cost"  :disabled="!isDraft" class="form-control form-control-sm text-end"></td>
                                    <td><input type="number" step="0.01" v-model.number="ln.markup_pct" :disabled="!isDraft" class="form-control form-control-sm text-end"></td>
                                    <td class="text-end text-muted small" style="color:#64748B;">
                                        <div>{{ fmt2(ln.unit_price) }}</div>
                                        <div v-if="distributedTotal > 0" class="small" style="color:#3F5C43;font-size:.68rem;line-height:1.1;">→ {{ fmt2(clientUnitPrice(ln)) }}</div>
                                    </td>
                                    <td class="text-end" style="color:#334155;font-weight:600;">
                                        <div v-if="distributedTotal > 0" style="color:#94A3B8;font-weight:400;font-size:.74rem;text-decoration:line-through;">{{ fmt0(ln.line_price) }}</div>
                                        <div style="color:#3F5C43;">{{ fmt0(clientLinePrice(ln)) }}</div>
                                    </td>
                                    <td class="text-end">
                                        <template v-if="isDraft">
                                            <button type="button" @click="saveLine(ln)"   class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.2rem;"><i class="fas fa-check"></i></button>
                                            <button type="button" @click="deleteLine(ln)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;padding:.2rem;"><i class="fas fa-times"></i></button>
                                        </template>
                                    </td>
                                </tr>
                                <tr v-if="isDraft" style="background:#EAF2E8;">
                                    <td></td>
                                    <td><input type="text" v-model="newLines[sec.c0d].item_ref" class="form-control form-control-sm" placeholder="ref"></td>
                                    <td><input type="text" v-model="newLines[sec.c0d].description" class="form-control form-control-sm" placeholder="Description of the line item" @keyup.enter="addLine(sec)"></td>
                                    <td><input type="number" step="0.0001" v-model.number="newLines[sec.c0d].qty" class="form-control form-control-sm text-end"></td>
                                    <td><input type="text" v-model="newLines[sec.c0d].uom" class="form-control form-control-sm" placeholder="ea"></td>
                                    <td><input type="number" step="0.01" v-model.number="newLines[sec.c0d].unit_cost"  class="form-control form-control-sm text-end"></td>
                                    <td><input type="number" step="0.01" v-model.number="newLines[sec.c0d].markup_pct" class="form-control form-control-sm text-end"></td>
                                    <td colspan="2"></td>
                                    <td class="text-end"><button type="button" @click="addLine(sec)" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;padding:.2rem .5rem;"><i class="fas fa-plus"></i></button></td>
                                </tr>
                                <tr v-if="!linesFor(sec.c0d).length && !isDraft">
                                    <td colspan="10" class="text-center py-3" style="color:#94A3B8;">No lines.</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>

                <!-- Add-section widget -->
                <div v-if="isDraft" class="card border-0 shadow-sm" style="background:#F8FAFC;">
                    <div class="card-body p-2 d-flex align-items-center gap-2">
                        <span style="color:#64748B;font-size:.82rem;"><i class="fas fa-plus-circle me-1" style="color:#7A8BA1;"></i>New section:</span>
                        <input type="text" v-model="newSection.section_name" placeholder="e.g. Site preparation" class="form-control form-control-sm" style="max-width:280px;" @keyup.enter="addSection">
                        <input type="text" v-model="newSection.notes" placeholder="Notes (optional)" class="form-control form-control-sm">
                        <button type="button" @click="addSection" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus me-1"></i>Add section</button>
                    </div>
                </div>
            </template>
        </div>
    </div>

    <!-- Submission ── -->
    <div class="tab-pane fade" id="tab-submission">
        <div class="card border-0 shadow-sm">
            <div class="card-header bg-white" style="border-bottom:1px solid #E2E8F0;">
                <strong style="color:#334155;"><i class="fas fa-paper-plane me-2" style="color:#7A8BA1;"></i>Submission details</strong>
                <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">All fields optional — save what you have; the tender auto-advances from PREP&nbsp;→&nbsp;SUBMISSION on the first save. Cross-check the <a href="#tab-prep" data-bs-toggle="tab" style="color:#7A8BA1;">Requirements checklist</a> to see what documents this tender needs.</div>
            </div>

            <div class="card-body p-3" style="background:#F8FAFC;">
                <?php $canWrite = UserGroups::can('Tenders','saveSubmissionAj'); ?>

                <!-- Bid amount + source ── (Slice 8O: MANUAL branch derives bid from cost + margin) -->
                <?php
                    $bpsInit  = (string)($t['bid_price_source'] ?? 'MANUAL');
                    $mcInit   = (float)($t['manual_cost']       ?? 0);
                    $mmInit   = (float)($t['manual_margin_pct'] ?? 0);
                    $subInit  = (float)($t['submission_amount'] ?? 0);
                ?>
                <?php
                    // Slice 8S UX cleanup: pull the latest pricing version's sum_price so PRICING_TAB source can auto-populate.
                    $pvForSub = $this->data['pricing_current'] ?? null;
                    $pvSumPrice = $pvForSub ? (float)$pvForSub['sum_price'] : 0.0;
                    $pvLabel    = $pvForSub ? ('v' . (int)$pvForSub['version_no'] . ' · ' . $pvForSub['status']) : '—';
                ?>
                <div class="mb-3 pb-3" style="border-bottom:1px solid #E2E8F0;" id="bid_source_panel"
                     data-bps-init="<?= htmlspecialchars($bpsInit); ?>"
                     data-pv-sum-price="<?= $pvSumPrice; ?>">
                    <strong style="color:#334155;font-size:.86rem;"><i class="fas fa-hand-holding-usd me-2" style="color:#7A8BA1;"></i>Bid amount &amp; source</strong>
                    <div class="row g-2 mt-1">
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Price source</label>
                            <select id="sub_price_src" class="form-select form-select-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                                <option value="MANUAL"      <?= $bpsInit === 'MANUAL'      ? 'selected' : ''; ?>>Manual (cost + margin)</option>
                                <option value="PRICING_TAB" <?= $bpsInit === 'PRICING_TAB' ? 'selected' : ''; ?>>From Pricing tab</option>
                            </select>
                            <div class="small mt-1" style="color:#94A3B8;font-size:.68rem;">Manual: enter cost + margin, bid computes. Pricing tab: syncs from the current version's sum_price.</div>
                        </div>
                        <div class="col-md-8">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Source justification note</label>
                            <input type="text" id="sub_price_note" value="<?= htmlspecialchars((string)($t['bid_price_source_note'] ?? '')); ?>" placeholder="e.g. External quote from ABC Ltd dated 15-Jul-26" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                    </div>

                    <!-- Hidden field driving the POST payload — display lives inside the active panel below. -->
                    <input type="hidden" id="sub_amount" value="<?= $subInit; ?>">

                    <!-- MANUAL cost + margin panel — Submitted bid lives here, auto-computed. -->
                    <div id="manual_cost_panel" class="row g-2 mt-2 pt-2" style="border-top:1px dashed #E2E8F0;">
                        <div class="col-12">
                            <div class="small mb-1" style="color:#8B6914;background:#FEF3E7;border-left:3px solid #D4A574;padding:.4rem .6rem;font-size:.74rem;">
                                <i class="fas fa-info-circle me-1"></i>Manual mode: enter what the tender scope will <em>cost</em> us, then the <em>margin</em> we're pricing over cost. The submitted bid is auto-computed and locked so the reasoning is auditable.
                            </div>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Cost of tender (<?= htmlspecialchars((string)$t['currency']); ?>)</label>
                            <input type="number" step="0.01" id="manual_cost" value="<?= $mcInit; ?>" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                            <div class="small mt-1" style="color:#94A3B8;font-size:.68rem;">Goods total / BOQ total / logistics + margin base.</div>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Margin %</label>
                            <input type="number" step="0.01" id="manual_margin_pct" value="<?= $mmInit; ?>" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#3F5C43;font-size:.78rem;font-weight:600;">Submitted bid amount (<?= htmlspecialchars((string)$t['currency']); ?>)</label>
                            <input type="text" id="manual_bid_preview" value="" readonly class="form-control form-control-sm" style="background:#EAF2E8;border:1px solid #7A9E7E;color:#166534;font-weight:700;font-size:1rem;">
                            <div class="small mt-1" style="color:#3F5C43;font-size:.68rem;"><i class="fas fa-equals me-1"></i>cost × (1 + margin/100) — this is what gets saved.</div>
                        </div>
                        <div class="col-md-3 d-flex align-items-end">
                            <div class="small" style="color:#64748B;font-size:.72rem;line-height:1.3;">
                                Updates automatically as you type. Click <strong>Save submission</strong> to persist.
                            </div>
                        </div>
                    </div>

                    <!-- PRICING_TAB panel — Submitted bid syncs from the current pricing version's sum_price. -->
                    <div id="pricing_tab_panel" class="row g-2 mt-2 pt-2" style="border-top:1px dashed #E2E8F0;display:none;">
                        <div class="col-12">
                            <div class="small mb-1" style="color:#3F5C43;background:#EAF2E8;border-left:3px solid #7A9E7E;padding:.4rem .6rem;font-size:.74rem;">
                                <i class="fas fa-info-circle me-1"></i>Pricing tab mode: the submitted bid comes from the current pricing version's total sell. Change the version to sync the number.
                            </div>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Current pricing version</label>
                            <input type="text" value="<?= htmlspecialchars($pvLabel); ?>" readonly class="form-control form-control-sm" style="background:#F1F5F9;color:#334155;">
                            <div class="small mt-1" style="color:#94A3B8;font-size:.68rem;">Manage versions on the <a href="#tab-pricing" data-bs-toggle="tab" style="color:#7A8BA1;">Pricing tab</a>.</div>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#3F5C43;font-size:.78rem;font-weight:600;">Submitted bid amount (<?= htmlspecialchars((string)$t['currency']); ?>)</label>
                            <input type="text" id="pricing_bid_preview" value="" readonly class="form-control form-control-sm" style="background:#EAF2E8;border:1px solid #7A9E7E;color:#166534;font-weight:700;font-size:1rem;">
                            <div class="small mt-1" style="color:#3F5C43;font-size:.68rem;"><i class="fas fa-code-branch me-1"></i>synced from pricing version sum_price.</div>
                        </div>
                        <div class="col-md-4 d-flex align-items-end">
                            <button type="button" id="btn_pricing_sync" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;padding:.4rem .8rem;" <?= $canWrite ? '' : 'disabled'; ?>>
                                <i class="fas fa-sync me-1"></i>Resync from pricing tab
                            </button>
                        </div>
                    </div>
                </div>

                <!-- Date / time / method / validity ── -->
                <div class="mb-3 pb-3" style="border-bottom:1px solid #E2E8F0;">
                    <strong style="color:#334155;font-size:.86rem;"><i class="fas fa-clock me-2" style="color:#7A8BA1;"></i>When &amp; how</strong>
                    <div class="row g-2 mt-1">
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Submission date</label>
                            <input type="date" id="sub_date" value="<?= htmlspecialchars((string)($t['submission_date'] ?? '')); ?>" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Submission time</label>
                            <input type="time" id="sub_time" value="<?= htmlspecialchars((string)($t['submission_time'] ?? '')); ?>" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Method</label>
                            <select id="sub_method" class="form-select form-select-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                                <option value="">—</option>
                                <?php foreach (['TENDER_PORTAL','PHYSICAL','EMAIL','COURIER','HAND_DELIVERED'] as $sm): ?>
                                    <option value="<?= $sm; ?>" <?= ($t['submission_method'] ?? '') === $sm ? 'selected' : ''; ?>><?= ucwords(strtolower(str_replace('_',' ',$sm))); ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Validity (days)</label>
                            <input type="number" min="0" id="sub_validity" value="<?= (int)($t['submission_validity_days'] ?? 0) ?: ''; ?>" placeholder="e.g. 90" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Follow-up date</label>
                            <input type="date" id="sub_follow" value="<?= htmlspecialchars((string)($t['submission_follow_up_date'] ?? '')); ?>" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                    </div>
                </div>

                <!-- Envelope structure (conditional on method=PHYSICAL) ── -->
                <div id="envelope_wrap" class="mb-3 pb-3" style="border-bottom:1px solid #E2E8F0;<?= ($t['submission_method'] ?? '') === 'PHYSICAL' ? '' : 'display:none;'; ?>">
                    <strong style="color:#334155;font-size:.86rem;"><i class="fas fa-envelope me-2" style="color:#7A8BA1;"></i>Physical envelope structure <span class="text-muted small" style="color:#94A3B8;font-weight:400;font-size:.72rem;">— required when method = Physical</span></strong>
                    <div class="row g-2 mt-1">
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Envelope scheme</label>
                            <select id="env_scheme" class="form-select form-select-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                                <option value="">—</option>
                                <?php foreach (['SINGLE'=>'Single envelope','TWO_ENVELOPE_TECH_FIN'=>'Two-envelope (tech + financial)','THREE_ENVELOPE'=>'Three-envelope'] as $k=>$lbl): ?>
                                    <option value="<?= $k; ?>" <?= ($t['submission_envelope_scheme'] ?? '') === $k ? 'selected' : ''; ?>><?= $lbl; ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Copies · original</label>
                            <input type="number" min="0" id="env_orig" value="<?= (int)($t['submission_copies_original'] ?? 0) ?: ''; ?>" placeholder="1" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Copies · duplicate</label>
                            <input type="number" min="0" id="env_dup" value="<?= (int)($t['submission_copies_duplicate'] ?? 0) ?: ''; ?>" placeholder="0" class="form-control form-control-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Sealing method</label>
                            <select id="env_seal" class="form-select form-select-sm" <?= $canWrite ? '' : 'disabled'; ?>>
                                <option value="">—</option>
                                <?php foreach (['NONE'=>'None','TAPE'=>'Tape','WAX'=>'Wax','TAMPER_EVIDENT'=>'Tamper-evident','OTHER'=>'Other'] as $k=>$lbl): ?>
                                    <option value="<?= $k; ?>" <?= ($t['submission_sealing_method'] ?? '') === $k ? 'selected' : ''; ?>><?= $lbl; ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                    </div>
                </div>

                <!-- Remarks ── -->
                <div>
                    <label class="form-label" style="color:#334155;font-size:.78rem;"><i class="fas fa-comment me-2" style="color:#7A8BA1;"></i>Remarks</label>
                    <textarea id="sub_remarks" rows="2" class="form-control form-control-sm" placeholder="Any notes about the submission — courier tracking no, witness names, chain-of-custody, etc." <?= $canWrite ? '' : 'disabled'; ?>><?= htmlspecialchars((string)($t['submission_remarks'] ?? '')); ?></textarea>
                </div>

                <!-- Slice 8T · Proof of submission attachments -->
                <?php
                    $subAtt      = $this->data['submission_attachments'] ?? [];
                    $canUpload   = UserGroups::can('Tenders','submissionAttachmentUploadAj');
                    $canRemoveAt = UserGroups::can('Tenders','submissionAttachmentRemoveAj');
                    $kindLabel = [
                        'RECEIPT'               => 'Physical receipt',
                        'COURIER_WAYBILL'       => 'Courier waybill',
                        'PORTAL_SCREENSHOT'     => 'Portal screenshot',
                        'SEALED_ENVELOPE_PHOTO' => 'Sealed envelope photo',
                        'ACKNOWLEDGMENT_EMAIL'  => 'Acknowledgment email',
                        'OTHER'                 => 'Other',
                    ];
                    $kindStyle = [
                        'RECEIPT'               => ['bg' => '#EAF2E8', 'fg' => '#3F5C43', 'br' => '#7A9E7E'],
                        'COURIER_WAYBILL'       => ['bg' => '#F5EAE1', 'fg' => '#8B4C2C', 'br' => '#B87A5A'],
                        'PORTAL_SCREENSHOT'     => ['bg' => '#F1F5F9', 'fg' => '#334155', 'br' => '#7A8BA1'],
                        'SEALED_ENVELOPE_PHOTO' => ['bg' => '#FEF3E7', 'fg' => '#8B6914', 'br' => '#D4A574'],
                        'ACKNOWLEDGMENT_EMAIL'  => ['bg' => '#F1F5F9', 'fg' => '#334155', 'br' => '#94A3B8'],
                        'OTHER'                 => ['bg' => '#F8FAFC', 'fg' => '#64748B', 'br' => '#94A3B8'],
                    ];
                    $fmtBytes = function ($b) {
                        $b = (int)$b;
                        if ($b < 1024) return $b . ' B';
                        if ($b < 1024 * 1024) return number_format($b / 1024, 1) . ' KB';
                        return number_format($b / 1024 / 1024, 1) . ' MB';
                    };
                ?>
                <div class="mt-3 pt-3" style="border-top:1px solid #E2E8F0;">
                    <div class="d-flex align-items-center justify-content-between mb-2">
                        <label class="form-label mb-0" style="color:#334155;font-size:.78rem;"><i class="fas fa-paperclip me-2" style="color:#7A8BA1;"></i>Proof of submission <span class="text-muted small" style="color:#94A3B8;font-weight:400;">(courier waybill · portal screenshot · sealed envelope photo · receipt · acknowledgment email)</span></label>
                        <?php if ($canUpload): ?>
                            <button type="button" id="btn_add_proof" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;padding:.3rem .8rem;"><i class="fas fa-upload me-1"></i>Add proof</button>
                        <?php endif; ?>
                    </div>

                    <?php if (empty($subAtt)): ?>
                        <div class="card border-0 shadow-sm" style="background:#F8FAFC;"><div class="card-body p-3 text-center small" style="color:#94A3B8;">
                            No proof uploaded yet. <?php if ($canUpload): ?>Click <strong>Add proof</strong> to attach a receipt, courier waybill, portal screenshot, or sealed-envelope photo.<?php endif; ?>
                        </div></div>
                    <?php else: ?>
                        <div class="card border-0 shadow-sm">
                            <div class="table-responsive">
                                <table class="table table-sm mb-0 align-middle" id="proof_table">
                                    <thead style="background:#F1F5F9;">
                                        <tr>
                                            <th style="color:#334155;width:12rem;">Kind</th>
                                            <th style="color:#334155;">Label / file</th>
                                            <th style="color:#334155;width:7rem;">Size</th>
                                            <th style="color:#334155;width:12rem;">Uploaded</th>
                                            <th style="width:7rem;"></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <?php foreach ($subAtt as $a):
                                            $ks = $kindStyle[$a['kind']] ?? $kindStyle['OTHER'];
                                        ?>
                                            <tr data-att-id="<?= (int)$a['c0d']; ?>">
                                                <td><span class="badge" style="background:<?= $ks['bg']; ?>;color:<?= $ks['fg']; ?>;border:1px solid <?= $ks['br']; ?>;font-size:.68rem;text-transform:capitalize;font-weight:500;"><?= htmlspecialchars($kindLabel[$a['kind']] ?? $a['kind']); ?></span></td>
                                                <td style="color:#334155;font-size:.82rem;">
                                                    <div><?= htmlspecialchars((string)$a['label']); ?></div>
                                                    <div class="small" style="color:#94A3B8;font-size:.68rem;font-family:monospace;"><?= htmlspecialchars((string)$a['original_filename']); ?></div>
                                                    <?php if (!empty($a['notes'])): ?><div class="small mt-1" style="color:#64748B;font-size:.7rem;font-style:italic;"><?= htmlspecialchars((string)$a['notes']); ?></div><?php endif; ?>
                                                </td>
                                                <td class="small" style="color:#64748B;font-size:.74rem;"><?= $fmtBytes($a['size_bytes']); ?></td>
                                                <td class="small" style="color:#64748B;font-size:.74rem;">
                                                    <?= htmlspecialchars((string)$a['uploaded_on']); ?>
                                                    <?php if (!empty($a['uploaded_by_name'])): ?><div style="font-size:.7rem;">by <?= htmlspecialchars((string)$a['uploaded_by_name']); ?></div><?php endif; ?>
                                                </td>
                                                <td class="text-end">
                                                    <?php
                                                        $mime = (string)($a['mime_type'] ?? '');
                                                        $isPreviewable = ($mime === 'application/pdf' || strpos($mime, 'image/') === 0);
                                                    ?>
                                                    <?php if ($isPreviewable): ?>
                                                        <button type="button" class="btn btn-sm btn-preview-proof" data-att-id="<?= (int)$a['c0d']; ?>" data-att-label="<?= htmlspecialchars((string)$a['label']); ?>" data-att-mime="<?= htmlspecialchars($mime); ?>" style="background:transparent;border:none;color:#7A9E7E;padding:.2rem .4rem;" title="Preview in modal"><i class="fas fa-eye"></i></button>
                                                    <?php endif; ?>
                                                    <a href="<?= PROOT; ?>Tenders/submissionAttachmentDownload/<?= (int)$a['c0d']; ?>" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.2rem .4rem;" title="Download"><i class="fas fa-download"></i></a>
                                                    <?php if ($canRemoveAt): ?>
                                                        <button type="button" class="btn btn-sm btn-remove-proof" data-att-id="<?= (int)$a['c0d']; ?>" style="background:transparent;border:none;color:#C48579;padding:.2rem .4rem;" title="Remove"><i class="fas fa-times"></i></button>
                                                    <?php endif; ?>
                                                </td>
                                            </tr>
                                        <?php endforeach; ?>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    <?php endif; ?>
                </div>
            </div>

            <?php if ($canWrite): ?>
            <div class="card-footer bg-white d-flex justify-content-between align-items-center" style="border-top:1px solid #E2E8F0;">
                <span class="text-muted small" style="color:#64748B;font-size:.74rem;">
                    <?php if ($t['tender_stage'] === 'PREP'): ?>
                        <i class="fas fa-arrow-right me-1" style="color:#D4A574;"></i>Saving will auto-advance the tender from <strong>Prep</strong> → <strong>Submission</strong>.
                    <?php else: ?>
                        <i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>Current stage: <strong><?= ucfirst(strtolower(str_replace('_',' ', $t['tender_stage']))); ?></strong> — save updates in place.
                    <?php endif; ?>
                </span>
                <button type="button" id="btn_save_sub" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save submission</button>
            </div>
            <?php endif; ?>
        </div>
    </div>

    <!-- FOLLOW UP ── stub -->
    <div class="tab-pane fade" id="tab-followup">
        <div class="card border-0 shadow-sm" style="background:#F8FAFC;">
            <div class="card-body p-4">
                <div class="d-flex align-items-center mb-2">
                    <i class="fas fa-hourglass-half me-2" style="color:#7A8BA1;font-size:1.1rem;"></i>
                    <strong style="color:#334155;font-size:.95rem;">Follow-up · Clarifications &amp; extensions</strong>
                </div>
                <div class="text-muted small" style="color:#64748B;">
                    After submission, log clarification letters (sent + received), bid-bond extensions, deadline pushes and site-visit reports here.
                    See the <a href="#tab-prep" data-bs-toggle="tab" style="color:#7A8BA1;">Prep</a> tab for the Follow-up doc checklist (5 doc types: Clarification Letter, Bid Extension, Bid Bond Extension, Site Visit Report, Pre-Bid Meeting Minutes).
                </div>
                <div class="mt-3 p-2" style="background:#fff;border:1px dashed #E2E8F0;border-radius:3px;color:#94A3B8;font-size:.78rem;">
                    <i class="fas fa-tools me-1"></i>Data-entry form coming in a follow-on slice. For now, use the PREP checklist to track expected documents.
                </div>
            </div>
        </div>
    </div>

    <!-- OPENING (Bidders) ── -->
    <div class="tab-pane fade" id="tab-opening">
        <div class="card border-0 shadow-sm">
            <?php if (UserGroups::can('Tenders','addBidderAj')): ?>
            <div class="card-body p-2" style="background:#F8FAFC;border-bottom:1px solid #E2E8F0;">
                <div class="row g-2 align-items-end">
                    <div class="col-md-3"><input type="text" id="b_name" placeholder="Bidder name *" class="form-control form-control-sm"></div>
                    <div class="col-md-2"><input type="number" step="0.01" id="b_amount" placeholder="Bid amount (TZS)" class="form-control form-control-sm"></div>
                    <div class="col-md-1"><input type="number" id="b_rank" placeholder="Rank" class="form-control form-control-sm"></div>
                    <div class="col-md-1"><label class="form-check-label" style="color:#334155;font-size:.78rem;"><input type="checkbox" id="b_us" class="form-check-input"> Us</label></div>
                    <div class="col-md-3"><input type="text" id="b_notes" placeholder="Notes" class="form-control form-control-sm"></div>
                    <div class="col-md-2"><button type="button" id="btn_add_bidder" class="btn btn-sm w-100" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus me-1"></i>Add bidder</button></div>
                </div>
            </div>
            <?php endif; ?>
            <div class="table-responsive">
                <table class="table table-sm mb-0 align-middle">
                    <thead style="background:#F1F5F9;">
                        <tr><th style="color:#334155;">Bidder</th><th class="text-end" style="color:#334155;">Bid amount</th><th style="color:#334155;">Rank</th><th style="color:#334155;">Notes</th></tr>
                    </thead>
                    <tbody>
                        <?php foreach ($bidders as $b): ?>
                            <tr <?= $b['is_us'] ? 'style="background:#DCFCE7;"' : ''; ?>>
                                <td style="color:#334155;font-weight:<?= $b['is_us'] ? '600' : '400'; ?>;">
                                    <?php if ($b['is_us']): ?><i class="fas fa-star me-1" style="color:#166534;font-size:.7rem;"></i><?php endif; ?>
                                    <?= htmlspecialchars($b['bidder_name']); ?>
                                </td>
                                <td class="text-end" style="color:#334155;"><?= number_format((float)$b['bid_amount']); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= $b['ranking'] ?? '—'; ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$b['notes']); ?></td>
                            </tr>
                        <?php endforeach; ?>
                        <?php if (empty($bidders)): ?><tr><td colspan="4" class="text-center py-3" style="color:#94A3B8;">No bidders logged.</td></tr><?php endif; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- NEGOTIATIONS ── stub -->
    <div class="tab-pane fade" id="tab-negotiations">
        <div class="card border-0 shadow-sm" style="background:#F8FAFC;">
            <div class="card-body p-4">
                <div class="d-flex align-items-center mb-2">
                    <i class="fas fa-handshake me-2" style="color:#7A8BA1;font-size:1.1rem;"></i>
                    <strong style="color:#334155;font-size:.95rem;">Negotiations · BAFO &amp; counter-proposals</strong>
                </div>
                <div class="text-muted small" style="color:#64748B;">
                    Log the Best And Final Offer (BAFO), revised price schedule, meeting minutes and counter-proposals here.
                    See the <a href="#tab-prep" data-bs-toggle="tab" style="color:#7A8BA1;">Prep</a> tab for the Negotiation doc checklist (6 doc types).
                </div>
                <div class="mt-3 p-2" style="background:#fff;border:1px dashed #E2E8F0;border-radius:3px;color:#94A3B8;font-size:.78rem;">
                    <i class="fas fa-tools me-1"></i>Full negotiations form coming with the Contract-Signing slice. For now, add a note via the <a href="#" data-bs-toggle="tab" data-bs-target="#tab-history" style="color:#7A8BA1;">Advance-stage</a> notes as you move through the stage.
                </div>
            </div>
        </div>
    </div>

    <!-- Stage history ── -->
    <div class="tab-pane fade" id="tab-history">
        <div class="card border-0 shadow-sm">
            <div class="table-responsive">
                <table class="table table-sm mb-0 align-middle">
                    <thead style="background:#F1F5F9;">
                        <tr><th style="color:#334155;">When</th><th style="color:#334155;">From</th><th style="color:#334155;">To</th><th style="color:#334155;">By</th><th style="color:#334155;">Notes</th></tr>
                    </thead>
                    <tbody>
                        <?php foreach ($hist as $h): ?>
                            <tr>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$h['changed_on']); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= $h['stage_from'] ? htmlspecialchars(ucfirst(strtolower(str_replace('_',' ',(string)$h['stage_from'])))) : ''; ?></td>
                                <td style="color:#334155;font-weight:500;"><?= htmlspecialchars(ucfirst(strtolower(str_replace('_',' ',(string)$h['stage_to'])))); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$h['changed_by_name']); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$h['notes']); ?></td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- Result ── Slice 8W · Vue 3 Options API root (reactive save + reason categories + stage advance) -->
    <div class="tab-pane fade" id="tab-awarded">
        <?php
            // Slice 8V · derive winner default: CompanyProfile.legal_name → fallback to bidders is_us
            if (!class_exists('CompanyProfile')) require_once ROOT . '/app/models/CompanyProfile.php';
            $ourProfile    = (new CompanyProfile())->get();
            $ourBidderName = trim((string)($ourProfile['legal_name'] ?? ''));
            if ($ourBidderName === '') {
                foreach ($this->data['bidders'] ?? [] as $b) {
                    if ((int)($b['is_us'] ?? 0) === 1) { $ourBidderName = (string)$b['bidder_name']; break; }
                }
            }
            $ourSubAmount = (float)($t['submission_amount'] ?? 0);
            $canWriteResult = UserGroups::can('Tenders','recordResultAj') ? 'true' : 'false';
            $canAdvanceStage = UserGroups::can('Tenders','advanceStageAj') ? 'true' : 'false';
        ?>
        <div id="tab_awarded_root" v-cloak>
            <!-- Slice 8X · Handover-to-FM checklist chip (mirrors the one on Contract Signing tab) -->
            <div class="card border-0 shadow-sm mb-3" style="background:#FDF7EC;border-left:3px solid #D4A574 !important;">
                <div class="card-body p-3">
                    <div class="d-flex align-items-center justify-content-between mb-2">
                        <strong style="color:#8B6914;font-size:.86rem;"><i class="fas fa-route me-1"></i>Handover to FM · steps</strong>
                        <span class="small" style="color:#64748B;font-size:.72rem;">{{ handoverDoneCount }} / {{ handoverSteps.length }} complete · next: <strong>{{ handoverNextLabel }}</strong></span>
                    </div>
                    <div class="d-flex flex-wrap gap-2">
                        <template v-for="(s, i) in handoverSteps" :key="i">
                            <span class="badge d-flex align-items-center gap-1" :style="handoverChipStyle(s, i)">
                                <i class="fas" :class="handoverChipIcon(s, i)"></i>
                                <span>{{ i + 1 }}. {{ s.label }}</span>
                            </span>
                            <span v-if="i < handoverSteps.length - 1" style="color:#94A3B8;font-size:.7rem;align-self:center;"><i class="fas fa-angle-right"></i></span>
                        </template>
                    </div>
                    <div class="mt-2 small" style="color:#64748B;font-size:.72rem;">
                        Full flow &amp; team assignments live on the <a href="#tab-contract" data-bs-toggle="tab" style="color:#8B6914;font-weight:600;">Contract signing tab</a> once the tender is Awarded.
                    </div>
                </div>
            </div>

            <!-- Read-only result summary -->
            <div v-if="result" class="card border-0 shadow-sm mb-3">
                <div class="card-body p-3">
                    <dl class="row mb-0" style="color:#334155;">
                        <dt class="col-md-3" style="color:#64748B;">Result</dt>
                        <dd class="col-md-9"><span class="badge" :style="statusBadgeStyle(result.result_status)">{{ statusLabel(result.result_status) }}</span></dd>
                        <dt class="col-md-3" style="color:#64748B;">Result date</dt><dd class="col-md-9">{{ result.result_date }}</dd>
                        <dt class="col-md-3" style="color:#64748B;">Winning bidder</dt><dd class="col-md-9">{{ result.winning_bidder || '—' }}</dd>
                        <dt class="col-md-3" style="color:#64748B;">Winning amount</dt><dd class="col-md-9">{{ result.winning_amount !== null ? 'TZS ' + fmt0(result.winning_amount) : '—' }}</dd>
                        <dt v-if="result.reason_category" class="col-md-3" style="color:#64748B;">Reason category</dt>
                        <dd v-if="result.reason_category" class="col-md-9"><span class="badge" style="background:#F1F5F9;color:#334155;border:1px solid #7A8BA1;font-size:.66rem;text-transform:capitalize;font-weight:500;">{{ categoryLabel(result.reason_category) }}</span></dd>
                        <dt v-if="result.reason" class="col-md-3" style="color:#64748B;">Reason (notes)</dt>
                        <dd v-if="result.reason" class="col-md-9" style="white-space:pre-wrap;">{{ result.reason }}</dd>
                        <dt v-if="result.lessons" class="col-md-3" style="color:#64748B;">Lessons</dt>
                        <dd v-if="result.lessons" class="col-md-9" style="white-space:pre-wrap;">{{ result.lessons }}</dd>
                    </dl>
                </div>
            </div>

            <!-- Stage advance widget -->
            <div v-if="canAdvanceStage && nextStage" class="card border-0 shadow-sm mb-3" style="background:#EAF2E8;border-left:3px solid #7A9E7E !important;">
                <div class="card-body p-3 d-flex align-items-center justify-content-between flex-wrap gap-2">
                    <div>
                        <strong style="color:#3F5C43;font-size:.86rem;"><i class="fas fa-arrow-right me-1"></i>Manually advance stage</strong>
                        <div class="small" style="color:#64748B;font-size:.74rem;">Current: <strong>{{ stageLabel(tenderStage) }}</strong> &nbsp;→&nbsp; Next: <strong>{{ stageLabel(nextStage) }}</strong></div>
                    </div>
                    <div class="d-flex gap-2 align-items-center flex-wrap">
                        <input type="text" v-model="advanceNotes" placeholder="Optional notes" class="form-control form-control-sm" style="max-width:320px;">
                        <button type="button" @click="advanceStage" :disabled="busyAdvance" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;padding:.4rem 1rem;">
                            <i class="fas" :class="busyAdvance ? 'fa-spinner fa-spin' : 'fa-arrow-right'"></i>
                            <span class="ms-1">Advance to {{ stageLabel(nextStage) }}</span>
                        </button>
                    </div>
                </div>
            </div>

            <!-- Editable result form -->
            <div v-if="canWriteResult" class="card border-0 shadow-sm">
                <div class="card-header bg-white" style="border-bottom:1px solid #E2E8F0;">
                    <strong style="color:#334155;font-size:.9rem;"><i class="fas fa-flag-checkered me-1" style="color:#7A8BA1;"></i>{{ result ? 'Update result' : 'Record result' }}</strong>
                </div>
                <div class="card-body p-3">
                    <div v-if="ourBidderName === '' || ourSubAmount <= 0" class="small mb-2" style="color:#8B6914;background:#FEF3E7;border-left:3px solid #D4A574;padding:.5rem .7rem;font-size:.74rem;">
                        <i class="fas fa-info-circle me-1"></i>Auto-populate on <strong>Won</strong> needs:
                        <span v-if="ourBidderName === ''">
                            <a :href="PROOT + 'CompanyProfile'" style="color:#8B6914;font-weight:600;">Company Profile</a> <em>legal name</em>
                        </span>
                        <span v-if="ourBidderName === '' && ourSubAmount <= 0"> + </span>
                        <span v-if="ourSubAmount <= 0">a saved <em>Submitted bid amount</em> on the <a href="#tab-submission" data-bs-toggle="tab" style="color:#8B6914;font-weight:600;">Submission tab</a></span>.
                    </div>

                    <div class="row g-2">
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Status</label>
                            <select v-model="draft.result_status" @change="onStatusChange" class="form-select form-select-sm">
                                <option v-for="s in STATUSES" :key="s" :value="s">{{ statusLabel(s) }}</option>
                            </select>
                        </div>
                        <div class="col-md-2">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Date</label>
                            <input type="date" v-model="draft.result_date" class="form-control form-control-sm">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">
                                Winning bidder
                                <span v-if="winnerFilledFromProfile" class="small" style="color:#3F5C43;font-weight:400;"><i class="fas fa-magic ms-1"></i>from Company Profile</span>
                            </label>
                            <input type="text" v-model="draft.winning_bidder" class="form-control form-control-sm">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">
                                Winning amount (TZS)
                                <span v-if="amountFilledFromSubmission" class="small" style="color:#3F5C43;font-weight:400;"><i class="fas fa-magic ms-1"></i>from Submission</span>
                            </label>
                            <input type="number" step="0.01" v-model.number="draft.winning_amount" class="form-control form-control-sm">
                        </div>

                        <!-- Slice 8W: reason category depends on status -->
                        <div class="col-md-4">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Reason category</label>
                            <select v-model="draft.reason_category" class="form-select form-select-sm">
                                <option value="">—</option>
                                <option v-for="cat in categoriesForStatus(draft.result_status)" :key="cat.key" :value="cat.key">{{ cat.label }}</option>
                            </select>
                        </div>
                        <div class="col-md-8">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Reason (notes)</label>
                            <input type="text" v-model="draft.reason" placeholder="Elaborate on the category above" class="form-control form-control-sm">
                        </div>

                        <div class="col-12">
                            <label class="form-label" style="color:#334155;font-size:.78rem;">Lessons learned (optional)</label>
                            <textarea v-model="draft.lessons" rows="2" class="form-control form-control-sm" placeholder="Anything to remember for the next tender"></textarea>
                        </div>
                    </div>
                    <div class="d-flex justify-content-between align-items-center mt-3">
                        <div class="small" style="color:#64748B;font-size:.72rem;">
                            <span v-if="draft.result_status === 'WON'"><i class="fas fa-arrow-right me-1" style="color:#7A9E7E;"></i>Saving with <strong>Won</strong> auto-advances the tender stage to <strong>Awarded</strong>.</span>
                            <span v-else><i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>Save updates the result in place — stays on this tab.</span>
                        </div>
                        <button type="button" @click="saveResult" :disabled="busySave" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;padding:.4rem 1.2rem;">
                            <i class="fas" :class="busySave ? 'fa-spinner fa-spin' : 'fa-save'"></i>
                            <span class="ms-1">Save result</span>
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Contract signing ── post-award (Slice 3) -->
    <div class="tab-pane fade" id="tab-contract">
        <?php
            $terms   = $this->data['contract_terms']   ?? null;
            $appr    = $this->data['contract_approval']?? null;
            $apprHst = $this->data['contract_history'] ?? [];
            $signing = $this->data['contract_signing'] ?? null;
            $receipts = $this->data['contract_receipts'] ?? [];
            $atLeastAwarded = $curIdx >= array_search('AWARDED', $stages, true) && $t['tender_status'] === 'WON';
            $canWriteTerms  = $atLeastAwarded && ($appr['status'] ?? '') !== 'APPROVED' && UserGroups::can('Tenders','saveContractTermsAj');
            $canSubmit      = $atLeastAwarded && $terms !== null && ($appr === null || in_array($appr['status'] ?? '', ['DECLINED','APPROVED'], true) === false) && UserGroups::can('Tenders','submitContractAj') && ($appr['status'] ?? '') !== 'IN_PROGRESS' && ($appr['status'] ?? '') !== 'APPROVED';
            $canRecordSigning = ($appr['status'] ?? '') === 'APPROVED' && UserGroups::can('Tenders','recordSigningAj');
            $canAddReceipt  = $signing !== null && UserGroups::can('Tenders','addContractReceiptAj');
            $totalReceived  = 0; foreach ($receipts as $r) $totalReceived += (float)$r['amount'];
            $contractValue  = (float)($terms['contract_value'] ?? 0);
            $remaining      = max(0, $contractValue - $totalReceived);
            $apprStatusColor = ['IN_PROGRESS' => '#D4A574', 'APPROVED' => '#7A9E7E', 'DECLINED' => '#C48579', 'CANCELLED' => '#94A3B8'];
        ?>

        <?php if (!$atLeastAwarded): ?>
            <div class="card border-0 shadow-sm" style="background:#F8FAFC;">
                <div class="card-body p-4">
                    <div class="d-flex align-items-center mb-2">
                        <i class="fas fa-hourglass-half me-2" style="color:#D4A574;font-size:1.1rem;"></i>
                        <strong style="color:#334155;font-size:.95rem;">Contract signing unlocks after Award</strong>
                    </div>
                    <div class="text-muted small" style="color:#64748B;">
                        Advance the tender to <strong>Awarded</strong> and record the result as <strong>Won</strong> before capturing contract terms.
                        Current stage: <strong><?= htmlspecialchars(ucfirst(strtolower(str_replace('_',' ', $t['tender_stage'])))); ?></strong> · status: <strong><?= htmlspecialchars(strtolower($t['tender_status'])); ?></strong>.
                    </div>
                </div>
            </div>
        <?php else: ?>

        <?php
            // Slice 8-UX regrouped cards. Field-level disabled flag depends on lock state + role.
            $isLocked        = ($appr['status'] ?? '') === 'APPROVED';
            $canExecUnlock   = !empty($this->data['can_edit_locked_terms']) && $isLocked;
            $auditRows       = $this->data['contract_terms_audit'] ?? [];
            // Slice 8-UX / Exec-unlock: when Exec has issued an unlock, ANY role with
            // saveContractTermsAj perm can edit until they save (auto-relock).
            $unlockActive    = !empty($terms) && (int)($terms['terms_unlock_active'] ?? 0) === 1;
            $canFmAmend      = $isLocked && $unlockActive && UserGroups::can('Tenders','saveContractTermsAj');
            // Fields are enabled when: pre-approval FM window, direct Exec override, or Exec-issued unlock.
            $fieldDisabled   = ($canWriteTerms || $canExecUnlock || $canFmAmend) ? '' : 'disabled';
            // Slice 8Z-r · render helpers that preserve a stored 0 (don't collapse to empty). The old
            // pattern `(float)$terms['x'] ?: ''` treated 0.00 as falsy → downstream users (e.g. Exec)
            // saw the field as blank even though FM had explicitly saved a 0.
            $renderFloat = function ($v) { return ($v === null || $v === '') ? '' : (float)$v; };
            $renderInt   = function ($v) { return ($v === null || $v === '') ? '' : (int)$v; };
            // Slice 8Z-r · per-section save button (rendered at the BOTTOM of each section by
            // $groupCardFtr). Every section-save button collects the SAME full-terms payload
            // (the server normaliser expects all fields), so per-section saves are safe.
            // $sectionKey is used to render a live status pill (done/total mandatory items) in the header.
            $sectionsCompleteness = (new Tenders())->contractSectionCompleteness((int)$t['c0d']);
            $renderSectionPill = function(?string $key) use ($sectionsCompleteness) {
                if (!$key || !isset($sectionsCompleteness[$key])) return '';
                $s = $sectionsCompleteness[$key];
                if ((int)$s['total'] === 0) return '';
                $done = (int)$s['done']; $total = (int)$s['total'];
                if ($done >= $total) {
                    return '<span class="ct-sec-status" data-section-key="' . htmlspecialchars($key) . '" style="background:#7A9E7E;color:#fff;font-size:.62rem;font-weight:600;padding:.15rem .45rem;border-radius:3px;text-transform:capitalize;white-space:nowrap;flex:0 0 auto;"><i class="fas fa-check-circle me-1"></i>All done</span>';
                }
                return '<span class="ct-sec-status" data-section-key="' . htmlspecialchars($key) . '" style="background:#D4A574;color:#fff;font-size:.62rem;font-weight:600;padding:.15rem .45rem;border-radius:3px;text-transform:capitalize;white-space:nowrap;flex:0 0 auto;">' . $done . ' / ' . $total . '</span>';
            };
            $groupCardHdr = function(string $ico, string $title, string $note = '', ?string $sectionKey = null) use ($renderSectionPill) {
                echo '<div class="card border-0 shadow-sm mb-3">';
                echo '<div class="card-header bg-white d-flex align-items-start justify-content-between gap-2" style="border-bottom:1px solid #E2E8F0;">';
                echo '<div><strong style="color:#334155;"><i class="fas ' . $ico . ' me-2" style="color:#7A8BA1;"></i>' . htmlspecialchars($title) . '</strong>';
                if ($note !== '') echo '<div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">' . htmlspecialchars($note) . '</div>';
                echo '</div>';
                echo $renderSectionPill($sectionKey);
                echo '</div><div class="card-body p-3" style="background:#F8FAFC;">';
            };
            $groupCardFtr = function(bool $showSave = false) {
                // Close the card-body, optionally render a right-aligned Save row, then close the card.
                echo '</div>';
                if ($showSave) {
                    echo '<div class="card-footer bg-white text-end" style="border-top:1px solid #E2E8F0;padding:.5rem .75rem;">';
                    echo '<button type="button" class="btn btn-sm btn-save-terms-section" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save section</button>';
                    echo '</div>';
                }
                echo '</div>';
            };
            $canSaveTerms = ($canWriteTerms || $canFmAmend || $canExecUnlock);
        ?>

        <!-- ── Lock / Unlock header ────────────────────────────────────── -->
        <?php if ($isLocked && $unlockActive): ?>
            <!-- Active Exec-issued unlock: any FM can amend until first save (auto-relocks). -->
            <div class="alert py-2 mb-3 d-flex align-items-center justify-content-between" style="background:#FEF3C7;border:1px solid #F59E0B;color:#78350F;font-size:.86rem;">
                <div>
                    <i class="fas fa-unlock-alt me-1"></i>
                    <strong>Terms unlocked by <?= htmlspecialchars((string)$terms['terms_unlock_by_name']); ?></strong>
                    on <?= htmlspecialchars((string)$terms['terms_unlock_on']); ?>
                    · reason: <em>“<?= htmlspecialchars((string)$terms['terms_unlock_reason']); ?>”</em>
                    · your save will auto-relock the terms.
                </div>
                <?php if ($canExecUnlock): ?>
                    <button type="button" class="btn btn-sm" id="btn_exec_relock"
                            style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;">
                        <i class="fas fa-lock me-1"></i> Cancel unlock
                    </button>
                <?php endif; ?>
            </div>
        <?php elseif ($isLocked): ?>
            <!-- Locked, no active unlock. -->
            <div class="alert py-2 mb-3 d-flex align-items-center justify-content-between" style="background:#F0FDF4;border:1px solid #7A9E7E;color:#166534;font-size:.86rem;">
                <div>
                    <i class="fas fa-lock me-1"></i>
                    <strong>Contract terms locked</strong> — approved by Executive. Every amendment is audit-logged and requires a reason.
                </div>
                <?php if ($canExecUnlock): ?>
                    <div class="d-flex gap-2">
                        <button type="button" class="btn btn-sm" id="btn_exec_unlock_for_fm"
                                style="background:#D4A574;border-color:#D4A574;color:#fff;font-weight:600;">
                            <i class="fas fa-user-unlock me-1"></i> Unlock for FM
                        </button>
                        <button type="button" class="btn btn-sm" id="btn_exec_unlock"
                                style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;">
                            <i class="fas fa-unlock me-1"></i> Executive edit
                        </button>
                    </div>
                <?php endif; ?>
            </div>
        <?php endif; ?>

        <!-- Reason input — used by BOTH Exec direct edits and FM amendments under an unlock. -->
        <div id="ct_exec_reason_wrap" class="alert py-2 mb-3" style="display:<?= $canFmAmend ? 'block' : 'none'; ?>;background:#FEF3C7;border:1px solid #F59E0B;color:#78350F;">
            <div class="d-flex align-items-center gap-2">
                <label class="form-label mb-0" style="font-weight:600;min-width:130px;font-size:.82rem;"><i class="fas fa-pen me-1"></i>Reason for edit</label>
                <input type="text" id="ct_reason" class="form-control form-control-sm"
                       placeholder="<?= $canFmAmend ? 'Optional — Exec unlock reason is used automatically if left blank' : 'Required — describes why locked terms are being changed'; ?>">
            </div>
        </div>

        <?php
            // Slice 8X · Handover checklist state + role-scoped seat RBAC.
            $userGroupUpper = strtoupper((string)($_SESSION['user_group_name'] ?? ''));
            $canAssignFM   = in_array($userGroupUpper, ['CRM','ADMINISTRATOR'], true);
            $canAssignAcc  = in_array($userGroupUpper, ['FINANCE MANAGER','ADMINISTRATOR'], true);
            $canAssignProc = in_array($userGroupUpper, ['FINANCE MANAGER','ADMINISTRATOR'], true);
            $canAssignPM   = in_array($userGroupUpper, ['EXECUTIVE','ADMINISTRATOR'], true);

            $usersFm   = (new Tenders())->usersInGroup('Finance Manager');
            $usersAcc  = (new Tenders())->usersInGroup('Accountant');
            $usersProc = (new Tenders())->usersInGroup('Procurement');
            $usersPm   = (new Tenders())->usersInGroup('Project Manager');

            $fmId   = (int)($terms['assigned_fm_user_id']           ?? 0);
            $accId  = (int)($terms['assigned_accountant_user_id']   ?? 0);
            $procId = (int)($terms['assigned_procurement_user_id']  ?? 0);
            $pmId   = (int)($terms['assigned_pm_user_id']           ?? 0);

            $stepDone_award     = ($t['tender_status'] === 'WON');
            $stepDone_fm        = $fmId > 0;
            $stepDone_terms     = $terms !== null && (float)($terms['contract_value'] ?? 0) > 0;
            $stepDone_fmTeam    = $accId > 0 && $procId > 0;
            $stepDone_submit    = $appr !== null;
            $stepDone_execAppr  = ($appr['status'] ?? '') === 'APPROVED';
            $stepDone_pm        = $pmId > 0;
            $stepDone_signed    = $signing !== null;

            $steps = [
                ['ico' => 'fa-flag-checkered', 'label' => 'Award recorded',                 'done' => $stepDone_award],
                ['ico' => 'fa-user-tie',      'label' => 'CRM assigns FM',                 'done' => $stepDone_fm],
                ['ico' => 'fa-file-contract', 'label' => 'FM fills contract terms',        'done' => $stepDone_terms],
                ['ico' => 'fa-users',         'label' => 'FM assigns Accountant + Procurement', 'done' => $stepDone_fmTeam],
                ['ico' => 'fa-paper-plane',   'label' => 'Submit for FM verify',           'done' => $stepDone_submit],
                ['ico' => 'fa-check-double',  'label' => 'Executive approves',             'done' => $stepDone_execAppr],
                ['ico' => 'fa-user-check',    'label' => 'Exec assigns PM',                'done' => $stepDone_pm],
                ['ico' => 'fa-signature',     'label' => 'Signing recorded',               'done' => $stepDone_signed],
            ];
            // Find the first NOT-done step: everything before is done, this is "current", everything after is future.
            $currentIdx = null;
            foreach ($steps as $i => $s) { if (!$s['done']) { $currentIdx = $i; break; } }
        ?>

        <!-- ── 8X · Handover FM · steps checklist chip ─────────────── -->
        <div class="card border-0 shadow-sm mb-3" style="background:#FDF7EC;border-left:3px solid #D4A574 !important;">
            <div class="card-body p-3">
                <div class="d-flex align-items-center justify-content-between mb-2">
                    <strong style="color:#8B6914;font-size:.86rem;"><i class="fas fa-route me-1"></i>Handover to FM · steps</strong>
                    <span class="small" style="color:#64748B;font-size:.72rem;">
                        <?= array_sum(array_column($steps, 'done')); ?> / <?= count($steps); ?> complete
                    </span>
                </div>
                <div class="d-flex flex-wrap gap-2">
                    <?php foreach ($steps as $i => $s):
                        $isCurrent = ($i === $currentIdx);
                        if ($s['done']) {
                            $bg = '#EAF2E8'; $fg = '#3F5C43'; $br = '#7A9E7E'; $badgeIco = 'fa-check';
                        } elseif ($isCurrent) {
                            $bg = '#FEF3E7'; $fg = '#8B6914'; $br = '#D4A574'; $badgeIco = $s['ico'];
                        } else {
                            $bg = '#F1F5F9'; $fg = '#94A3B8'; $br = '#E2E8F0'; $badgeIco = $s['ico'];
                        }
                    ?>
                        <span class="badge d-flex align-items-center gap-1" style="background:<?= $bg; ?>;color:<?= $fg; ?>;border:1px solid <?= $br; ?>;font-size:.72rem;font-weight:500;text-transform:capitalize;padding:.45rem .7rem;line-height:1.3;">
                            <i class="fas <?= $badgeIco; ?>"></i>
                            <span><?= $i + 1; ?>. <?= htmlspecialchars($s['label']); ?></span>
                        </span>
                        <?php if ($i < count($steps) - 1): ?>
                            <span style="color:#94A3B8;font-size:.7rem;align-self:center;"><i class="fas fa-angle-right"></i></span>
                        <?php endif; ?>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>

        <!-- ── 8X · Team assignments (role-scoped) ──────────────────── -->
        <?php $groupCardHdr('fa-users-cog','Team assignments','Each role picks their nominee. CRM assigns FM; FM assigns Accountant + Procurement; Executive assigns PM. Seats are handed to the new project on Exec approval.', 'team'); ?>
        <?php
            /**
             * 8Y · Render one seat.
             *   - Owner (canAssign=true) sees the dropdown to pick / change.
             *   - Non-owner sees a static chip: filled name + "assigned by X on DATE"
             *     when the seat is already filled, or "Awaiting assignment by X" when empty.
             *     A hidden input carries the current value so collectTerms() re-sends it
             *     unchanged (the model's per-role RBAC would ignore any attempt to change).
             */
            $renderSeat = function (string $selId, string $label, string $assignerRole,
                                    bool $canAssign, int $currentId, array $userOptions)
                use ($canWriteTerms, $canFmAmend, $canExecUnlock) {
                $editable = ($canAssign && ($canWriteTerms || $canFmAmend || $canExecUnlock));
                $currentName = '';
                foreach ($userOptions as $u) if ((int)$u['c0d'] === $currentId) { $currentName = (string)$u['full_name']; break; }
                echo '<div class="col-md-3">';
                echo '  <label class="form-label d-flex align-items-center gap-1" style="color:#334155;font-size:.78rem;">';
                echo '    <span>' . htmlspecialchars($label) . '</span>';
                if ($editable) {
                    echo '    <i class="fas fa-pencil-alt" style="color:#7A9E7E;font-size:.6rem;" title="You can assign this seat"></i>';
                } elseif ($currentId > 0) {
                    echo '    <i class="fas fa-check-circle" style="color:#7A9E7E;font-size:.7rem;" title="Assigned"></i>';
                } else {
                    echo '    <i class="fas fa-hourglass-half" style="color:#94A3B8;font-size:.6rem;" title="Awaiting assignment"></i>';
                }
                echo '  </label>';
                if ($editable) {
                    // Owner — real dropdown; save button carries the value.
                    echo '  <select id="' . htmlspecialchars($selId) . '" class="form-select form-select-sm ct-field">';
                    echo '    <option value="">— Pick a ' . htmlspecialchars($label) . ' —</option>';
                    foreach ($userOptions as $u) {
                        $sel = ((int)$u['c0d'] === $currentId) ? 'selected' : '';
                        echo '    <option value="' . (int)$u['c0d'] . '" ' . $sel . '>' . htmlspecialchars((string)$u['full_name']) . '</option>';
                    }
                    echo '  </select>';
                } elseif ($currentId > 0) {
                    // Filled + I can't change it → clean chip with name; hidden input preserves value.
                    echo '  <div class="d-flex align-items-center gap-2 px-2 py-2 rounded" style="background:#EAF2E8;border:1px solid #7A9E7E33;min-height:32px;">';
                    echo '    <i class="fas fa-user-check" style="color:#7A9E7E;font-size:.72rem;"></i>';
                    echo '    <span style="color:#3F5C43;font-weight:600;font-size:.82rem;line-height:1;">' . htmlspecialchars($currentName) . '</span>';
                    echo '  </div>';
                    echo '  <div class="small mt-1" style="color:#94A3B8;font-size:.68rem;"><i class="fas fa-lock me-1"></i>Assigned by ' . htmlspecialchars($assignerRole) . '</div>';
                    echo '  <input type="hidden" id="' . htmlspecialchars($selId) . '" value="' . (int)$currentId . '">';
                } else {
                    // Not assigned + I can't do it → passive "awaiting" pill.
                    echo '  <div class="d-flex align-items-center gap-2 px-2 py-2 rounded" style="background:#F1F5F9;border:1px dashed #CBD5E1;min-height:32px;">';
                    echo '    <i class="fas fa-hourglass-half" style="color:#94A3B8;font-size:.72rem;"></i>';
                    echo '    <span style="color:#64748B;font-style:italic;font-size:.78rem;line-height:1;">Awaiting ' . htmlspecialchars($assignerRole) . '</span>';
                    echo '  </div>';
                    echo '  <div class="small mt-1" style="color:#94A3B8;font-size:.68rem;">&nbsp;</div>';
                    echo '  <input type="hidden" id="' . htmlspecialchars($selId) . '" value="">';
                }
                echo '</div>';
            };
        ?>
        <div class="row g-2">
            <?php
                $renderSeat('ct_assigned_fm',   'Finance Manager', 'CRM',       $canAssignFM,   $fmId,   $usersFm);
                $renderSeat('ct_assigned_acc',  'Accountant',      'FM',        $canAssignAcc,  $accId,  $usersAcc);
                $renderSeat('ct_assigned_proc', 'Procurement',     'FM',        $canAssignProc, $procId, $usersProc);
                $renderSeat('ct_assigned_pm',   'Project Manager', 'Executive', $canAssignPM,   $pmId,   $usersPm);
            ?>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <!-- ── 1. Financial ──────────────────────────────────────────── -->
        <?php $groupCardHdr('fa-file-contract','Financial','Contract identifiers, headline value and payment shape.', 'financial'); ?>
        <div class="row g-2">
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Contract no</label>
                <input type="text" id="ct_no" value="<?= htmlspecialchars((string)($terms['contract_no'] ?? '')); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Contract date</label>
                <input type="date" id="ct_date" value="<?= htmlspecialchars((string)($terms['contract_date'] ?? '')); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Contract value (<?= htmlspecialchars((string)$t['currency']); ?>)</label>
                <input type="number" step="0.01" id="ct_value" value="<?= (float)($terms['contract_value'] ?? 0); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Payment basis</label>
                <select id="ct_pb" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="">—</option>
                    <?php foreach (['LUMP_SUM'=>'Lump sum','MILESTONE'=>'Milestone','PROGRESS'=>'Progress-based','TIME_MATERIAL'=>'Time & material'] as $k=>$lbl): ?>
                        <option value="<?= $k; ?>" <?= (($terms['payment_basis'] ?? '') === $k) ? 'selected' : ''; ?>><?= $lbl; ?></option>
                    <?php endforeach; ?>
                </select>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Delivery (days)</label>
                <input type="number" min="0" id="ct_dtd" value="<?= $renderInt($terms['delivery_timeline_days'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Payment net (days)</label>
                <input type="number" min="0" id="ct_pnd" value="<?= $renderInt($terms['payment_net_days'] ?? null); ?>" placeholder="e.g. 30" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-12">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Payment terms</label>
                <input type="text" id="ct_pay" value="<?= htmlspecialchars((string)($terms['payment_terms'] ?? '')); ?>" placeholder="Free text · e.g. 30% advance · 60% on delivery · 10% retention 12m" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <!-- ── 2. Advance & Advance Payment Guarantee ───────────────── -->
        <?php $groupCardHdr('fa-hand-holding-usd','Advance & APG','Upfront draw plus the guarantee the bank issues against it.', 'advance'); ?>
        <div class="row g-2">
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Advance %</label>
                <input type="number" step="0.01" min="0" max="100" id="ct_ap" value="<?= $renderFloat($terms['advance_pct'] ?? null); ?>" class="form-control form-control-sm ct-field ct-advance-pct" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Advance amount (computed)</label>
                <input type="text" id="ct_ap_amt" readonly class="form-control form-control-sm" style="background:#F1F5F9;color:#334155;" value="<?= number_format(((float)($terms['contract_value'] ?? 0)) * ((float)($terms['advance_pct'] ?? 0)) / 100); ?>">
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">APG required?</label>
                <select id="ct_apg_req" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="0" <?= empty($terms['apg_required']) ? 'selected' : ''; ?>>No</option>
                    <option value="1" <?= !empty($terms['apg_required']) ? 'selected' : ''; ?>>Yes</option>
                </select>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">APG issuing bank</label>
                <input type="text" id="ct_apg_bank" value="<?= htmlspecialchars((string)($terms['apg_bank'] ?? '')); ?>" placeholder="e.g. CRDB Bank" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">APG validity (months)</label>
                <input type="number" min="0" id="ct_apg_val" value="<?= $renderInt($terms['apg_validity_months'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-12">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Advance conditions</label>
                <textarea id="ct_ac" rows="2" placeholder="Trigger conditions the client requires before releasing the advance — e.g. APG in-hand + signed contract + insurance cert" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>><?= htmlspecialchars((string)($terms['advance_conditions'] ?? '')); ?></textarea>
            </div>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <!-- ── 3. Performance Guarantee & Bid Bond ──────────────────── -->
        <?php $groupCardHdr('fa-shield-alt','Performance Guarantee & Bid Bond','Buyer-facing collateral held for the duration of the contract.', 'pg'); ?>
        <div class="row g-2">
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Bid bond value</label>
                <input type="number" step="0.01" id="ct_bb" value="<?= $renderFloat($terms['bid_bond_value'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Performance bond value</label>
                <input type="number" step="0.01" id="ct_pbv" value="<?= $renderFloat($terms['performance_bond_value'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">PG type</label>
                <select id="ct_pgt" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="">—</option>
                    <?php foreach (['BANK'=>'Bank guarantee','INSURANCE'=>'Insurance bond','RETENTION_ONLY'=>'Retention only'] as $k=>$lbl): ?>
                        <option value="<?= $k; ?>" <?= (($terms['pg_type'] ?? '') === $k) ? 'selected' : ''; ?>><?= $lbl; ?></option>
                    <?php endforeach; ?>
                </select>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">PG issuing bank</label>
                <input type="text" id="ct_pgb" value="<?= htmlspecialchars((string)($terms['pg_bank'] ?? '')); ?>" placeholder="e.g. NMB" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Performance bond ref</label>
                <input type="text" id="ct_pbr" value="<?= htmlspecialchars((string)($terms['performance_bond_ref'] ?? '')); ?>" placeholder="e.g. CRDB-BG-2026-0091" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">PG validity (months)</label>
                <input type="number" min="0" id="ct_pgvm" value="<?= $renderInt($terms['pg_validity_months'] ?? null); ?>" placeholder="e.g. 24" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <!-- ── 4. Retention · Warranty · Liquidated Damages ─────────── -->
        <?php $groupCardHdr('fa-percentage','Retention · Warranty · Liquidated Damages','Buyer protections that stretch past delivery.', 'retention_warranty'); ?>
        <div class="row g-2">
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Retention %</label>
                <input type="number" step="0.01" min="0" max="100" id="ct_rp" value="<?= $renderFloat($terms['retention_pct'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-4">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Retention release trigger</label>
                <input type="text" id="ct_rrt" value="<?= htmlspecialchars((string)($terms['retention_release_trigger'] ?? '')); ?>" placeholder="e.g. 12 months after final acceptance" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Warranty (months)</label>
                <input type="number" min="0" id="ct_wm" value="<?= $renderInt($terms['warranty_months'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">LD % / day</label>
                <input type="number" step="0.001" min="0" id="ct_ldd" value="<?= $renderFloat($terms['ld_pct_per_day'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">LD cap %</label>
                <input type="number" step="0.01" min="0" max="100" id="ct_ldc" value="<?= $renderFloat($terms['ld_cap_pct'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-12">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Warranty coverage</label>
                <textarea id="ct_wcov" rows="2" placeholder="What the warranty covers (defects, parts, workmanship, exclusions)" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>><?= htmlspecialchars((string)($terms['warranty_coverage'] ?? '')); ?></textarea>
            </div>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <!-- ── 5. Tax & Compliance ──────────────────────────────────── -->
        <?php $groupCardHdr('fa-balance-scale','Tax & Compliance','How the contract is taxed + booking hooks for Finance.', 'tax'); ?>
        <?php
            // Slice 8Z-t · when tax_treatment ≠ TAXABLE, the TRA VAT exemption certificate
            // must live in the Bonds tracker with status = RECEIVED before FM can hand off.
            $curTt = strtoupper((string)($terms['tax_treatment'] ?? ''));
            $vatCertNeeded = in_array($curTt, ['EXEMPT','ZERO_RATED','MIXED'], true);
            $vatCertPresent = false;
            if ($vatCertNeeded && !empty($this->data['contract_bonds'])) {
                foreach ($this->data['contract_bonds'] as $b) {
                    if ((string)$b['bond_type'] === 'VAT_EXEMPTION_CERT' && (string)$b['status'] === 'RECEIVED') { $vatCertPresent = true; break; }
                }
            }
        ?>
        <div id="ct_vat_cert_banner" class="alert py-2 mb-2" style="display:<?= $vatCertNeeded ? 'block' : 'none'; ?>;background:<?= $vatCertPresent ? '#EAF2E8' : '#FEF3C7'; ?>;border:1px solid <?= $vatCertPresent ? '#7A9E7E' : '#F59E0B'; ?>;color:<?= $vatCertPresent ? '#3F5C43' : '#78350F'; ?>;font-size:.78rem;">
            <div class="d-flex align-items-center justify-content-between">
                <div>
                    <i id="ct_vat_cert_ico" class="fas <?= $vatCertPresent ? 'fa-check-circle' : 'fa-exclamation-triangle'; ?> me-1"></i>
                    <strong id="ct_vat_cert_msg">
                        <?php if ($vatCertPresent): ?>
                            VAT exemption certificate on file — TRA compliance OK.
                        <?php else: ?>
                            Tax treatment isn't taxable — add the TRA <strong>VAT exemption certificate</strong> in the Bonds tracker (status RECEIVED) before FM can hand off.
                        <?php endif; ?>
                    </strong>
                </div>
                <a href="#" id="ct_vat_cert_jump" class="btn btn-sm ms-2" style="background:transparent;border:1px solid #78350F;color:#78350F;font-weight:600;font-size:.68rem;padding:.1rem .5rem;<?= $vatCertPresent ? 'display:none;' : ''; ?>"><i class="fas fa-arrow-right me-1"></i>Go to Bonds tracker</a>
            </div>
        </div>
        <div class="row g-2">
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">VAT treatment</label>
                <select id="ct_vt" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="">—</option>
                    <?php foreach (['INCLUSIVE'=>'Inclusive','EXCLUSIVE'=>'Exclusive','EXEMPT'=>'Exempt'] as $k=>$lbl): ?>
                        <option value="<?= $k; ?>" <?= (($terms['vat_treatment'] ?? '') === $k) ? 'selected' : ''; ?>><?= $lbl; ?></option>
                    <?php endforeach; ?>
                </select>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Tax treatment</label>
                <select id="ct_tt" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="">—</option>
                    <?php foreach (['TAXABLE'=>'Taxable','EXEMPT'=>'Exempt','ZERO_RATED'=>'Zero-rated','MIXED'=>'Mixed'] as $k=>$lbl): ?>
                        <option value="<?= $k; ?>" <?= (($terms['tax_treatment'] ?? '') === $k) ? 'selected' : ''; ?>><?= $lbl; ?></option>
                    <?php endforeach; ?>
                </select>
            </div>
            <div class="col-md-4">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Tax exemption basis</label>
                <input type="text" id="ct_teb" value="<?= htmlspecialchars((string)($terms['tax_exemption_basis'] ?? '')); ?>" placeholder="e.g. Diplomatic mission · TRA cert no." class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">WHT %</label>
                <input type="number" step="0.01" min="0" max="100" id="ct_wp" value="<?= $renderFloat($terms['wht_pct'] ?? null); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-2">
                <label class="form-label" style="color:#334155;font-size:.78rem;">GL / cost centre</label>
                <input type="text" id="ct_gl" value="<?= htmlspecialchars((string)($terms['gl_code'] ?? '')); ?>" placeholder="e.g. 4200-CIV" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">FX matches cost base?</label>
                <select id="ct_fx" class="form-select form-select-sm ct-field" <?= $fieldDisabled; ?>>
                    <option value="1" <?= !isset($terms['fx_matches_cost_base']) || (int)($terms['fx_matches_cost_base'] ?? 1) === 1 ? 'selected' : ''; ?>>Yes — no FX risk</option>
                    <option value="0" <?= isset($terms['fx_matches_cost_base']) && (int)$terms['fx_matches_cost_base'] === 0 ? 'selected' : ''; ?>>No — FX risk to flag</option>
                </select>
            </div>
            <div class="col-md-3">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Insurance ref (CAR / WC)</label>
                <input type="text" id="ct_ir" value="<?= htmlspecialchars((string)($terms['insurance_ref'] ?? '')); ?>" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>>
            </div>
            <div class="col-12">
                <label class="form-label" style="color:#334155;font-size:.78rem;">Notes (private to Finance / Exec)</label>
                <textarea id="ct_notes" rows="2" class="form-control form-control-sm ct-field" <?= $fieldDisabled; ?>><?= htmlspecialchars((string)($terms['notes'] ?? '')); ?></textarea>
            </div>
        </div>
        <?php $groupCardFtr($canSaveTerms); ?>

        <?php if ($canWriteTerms || $canExecUnlock): ?>
        <div class="text-end mb-3">
            <button type="button" id="btn_save_terms" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;">
                <i class="fas fa-save me-1"></i>Save terms
            </button>
        </div>
        <?php endif; ?>

        <!-- ── Audit trail (Exec + Admin only) — collapsed by default ──── -->
        <?php if (!empty($this->data['can_edit_locked_terms']) || strtoupper((string)($_SESSION['user_group_name'] ?? '')) === 'ADMINISTRATOR'): ?>
        <div class="card border-0 shadow-sm mb-3">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;cursor:pointer;user-select:none;"
                 data-bs-toggle="collapse" data-bs-target="#auditTrailBody" aria-expanded="false" aria-controls="auditTrailBody">
                <div>
                    <strong style="color:#334155;"><i class="fas fa-history me-2" style="color:#7A8BA1;"></i>Contract-terms audit trail</strong>
                    <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">Every changed field — who, when, from what to what. Post-approval edits flagged in amber.</div>
                </div>
                <div class="d-flex align-items-center gap-2">
                    <span class="badge" style="background:#F1F5F9;color:#334155;font-size:.68rem;"><?= count($auditRows); ?> change<?= count($auditRows) === 1 ? '' : 's' ?></span>
                    <i class="fas fa-chevron-down" id="auditTrailChevron" style="color:#94A3B8;font-size:.72rem;transition:transform .2s;"></i>
                </div>
            </div>
            <div class="card-body p-0 collapse" id="auditTrailBody">
                <?php if (empty($auditRows)): ?>
                    <div class="p-3 text-center text-muted small" style="color:#94A3B8;">No changes yet.</div>
                <?php else: ?>
                    <table class="table table-sm mb-0 align-middle">
                        <thead style="background:#F1F5F9;">
                            <tr>
                                <th style="color:#334155;font-size:.72rem;">When</th>
                                <th style="color:#334155;font-size:.72rem;">By</th>
                                <th style="color:#334155;font-size:.72rem;">Field</th>
                                <th style="color:#334155;font-size:.72rem;">From</th>
                                <th style="color:#334155;font-size:.72rem;">To</th>
                                <th style="color:#334155;font-size:.72rem;">Reason</th>
                                <th style="color:#334155;font-size:.72rem;">Post-approval</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php foreach ($auditRows as $a): ?>
                                <tr style="<?= (int)$a['post_approval'] === 1 ? 'background:#FEF3C7;' : ''; ?>">
                                    <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$a['changed_on']); ?></td>
                                    <td class="small" style="color:#334155;">
                                        <?= htmlspecialchars((string)$a['changed_by_name']); ?>
                                        <div class="text-muted" style="font-size:.62rem;text-transform:capitalize;"><?= htmlspecialchars(strtolower((string)$a['changed_by_group'])); ?></div>
                                    </td>
                                    <td class="small" style="color:#334155;"><code style="color:#334155;background:#F1F5F9;padding:1px 5px;border-radius:3px;font-size:.7rem;"><?= htmlspecialchars((string)$a['field_name']); ?></code></td>
                                    <td class="small text-muted" style="color:#94A3B8;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="<?= htmlspecialchars((string)($a['old_value'] ?? '—')); ?>"><?= htmlspecialchars($a['old_value'] === null ? '—' : (string)$a['old_value']); ?></td>
                                    <td class="small" style="color:#166534;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="<?= htmlspecialchars((string)($a['new_value'] ?? '—')); ?>"><strong><?= htmlspecialchars($a['new_value'] === null ? '—' : (string)$a['new_value']); ?></strong></td>
                                    <td class="small text-muted" style="color:#64748B;max-width:220px;"><?= htmlspecialchars((string)$a['reason']); ?></td>
                                    <td>
                                        <?php if ((int)$a['post_approval'] === 1): ?>
                                            <span class="badge" style="background:#F59E0B;color:#fff;font-size:.62rem;">Post-approval</span>
                                        <?php else: ?>
                                            <span class="text-muted small">—</span>
                                        <?php endif; ?>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                        </tbody>
                    </table>
                <?php endif; ?>
            </div>
        </div>
        <?php endif; ?>

        <?php ob_start(); /* Slice 8Z-q · buffer Section 2 so we can echo it AFTER the bonds+FM blocks — FM needs to fill those first before the Verify button. */ ?>
        <!-- ── Section 2 · FM / Exec approval chain ───────────────────── -->
        <div class="card border-0 shadow-sm mb-3">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                <div>
                    <strong style="color:#334155;"><i class="fas fa-user-check me-2" style="color:#7A8BA1;"></i>Approval chain · <code>TENDER_CONTRACT_APPROVAL</code></strong>
                    <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">Finance Manager verifies → Executive approves. On Exec approval the tender auto-advances Awarded → Contract signing.</div>
                </div>
                <?php if ($appr): ?>
                    <span class="badge" style="background:<?= $apprStatusColor[$appr['status']] ?? '#94A3B8'; ?>;color:#fff;font-size:.72rem;text-transform:capitalize;"><?= htmlspecialchars(strtolower(str_replace('_',' ', $appr['status']))); ?></span>
                <?php endif; ?>
            </div>
            <div class="card-body p-3" style="background:#F8FAFC;">
                <?php if (!$appr): ?>
                    <div class="d-flex align-items-center justify-content-between">
                        <div class="text-muted small" style="color:#64748B;">
                            <i class="fas fa-info-circle me-1" style="color:#7A8BA1;"></i>Not yet submitted. Capture the terms above, then submit for FM verification.
                        </div>
                        <?php if ($canSubmit): ?><button type="button" id="btn_submit_contract" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"><i class="fas fa-paper-plane me-1"></i>Submit for FM verification</button><?php endif; ?>
                    </div>
                <?php else: ?>
                    <div class="d-flex align-items-center justify-content-between mb-3">
                        <div style="color:#334155;font-size:.86rem;">
                            <strong>Current step:</strong> <?= htmlspecialchars((string)($appr['current_step_label'] ?? '—')); ?>
                            <span style="color:#94A3B8;font-size:.72rem;">· role: <?= htmlspecialchars((string)($appr['role_required'] ?? '')); ?></span>
                        </div>
                        <a href="<?= PROOT; ?>FinChains/myQueue" class="btn btn-sm" style="background:#F8FAFC;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-inbox me-1" style="color:#7A8BA1;"></i>Open queue</a>
                    </div>

                    <!-- History timeline -->
                    <div class="table-responsive">
                        <table class="table table-sm mb-0 align-middle">
                            <thead style="background:#F1F5F9;">
                                <tr><th style="color:#334155;">When</th><th style="color:#334155;">Step</th><th style="color:#334155;">Action</th><th style="color:#334155;">By</th><th style="color:#334155;">Comment</th></tr>
                            </thead>
                            <tbody>
                                <?php foreach ($apprHst as $h): ?>
                                <tr>
                                    <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$h['created_on']); ?></td>
                                    <td class="text-muted small" style="color:#334155;"><?= htmlspecialchars((string)($h['step_label'] ?? '')); ?></td>
                                    <td style="color:#334155;"><span class="badge" style="background:#E2E8F0;color:#334155;font-size:.62rem;text-transform:capitalize;"><?= htmlspecialchars(strtolower((string)$h['action'])); ?></span></td>
                                    <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)($h['actor_name'] ?? $h['actor_user_id'] ?? '')); ?></td>
                                    <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$h['comment']); ?></td>
                                </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>

                    <?php
                        // Slice 8Y · Inline verify + hand-off panel for the current-step actor.
                        // FM_VERIFY  → FM sees Executive picker + completeness check + approve/return buttons.
                        // EXEC_APPROVE → Exec sees PM picker + approve/return buttons.
                        $curStepKey = strtoupper((string)($appr['current_step_key'] ?? ''));
                        $isFmStep   = $curStepKey === 'FM_VERIFY'    && in_array($userGroupUpper, ['FINANCE MANAGER','ADMINISTRATOR'], true);
                        $isExecStep = $curStepKey === 'EXEC_APPROVE' && in_array($userGroupUpper, ['EXECUTIVE','ADMINISTRATOR'], true);
                        if (($isFmStep || $isExecStep) && ($appr['status'] ?? '') === 'IN_PROGRESS'
                            && UserGroups::can('FinChains','approveAj')) {
                            $missing = (new Tenders())->contractCompletenessMissing((int)$t['c0d']);
                            $canReturn = UserGroups::can('FinChains','returnToOriginatorAj');
                            $usersExec = (new Tenders())->usersInGroup('Executive');
                            // Lookup names for the seats already stored in tender_contract_terms — used to
                            // populate the approve payload with proper display names for the audit log.
                            $nameById = function(array $rows, int $id): string {
                                if ($id <= 0) return '';
                                foreach ($rows as $r) if ((int)$r['c0d'] === $id) return (string)$r['full_name'];
                                return '';
                            };
                            $accName  = $nameById($usersAcc,  $accId);
                            $procName = $nameById($usersProc, $procId);
                            $pmName   = $nameById($usersPm,   $pmId);
                    ?>
                        <div class="mt-3 pt-3" style="border-top:1px dashed #CBD5E1;">
                            <div class="d-flex align-items-center gap-2 mb-2">
                                <i class="fas fa-user-shield" style="color:#7A9E7E;"></i>
                                <strong style="color:#334155;font-size:.9rem;">
                                    <?= $isFmStep ? 'Your verification — hand off to Executive' : 'Executive review — approve & authorise'; ?>
                                </strong>
                            </div>

                            <!-- Completeness checklist · Slice 8Z-r · every item stays visible; done items get a green tick, pending items an amber dot. Rewritten in-place after every save via refreshCompleteness(). -->
                            <?php
                                $checklist = (new Tenders())->contractCompletenessChecklist((int)$t['c0d']);
                                $doneCount = 0; foreach ($checklist as $ci) if (!empty($ci['ok'])) $doneCount++;
                                $totalCount = count($checklist);
                                $allOk = empty($missing);
                            ?>
                            <div id="ct_completeness_wrap">
                                <div class="alert py-2 mb-2" style="background:<?= $allOk ? '#EAF2E8' : '#FEF3C7'; ?>;border:1px solid <?= $allOk ? '#7A9E7E' : '#F59E0B'; ?>;color:<?= $allOk ? '#3F5C43' : '#78350F'; ?>;font-size:.82rem;">
                                    <div class="mb-1 d-flex align-items-center justify-content-between">
                                        <div>
                                            <?php if ($allOk): ?>
                                                <i class="fas fa-check-circle me-1" style="color:#7A9E7E;"></i><strong>All mandatory contract terms + seats are filled — ready to hand off.</strong>
                                            <?php else: ?>
                                                <i class="fas fa-exclamation-triangle me-1"></i><strong>Before handing off, fill:</strong>
                                            <?php endif; ?>
                                        </div>
                                        <span class="badge" style="background:<?= $allOk ? '#7A9E7E' : '#D4A574'; ?>;color:#fff;font-size:.66rem;font-weight:600;">
                                            <?= $doneCount; ?> / <?= $totalCount; ?> done
                                        </span>
                                    </div>
                                    <div class="row g-1" style="font-size:.74rem;">
                                        <?php foreach ($checklist as $ci):
                                            $ok = !empty($ci['ok']);
                                        ?>
                                            <div class="col-md-4 col-sm-6" style="color:<?= $ok ? '#3F5C43' : '#78350F'; ?>;">
                                                <?php if ($ok): ?>
                                                    <i class="fas fa-check-circle me-1" style="color:#7A9E7E;font-size:.78rem;vertical-align:middle;"></i>
                                                    <span style="text-decoration:line-through;text-decoration-color:#7A9E7E80;text-decoration-thickness:1px;opacity:.85;"><?= htmlspecialchars((string)$ci['label']); ?></span>
                                                <?php else: ?>
                                                    <i class="far fa-circle me-1" style="color:#D4A574;font-size:.72rem;vertical-align:middle;"></i>
                                                    <?= htmlspecialchars((string)$ci['label']); ?>
                                                <?php endif; ?>
                                            </div>
                                        <?php endforeach; ?>
                                    </div>
                                </div>
                            </div>

                            <!-- Next-role picker: FM picks Exec, Exec picks PM (moved from top seat card per user ask). -->
                            <?php if ($isFmStep): ?>
                                <div class="row g-2 align-items-end mb-2">
                                    <div class="col-md-3">
                                        <label class="form-label" style="color:#334155;font-size:.78rem;">
                                            <i class="fas fa-user-tie me-1" style="color:#7A8BA1;"></i>
                                            Executive to hand off to <span style="color:#C48579;">*</span>
                                        </label>
                                        <select id="fm_pick_exec" class="form-select form-select-sm">
                                            <option value="">— Pick —</option>
                                            <?php foreach ($usersExec as $u): ?>
                                                <option value="<?= (int)$u['c0d']; ?>" data-name="<?= htmlspecialchars((string)$u['full_name']); ?>">
                                                    <?= htmlspecialchars((string)$u['full_name']); ?>
                                                </option>
                                            <?php endforeach; ?>
                                        </select>
                                    </div>
                                    <div class="col-md-9">
                                        <label class="form-label" style="color:#334155;font-size:.78rem;">Comment (optional)</label>
                                        <input type="text" id="fm_comment" class="form-control form-control-sm" placeholder="Notes for the Executive (optional on approve, required on return)">
                                    </div>
                                </div>
                            <?php else: ?>
                                <div class="row g-2 align-items-end mb-2">
                                    <div class="col-md-3">
                                        <label class="form-label" style="color:#334155;font-size:.78rem;">
                                            <i class="fas fa-user-check me-1" style="color:#7A8BA1;"></i>
                                            Project Manager <span style="color:#C48579;">*</span>
                                        </label>
                                        <select id="exec_pick_pm" class="form-select form-select-sm">
                                            <option value="">— Pick —</option>
                                            <?php foreach ($usersPm as $u): ?>
                                                <option value="<?= (int)$u['c0d']; ?>" data-name="<?= htmlspecialchars((string)$u['full_name']); ?>" <?= ((int)$u['c0d'] === $pmId) ? 'selected' : ''; ?>>
                                                    <?= htmlspecialchars((string)$u['full_name']); ?>
                                                </option>
                                            <?php endforeach; ?>
                                        </select>
                                    </div>
                                    <div class="col-md-9">
                                        <label class="form-label" style="color:#334155;font-size:.78rem;">Comment (optional)</label>
                                        <input type="text" id="fm_comment" class="form-control form-control-sm" placeholder="Notes on this decision (optional on approve, required on return)">
                                    </div>
                                </div>

                                <!-- 8Y · Optional signing-now shortcut. Off by default → keep the ceremonial signing event. -->
                                <div class="border rounded p-2 mb-2" style="background:#FDF7EC;border-color:#D4A574 !important;">
                                    <div class="form-check mb-1">
                                        <input type="checkbox" id="exec_sign_now" class="form-check-input">
                                        <label for="exec_sign_now" class="form-check-label" style="color:#8B6914;font-weight:600;font-size:.82rem;">
                                            <i class="fas fa-signature me-1"></i>Record signing now &mdash; skip separate ceremony
                                        </label>
                                        <div class="text-muted small mt-1" style="color:#8B6914;font-size:.72rem;">
                                            Use this when Executive approval <em>is</em> the signing act (e.g. MD signs on the spot). Advances Contract signing &rarr; Execution immediately.
                                        </div>
                                    </div>
                                    <div id="exec_sign_now_body" class="row g-2 mt-1" style="display:none;">
                                        <div class="col-md-3">
                                            <label class="form-label" style="color:#334155;font-size:.72rem;">Signed date *</label>
                                            <input type="date" id="exec_signed_date" class="form-control form-control-sm" value="<?= date('Y-m-d'); ?>">
                                        </div>
                                        <div class="col-md-4">
                                            <label class="form-label" style="color:#334155;font-size:.72rem;">Venue</label>
                                            <input type="text" id="exec_signed_venue" class="form-control form-control-sm" placeholder="e.g. HQ · Boardroom">
                                        </div>
                                        <div class="col-md-5">
                                            <label class="form-label" style="color:#334155;font-size:.72rem;">Our signatories</label>
                                            <input type="text" id="exec_our_sig" class="form-control form-control-sm" placeholder="MD, FM">
                                        </div>
                                    </div>
                                </div>
                            <?php endif; ?>

                            <div class="d-flex justify-content-end gap-2">
                                <?php if ($canReturn): ?>
                                    <button type="button" id="btn_return_to_prev" class="btn btn-sm"
                                        style="background:#F8FAFC;border:1px solid #D4A574;color:#8B6914;font-weight:600;">
                                        <i class="fas fa-user-edit me-1"></i>
                                        <?= $isFmStep ? 'Return to CRM' : 'Return to FM'; ?>
                                    </button>
                                <?php endif; ?>
                                <button type="button" id="btn_fm_handoff" class="btn btn-sm"
                                    style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"
                                    <?= empty($missing) ? '' : 'disabled title="Fill mandatory fields first"'; ?>>
                                    <i class="fas fa-paper-plane me-1"></i>
                                    <?= $isFmStep ? 'Verify & hand off to Executive' : 'Approve & authorise signing'; ?>
                                </button>
                            </div>

                            <script>
                            (function () {
                                var $return = document.getElementById('btn_return_to_prev');
                                var $go     = document.getElementById('btn_fm_handoff');
                                var approvalId = <?= (int)($appr['c0d'] ?? 0); ?>;
                                var isFmStep = <?= $isFmStep ? 'true' : 'false'; ?>;
                                function comment() { return (document.getElementById('fm_comment').value || '').trim(); }

                                // 8Y · Reveal the sign-now field row when the checkbox is on (Exec step only).
                                var $signNow = document.getElementById('exec_sign_now');
                                var $signBody = document.getElementById('exec_sign_now_body');
                                if ($signNow && $signBody) {
                                    $signNow.addEventListener('change', function () {
                                        $signBody.style.display = $signNow.checked ? '' : 'none';
                                    });
                                }

                                if ($return) $return.addEventListener('click', function () {
                                    var cmt = comment();
                                    // FM step 1 → returnToOriginator (cancels + sends back to CRM).
                                    // Exec step 2 → sendBack (walks the chain back to FM_VERIFY, keeps the approval).
                                    var endpoint = isFmStep ? 'FinChains/returnToOriginatorAj' : 'FinChains/sendBackAj';
                                    var backTo   = isFmStep ? 'CRM' : 'Finance Manager';
                                    var msg      = isFmStep
                                        ? 'The current approval will be cancelled. CRM will need to edit + re-submit.'
                                        : 'The approval will step back to Finance Manager for corrections. The FM keeps the current approval and can re-submit to you.';
                                    if (!cmt) { $.alert({title:'Comment required', content:'Please explain why you are returning the contract to ' + backTo + '.', type:'orange'}); return; }
                                    $.confirm({
                                        title: 'Return to ' + backTo + '?',
                                        content: msg,
                                        type: 'orange',
                                        buttons: {
                                            confirm: { text: 'Return to ' + backTo, btnClass: 'btn-warning', action: function () {
                                                $.post('<?= PROOT; ?>' + endpoint, {
                                                    approval_id: approvalId, comment: cmt
                                                }, function (r) {
                                                    if (r && r.ok) { rsToast('Returned to ' + backTo + '.', 'success'); setTimeout(function(){ location.reload(); }, 600); }
                                                    else { $.alert({title:'Could not return', content: (r && r.msg) || 'Server error', type:'red'}); }
                                                }, 'json');
                                            }},
                                            cancel: function () {}
                                        }
                                    });
                                });

                                if ($go) $go.addEventListener('click', function () {
                                    var payload = { approval_id: approvalId, comment: comment() };
                                    if (isFmStep) {
                                        var sel = document.getElementById('fm_pick_exec');
                                        var uid = sel.value;
                                        if (!uid) { $.alert({title:'Executive required', content:'Please pick which Executive to hand off to.', type:'orange'}); return; }
                                        var name = sel.options[sel.selectedIndex].getAttribute('data-name') || '';
                                        // Acc + Proc were already saved to tender_contract_terms via the Team card;
                                        // re-pass them here so the chain audit log records who FM chose.
                                        payload['assignments[ACCOUNTANT][user_id]']    = <?= (int)$accId; ?>;
                                        payload['assignments[ACCOUNTANT][user_name]']  = <?= json_encode($accName, JSON_UNESCAPED_UNICODE); ?>;
                                        payload['assignments[PROCUREMENT][user_id]']   = <?= (int)$procId; ?>;
                                        payload['assignments[PROCUREMENT][user_name]'] = <?= json_encode($procName, JSON_UNESCAPED_UNICODE); ?>;
                                        payload['assignments[EXECUTIVE][user_id]']     = uid;
                                        payload['assignments[EXECUTIVE][user_name]']   = name;
                                    } else {
                                        // Exec step — PM picked here on the approve panel (moved from top seat card).
                                        var pmSel = document.getElementById('exec_pick_pm');
                                        var chosenPmId = pmSel ? pmSel.value : '';
                                        if (!chosenPmId) { $.alert({title:'Project Manager required', content:'Please pick which Project Manager to run the project.', type:'orange'}); return; }
                                        var chosenPmName = pmSel.options[pmSel.selectedIndex].getAttribute('data-name') || '';
                                        payload['assignments[PROJECT_MANAGER][user_id]']   = chosenPmId;
                                        payload['assignments[PROJECT_MANAGER][user_name]'] = chosenPmName;

                                        // 8Y · Optional "record signing now" — skip the ceremony, auto-advance to Execution.
                                        var signNow = document.getElementById('exec_sign_now');
                                        if (signNow && signNow.checked) {
                                            var sd = (document.getElementById('exec_signed_date').value || '').trim();
                                            if (!sd) { $.alert({title:'Signed date required', content:'Enter the signed date to record signing now.', type:'orange'}); return; }
                                            payload['record_signing_now'] = '1';
                                            payload['signed_date']        = sd;
                                            payload['signed_venue']       = (document.getElementById('exec_signed_venue').value || '').trim();
                                            payload['our_signatories']    = (document.getElementById('exec_our_sig').value    || '').trim();
                                        }
                                    }
                                    var signingNow = !isFmStep && document.getElementById('exec_sign_now') && document.getElementById('exec_sign_now').checked;
                                    $.confirm({
                                        title: isFmStep ? 'Hand off to Executive?' : (signingNow ? 'Approve + record signing + go to Execution?' : 'Approve contract?'),
                                        content: isFmStep
                                            ? 'This will notify the chosen Executive that the contract awaits their approval.'
                                            : (signingNow
                                                ? 'Contract will be approved, signing recorded with your details, and stage advanced straight to Execution. PM + team will be notified.'
                                                : 'This authorises the signing event and creates the project. Someone still needs to record the physical signing event to advance to Execution. Are you sure?'),
                                        type: 'green',
                                        buttons: {
                                            confirm: { text: 'Yes, proceed', btnClass: 'btn-success', action: function () {
                                                $.post('<?= PROOT; ?>FinChains/approveAj', payload, function (r) {
                                                    if (r && r.ok) { rsToast(r.msg || 'Done.', 'success'); setTimeout(function(){ location.reload(); }, 600); }
                                                    else { $.alert({title:'Could not approve', content: (r && r.msg) || 'Server error', type:'red'}); }
                                                }, 'json');
                                            }},
                                            cancel: function () {}
                                        }
                                    });
                                });
                            })();
                            </script>
                        </div>
                    <?php } ?>
                <?php endif; ?>
            </div>
        </div>

        <?php $__section2ApprovalStrip = ob_get_clean(); /* Slice 8Z-q · captured — echoed after bonds + FM attachments blocks below. */ ?>

        <!-- ── Slice 8Z-q · Bonds tracker + FM attachments · Vue 3 Options API root ── -->
        <?php
            // Ensure the FM-attach class is loaded so SUBTYPES::const is available in the view.
            if (!class_exists('TenderFmVerificationAttachments')) require_once ROOT . '/app/models/TenderFmVerificationAttachments.php';
            $bonds         = $this->data['contract_bonds']        ?? [];
            $fmAttach      = $this->data['fm_verify_attachments'] ?? [];
            $canBondWrite  = UserGroups::can('Tenders','bondSaveAj');
            $canFmAttWrite = UserGroups::can('Tenders','fmAttachUploadAj');
        ?>
        <div id="ct_fm_root" v-cloak>
            <!-- Bonds & Receipts tracker -->
            <div class="card border-0 shadow-sm mb-3">
                <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                    <div>
                        <strong style="color:#334155;"><i class="fas fa-shield-alt me-2" style="color:#7A8BA1;"></i>Bonds &amp; Receipts tracker</strong>
                        <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">One row per bond / certificate — APG, PG, retention bond, insurance cert, TRA tax clearance. Track PENDING → RECEIVED with validity + supporting doc.</div>
                    </div>
                    <button v-if="canBondWrite" type="button" @click="openBondAdd" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus me-1"></i>Add bond / receipt</button>
                </div>
                <div class="card-body p-0">
                    <div class="table-responsive">
                        <table class="table table-sm mb-0 align-middle">
                            <thead style="background:#F1F5F9;">
                                <tr style="font-size:.68rem;color:#334155;">
                                    <th>Type</th><th>Status</th><th>Reference</th><th>Issuer</th>
                                    <th class="text-end">Amount</th><th>Received</th><th>Valid until</th>
                                    <th style="width:120px;">Doc</th><th style="width:80px;"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-if="!bonds.length"><td colspan="9" class="text-center text-muted py-3" style="font-size:.72rem;color:#94A3B8;">No bonds captured yet. Click "Add bond / receipt" to track the first one.</td></tr>
                                <tr v-for="b in bonds" :key="b.c0d" style="font-size:.78rem;">
                                    <td>
                                        <div style="color:#334155;font-weight:500;">{{ bondTypeLabels[b.bond_type] || b.bond_type }}</div>
                                        <div v-if="b.remarks" class="small" style="color:#64748B;font-size:.66rem;line-height:1.2;">{{ b.remarks }}</div>
                                    </td>
                                    <td><span class="badge" :style="{background: statusColor(b.status), color:'#fff', fontSize:'.62rem', textTransform:'capitalize'}">{{ b.status }}</span></td>
                                    <td style="font-family:monospace;color:#334155;font-size:.72rem;">{{ b.reference_no || '—' }}</td>
                                    <td style="color:#334155;font-size:.74rem;">{{ b.issuer || '—' }}</td>
                                    <td class="text-end" style="color:#334155;font-family:monospace;font-size:.72rem;">
                                        <span v-if="b.amount !== null">{{ fmtAmt(b.amount) }} {{ b.currency }}</span>
                                        <span v-else>—</span>
                                    </td>
                                    <td style="color:#64748B;font-size:.68rem;">{{ b.received_date || '—' }}</td>
                                    <td>
                                        <span style="color:#64748B;font-size:.68rem;">{{ b.validity_until || '—' }}</span>
                                        <div v-if="b.expiry_chip && b.expiry_chip !== 'OK'"><span class="badge" :style="{background: expiryColor(b.expiry_chip), color:'#fff', fontSize:'.58rem'}">{{ b.expiry_chip }}</span></div>
                                    </td>
                                    <td>
                                        <template v-if="b.document_path">
                                            <a :href="PROOT + 'Tenders/bondDocPreview/' + b.c0d" target="_blank" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.15rem;" title="Preview"><i class="fas fa-eye"></i></a>
                                            <a :href="PROOT + 'Tenders/bondDocDownload/' + b.c0d" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.15rem;" title="Download"><i class="fas fa-download"></i></a>
                                        </template>
                                        <span v-else class="small" style="color:#94A3B8;font-size:.66rem;">no doc</span>
                                        <button v-if="canBondWrite" type="button" @click="openBondUpload(b)" class="btn btn-sm" style="background:transparent;border:none;color:#7A9E7E;padding:.15rem;" title="Upload / replace doc"><i class="fas fa-upload"></i></button>
                                    </td>
                                    <td class="text-end">
                                        <template v-if="canBondWrite">
                                            <button type="button" @click="openBondEdit(b)" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.15rem;" title="Edit"><i class="fas fa-pencil-alt"></i></button>
                                            <button type="button" @click="deleteBond(b)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;padding:.15rem;" title="Remove"><i class="fas fa-times"></i></button>
                                        </template>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

            <!-- FM verification attachments -->
            <div class="card border-0 shadow-sm mb-3">
                <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                    <div>
                        <strong style="color:#334155;"><i class="fas fa-folder-open me-2" style="color:#7A8BA1;"></i>FM verification attachments</strong>
                        <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">
                            FM's decision memos. Approve is blocked until the 3 mandatory subtypes are uploaded:
                            <strong>Cover memo · Cash-flow projection · Profitability model</strong>.
                        </div>
                    </div>
                    <div class="d-flex align-items-center gap-2">
                        <span class="badge" :style="{background: mandatoryOk ? '#7A9E7E' : '#D4A574', color:'#fff', fontSize:'.66rem', textTransform:'capitalize'}">{{ mandatoryDone }} / {{ mandatoryTotal }} mandatory</span>
                        <button v-if="canFmAttWrite" type="button" @click="openFmUpload" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-upload me-1"></i>Upload</button>
                    </div>
                </div>
                <div class="card-body p-0">
                    <div v-if="!mandatoryOk" class="p-2" style="background:#FDF7EC;border-bottom:1px solid #F0DEBB;color:#8B6914;font-size:.72rem;">
                        <i class="fas fa-exclamation-triangle me-1" style="color:#D4A574;"></i>
                        Missing before FM can approve: <strong>{{ missingLabels.join(', ') }}</strong>
                    </div>
                    <div class="table-responsive">
                        <table class="table table-sm mb-0 align-middle">
                            <thead style="background:#F1F5F9;">
                                <tr style="font-size:.68rem;color:#334155;">
                                    <th>Subtype</th><th>Label</th><th>File</th><th>Uploaded</th><th style="width:100px;"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-if="!fmAttach.length"><td colspan="5" class="text-center text-muted py-3" style="font-size:.72rem;color:#94A3B8;">Nothing uploaded yet. FM: your Cover memo + Cash-flow + Profitability model unlock Approve.</td></tr>
                                <tr v-for="a in fmAttach" :key="a.c0d" style="font-size:.78rem;">
                                    <td>
                                        <span class="badge" :style="{background: isMandatorySubtype(a.subtype) ? '#EEF2F6' : '#F1F5F9', color:'#334155', border: '1px solid ' + (isMandatorySubtype(a.subtype) ? '#7A8BA1' : '#E2E8F0'), fontSize:'.62rem', textTransform:'capitalize'}">
                                            {{ subtypeLabel(a.subtype) }}
                                            <i v-if="isMandatorySubtype(a.subtype)" class="fas fa-star ms-1" style="color:#D4A574;font-size:.58rem;" title="Mandatory"></i>
                                        </span>
                                    </td>
                                    <td style="color:#334155;font-size:.74rem;">{{ a.label || '—' }}</td>
                                    <td>
                                        <a :href="PROOT + 'Tenders/fmAttachPreview/' + a.c0d" target="_blank" style="color:#7A8BA1;font-size:.72rem;text-decoration:none;"><i class="fas fa-file me-1"></i>{{ a.original_filename }}</a>
                                        <span class="small ms-1" style="color:#94A3B8;font-size:.62rem;">({{ fmtKb(a.size_bytes) }} KB)</span>
                                    </td>
                                    <td style="color:#64748B;font-size:.66rem;">{{ a.uploaded_by_name }}<br><span style="font-size:.62rem;color:#94A3B8;">{{ fmtWhen(a.uploaded_on) }}</span></td>
                                    <td class="text-end">
                                        <a :href="PROOT + 'Tenders/fmAttachDownload/' + a.c0d" class="btn btn-sm" style="background:transparent;border:none;color:#7A8BA1;padding:.15rem;" title="Download"><i class="fas fa-download"></i></a>
                                        <button v-if="canFmAttWrite" type="button" @click="deleteFmAttach(a)" class="btn btn-sm" style="background:transparent;border:none;color:#C48579;padding:.15rem;" title="Remove"><i class="fas fa-times"></i></button>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <!-- ── Slice 8Z-s · Executive → PM Kickoff Brief ─────────────── -->
        <?php
            if (!class_exists('TenderExecKickoffBrief')) require_once ROOT . '/app/models/TenderExecKickoffBrief.php';
            $kb              = $this->data['kickoff_brief']            ?? [];
            $kbCeiling       = $this->data['kickoff_budget_ceiling']   ?? null;
            $kbEditableSecs  = $this->data['kickoff_editable_sections'] ?? [];
            $canEditFmHalf   = in_array('fm_gates',   $kbEditableSecs, true) || in_array('fm_risks', $kbEditableSecs, true);
            $canEditExecHalf = in_array('kickoff',    $kbEditableSecs, true);

            $kbVal = function ($k, $default = '') use ($kb) { return htmlspecialchars((string)($kb[$k] ?? $default)); };
            $kbNum = function ($k) use ($kb) { $v = $kb[$k] ?? ''; return ($v === '' || $v === null) ? '' : htmlspecialchars((string)$v); };
            $kbSel = function ($k, $val) use ($kb) { return ((string)($kb[$k] ?? '') === $val) ? ' selected' : ''; };
            $kbChk = function ($k) use ($kb) { return !empty($kb[$k]) ? ' checked' : ''; };

            $renderChip = function ($label, $checked) {
                $bg = $checked ? '#7A9E7E' : '#F1F5F9';
                $fg = $checked ? '#fff' : '#94A3B8';
                $ico = $checked ? 'fas fa-check' : 'far fa-circle';
                return '<span class="badge me-1 mb-1" style="background:' . $bg . ';color:' . $fg . ';font-size:.66rem;font-weight:500;text-transform:capitalize;border:1px solid #E2E8F0;"><i class="' . $ico . ' me-1"></i>' . htmlspecialchars($label) . '</span>';
            };
        ?>
        <div class="card border-0 shadow-sm mb-3" style="border-left:3px solid #7A9E7E !important;">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                <div>
                    <strong style="color:#334155;"><i class="fas fa-flag-checkered me-2" style="color:#7A9E7E;"></i>Executive → PM kickoff brief</strong>
                    <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">FM captures the financial gates + risks. Executive captures the mandate, guardrails, operational gates, strategic risks and reporting cadence. Everything below travels to the PM on project auto-provisioning.</div>
                </div>
                <?php if (!empty($kb['fm_edited_on']) || !empty($kb['exec_edited_on'])): ?>
                    <div class="text-muted small text-end" style="font-size:.66rem;color:#94A3B8;">
                        <?php if (!empty($kb['fm_edited_on'])): ?>
                            <div>FM: <?= htmlspecialchars((string)($kb['fm_edited_by_name'] ?? '')); ?> · <?= htmlspecialchars(date('d M · H:i', strtotime((string)$kb['fm_edited_on']))); ?></div>
                        <?php endif; ?>
                        <?php if (!empty($kb['exec_edited_on'])): ?>
                            <div>Exec: <?= htmlspecialchars((string)($kb['exec_edited_by_name'] ?? '')); ?> · <?= htmlspecialchars(date('d M · H:i', strtotime((string)$kb['exec_edited_on']))); ?></div>
                        <?php endif; ?>
                    </div>
                <?php endif; ?>
            </div>

            <div class="card-body p-3">
                <div class="row g-3">
                    <!-- ── LEFT · FM half (Financial gates + risks) ────────── -->
                    <div class="col-md-6">
                        <div class="kb-half-card d-flex flex-column" style="background:#F8FAFC;border:1px solid #E2E8F0;border-radius:4px;padding:.75rem;height:100%;">
                            <div class="mb-2">
                                <strong style="color:#334155;font-size:.82rem;"><i class="fas fa-university me-1" style="color:#7A8BA1;"></i>Finance Manager — financial gates &amp; risks</strong>
                            </div>
                            <fieldset <?= $canEditFmHalf ? '' : 'disabled'; ?> id="kb_fm_form" class="flex-grow-1">
                                <div class="mb-2">
                                    <div class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;margin-bottom:.15rem;">Pre-mobilization financial gates</div>
                                    <?php foreach (['gate_insurance_activated','gate_advance_requested','gate_tra_efiscal_setup','gate_wcf_nssf_verified'] as $fld):
                                        $lbl = TenderExecKickoffBrief::LABELS[$fld] ?? $fld;
                                    ?>
                                        <label class="d-block" style="font-size:.76rem;color:#334155;">
                                            <input type="checkbox" class="form-check-input me-1" name="<?= $fld; ?>" value="1"<?= $kbChk($fld); ?>>
                                            <?= htmlspecialchars($lbl); ?>
                                        </label>
                                    <?php endforeach; ?>
                                </div>
                                <div class="mb-1">
                                    <div class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;margin-bottom:.15rem;">Financial risk flags</div>
                                    <?php foreach (['risk_client_payment','risk_fx_exposure','risk_wcf_nssf_compliance'] as $fld):
                                        $lbl = TenderExecKickoffBrief::LABELS[$fld] ?? $fld;
                                    ?>
                                        <label class="d-block" style="font-size:.76rem;color:#334155;">
                                            <input type="checkbox" class="form-check-input me-1" name="<?= $fld; ?>" value="1"<?= $kbChk($fld); ?>>
                                            <?= htmlspecialchars($lbl); ?>
                                        </label>
                                    <?php endforeach; ?>
                                </div>
                            </fieldset>
                            <?php if ($canEditFmHalf): ?>
                                <div class="text-end mt-2 pt-2" style="border-top:1px solid #E2E8F0;">
                                    <button type="button" id="btn_kb_save_fm" class="btn btn-sm" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save FM half</button>
                                </div>
                            <?php else: ?>
                                <div class="small mt-1" style="color:#94A3B8;font-size:.66rem;text-transform:capitalize;">Read-only · Finance Manager edits this half</div>
                            <?php endif; ?>
                        </div>
                    </div>

                    <!-- ── RIGHT · Exec half (Kickoff + guardrails + ops gates + risks + reporting) ── -->
                    <div class="col-md-6">
                        <div class="kb-half-card d-flex flex-column" style="background:#F8FAFC;border:1px solid #E2E8F0;border-radius:4px;padding:.75rem;height:100%;">
                            <div class="mb-2">
                                <strong style="color:#334155;font-size:.82rem;"><i class="fas fa-user-tie me-1" style="color:#7A9E7E;"></i>Executive — mandate to PM</strong>
                            </div>
                            <fieldset <?= $canEditExecHalf ? '' : 'disabled'; ?> id="kb_exec_form" class="flex-grow-1">
                                <!-- A · Kickoff essentials -->
                                <div class="row g-2 mb-2">
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Priority</label>
                                        <select name="priority" class="form-select form-select-sm">
                                            <option value="LOW"<?= $kbSel('priority','LOW'); ?>>Low</option>
                                            <option value="NORMAL"<?= $kbSel('priority','NORMAL'); ?>>Normal</option>
                                            <option value="HIGH"<?= $kbSel('priority','HIGH'); ?>>High</option>
                                        </select>
                                    </div>
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Target kickoff</label>
                                        <input type="date" name="target_kickoff_date" value="<?= $kbVal('target_kickoff_date'); ?>" class="form-control form-control-sm">
                                    </div>
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Reporting cadence</label>
                                        <select name="reporting_cadence" class="form-select form-select-sm">
                                            <option value="">—</option>
                                            <option value="WEEKLY"<?= $kbSel('reporting_cadence','WEEKLY'); ?>>Weekly</option>
                                            <option value="BIWEEKLY"<?= $kbSel('reporting_cadence','BIWEEKLY'); ?>>Bi-weekly</option>
                                            <option value="MONTHLY"<?= $kbSel('reporting_cadence','MONTHLY'); ?>>Monthly</option>
                                            <option value="ADHOC"<?= $kbSel('reporting_cadence','ADHOC'); ?>>Adhoc</option>
                                        </select>
                                    </div>
                                </div>

                                <!-- B · Guardrails -->
                                <div class="row g-2 mb-2">
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Margin floor %</label>
                                        <input type="number" step="0.01" min="0" max="100" name="margin_floor_pct" value="<?= $kbNum('margin_floor_pct'); ?>" class="form-control form-control-sm">
                                    </div>
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Budget ceiling (auto)</label>
                                        <input type="text" id="kb_budget_ceiling" readonly value="<?= $kbCeiling !== null ? number_format((float)$kbCeiling) : '—'; ?>" class="form-control form-control-sm" style="background:#F1F5F9;color:#334155;">
                                    </div>
                                    <div class="col-4">
                                        <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Change-order threshold %</label>
                                        <input type="number" step="0.01" min="0" max="100" name="change_order_threshold_pct" value="<?= $kbNum('change_order_threshold_pct'); ?>" placeholder="e.g. 5" class="form-control form-control-sm">
                                    </div>
                                </div>

                                <!-- C-Exec · Operational gates -->
                                <div class="mb-2">
                                    <div class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;margin-bottom:.15rem;">Pre-mobilization operational gates</div>
                                    <?php foreach (['gate_site_visit','gate_mobilization','gate_long_lead','gate_permits','gate_osha_safety_plan'] as $fld):
                                        $lbl = TenderExecKickoffBrief::LABELS[$fld] ?? $fld;
                                    ?>
                                        <label class="d-inline-block me-2" style="font-size:.76rem;color:#334155;">
                                            <input type="checkbox" class="form-check-input me-1" name="<?= $fld; ?>" value="1"<?= $kbChk($fld); ?>>
                                            <?= htmlspecialchars($lbl); ?>
                                        </label>
                                    <?php endforeach; ?>
                                </div>

                                <!-- D-Exec · Strategic risks -->
                                <div class="mb-2">
                                    <div class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;margin-bottom:.15rem;">Strategic / operational risk flags</div>
                                    <?php foreach (['risk_tight_schedule','risk_site_access','risk_scope_ambiguity','risk_ppra_reporting'] as $fld):
                                        $lbl = TenderExecKickoffBrief::LABELS[$fld] ?? $fld;
                                    ?>
                                        <label class="d-inline-block me-2" style="font-size:.76rem;color:#334155;">
                                            <input type="checkbox" class="form-check-input me-1" name="<?= $fld; ?>" value="1"<?= $kbChk($fld); ?>>
                                            <?= htmlspecialchars($lbl); ?>
                                        </label>
                                    <?php endforeach; ?>
                                </div>

                                <!-- E · Escalation contact -->
                                <div class="mb-2">
                                    <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Escalation contact (name)</label>
                                    <input type="text" name="escalation_contact_name" value="<?= $kbVal('escalation_contact_name'); ?>" placeholder="e.g. MD · CFO" class="form-control form-control-sm">
                                </div>

                                <!-- A · Instructions -->
                                <div>
                                    <label class="ts-lbl" style="color:#64748B;font-size:.66rem;text-transform:capitalize;">Instructions to PM</label>
                                    <textarea name="instructions_to_pm" rows="3" placeholder="Specific directions for kickoff — what to prioritise, who to call, what to watch." class="form-control form-control-sm"><?= $kbVal('instructions_to_pm'); ?></textarea>
                                </div>
                            </fieldset>
                            <?php if ($canEditExecHalf): ?>
                                <div class="text-end mt-2 pt-2" style="border-top:1px solid #E2E8F0;">
                                    <button type="button" id="btn_kb_save_exec" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i>Save Exec half</button>
                                </div>
                            <?php else: ?>
                                <div class="small mt-1" style="color:#94A3B8;font-size:.66rem;text-transform:capitalize;">Read-only · Executive edits this half</div>
                            <?php endif; ?>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <?php /* Slice 8Z-q · now emit the buffered Section 2 approval strip AFTER FM has seen bonds + attachments. */ echo $__section2ApprovalStrip ?? ''; ?>

        <!-- ── Section 3 · Signing event ─────────────────────────────── -->
        <div class="card border-0 shadow-sm mb-3">
            <div class="card-header bg-white" style="border-bottom:1px solid #E2E8F0;">
                <strong style="color:#334155;"><i class="fas fa-signature me-2" style="color:#7A8BA1;"></i>Signing event</strong>
                <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">
                    Unlocks after the Executive approves the contract terms. Recording the signing auto-advances Contract signing → Execution.
                </div>
            </div>
            <div class="card-body p-3" style="background:#F8FAFC;">
                <?php if (!$canRecordSigning && !$signing): ?>
                    <div class="text-muted small" style="color:#94A3B8;font-size:.82rem;">
                        <i class="fas fa-lock me-1"></i>Locked. Waiting for Executive approval of contract terms.
                    </div>
                <?php else: ?>
                    <div class="row g-2">
                        <div class="col-md-3"><label class="form-label" style="color:#334155;font-size:.78rem;">Signed date *</label>
                            <input type="date" id="sg_date" value="<?= htmlspecialchars((string)($signing['signed_date'] ?? date('Y-m-d'))); ?>" class="form-control form-control-sm" <?= $canRecordSigning ? '' : 'disabled'; ?>></div>
                        <div class="col-md-9"><label class="form-label" style="color:#334155;font-size:.78rem;">Venue</label>
                            <input type="text" id="sg_venue" value="<?= htmlspecialchars((string)($signing['signed_venue'] ?? '')); ?>" placeholder="e.g. Ministry of Health · Dodoma · Conference Room B" class="form-control form-control-sm" <?= $canRecordSigning ? '' : 'disabled'; ?>></div>
                        <div class="col-md-6"><label class="form-label" style="color:#334155;font-size:.78rem;">Our signatories</label>
                            <input type="text" id="sg_us" value="<?= htmlspecialchars((string)($signing['our_signatories'] ?? '')); ?>" placeholder="MD, FM, Legal" class="form-control form-control-sm" <?= $canRecordSigning ? '' : 'disabled'; ?>></div>
                        <div class="col-md-6"><label class="form-label" style="color:#334155;font-size:.78rem;">Their signatories</label>
                            <input type="text" id="sg_them" value="<?= htmlspecialchars((string)($signing['their_signatories'] ?? '')); ?>" placeholder="Accounting Officer, DPS" class="form-control form-control-sm" <?= $canRecordSigning ? '' : 'disabled'; ?>></div>
                        <div class="col-12"><label class="form-label" style="color:#334155;font-size:.78rem;">Notes</label>
                            <textarea id="sg_notes" rows="2" class="form-control form-control-sm" placeholder="Witnesses, exchanged copies, chain of custody…" <?= $canRecordSigning ? '' : 'disabled'; ?>><?= htmlspecialchars((string)($signing['notes'] ?? '')); ?></textarea></div>
                    </div>
                    <?php if ($canRecordSigning): ?>
                    <div class="text-end mt-2">
                        <button type="button" id="btn_save_signing" class="btn btn-sm" style="background:#7A9E7E;border-color:#7A9E7E;color:#fff;font-weight:600;"><i class="fas fa-save me-1"></i><?= $signing ? 'Update signing' : 'Record signing → advance to Execution'; ?></button>
                    </div>
                    <?php endif; ?>
                <?php endif; ?>
            </div>
        </div>

        <!-- ── Section 4 · Payment receipts ─────────────────────────── -->
        <div class="card border-0 shadow-sm">
            <div class="card-header bg-white d-flex align-items-center justify-content-between" style="border-bottom:1px solid #E2E8F0;">
                <div>
                    <strong style="color:#334155;"><i class="fas fa-hand-holding-usd me-2" style="color:#7A8BA1;"></i>Contract receipts</strong>
                    <div class="text-muted small mt-1" style="color:#64748B;font-size:.72rem;">Log advance, milestone, retention and final tranches received from the buyer.</div>
                </div>
                <div class="text-end" style="font-size:.82rem;">
                    <span style="color:#64748B;">Received:</span> <strong style="color:#334155;">TZS <?= number_format($totalReceived); ?></strong>
                    <?php if ($contractValue > 0): ?>
                        <span style="color:#94A3B8;font-size:.72rem;"> · remaining TZS <?= number_format($remaining); ?></span>
                    <?php endif; ?>
                </div>
            </div>

            <?php if ($canAddReceipt): ?>
            <div class="card-body p-2" style="background:#F8FAFC;border-bottom:1px solid #E2E8F0;">
                <div class="row g-2 align-items-end">
                    <div class="col-md-2"><input type="text"   id="rc_no"     class="form-control form-control-sm" placeholder="Receipt no"></div>
                    <div class="col-md-2"><input type="date"   id="rc_date"   value="<?= date('Y-m-d'); ?>" class="form-control form-control-sm"></div>
                    <div class="col-md-2"><input type="number" step="0.01" id="rc_amt" class="form-control form-control-sm" placeholder="Amount (TZS)"></div>
                    <div class="col-md-2"><select id="rc_type" class="form-select form-select-sm">
                        <?php foreach (['ADVANCE'=>'Advance','MILESTONE'=>'Milestone','RETENTION'=>'Retention','FINAL'=>'Final','OTHER'=>'Other'] as $k=>$lbl): ?>
                            <option value="<?= $k; ?>"><?= $lbl; ?></option>
                        <?php endforeach; ?>
                    </select></div>
                    <div class="col-md-3"><input type="text" id="rc_ref" class="form-control form-control-sm" placeholder="Cheque / bank ref"></div>
                    <div class="col-md-1"><button type="button" id="btn_add_receipt" class="btn btn-sm w-100" style="background:#7A8BA1;border-color:#7A8BA1;color:#fff;font-weight:600;"><i class="fas fa-plus"></i></button></div>
                </div>
            </div>
            <?php endif; ?>

            <div class="table-responsive">
                <table class="table table-sm mb-0 align-middle">
                    <thead style="background:#F1F5F9;">
                        <tr>
                            <th style="color:#334155;">Date</th>
                            <th style="color:#334155;">Receipt #</th>
                            <th style="color:#334155;">Type</th>
                            <th class="text-end" style="color:#334155;">Amount</th>
                            <th style="color:#334155;">Ref</th>
                            <th style="color:#334155;">By</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($receipts as $r): ?>
                            <tr>
                                <td class="text-muted small" style="color:#334155;"><?= htmlspecialchars((string)$r['receipt_date']); ?></td>
                                <td style="color:#334155;font-weight:500;"><?= htmlspecialchars((string)$r['receipt_no']) ?: '—'; ?></td>
                                <td><span class="badge" style="background:#E2E8F0;color:#334155;font-size:.62rem;text-transform:capitalize;"><?= htmlspecialchars(strtolower((string)$r['receipt_type'])); ?></span></td>
                                <td class="text-end" style="color:#334155;font-weight:500;"><?= number_format((float)$r['amount']); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$r['reference']); ?></td>
                                <td class="text-muted small" style="color:#64748B;"><?= htmlspecialchars((string)$r['created_by_name']); ?></td>
                                <td class="text-end">
                                    <?php if (UserGroups::can('Tenders','deleteContractReceiptAj')): ?>
                                        <button type="button" class="btn btn-sm btn-del-receipt" data-rid="<?= (int)$r['c0d']; ?>" title="Delete receipt" style="background:transparent;border:none;color:#C48579;padding:.2rem .4rem;"><i class="fas fa-times"></i></button>
                                    <?php endif; ?>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                        <?php if (empty($receipts)): ?><tr><td colspan="7" class="text-center py-3" style="color:#94A3B8;">No receipts logged.</td></tr><?php endif; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <?php endif; ?>
    </div>

    <!-- EXECUTION ── linked project -->
    <div class="tab-pane fade" id="tab-execution">
        <div class="card border-0 shadow-sm" style="background:#F8FAFC;">
            <div class="card-body p-4">
                <div class="d-flex align-items-center mb-2">
                    <i class="fas fa-play-circle me-2" style="color:#7A8BA1;font-size:1.1rem;"></i>
                    <strong style="color:#334155;font-size:.95rem;">Execution · project handoff</strong>
                </div>
                <?php if (!empty($t['linked_project_id'])): ?>
                    <div class="mt-3 p-3" style="background:#DCFCE7;border:1px solid #86EFAC;border-radius:3px;color:#166534;">
                        <i class="fas fa-check-circle me-1"></i>
                        <strong>Project <?= htmlspecialchars((string)$t['project_no']); ?></strong> was created from this tender.
                        <?php if (!empty($t['crm_status'])): ?>CRM status: <strong><?= htmlspecialchars((string)$t['crm_status']); ?></strong>.<?php endif; ?>
                        <div class="mt-2">
                            <a href="<?= PROOT; ?>Projects" class="btn btn-sm" style="background:#166534;border-color:#166534;color:#fff;font-weight:600;"><i class="fas fa-project-diagram me-1"></i>Open project</a>
                            <?php if (($t['crm_status'] ?? '') === 'PENDING'): ?>
                                <a href="<?= PROOT; ?>Onboarding" class="btn btn-sm ms-2" style="background:#F8FAFC;border:1px solid #E2E8F0;color:#334155;"><i class="fas fa-clipboard-check me-1"></i>Onboarding queue</a>
                            <?php endif; ?>
                        </div>
                    </div>
                <?php else: ?>
                    <div class="text-muted small" style="color:#64748B;">
                        No project linked yet. Projects auto-provision the moment the Executive approves the contract terms on the <a href="#tab-contract" data-bs-toggle="tab" style="color:#7A8BA1;">Contract signing</a> tab — no manual step required.
                    </div>
                    <div class="mt-3 p-2" style="background:#fff;border:1px dashed #E2E8F0;border-radius:3px;color:#94A3B8;font-size:.78rem;">
                        <i class="fas fa-info-circle me-1"></i>Sequence: Awarded → Won → FM captures financial terms → Exec approves → project auto-created (with <code>crm_status = PENDING</code>) → Onboarding chain gates Ops.
                    </div>
                <?php endif; ?>
            </div>
        </div>
    </div>
</div>

<?php $this->end(); ?>

<?php $this->start('section_js'); ?>
<script>
$(function () {
    var PROOT = '<?= PROOT; ?>';
    var TID   = <?= (int)$t['c0d']; ?>;

    $('#btn_advance').on('click', function () {
        var s = $('#new_stage').val();
        $.confirm({
            title: 'Advance to ' + s.replace('_', ' ') + '?',
            content: 'Stage moves are one-way — you cannot revert.',
            type: 'orange',
            buttons: {
                yes: { text: 'Advance', btnClass: 'btn-warning', action: function () {
                    $.post(PROOT + 'Tenders/advanceStageAj', { tender_id: TID, stage: s, notes: $('#stage_notes').val() }, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast('Stage advanced. Reloading…', 'success'); setTimeout(function () { location.reload(); }, 400); }
                            else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    $('#btn_add_bidder').on('click', function () {
        var name = $('#b_name').val().trim();
        if (!name) { rsToast('Bidder name required.', 'warning'); return; }
        $.post(PROOT + 'Tenders/addBidderAj', {
            tender_id: TID, bidder_name: name, is_us: $('#b_us').is(':checked') ? 1 : 0,
            bid_amount: $('#b_amount').val() || 0, ranking: $('#b_rank').val() || '',
            notes: $('#b_notes').val()
        }, 'json').done(function (res) {
            if (res && res.ok) { rsToast('Bidder added.', 'success'); setTimeout(function () { location.reload(); }, 400); }
            else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
        });
    });

    // Awarded-tab result form + auto-populate + save all moved into Vue 3 root at end of file (Slice 8W).

    // ── Requirements tab ────────────────────────────────────────────
    function updateReqCounters() {
        var totalSel = 0, totalStat = 0;
        var perCat = {};
        $('.chk-req').each(function () {
            var cat = $(this).data('cat');
            perCat[cat] = perCat[cat] || {sel: 0, tot: 0, stat: 0};
            perCat[cat].tot++;
            if (this.checked) { totalSel++; perCat[cat].sel++; if ($(this).data('statutory') == 1) { totalStat++; perCat[cat].stat++; } }
        });
        $('#req_summary').text(totalSel + ' selected · ' + totalStat + ' statutory');
        $('.req-cat-count').each(function () {
            var c = $(this).data('cat');
            if (!perCat[c]) return;
            var extra = perCat[c].stat > 0 ? ' · ' + perCat[c].stat + ' statutory' : '';
            $(this).text(perCat[c].sel + ' / ' + perCat[c].tot + ' selected' + extra);
        });
        // Row background reflects selection
        $('.chk-req').each(function () {
            $(this).closest('label').css('background', this.checked ? '#F1F5F9' : '#fff');
        });
    }
    $('#tab-prep').on('change', '.chk-req', updateReqCounters);

    $('#req_search').on('input', function () {
        var q = $(this).val().trim().toLowerCase();
        $('.req-item').each(function () {
            $(this).toggle(!q || (String($(this).data('label')).indexOf(q) !== -1));
        });
    });

    $('#btn_stat_defaults').on('click', function () {
        $.post(PROOT + 'Tenders/applyStatutoryDefaultsAj', { tender_id: TID }, 'json')
            .done(function (res) {
                if (res && res.ok) {
                    // Tick every statutory checkbox that isn't already checked
                    $('.chk-req[data-statutory="1"]').prop('checked', true);
                    updateReqCounters();
                    rsToast('Statutory defaults applied (' + res.added + ' persisted).', 'success');
                } else { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
            });
    });

    $('#btn_clear_reqs').on('click', function () {
        $.confirm({
            title: 'Clear all requirements?',
            content: 'Every tick on this tender will be removed.',
            type: 'orange',
            buttons: {
                yes: { text: 'Clear all', btnClass: 'btn-warning', action: function () {
                    $.post(PROOT + 'Tenders/clearRequirementsAj', { tender_id: TID }, 'json')
                        .done(function (res) {
                            if (res && res.ok) {
                                $('.chk-req').prop('checked', false);
                                updateReqCounters();
                                rsToast('Cleared.', 'success');
                            } else { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    $('#btn_save_reqs').on('click', function () {
        var ids = $('.chk-req:checked').map(function () { return this.value; }).get();
        $.post(PROOT + 'Tenders/setRequirementsAj', { tender_id: TID, doc_type_ids: ids }, 'json')
            .done(function (res) {
                if (res && res.ok) { rsToast('Saved ' + res.saved + ' requirement(s).', 'success'); }
                else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
            });
    });

    // ── Submission tab ──────────────────────────────────────────────
    function envToggle() {
        var isPhys = $('#sub_method').val() === 'PHYSICAL';
        $('#envelope_wrap').toggle(isPhys);
    }
    $('#sub_method').on('change', envToggle);

    $('#btn_save_sub').on('click', function () {
        var payload = {
            tender_id:                  TID,
            submission_amount:          $('#sub_amount').val() || 0,
            submission_method:          $('#sub_method').val(),
            submission_date:            $('#sub_date').val(),
            submission_time:            $('#sub_time').val(),
            submission_validity_days:   $('#sub_validity').val(),
            submission_follow_up_date:  $('#sub_follow').val(),
            submission_remarks:         $('#sub_remarks').val(),
            submission_envelope_scheme: $('#env_scheme').val(),
            submission_copies_original: $('#env_orig').val(),
            submission_copies_duplicate:$('#env_dup').val(),
            submission_sealing_method:  $('#env_seal').val(),
            bid_price_source:           $('#sub_price_src').val(),
            bid_price_source_note:      $('#sub_price_note').val(),
            manual_cost:                $('#manual_cost').val()       || 0,
            manual_margin_pct:          $('#manual_margin_pct').val() || 0,
        };
        var $btn = $('#btn_save_sub').prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-1"></i>Saving…');
        $.post(PROOT + 'Tenders/saveSubmissionAj', payload, 'json')
            .done(function (res) {
                if (res && res.ok) { rsToast('Submission saved. Reloading…', 'success'); setTimeout(function () { location.reload(); }, 500); }
                else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error', 5000);
                                      $btn.prop('disabled', false).html('<i class="fas fa-save me-1"></i>Save submission'); }
            })
            .fail(function () { rsToast('Server unreachable.', 'error');
                                 $btn.prop('disabled', false).html('<i class="fas fa-save me-1"></i>Save submission'); });
    });

    // ── Slice 8P · Edit Details modal (CRM / Admin / Exec) ─────────
    $('#btn_edit_details').on('click', function () {
        var td = <?= json_encode([
            'source_type'       => (string)($t['source_type']       ?? 'PRIVATE_CLIENT'),
            'source_ref'        => (string)($t['source_ref']        ?? ''),
            'source_url'        => (string)($t['source_url']        ?? ''),
            'tender_title'      => (string)($t['tender_title']      ?? ''),
            'tender_industry'   => (string)($t['tender_industry']   ?? ''),
            'region'            => (string)($t['region']            ?? ''),
            'district'          => (string)($t['district']          ?? ''),
            'tender_description'=> (string)($t['tender_description']?? ''),
            'submission_method' => (string)($t['submission_method'] ?? ''),
        ], JSON_UNESCAPED_SLASHES); ?>;
        function esc(v) { return $('<div>').text(v || '').html(); }
        var opts = ['NEST_PUBLIC','PRIVATE_CLIENT','INVITATION','REFERRAL','WALK_IN'];
        var srcOpts = opts.map(function (o) {
            return '<option value="' + o + '"' + (td.source_type === o ? ' selected' : '') + '>' + o + '</option>';
        }).join('');
        var html = '' +
            '<div class="row g-2" style="font-size:.82rem;">' +
                '<div class="col-md-8"><label class="form-label" style="color:#334155;font-size:.72rem;">Title</label><input type="text" id="ed_title" value="' + esc(td.tender_title) + '" class="form-control form-control-sm"></div>' +
                '<div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Industry</label><input type="text" id="ed_industry" value="' + esc(td.tender_industry) + '" class="form-control form-control-sm" placeholder="e.g. Telecom"></div>' +
                '<div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Source</label><select id="ed_source" class="form-select form-select-sm">' + srcOpts + '</select></div>' +
                '<div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Source ref</label><input type="text" id="ed_source_ref" value="' + esc(td.source_ref) + '" class="form-control form-control-sm"></div>' +
                '<div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Source URL</label><input type="text" id="ed_source_url" value="' + esc(td.source_url) + '" class="form-control form-control-sm"></div>' +
                '<div class="col-md-3"><label class="form-label" style="color:#334155;font-size:.72rem;">Region</label><input type="text" id="ed_region" value="' + esc(td.region) + '" class="form-control form-control-sm"></div>' +
                '<div class="col-md-3"><label class="form-label" style="color:#334155;font-size:.72rem;">District</label><input type="text" id="ed_district" value="' + esc(td.district) + '" class="form-control form-control-sm"></div>' +
                '<div class="col-md-6"><label class="form-label" style="color:#334155;font-size:.72rem;">Submission method</label><input type="text" id="ed_sub_method" value="' + esc(td.submission_method) + '" class="form-control form-control-sm" placeholder="e.g. Hand-delivered, sealed envelope"></div>' +
                '<div class="col-12"><label class="form-label" style="color:#334155;font-size:.72rem;">Description</label><textarea id="ed_desc" class="form-control form-control-sm" rows="4">' + esc(td.tender_description) + '</textarea></div>' +
                '<div class="col-12 small" style="color:#94A3B8;font-size:.68rem;"><i class="fas fa-lock me-1"></i>Type, tender number, buyer name, and customer are locked (set at intake).</div>' +
            '</div>';
        $.confirm({
            title: 'Edit tender details', content: html, columnClass: 'col-md-8', type: 'blue',
            buttons: {
                yes: { text: 'Save details', btnClass: 'btn-primary', action: function () {
                    var payload = {
                        tender_id:          TID,
                        tender_title:       $('#ed_title').val(),
                        tender_industry:    $('#ed_industry').val(),
                        source_type:        $('#ed_source').val(),
                        source_ref:         $('#ed_source_ref').val(),
                        source_url:         $('#ed_source_url').val(),
                        region:             $('#ed_region').val(),
                        district:           $('#ed_district').val(),
                        submission_method:  $('#ed_sub_method').val(),
                        tender_description: $('#ed_desc').val(),
                    };
                    $.post(PROOT + 'Tenders/saveDetailsAj', payload, null, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast('Details saved. Reloading…', 'success'); setTimeout(function () { location.reload(); }, 400); }
                            else rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    // ── Slice 8O + 8S · Bid amount panels: MANUAL (cost+margin) or PRICING_TAB (version sum_price) ─────
    // #sub_amount is a hidden input that carries the actual number to the POST payload;
    // #manual_bid_preview / #pricing_bid_preview are read-only display fields inside each panel.
    var PV_SUM_PRICE = parseFloat($('#bid_source_panel').data('pv-sum-price')) || 0;
    function fmtMoney(n) {
        var f = parseFloat(n); if (!isFinite(f)) f = 0;
        return f.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    }
    function applyManualBidVisibility() {
        var src = $('#sub_price_src').val() || 'MANUAL';
        var isManual  = (src === 'MANUAL');
        var isPricing = (src === 'PRICING_TAB');
        $('#manual_cost_panel').toggle(isManual);
        $('#pricing_tab_panel').toggle(isPricing);
        if (isManual)  recomputeManualBid();
        if (isPricing) syncPricingBid();
    }
    function recomputeManualBid() {
        var cost = parseFloat($('#manual_cost').val()) || 0;
        var mp   = parseFloat($('#manual_margin_pct').val()) || 0;
        var bid  = Math.round(cost * (1 + mp / 100) * 100) / 100;
        $('#manual_bid_preview').val(fmtMoney(bid));
        if (cost > 0) $('#sub_amount').val(bid.toFixed(2));
    }
    function syncPricingBid() {
        // Refresh from the initial-render server value; the "Resync" button re-fetches via ajax if we want.
        $('#pricing_bid_preview').val(fmtMoney(PV_SUM_PRICE));
        if (PV_SUM_PRICE > 0) $('#sub_amount').val(PV_SUM_PRICE.toFixed(2));
    }
    $('#sub_price_src').on('change', applyManualBidVisibility);
    $('#manual_cost, #manual_margin_pct').on('input', recomputeManualBid);
    $('#btn_pricing_sync').on('click', function () {
        // Re-fetch the latest sum_price from the server in case the user just changed the pricing tab.
        $.getJSON(PROOT + 'Tenders/pricingSnapshotAj', { tender_id: TID }, function () {})
            .always(function () {
                // pricingSnapshotAj takes version_id — but we don't have it here without a tender-current lookup.
                // Cheap path: just re-emit the initial value and toast that Pricing tab is the source of truth.
                syncPricingBid();
                if (window.rsToast) rsToast('Bid re-synced from pricing version (' + fmtMoney(PV_SUM_PRICE) + '). Save to persist.', 'success');
            });
    });
    applyManualBidVisibility();

    // ── Slice 8T · Proof-of-submission attachments ────────────────
    $('#btn_add_proof').on('click', function () {
        var kinds = {
            RECEIPT: 'Physical receipt',
            COURIER_WAYBILL: 'Courier waybill',
            PORTAL_SCREENSHOT: 'Portal screenshot',
            SEALED_ENVELOPE_PHOTO: 'Sealed envelope photo',
            ACKNOWLEDGMENT_EMAIL: 'Acknowledgment email',
            OTHER: 'Other',
        };
        var opts = Object.keys(kinds).map(function (k) { return '<option value="' + k + '">' + kinds[k] + '</option>'; }).join('');
        var html =
            '<form id="proof_form" enctype="multipart/form-data" class="row g-2" style="font-size:.82rem;">' +
                '<div class="col-md-4"><label class="form-label" style="color:#334155;font-size:.72rem;">Kind</label>' +
                    '<select id="proof_kind" class="form-select form-select-sm">' + opts + '</select></div>' +
                '<div class="col-md-8"><label class="form-label" style="color:#334155;font-size:.72rem;">Label</label>' +
                    '<input type="text" id="proof_label" class="form-control form-control-sm" placeholder="e.g. DHL waybill 1234567890"></div>' +
                '<div class="col-12"><label class="form-label" style="color:#334155;font-size:.72rem;">File</label>' +
                    '<input type="file" id="proof_file" name="proof_file" class="form-control form-control-sm" accept=".pdf,.jpg,.jpeg,.png,.webp,.heic,.gif,.doc,.docx,.xls,.xlsx,.zip,.txt">' +
                    '<div class="small mt-1" style="color:#94A3B8;font-size:.68rem;">PDF · image · DOC/DOCX · XLS/XLSX · ZIP. Max 10 MB.</div></div>' +
                '<div class="col-12"><label class="form-label" style="color:#334155;font-size:.72rem;">Notes (optional)</label>' +
                    '<input type="text" id="proof_notes" class="form-control form-control-sm" placeholder="Any context — witness name, chain of custody, deadline compliance, etc."></div>' +
            '</form>';
        $.confirm({
            title: 'Add proof of submission', content: html, columnClass: 'col-md-8', type: 'green',
            buttons: {
                yes: { text: 'Upload', btnClass: 'btn-success', action: function () {
                    var $file = $('#proof_file')[0];
                    if (!$file || !$file.files || !$file.files[0]) { rsToast('Choose a file first.', 'warning'); return false; }
                    var fd = new FormData();
                    fd.append('tender_id', TID);
                    fd.append('kind',      $('#proof_kind').val());
                    fd.append('label',     $('#proof_label').val());
                    fd.append('notes',     $('#proof_notes').val());
                    fd.append('proof_file', $file.files[0]);
                    var self = this; self.setContent('<div class="p-3 text-center small"><i class="fas fa-spinner fa-spin me-1"></i>Uploading…</div>');
                    $.ajax({
                        url: PROOT + 'Tenders/submissionAttachmentUploadAj',
                        method: 'POST', data: fd, contentType: false, processData: false, dataType: 'json',
                    }).done(function (res) {
                        if (res && res.ok) { rsToast('Uploaded. Reloading…', 'success'); setTimeout(function () { location.reload(); }, 500); }
                        else { rsToast('Upload failed: ' + (res && res.msg || 'unknown'), 'error', 6000); self.setContent(html); }
                    }).fail(function () { rsToast('Network error during upload.', 'error'); self.setContent(html); });
                    return false;
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });
    // Slice 8U · preview PDF / image submission attachments in jquery-confirm iframe modal.
    $('#proof_table').on('click', '.btn-preview-proof', function () {
        var aid   = parseInt($(this).data('att-id'), 10);
        var label = String($(this).data('att-label') || 'Attachment');
        var mime  = String($(this).data('att-mime')  || '');
        var url   = PROOT + 'Tenders/submissionAttachmentPreview/' + aid;
        var body;
        if (mime.indexOf('image/') === 0) {
            body = '<div class="text-center" style="background:#F8FAFC;padding:.5rem;border-radius:3px;">' +
                       '<img src="' + url + '" style="max-width:100%;max-height:70vh;border:1px solid #E2E8F0;border-radius:3px;">' +
                   '</div>';
        } else {
            body = '<iframe src="' + url + '" style="width:100%;height:70vh;border:1px solid #E2E8F0;border-radius:3px;background:#F8FAFC;" title="' + label + ' preview"></iframe>';
        }
        $.confirm({
            title: '<span style="font-size:.9rem;color:#334155;"><i class="fas fa-eye me-1" style="color:#7A9E7E;"></i>' + label + ' <span class="small ms-1" style="color:#94A3B8;font-weight:400;font-size:.72rem;">' + mime + '</span></span>',
            content: body, columnClass: 'col-md-11', escapeKey: true, backgroundDismiss: true,
            buttons: {
                newTab:   { text: '<i class="fas fa-external-link-alt me-1"></i>Open in new tab', btnClass: 'btn-sm', action: function () { window.open(url, '_blank', 'noopener'); } },
                download: { text: '<i class="fas fa-download me-1"></i>Download',                 btnClass: 'btn-sm', action: function () { window.open(PROOT + 'Tenders/submissionAttachmentDownload/' + aid, '_blank'); } },
                close:    { text: 'Close', btnClass: 'btn-light btn-sm' }
            }
        });
    });

    $('#proof_table').on('click', '.btn-remove-proof', function () {
        var aid = parseInt($(this).data('att-id'), 10);
        $.confirm({
            title: 'Remove this proof?',
            content: 'The file will be removed from disk. The audit record survives with deleted = 1.',
            type: 'orange',
            buttons: {
                yes: { text: 'Remove', btnClass: 'btn-warning', action: function () {
                    $.post(PROOT + 'Tenders/submissionAttachmentRemoveAj', { attachment_id: aid }, null, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast('Removed.', 'success'); setTimeout(function () { location.reload(); }, 300); }
                            else rsToast('Remove failed: ' + (res && res.msg || 'unknown'), 'error');
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    // ── Contract signing tab ────────────────────────────────────────
    function collectTerms() {
        return {
            tender_id:                  TID,
            // Financial
            contract_no:                $('#ct_no').val(),
            contract_date:              $('#ct_date').val(),
            contract_value:             $('#ct_value').val() || 0,
            payment_basis:              $('#ct_pb').val(),
            payment_net_days:           $('#ct_pnd').val(),
            payment_terms:              $('#ct_pay').val(),
            delivery_timeline_days:     $('#ct_dtd').val(),
            // Advance + APG
            advance_pct:                $('#ct_ap').val(),
            apg_required:               $('#ct_apg_req').val(),
            apg_bank:                   $('#ct_apg_bank').val(),
            apg_validity_months:        $('#ct_apg_val').val(),
            advance_conditions:         $('#ct_ac').val(),
            // Performance guarantee + bid bond
            bid_bond_value:             $('#ct_bb').val(),
            performance_bond_value:     $('#ct_pbv').val(),
            pg_type:                    $('#ct_pgt').val(),
            pg_bank:                    $('#ct_pgb').val(),
            performance_bond_ref:       $('#ct_pbr').val(),
            pg_validity_months:         $('#ct_pgvm').val(),
            // Retention + Warranty + LD
            retention_pct:              $('#ct_rp').val(),
            retention_release_trigger:  $('#ct_rrt').val(),
            warranty_months:            $('#ct_wm').val(),
            warranty_coverage:          $('#ct_wcov').val(),
            ld_pct_per_day:             $('#ct_ldd').val(),
            ld_cap_pct:                 $('#ct_ldc').val(),
            // Tax + compliance
            vat_treatment:              $('#ct_vt').val(),
            tax_treatment:              $('#ct_tt').val(),
            tax_exemption_basis:        $('#ct_teb').val(),
            wht_pct:                    $('#ct_wp').val(),
            gl_code:                    $('#ct_gl').val(),
            fx_matches_cost_base:       $('#ct_fx').val(),
            insurance_ref:              $('#ct_ir').val(),
            notes:                      $('#ct_notes').val(),
            // Slice 8X · Team assignments (per-role RBAC enforced server-side)
            assigned_fm_user_id:          $('#ct_assigned_fm').val()   || '',
            assigned_accountant_user_id:  $('#ct_assigned_acc').val()  || '',
            assigned_procurement_user_id: $('#ct_assigned_proc').val() || '',
            assigned_pm_user_id:          $('#ct_assigned_pm').val()   || '',
            // Post-approval override reason (empty for pre-approval edits — server ignores)
            reason:                     $('#ct_reason').val() || '',
        };
    }

    // Advance amount live-recompute
    function refreshAdvanceAmount() {
        var v = parseFloat($('#ct_value').val() || 0);
        var p = parseFloat($('#ct_ap').val() || 0);
        $('#ct_ap_amt').val(Math.round(v * p / 100).toLocaleString());
    }
    $('#ct_value, #ct_ap').on('input', refreshAdvanceAmount);

    // Executive direct edit — reveals inputs + reason field on locked-terms page (no state change)
    $('#btn_exec_unlock').on('click', function () {
        $('.ct-field').prop('disabled', false);
        $('#ct_exec_reason_wrap').show();
        $('#ct_reason').focus();
        rsToast('Executive edit active. Enter a reason before saving — the change is audit-logged.', 'warning', 6000);
    });

    // Executive UNLOCK FOR FM — persists an unlock state so any FM can amend; auto-relocks on save.
    $('#btn_exec_unlock_for_fm').on('click', function () {
        $.confirm({
            title: 'Unlock terms for Finance Manager?',
            content:
                '<div class="mb-2 small text-muted">Enter the reason FM will amend the terms — this is audit-logged and shown to every FM.</div>' +
                '<input type="text" id="unlock_reason" class="form-control form-control-sm" placeholder="e.g. Client requested a lower retention %">',
            type: 'orange',
            buttons: {
                unlock: { text: 'Unlock', btnClass: 'btn-warning', action: function () {
                    var reason = $('#unlock_reason').val().trim();
                    if (!reason) { rsToast('Reason required.', 'error'); return false; }
                    $.post(PROOT + 'Tenders/unlockContractTermsAj', { tender_id: TID, reason: reason }, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast(res.msg, 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 700); }
                            else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error', 5000); }
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    // Executive re-lock (cancels an active unlock without a save)
    $('#btn_exec_relock').on('click', function () {
        $.confirm({
            title: 'Cancel the unlock?',
            content: 'The terms will be locked again. Any pending FM amendments not yet saved will be discarded.',
            type: 'red',
            buttons: {
                relock: { text: 'Cancel unlock', btnClass: 'btn-danger', action: function () {
                    $.post(PROOT + 'Tenders/relockContractTermsAj', { tender_id: TID }, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast(res.msg, 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 600); }
                            else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error', 5000); }
                        });
                }},
                keep: { text: 'Keep unlocked', btnClass: 'btn-light' }
            }
        });
    });

    // Slice 8Z-r · Refresh the "Before handing off, fill" checklist + Verify-button gate
    // in-place after every save (section save, bond CRUD, FM attach CRUD). Exposed on window
    // so the Vue #ct_fm_root root can call it after its own mutations.
    function refreshCompleteness() {
        var $wrap = $('#ct_completeness_wrap');
        if (!$wrap.length) return; // FM/Exec strip not rendered for this user — nothing to refresh
        $.post(PROOT + 'Tenders/contractCompletenessAj', { tender_id: TID }, 'json')
            .done(function (res) {
                if (!res || !res.ok) return;
                var $goBtn    = $('#btn_fm_handoff');
                var checklist = res.checklist || [];
                var allOk     = !!res.all_ok;
                var done = 0;
                for (var i = 0; i < checklist.length; i++) if (checklist[i].ok) done++;
                var total = checklist.length;

                var esc = function (s) { return String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); };
                var items = checklist.map(function (c) {
                    if (c.ok) {
                        return '<div class="col-md-4 col-sm-6" style="color:#3F5C43;">'
                             + '<i class="fas fa-check-circle me-1" style="color:#7A9E7E;font-size:.78rem;vertical-align:middle;"></i>'
                             + '<span style="text-decoration:line-through;text-decoration-color:#7A9E7E80;text-decoration-thickness:1px;opacity:.85;">' + esc(c.label) + '</span>'
                             + '</div>';
                    }
                    return '<div class="col-md-4 col-sm-6" style="color:#78350F;">'
                         + '<i class="far fa-circle me-1" style="color:#D4A574;font-size:.72rem;vertical-align:middle;"></i>'
                         + esc(c.label)
                         + '</div>';
                }).join('');

                var headerHtml = allOk
                    ? '<i class="fas fa-check-circle me-1" style="color:#7A9E7E;"></i><strong>All mandatory contract terms + seats are filled — ready to hand off.</strong>'
                    : '<i class="fas fa-exclamation-triangle me-1"></i><strong>Before handing off, fill:</strong>';

                $wrap.html(
                    '<div class="alert py-2 mb-2" style="background:' + (allOk ? '#EAF2E8' : '#FEF3C7') + ';border:1px solid ' + (allOk ? '#7A9E7E' : '#F59E0B') + ';color:' + (allOk ? '#3F5C43' : '#78350F') + ';font-size:.82rem;">'
                  + '  <div class="mb-1 d-flex align-items-center justify-content-between">'
                  + '    <div>' + headerHtml + '</div>'
                  + '    <span class="badge" style="background:' + (allOk ? '#7A9E7E' : '#D4A574') + ';color:#fff;font-size:.66rem;font-weight:600;">' + done + ' / ' + total + ' done</span>'
                  + '  </div>'
                  + '  <div class="row g-1" style="font-size:.74rem;">' + items + '</div>'
                  + '</div>'
                );
                if ($goBtn.length) {
                    if (allOk) $goBtn.prop('disabled', false).removeAttr('title');
                    else       $goBtn.prop('disabled', true).attr('title', 'Fill mandatory fields first');
                }

                // Slice 8Z-r · repaint the per-section status pills in each card header
                var sections = res.sections || {};
                $('.ct-sec-status').each(function () {
                    var $pill = $(this);
                    var key = $pill.attr('data-section-key');
                    var s = sections[key];
                    if (!s || (s.total | 0) === 0) { $pill.hide(); return; }
                    $pill.show();
                    if (s.all_ok || s.done >= s.total) {
                        $pill.css('background','#7A9E7E').html('<i class="fas fa-check-circle me-1"></i>All done');
                    } else {
                        $pill.css('background','#D4A574').text((s.done | 0) + ' / ' + (s.total | 0));
                    }
                });
            });
    }
    window.rsRefreshContractCompleteness = refreshCompleteness;

    // Slice 8Z-r · shared save handler for the bottom "Save terms" button AND every per-section
    // save button (rendered by groupCardHdr with $showSave=true). No page reload — the form values
    // already reflect what was persisted; audit-trail deltas are stale until manual refresh.
    function saveTermsFromButton($btn, sectionLabel) {
        var payload = collectTerms();
        if ($('#ct_exec_reason_wrap').is(':visible') && !payload.reason.trim()) {
            rsToast('A reason is required when editing locked terms.', 'error');
            $('#ct_reason').focus();
            return;
        }
        var originalHtml = $btn.html();
        $btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-1"></i>Saving…');
        $.post(PROOT + 'Tenders/saveContractTermsAj', payload, 'json')
            .done(function (res) {
                $btn.prop('disabled', false).html(originalHtml);
                if (res && res.ok) {
                    rsToast(sectionLabel ? (sectionLabel + ' saved.') : 'Contract terms saved.', 'success');
                    refreshCompleteness();
                } else {
                    rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                }
            })
            .fail(function () {
                $btn.prop('disabled', false).html(originalHtml);
                rsToast('Network error while saving.', 'error');
            });
    }

    $('#btn_save_terms').on('click', function () {
        saveTermsFromButton($(this), '');
    });

    // Per-section save: find the enclosing card's title and use it as the toast label.
    $(document).on('click', '.btn-save-terms-section', function () {
        var $btn = $(this);
        var title = $btn.closest('.card').find('.card-header strong').text().trim() || 'Section';
        saveTermsFromButton($btn, title);
    });

    // Slice 8Z-s · Kickoff brief — each half posts only the inputs it owns; server RBAC
    // silently drops anything the caller isn't allowed to write, so the two halves
    // can't step on each other even if the HTML were tampered with.
    function saveKickoffHalf($btn, $form, label) {
        var payload = { tender_id: TID };
        // Grab every input inside the form, including unchecked checkboxes (as 0)
        $form.find('input, select, textarea').each(function () {
            var $el = $(this); var name = $el.attr('name');
            if (!name) return;
            if ($el.attr('type') === 'checkbox') payload[name] = $el.is(':checked') ? 1 : 0;
            else payload[name] = $el.val();
        });
        var originalHtml = $btn.html();
        $btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-1"></i>Saving…');
        $.post(PROOT + 'Tenders/saveKickoffBriefAj', payload, 'json')
            .done(function (res) {
                $btn.prop('disabled', false).html(originalHtml);
                if (res && res.ok) {
                    rsToast(label + ' saved.', 'success');
                    // Margin floor changed → recompute budget ceiling on screen
                    var mf = parseFloat($form.find('[name=margin_floor_pct]').val() || 0);
                    var cv = parseFloat($('#ct_value').val() || 0);
                    if (mf > 0 && cv > 0) {
                        $('#kb_budget_ceiling').val(Math.round(cv * (1 - mf / 100)).toLocaleString());
                    } else if (mf === 0 && cv > 0) {
                        $('#kb_budget_ceiling').val(Math.round(cv).toLocaleString());
                    }
                } else {
                    rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                }
            })
            .fail(function () {
                $btn.prop('disabled', false).html(originalHtml);
                rsToast('Network error while saving.', 'error');
            });
    }
    $('#btn_kb_save_fm').on('click', function () {
        saveKickoffHalf($(this), $('#kb_fm_form'), 'Kickoff brief · FM half');
    });
    $('#btn_kb_save_exec').on('click', function () {
        saveKickoffHalf($(this), $('#kb_exec_form'), 'Kickoff brief · Exec half');
    });

    // Slice 8Z-t · TRA VAT exemption certificate banner — appears/hides live as tax_treatment
    // changes. Content refresh only fires on save (refreshCompleteness() re-fetches from server).
    $('#ct_tt').on('change', function () {
        var v = ($(this).val() || '').toUpperCase();
        var needed = (v === 'EXEMPT' || v === 'ZERO_RATED' || v === 'MIXED');
        $('#ct_vat_cert_banner').toggle(needed);
    });
    // Scroll to Bonds tracker + hint the user to add a VAT_EXEMPTION_CERT row.
    $('#ct_vat_cert_jump').on('click', function (e) {
        e.preventDefault();
        var $bondsCard = $('#ct_fm_root .card').first();
        if (!$bondsCard.length) return;
        $('html, body').animate({ scrollTop: $bondsCard.offset().top - 20 }, 300);
        if (window.rsToast) rsToast('Click "Add bond / receipt" and pick VAT exemption certificate.', 'info', 5000);
    });

    $('#btn_submit_contract').on('click', function () {
        $.confirm({
            title: 'Submit contract terms for approval?',
            content: 'The Finance Manager will verify first, then the Executive approves & authorises signing. Terms lock once Exec approves.',
            type: 'orange',
            buttons: {
                yes: { text: 'Submit', btnClass: 'btn-warning', action: function () {
                    $.post(PROOT + 'Tenders/submitContractAj', { tender_id: TID }, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast('Submitted for FM verification (approval #' + res.approval_id + ').', 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 700); }
                            else                { rsToast('Submit failed: ' + (res.msg || 'unknown'), 'error', 5000); }
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    /* Slice 8Z-q · Bonds & FM attachments — moved to Vue 3 Options API root (see #ct_fm_root script block further down). No page reloads. */

    $('#btn_save_signing').on('click', function () {
        var payload = {
            tender_id:        TID,
            signed_date:      $('#sg_date').val(),
            signed_venue:     $('#sg_venue').val(),
            our_signatories:  $('#sg_us').val(),
            their_signatories:$('#sg_them').val(),
            notes:            $('#sg_notes').val(),
        };
        $.post(PROOT + 'Tenders/recordSigningAj', payload, 'json')
            .done(function (res) {
                if (res && res.ok) { rsToast('Signing recorded. Reloading…', 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 600); }
                else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error', 5000); }
            });
    });

    $('#btn_add_receipt').on('click', function () {
        var amt = parseFloat($('#rc_amt').val()) || 0;
        if (amt <= 0) { rsToast('Enter an amount > 0.', 'warning'); return; }
        var payload = {
            tender_id:    TID,
            receipt_no:   $('#rc_no').val(),
            receipt_date: $('#rc_date').val(),
            amount:       amt,
            receipt_type: $('#rc_type').val(),
            reference:    $('#rc_ref').val(),
        };
        $.post(PROOT + 'Tenders/addContractReceiptAj', payload, 'json')
            .done(function (res) {
                if (res && res.ok) { rsToast('Receipt logged.', 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 400); }
                else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
            });
    });

    $('#tab-contract').on('click', '.btn-del-receipt', function () {
        var rid = parseInt($(this).data('rid'), 10);
        $.confirm({
            title: 'Delete receipt?',
            content: 'This removes the receipt row. Journal entries (if any) are not affected.',
            type: 'orange',
            buttons: {
                yes: { text: 'Delete', btnClass: 'btn-warning', action: function () {
                    $.post(PROOT + 'Tenders/deleteContractReceiptAj', { receipt_id: rid }, 'json')
                        .done(function (res) {
                            if (res && res.ok) { rsToast('Deleted.', 'success'); setTimeout(function () { location.hash = 'tab-contract'; location.reload(); }, 300); }
                            else                { rsToast('Failed: ' + (res.msg || 'unknown'), 'error'); }
                        });
                }},
                cancel: { text: 'Cancel', btnClass: 'btn-light' }
            }
        });
    });

    // Auto-select the tab from URL hash (e.g. #tab-contract from an approver's return-url)
    if (location.hash && location.hash.indexOf('tab-') === 1) {
        var t = $('a[data-bs-toggle="tab"][href="' + location.hash + '"]');
        if (t.length) new bootstrap.Tab(t[0]).show();
    }

    // Manual "Create project" handler retired — projects auto-provision on Exec approval
    // of TENDER_CONTRACT. See Tenders::onContractApproved().

    // Pricing tab handlers → moved to Vue 3 Options API root (Slice 8M · see script below).
});
</script>

<!-- Slice 8L · Items tab + Slice 8M · Pricing tab · Vue 3 Options API roots -->
<!-- Locally-hosted Vue so raw {{ }} braces don't leak when the CDN is unreachable (offline / blocked network). -->
<script src="<?= PROOT; ?>js/Olibs/vue.global.prod.js?v=3.5.13"></script>
<style>[v-cloak]{display:none !important;}</style>

<!-- Slice 8M · Pricing tab Vue root -->
<script>
(function () {
    var TID       = <?= (int)$t['c0d']; ?>;
    var PROOT     = <?= json_encode(PROOT); ?>;
    var bootVersions = <?= json_encode($this->data['pricing_versions']         ?? [], JSON_UNESCAPED_SLASHES); ?>;
    var bootCurrent  = <?= json_encode($this->data['pricing_current']          ?? null, JSON_UNESCAPED_SLASHES); ?>;
    var bootSections = <?= json_encode($this->data['pricing_sections']         ?? [], JSON_UNESCAPED_SLASHES); ?>;
    // JSON_FORCE_OBJECT is dangerous — it recurses into nested arrays and turns them into {"0":x,"1":y,...}
    // Serialise only the outer array manually so section-id keys are string keys but each section's LINES
    // stay as a real JS array.
    var bootLinesBy  = (function () {
        var raw = <?php
            $lbs = $this->data['pricing_lines_by_section'] ?? [];
            $out = new stdClass();
            foreach ($lbs as $sid => $lines) { $out->{(string)$sid} = $lines; }
            echo json_encode($out, JSON_UNESCAPED_SLASHES);
        ?>;
        return raw || {};
    })();
    var tenderItems  = <?= json_encode($this->data['tender_items']             ?? [], JSON_UNESCAPED_SLASHES); ?>;
    var bootOverheads= <?= json_encode($this->data['pricing_overheads']        ?? [], JSON_UNESCAPED_SLASHES); ?>;
    var canCreateVer = <?= $pv_canCreateVer; ?>;
    var canSubmit    = <?= $pv_canSubmit;    ?>;
    var canApply     = <?= $pv_canApply;     ?>;
    var canSeed      = <?= $pv_canSeed;      ?>;

    var OH_CATEGORY_LABELS = {
        MANPOWER:           'Manpower',
        EQUIPMENT:          'Equipment',
        TRANSPORT:          'Transport',
        DISMANTLE_ASSEMBLE: 'Dismantle / Assemble',
        SITE_SETUP:         'Site setup',
        ADMIN_OVERHEAD:     'Admin / PM',
        CUSTOMS_DUTY:       'Customs duty',
        FREIGHT_INSURANCE:  'Freight + insurance',
        CLEARING_HANDLING:  'Clearing + handling',
        OTHER:              'Other',
    };

    var STATUS_BADGE = {
        DRAFT:      'background:#94A3B8;color:#fff;font-size:.62rem;text-transform:capitalize;',
        SUBMITTED:  'background:#D4A574;color:#fff;font-size:.62rem;text-transform:capitalize;',
        APPROVED:   'background:#7A9E7E;color:#fff;font-size:.62rem;text-transform:capitalize;',
        DECLINED:   'background:#C48579;color:#fff;font-size:.62rem;text-transform:capitalize;',
        SUPERSEDED: 'background:#94A3B8;color:#fff;font-size:.62rem;text-transform:capitalize;',
    };

    function emptyNewLine(defMarkup) {
        return { item_ref:'', description:'', qty:1, uom:'', unit_cost:0, markup_pct: Number(defMarkup) || 0 };
    }

    var app = Vue.createApp({
        data: function () {
            var newLines = {};
            var defMarkup = bootCurrent ? bootCurrent.default_markup_pct : 0;
            (bootSections || []).forEach(function (s) { newLines[s.c0d] = emptyNewLine(defMarkup); });
            return {
                PROOT: PROOT,
                versions:         bootVersions.slice(),
                currentVersionId: bootCurrent ? bootCurrent.c0d : 0,
                version:          bootCurrent,
                sections:         bootSections.slice(),
                linesBySection:   Object.assign({}, bootLinesBy),
                newLines:         newLines,
                newSection:       { section_name: '', notes: '' },
                headerDraft:      bootCurrent ? {
                    version_label:      bootCurrent.version_label,
                    vat_pct:            Number(bootCurrent.vat_pct),
                    contingency_pct:    Number(bootCurrent.contingency_pct),
                    prelims_amount:     Number(bootCurrent.prelims_amount),
                    default_markup_pct: Number(bootCurrent.default_markup_pct),
                    pricing_mode:         bootCurrent.pricing_mode         || 'PER_ITEM',
                    lumpsum_amount:       Number(bootCurrent.lumpsum_amount || 0),
                    lumpsum_notes:        bootCurrent.lumpsum_notes         || '',
                    procurement_mode:     bootCurrent.procurement_mode      || 'NA',
                    client_boq_visibility: bootCurrent.client_boq_visibility || 'ITEMS_AND_SECTIONS',
                } : { version_label:'', vat_pct:18, contingency_pct:0, prelims_amount:0, default_markup_pct:0, pricing_mode:'PER_ITEM', lumpsum_amount:0, lumpsum_notes:'', procurement_mode:'NA', client_boq_visibility:'ITEMS_AND_SECTIONS' },
                overheads:        bootOverheads.slice(),
                newOverhead:      { category:'MANPOWER', label:'', amount:0, display_mode:'DISTRIBUTED' },
                OH_CATEGORIES:    ['MANPOWER','EQUIPMENT','TRANSPORT','DISMANTLE_ASSEMBLE','SITE_SETUP','ADMIN_OVERHEAD','CUSTOMS_DUTY','FREIGHT_INSURANCE','CLEARING_HANDLING','OTHER'],
                canCreateVer:     canCreateVer,
                canSubmit:        canSubmit,
                canApply:         canApply,
                canSeed:          canSeed,
                hasTenderItems:   (tenderItems || []).length > 0,
                tenderItemCount:  (tenderItems || []).length,
            };
        },
        computed: {
            isDraft: function () { return !!(this.version && this.version.status === 'DRAFT'); },
            totalLineCount: function () {
                var n = 0; for (var k in this.linesBySection) n += (this.linesBySection[k] || []).length; return n;
            },
            // Slice 8S: client-facing margin uses direct cost only (strips overhead pool). true margin = version.margin_pct.
            clientMarginPct: function () {
                if (!this.version) return 0;
                var sp = parseFloat(this.version.sum_price)    || 0;
                var sc = parseFloat(this.version.sum_cost)     || 0;
                var so = parseFloat(this.version.sum_overhead) || 0;
                var directCost = sc - so;
                return sp > 0 ? ((sp - directCost) / sp) * 100 : 0;
            },
            // Slice 8S: distributed overhead pool total (only DISTRIBUTED mode contributes to per-item distribution).
            distributedTotal: function () {
                return (this.overheads || []).reduce(function (s, o) {
                    if (o.display_mode !== 'DISTRIBUTED') return s;
                    var v = parseFloat(o.amount); return s + (isFinite(v) ? v : 0);
                }, 0);
            },
            // Denominator for pro-rata distribution: sum of every raw line_price across all sections in the current version.
            directLineTotal: function () {
                var self = this;
                return this.sections.reduce(function (s, sec) {
                    var lines = self.linesFor(sec.c0d) || [];
                    return s + lines.reduce(function (t, ln) {
                        var v = parseFloat(ln.line_price); return t + (isFinite(v) ? v : 0);
                    }, 0);
                }, 0);
            },
        },
        methods: {
            // Slice 8S · client-facing line price = raw line_price + pro-rata share of DISTRIBUTED overhead pool.
            // LUMPSUM mode ignores distribution (client sees one number regardless).
            clientLinePrice: function (ln) {
                var raw = parseFloat(ln.line_price) || 0;
                if (!this.version || this.version.pricing_mode === 'LUMPSUM') return raw;
                var pool  = this.distributedTotal;
                var denom = this.directLineTotal;
                if (pool <= 0 || denom <= 0) return raw;
                return raw + (raw / denom) * pool;
            },
            clientUnitPrice: function (ln) {
                var qty = parseFloat(ln.qty) || 0;
                if (qty <= 0) return 0;
                return this.clientLinePrice(ln) / qty;
            },
            // Convert markup % (added on cost) to the equivalent margin % (as share of sell).
            //   markup 22% → margin ≈ 18%. Formula: margin = markup / (1 + markup/100).
            markupToMargin: function (markupPct) {
                var m = parseFloat(markupPct); if (!isFinite(m) || m <= -100) return 0;
                return m / (1 + m / 100);
            },
            // DB decimals arrive as strings from PDO — coerce defensively so NaN never leaks into the DOM.
            fmt0: function (n) { var f = parseFloat(n); if (!isFinite(f)) f = 0; return f.toLocaleString('en-US', { maximumFractionDigits: 0 }); },
            fmt1: function (n) { var f = parseFloat(n); if (!isFinite(f)) f = 0; return f.toFixed(1); },
            fmt2: function (n) { var f = parseFloat(n); if (!isFinite(f)) f = 0; return f.toFixed(2); },
            statusBadge: function (s) { return STATUS_BADGE[s] || STATUS_BADGE.DRAFT; },
            linesFor: function (sid) { return this.linesBySection[sid] || []; },
            switchVersion: function () {
                if (!this.currentVersionId) return;
                window.location.href = PROOT + 'Tenders/view/' + TID + '?pv=' + this.currentVersionId + '#tab-pricing';
            },
            refreshSnapshot: function (versionId) {
                var self = this;
                var vid = versionId || (this.version && this.version.c0d) || 0;
                if (!vid) return;
                return $.post(PROOT + 'Tenders/pricingSnapshotAj', { version_id: vid }, null, 'json')
                    .then(function (res) {
                        if (!res || !res.ok || !res.snapshot) return;
                        self.version = res.snapshot.version;
                        self.sections = res.snapshot.sections;
                        self.linesBySection = res.snapshot.lines_by_section || {};
                        var defMk = Number(self.version.default_markup_pct) || 0;
                        var freshNew = {};
                        self.sections.forEach(function (s) {
                            freshNew[s.c0d] = self.newLines[s.c0d] || emptyNewLine(defMk);
                        });
                        self.newLines = freshNew;
                        self.overheads = res.snapshot.overheads || [];
                        self.headerDraft = {
                            version_label:         self.version.version_label,
                            vat_pct:               Number(self.version.vat_pct),
                            contingency_pct:       Number(self.version.contingency_pct),
                            prelims_amount:        Number(self.version.prelims_amount),
                            default_markup_pct:    defMk,
                            pricing_mode:          self.version.pricing_mode         || 'PER_ITEM',
                            lumpsum_amount:        Number(self.version.lumpsum_amount || 0),
                            lumpsum_notes:         self.version.lumpsum_notes        || '',
                            procurement_mode:      self.version.procurement_mode     || 'NA',
                            client_boq_visibility: self.version.client_boq_visibility|| 'ITEMS_AND_SECTIONS',
                        };
                    });
            },
            setMode: function (mode) {
                if (!this.isDraft) { rsToast('Only DRAFT versions can change mode.', 'warning'); return; }
                this.headerDraft.pricing_mode = mode;
            },
            modeButtonStyle: function (mode) {
                var active = this.headerDraft.pricing_mode === mode;
                if (active) return 'background:#7A9E7E;border:1px solid #7A9E7E;color:#fff;font-weight:600;padding:.15rem .55rem;font-size:.74rem;';
                return 'background:#F1F5F9;border:1px solid #E2E8F0;color:#64748B;padding:.15rem .55rem;font-size:.74rem;';
            },
            // Slice 8S · overhead pool helpers + CRUD
            categoryLabel: function (c) { return OH_CATEGORY_LABELS[c] || c; },
            modeSelectStyle: function (m) {
                if (m === 'PRELIMS_LINE')  return 'background:#EAF2E8;color:#3F5C43;';
                if (m === 'INTERNAL_ONLY') return 'background:#F5EAE1;color:#8B4C2C;';
                return 'background:#F1F5F9;color:#334155;';
            },
            addOverhead: function () {
                var self = this;
                if (!self.newOverhead.label || !self.newOverhead.label.trim()) { rsToast('Label required.', 'warning'); return; }
                $.post(PROOT + 'Tenders/pricingOverheadsAddAj', $.extend({ version_id: self.version.c0d, tender_id: TID }, self.newOverhead), null, 'json')
                    .done(function (res) {
                        if (res && res.ok) {
                            self.newOverhead = { category:'MANPOWER', label:'', amount:0, display_mode:'DISTRIBUTED' };
                            self.refreshSnapshot();
                        } else rsToast('Add failed: ' + (res && res.msg || 'unknown'), 'error');
                    });
            },
            saveOverhead: function (oh) {
                var self = this;
                $.post(PROOT + 'Tenders/pricingOverheadsUpdateAj', {
                    overhead_id: oh.c0d, category: oh.category, label: oh.label,
                    amount: oh.amount, display_mode: oh.display_mode, notes: oh.notes || '',
                }, null, 'json').done(function (res) {
                    if (res && res.ok) { rsToast('Overhead saved.', 'success'); self.refreshSnapshot(); }
                    else rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error');
                });
            },
            deleteOverhead: function (oh) {
                var self = this;
                $.confirm({ title: 'Remove overhead line?', content: '"' + oh.label + '" (' + oh.category + ')',
                    buttons: {
                        yes: { text: 'Remove', btnClass: 'btn-warning', action: function () {
                            $.post(PROOT + 'Tenders/pricingOverheadsRemoveAj', { overhead_id: oh.c0d }, null, 'json')
                                .done(function () { self.refreshSnapshot(); });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            loadOverheadTemplate: function (tplKey) {
                var self = this;
                var friendly = tplKey === 'GOODS_IMPORT' ? 'Goods · Import' : 'Goods · Local';
                $.confirm({ title: 'Quick-load ' + friendly + ' overhead template?', content: 'Adds the standard categories at zero amount. Existing lines with the same label are skipped.',
                    buttons: {
                        yes: { text: 'Load', btnClass: 'btn-primary', action: function () {
                            $.post(PROOT + 'Tenders/pricingOverheadsLoadTemplateAj', { version_id: self.version.c0d, tender_id: TID, template: tplKey }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) { rsToast(res.added + ' line(s) loaded, ' + (res.skipped || 0) + ' skipped.', 'success'); self.refreshSnapshot(); }
                                    else rsToast('Load failed: ' + (res && res.msg || 'unknown'), 'error');
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            createDraft: function () {
                var self = this;
                var cloneFrom = self.version ? self.version.c0d : 0;
                $.confirm({
                    title: 'New pricing draft?',
                    content: cloneFrom ? 'Cloning from selected version — sections + lines carry over, you can then adjust.' : 'Blank draft. Add sections + lines from scratch.',
                    type: 'blue',
                    buttons: {
                        yes: { text: 'Create', btnClass: 'btn-primary', action: function () {
                            $.post(PROOT + 'Tenders/pricingCreateVersionAj', { tender_id: TID, clone_from: cloneFrom }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) {
                                        rsToast('Draft created.', 'success');
                                        // A new draft means the versions list changed → single reload to pick up options; land on new draft.
                                        window.location.href = PROOT + 'Tenders/view/' + TID + '?pv=' + res.version_id + '#tab-pricing';
                                    } else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            // Slice 8U · preview pricing PDF inside a jquery-confirm iframe modal (rather than downloading).
            // FPDF's Output('I') already sets Content-Disposition:inline, so the iframe just renders the PDF.
            previewPricingPdf: function (audience) {
                var url = PROOT + 'Tenders/pricingPdf/' + this.version.c0d + '?audience=' + audience;
                var isClient = (audience === 'client');
                var chipStyle = isClient
                    ? 'background:#EAF2E8;color:#3F5C43;border:1px solid #7A9E7E;'
                    : 'background:#F5EAE1;color:#8B4C2C;border:1px solid #B87A5A;';
                var label = isClient ? 'Client PDF' : 'Internal PDF';
                $.confirm({
                    title: '<span style="font-size:.9rem;color:#334155;"><i class="fas fa-file-pdf me-1" style="color:#B87A5A;"></i>' + label + ' preview <span class="badge ms-1" style="' + chipStyle + 'font-size:.62rem;text-transform:capitalize;font-weight:500;">v' + this.version.version_no + ' · ' + (this.version.status || '').toLowerCase() + '</span></span>',
                    content: '<iframe src="' + url + '" style="width:100%;height:70vh;border:1px solid #E2E8F0;border-radius:3px;background:#F8FAFC;" title="' + label + ' preview"></iframe>',
                    columnClass: 'col-md-11',
                    escapeKey: true,
                    backgroundDismiss: true,
                    buttons: {
                        newTab:   { text: '<i class="fas fa-external-link-alt me-1"></i>Open in new tab', btnClass: 'btn-sm', action: function () { window.open(url, '_blank', 'noopener'); } },
                        download: { text: '<i class="fas fa-download me-1"></i>Download',                 btnClass: 'btn-sm', action: function () { window.open(url + '&disposition=attachment', '_blank'); } },
                        close:    { text: 'Close', btnClass: 'btn-light btn-sm' }
                    }
                });
            },
            // Empty-state one-click default: create a blank draft AND seed it from tender items in one flow.
            createDraftAndSeed: function () {
                $.post(PROOT + 'Tenders/pricingCreateVersionAj', { tender_id: TID, clone_from: 0 }, null, 'json')
                    .done(function (res) {
                        if (!res || !res.ok) { rsToast('Draft creation failed: ' + (res && res.msg || 'unknown'), 'error', 5000); return; }
                        var vid = res.version_id;
                        $.post(PROOT + 'Tenders/pricingSeedFromItemsAj', { version_id: vid, section_id: 0 }, null, 'json')
                            .done(function (r2) {
                                if (r2 && r2.ok) rsToast('Draft created · ' + (r2.added || 0) + ' item(s) seeded.', 'success');
                                else rsToast('Draft created, but seeding items failed: ' + (r2 && r2.msg || 'unknown'), 'warning', 5000);
                                window.location.href = PROOT + 'Tenders/view/' + TID + '?pv=' + vid + '#tab-pricing';
                            });
                    });
            },
            saveHeader: function () {
                var self = this;
                $.post(PROOT + 'Tenders/pricingUpdateVersionAj', $.extend({ version_id: self.version.c0d }, self.headerDraft), null, 'json')
                    .done(function (res) {
                        if (res && res.ok) { rsToast('Version settings saved.', 'success'); self.refreshSnapshot(); }
                        else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error');
                    });
            },
            addSection: function () {
                var self = this;
                var name = (self.newSection.section_name || '').trim();
                if (!name) { rsToast('Enter a section name.', 'warning'); return; }
                $.post(PROOT + 'Tenders/pricingAddSectionAj', {
                    tender_id: TID, version_id: self.version.c0d,
                    section_name: name, notes: self.newSection.notes || '',
                }, null, 'json').done(function (res) {
                    if (res && res.ok) {
                        rsToast('Section added.', 'success');
                        self.newSection = { section_name: '', notes: '' };
                        self.refreshSnapshot();
                    } else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error');
                });
            },
            deleteSection: function (sec) {
                var self = this;
                $.confirm({
                    title: 'Delete section + its lines?',
                    content: 'All lines under "' + sec.section_name + '" will be removed.',
                    type: 'orange',
                    buttons: {
                        yes: { text: 'Delete', btnClass: 'btn-warning', action: function () {
                            $.post(PROOT + 'Tenders/pricingDeleteSectionAj', { section_id: sec.c0d }, null, 'json')
                                .done(function () { self.refreshSnapshot(); });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            addLine: function (sec) {
                var self = this;
                var nl = self.newLines[sec.c0d];
                if (!nl || !(nl.description || '').trim()) { rsToast('Description required.', 'warning'); return; }
                $.post(PROOT + 'Tenders/pricingAddLineAj', $.extend({ section_id: sec.c0d }, nl), null, 'json')
                    .done(function (res) {
                        if (res && res.ok) {
                            self.newLines[sec.c0d] = emptyNewLine(self.version.default_markup_pct);
                            self.refreshSnapshot();
                        } else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error');
                    });
            },
            saveLine: function (ln) {
                var self = this;
                $.post(PROOT + 'Tenders/pricingUpdateLineAj', {
                    line_id:     ln.c0d,
                    item_ref:    ln.item_ref || '',
                    description: ln.description || '',
                    qty:         ln.qty,
                    uom:         ln.uom || '',
                    unit_cost:   ln.unit_cost,
                    markup_pct:  ln.markup_pct,
                }, null, 'json').done(function (res) {
                    if (res && res.ok) { rsToast('Line updated.', 'success'); self.refreshSnapshot(); }
                    else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error');
                });
            },
            deleteLine: function (ln) {
                var self = this;
                $.post(PROOT + 'Tenders/pricingDeleteLineAj', { line_id: ln.c0d }, null, 'json')
                    .done(function () { self.refreshSnapshot(); });
            },
            seedFromItems: function () {
                var self = this;
                $.confirm({
                    title: 'Seed pricing from tender items?',
                    content: 'Copies the buyer\'s ' + self.tenderItemCount + ' item(s) into this draft as pricing lines with cost=0 and markup = default. Duplicates (same ref + description) are skipped.',
                    type: 'blue',
                    buttons: {
                        yes: { text: 'Seed', btnClass: 'btn-primary', action: function () {
                            $.post(PROOT + 'Tenders/pricingSeedFromItemsAj', { version_id: self.version.c0d, section_id: 0 }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) {
                                        rsToast(res.added + ' line(s) added, ' + (res.skipped || 0) + ' skipped.', 'success');
                                        self.refreshSnapshot();
                                    } else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            submitForApproval: function () {
                var self = this;
                $.confirm({
                    title: 'Submit pricing for approval?',
                    content: 'The version freezes at SUBMITTED. Chain: PM review → FM verify → Executive approve. To adjust later, create a new draft.',
                    type: 'orange',
                    buttons: {
                        yes: { text: 'Submit', btnClass: 'btn-warning', action: function () {
                            $.post(PROOT + 'Tenders/pricingSubmitAj', { version_id: self.version.c0d }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) { rsToast('Submitted (approval #' + res.approval_id + ').', 'success'); self.refreshSnapshot(); }
                                    else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            applyToTender: function () {
                var self = this;
                $.confirm({
                    title: 'Apply this version as the bid amount?',
                    content: 'The tender\'s submission_amount will be set to the version\'s sell total, and price source flipped to PRICING_TAB.',
                    type: 'green',
                    buttons: {
                        yes: { text: 'Apply', btnClass: 'btn-success', action: function () {
                            $.post(PROOT + 'Tenders/pricingApplyAj', { version_id: self.version.c0d }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) { rsToast('Applied. Reloading…', 'success'); setTimeout(function () { window.location.reload(); }, 400); }
                                    else rsToast('Failed: ' + (res && res.msg || 'unknown'), 'error');
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
        },
    });

    $(document).ready(function () {
        if (typeof Vue === 'undefined') {
            // Vue failed to load — strip v-cloak so users see the raw HTML fallback instead of a blank tab.
            $('#pv_app_root').removeAttr('v-cloak').css('display','block');
            $('#pv_app_root').prepend('<div class="alert alert-warning small">Pricing UI could not initialise (Vue failed to load). Refresh the page — if this persists, contact Admin.</div>');
            return;
        }
        var el = document.getElementById('pv_app_root');
        if (!el) return;
        // Surface runtime errors to the console (silent template failures = blank tab).
        app.config.errorHandler = function (err, instance, info) {
            console.error('[pricing-vue]', info, err);
            $('#pv_app_root').removeAttr('v-cloak').css('display','block');
            $('#pv_app_root').prepend('<div class="alert alert-danger small">Pricing UI error: ' + (err && err.message || err) + ' — see console.</div>');
        };
        try {
            app.mount('#pv_app_root');
        } catch (e) {
            console.error('[pricing-vue] mount threw:', e);
            $('#pv_app_root').removeAttr('v-cloak').css('display','block');
            $('#pv_app_root').prepend('<div class="alert alert-danger small">Pricing UI failed to mount: ' + (e && e.message || e) + ' — see console.</div>');
        }
    });
})();
</script>
<script>
(function () {
    var bootItems = <?= json_encode($this->data['tender_items'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
    var TID       = <?= (int)$t['c0d']; ?>;
    var PROOT     = <?= json_encode(PROOT); ?>;
    var canWrite  = <?= UserGroups::can('Tenders','itemsAddAj') ? 'true' : 'false'; ?>;
    var defaultKind = <?= json_encode($this->data['tender_items_default_kind'] ?? 'GOOD'); ?>;

    var KIND_LABELS = { GOOD:'Good', SERVICE:'Service', WORKS_BOQ:'Works BOQ', LOGISTICS:'Logistics', OTHER:'Other' };
    var KIND_STYLES = {
        GOOD:      'background:#EAF2E8;color:#3F5C43;border:1px solid #7A9E7E;',
        SERVICE:   'background:#F1F5F9;color:#334155;border:1px solid #7A8BA1;',
        WORKS_BOQ: 'background:#F5EAE1;color:#8B4C2C;border:1px solid #B87A5A;',
        LOGISTICS: 'background:#FEF3E7;color:#8B6914;border:1px solid #D4A574;',
        OTHER:     'background:#F8FAFC;color:#64748B;border:1px solid #94A3B8;',
    };

    var app = Vue.createApp({
        data: function () {
            return {
                items:       bootItems.slice(),
                canWrite:    canWrite,
                adding:      false,
                editingId:   0,
                busy:        false,
                draft:       this.emptyDraft(defaultKind),
                KINDS:       ['GOOD','SERVICE','WORKS_BOQ','LOGISTICS','OTHER'],
            };
        },
        methods: {
            emptyDraft: function (kind) {
                return { item_ref:'', description:'', spec_notes:'', qty:1, uom:'', line_kind: kind || defaultKind };
            },
            fmtQty: function (n) {
                var f = parseFloat(n); if (!isFinite(f)) return '—';
                return f % 1 === 0 ? String(f) : f.toFixed(4).replace(/0+$/,'').replace(/\.$/,'');
            },
            kindLabel: function (k) { return KIND_LABELS[k] || k; },
            kindStyle: function (k) { return (KIND_STYLES[k] || KIND_STYLES.OTHER) + 'font-size:.66rem;text-transform:capitalize;'; },
            beginAdd: function () {
                this.editingId = 0;
                this.draft = this.emptyDraft(defaultKind);
                this.adding = true;
            },
            cancelAdd: function () { this.adding = false; this.draft = this.emptyDraft(defaultKind); },
            beginEdit: function (it) {
                this.adding = false;
                this.editingId = it.c0d;
                this.draft = {
                    item_ref: it.item_ref || '', description: it.description, spec_notes: it.spec_notes || '',
                    qty: parseFloat(it.qty), uom: it.uom || '', line_kind: it.line_kind,
                };
            },
            cancelEdit: function () { this.editingId = 0; this.draft = this.emptyDraft(defaultKind); },
            saveNew: function () {
                if (!this.draft.description || !this.draft.description.trim()) {
                    if (window.rsToast) rsToast('Description is required.', 'warning'); return;
                }
                var self = this; this.busy = true;
                $.post(PROOT + 'Tenders/itemsAddAj', $.extend({ tender_id: TID }, this.draft), null, 'json')
                    .always(function () { self.busy = false; })
                    .done(function (res) {
                        if (res && res.ok) {
                            self.items.push({
                                c0d: res.id, tender_id: TID, line_no: self.items.length + 1,
                                item_ref: self.draft.item_ref || null,
                                description: self.draft.description,
                                spec_notes: self.draft.spec_notes || null,
                                qty: self.draft.qty, uom: self.draft.uom || null,
                                line_kind: self.draft.line_kind,
                            });
                            self.cancelAdd();
                            if (window.rsToast) rsToast('Line added.', 'success');
                        } else if (window.rsToast) rsToast('Add failed: ' + (res && res.msg || 'unknown'), 'error');
                    })
                    .fail(function () { if (window.rsToast) rsToast('Network error adding line.', 'error'); });
            },
            saveEdit: function () {
                if (!this.draft.description || !this.draft.description.trim()) {
                    if (window.rsToast) rsToast('Description is required.', 'warning'); return;
                }
                var self = this, iid = this.editingId; this.busy = true;
                $.post(PROOT + 'Tenders/itemsUpdateAj', $.extend({ item_id: iid }, this.draft), null, 'json')
                    .always(function () { self.busy = false; })
                    .done(function (res) {
                        if (res && res.ok) {
                            var i = self.items.findIndex(function (x) { return x.c0d === iid; });
                            if (i >= 0) {
                                self.items[i].item_ref    = self.draft.item_ref || null;
                                self.items[i].description = self.draft.description;
                                self.items[i].spec_notes  = self.draft.spec_notes || null;
                                self.items[i].qty         = self.draft.qty;
                                self.items[i].uom         = self.draft.uom || null;
                                self.items[i].line_kind   = self.draft.line_kind;
                            }
                            self.cancelEdit();
                            if (window.rsToast) rsToast('Line updated.', 'success');
                        } else if (window.rsToast) rsToast('Update failed: ' + (res && res.msg || 'unknown'), 'error');
                    })
                    .fail(function () { if (window.rsToast) rsToast('Network error updating line.', 'error'); });
            },
            remove: function (it) {
                var self = this;
                $.confirm({ title: 'Remove line?', content: 'This will remove line ' + it.line_no + ' — ' + it.description + '.',
                    buttons: {
                        yes: { text: 'Remove', btnClass: 'btn-danger', action: function () {
                            $.post(PROOT + 'Tenders/itemsRemoveAj', { item_id: it.c0d }, null, 'json')
                                .done(function (res) {
                                    if (res && res.ok) {
                                        self.items = self.items.filter(function (x) { return x.c0d !== it.c0d; });
                                        if (window.rsToast) rsToast('Line removed.', 'success');
                                    } else if (window.rsToast) rsToast('Remove failed: ' + (res && res.msg || 'unknown'), 'error');
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            openBulk: function () {
                var self = this;
                var html = '' +
                    '<div class="small mb-2" style="color:#64748B;">One line per row. Format: <code>description | qty | uom | item_ref | spec_notes</code> (only description is required). Kind defaults to <strong>' + KIND_LABELS[defaultKind] + '</strong>.</div>' +
                    '<textarea id="ti_bulk_ta" class="form-control" rows="10" placeholder="Fiber optic cable OM4 | 500 | m | FO-OM4 | LSZH jacket\nSC/APC connector | 200 | ea"></textarea>';
                $.confirm({ title: 'Bulk paste tender items', content: html, columnClass: 'col-md-8',
                    buttons: {
                        yes: { text: 'Import', btnClass: 'btn-primary', action: function () {
                            var raw = $('#ti_bulk_ta').val() || '';
                            var lines = raw.split(/\r?\n/).map(function (l) { return l.trim(); }).filter(Boolean);
                            var rows = lines.map(function (l) {
                                var parts = l.split('|').map(function (s) { return s.trim(); });
                                return {
                                    description: parts[0] || '', qty: parts[1] || 1, uom: parts[2] || '',
                                    item_ref: parts[3] || '',  spec_notes: parts[4] || '',
                                    line_kind: defaultKind,
                                };
                            });
                            if (!rows.length) { if (window.rsToast) rsToast('Nothing to import.', 'warning'); return; }
                            $.post(PROOT + 'Tenders/itemsBulkImportAj', { tender_id: TID, rows: JSON.stringify(rows) }, null, 'json')
                                .done(function (res) {
                                    if (res && res.added) {
                                        if (window.rsToast) rsToast(res.added + ' line(s) imported. Reloading tab…', 'success');
                                        $.getJSON(PROOT + 'Tenders/itemsListAj', { tender_id: TID }, function (r) {
                                            if (r && r.ok) self.items = r.items;
                                        });
                                    } else if (window.rsToast) rsToast('Import failed.', 'error');
                                });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
        },
    });

    $(document).ready(function () {
        if (typeof Vue === 'undefined') {
            $('#ti_app_root').removeAttr('v-cloak').css('display','block');
            $('#ti_app_root').prepend('<div class="alert alert-warning small">Items UI could not initialise (Vue failed to load). Refresh the page.</div>');
            return;
        }
        if (document.getElementById('ti_app_root')) app.mount('#ti_app_root');
    });
})();
</script>

<!-- Slice 8W · Awarded tab · Vue 3 Options API root (reactive save + reason categories + stage advance) -->
<script>
(function () {
    var TID   = <?= (int)$t['c0d']; ?>;
    var PROOT = <?= json_encode(PROOT); ?>;
    var bootResult       = <?= json_encode($this->data['result'] ?? null, JSON_UNESCAPED_SLASHES); ?>;
    var bootStage        = <?= json_encode((string)$t['tender_stage']); ?>;
    var bootStatus       = <?= json_encode((string)$t['tender_status']); ?>;
    var bootOurBidder    = <?= json_encode($ourBidderName); ?>;
    var bootOurSubAmount = <?= (float)$ourSubAmount; ?>;
    var canWriteResult   = <?= $canWriteResult; ?>;
    var canAdvanceStage  = <?= $canAdvanceStage; ?>;

    // Slice 8X · seed handover flags from the current server state (contract terms + signing).
    var bootHandover = <?php
        $ht = $this->data['contract_terms']   ?? null;
        $hs = $this->data['contract_signing'] ?? null;
        $ha = $this->data['contract_approval']?? null;
        echo json_encode([
            'award_recorded'    => ((string)($t['tender_status'] ?? '') === 'WON'),
            'fm_assigned'       => (int)($ht['assigned_fm_user_id']          ?? 0) > 0,
            'terms_filled'      => $ht !== null && (float)($ht['contract_value'] ?? 0) > 0,
            'fm_team_assigned'  => (int)($ht['assigned_accountant_user_id']  ?? 0) > 0 && (int)($ht['assigned_procurement_user_id'] ?? 0) > 0,
            'submitted'         => $ha !== null,
            'exec_approved'     => (string)($ha['status'] ?? '') === 'APPROVED',
            'pm_assigned'       => (int)($ht['assigned_pm_user_id']          ?? 0) > 0,
            'signed'            => $hs !== null,
        ], JSON_UNESCAPED_SLASHES);
    ?>;

    var STAGES = ['PREP','SUBMISSION','FOLLOW_UP','OPENING','NEGOTIATIONS','AWARDED','CONTRACT_SIGNING','EXECUTION'];
    var STAGE_LABEL = {
        PREP: 'Prep', SUBMISSION: 'Submission', FOLLOW_UP: 'Follow up', OPENING: 'Opening',
        NEGOTIATIONS: 'Negotiations', AWARDED: 'Awarded', CONTRACT_SIGNING: 'Contract signing', EXECUTION: 'Execution',
    };
    var STATUS_LABEL = { WON: 'Won', LOST: 'Lost', CANCELLED: 'Cancelled', WITHDRAWN: 'Withdrawn' };
    var STATUS_STYLE = {
        WON:       'background:#7A9E7E;color:#fff;font-size:.66rem;text-transform:capitalize;font-weight:500;',
        LOST:      'background:#C48579;color:#fff;font-size:.66rem;text-transform:capitalize;font-weight:500;',
        CANCELLED: 'background:#94A3B8;color:#fff;font-size:.66rem;text-transform:capitalize;font-weight:500;',
        WITHDRAWN: 'background:#94A3B8;color:#fff;font-size:.66rem;text-transform:capitalize;font-weight:500;',
    };

    // Reason categories keyed by status. Order matters: shown as-is in the dropdown.
    var REASON_CATS = {
        WON: [
            { key:'WON_BEST_PRICE',      label:'Best price' },
            { key:'WON_BEST_TECHNICAL',  label:'Best technical / spec compliance' },
            { key:'WON_EXPERIENCE',      label:'Experience / references' },
            { key:'WON_RELATIONSHIP',    label:'Client relationship' },
            { key:'WON_SOLE_BIDDER',     label:'Sole bidder' },
            { key:'WON_OTHER',           label:'Other' },
        ],
        LOST: [
            { key:'LOST_PRICE_TOO_HIGH',    label:'Price too high' },
            { key:'LOST_TECHNICAL_GAP',     label:'Technical / spec gap' },
            { key:'LOST_UNFINISHED_DOCS',   label:'Unfinished documentation' },
            { key:'LOST_LATE_SUBMISSION',   label:'Late submission' },
            { key:'LOST_CLIENT_INTERNAL',   label:'Client internal / political' },
            { key:'LOST_OTHER',             label:'Other' },
        ],
        CANCELLED: [
            { key:'CANCELLED_CLIENT_CANCELLED', label:'Client cancelled the tender' },
            { key:'CANCELLED_SCOPE_CHANGE',     label:'Scope changed materially' },
            { key:'CANCELLED_FUNDING_LOST',     label:'Client lost funding' },
            { key:'CANCELLED_OTHER',            label:'Other' },
        ],
        WITHDRAWN: [
            { key:'WITHDRAWN_TIME_PRESSURE',        label:'Not enough time to bid properly' },
            { key:'WITHDRAWN_DECIDED_NOT_TO_BID',   label:'Decided not to bid (strategic)' },
            { key:'WITHDRAWN_RESOURCE_UNAVAILABLE', label:'Resources unavailable' },
            { key:'WITHDRAWN_OTHER',                label:'Other' },
        ],
    };
    var ALL_CAT_LABELS = {};
    Object.keys(REASON_CATS).forEach(function (st) {
        REASON_CATS[st].forEach(function (c) { ALL_CAT_LABELS[c.key] = c.label; });
    });

    function emptyDraftFromResult(r) {
        return {
            result_status:   r ? r.result_status : 'WON',
            result_date:     r && r.result_date ? r.result_date : new Date().toISOString().slice(0, 10),
            winning_bidder:  r ? (r.winning_bidder  || '') : '',
            winning_amount:  r ? (parseFloat(r.winning_amount) || 0) : 0,
            reason_category: r ? (r.reason_category || '') : '',
            reason:          r ? (r.reason  || '') : '',
            lessons:         r ? (r.lessons || '') : '',
        };
    }

    var app = Vue.createApp({
        data: function () {
            return {
                PROOT: PROOT,
                STATUSES: ['WON','LOST','CANCELLED','WITHDRAWN'],
                result:          bootResult,
                tenderStage:     bootStage,
                tenderStatus:    bootStatus,
                ourBidderName:   bootOurBidder,
                ourSubAmount:    bootOurSubAmount,
                canWriteResult:  canWriteResult,
                canAdvanceStage: canAdvanceStage,
                draft:           emptyDraftFromResult(bootResult),
                advanceNotes:    '',
                busySave:        false,
                busyAdvance:     false,
                winnerFilledFromProfile:  false,
                amountFilledFromSubmission: false,
                handover:        bootHandover,
            };
        },
        computed: {
            nextStage: function () {
                var i = STAGES.indexOf(this.tenderStage);
                return (i >= 0 && i < STAGES.length - 1) ? STAGES[i + 1] : null;
            },
            // Slice 8X · Handover-to-FM sequence, reactive to result + tenderStatus changes.
            handoverSteps: function () {
                var h = this.handover || {};
                var wonNow = h.award_recorded || this.tenderStatus === 'WON' || (this.result && this.result.result_status === 'WON');
                return [
                    { label: 'Award recorded',                     done: !!wonNow },
                    { label: 'CRM assigns FM',                     done: !!h.fm_assigned },
                    { label: 'FM fills contract terms',            done: !!h.terms_filled },
                    { label: 'FM assigns Accountant + Procurement',done: !!h.fm_team_assigned },
                    { label: 'Submit for FM verify',               done: !!h.submitted },
                    { label: 'Executive approves',                 done: !!h.exec_approved },
                    { label: 'Exec assigns PM',                    done: !!h.pm_assigned },
                    { label: 'Signing recorded',                   done: !!h.signed },
                ];
            },
            handoverDoneCount: function () {
                var n = 0; this.handoverSteps.forEach(function (s) { if (s.done) n++; }); return n;
            },
            handoverNextLabel: function () {
                var next = this.handoverSteps.find(function (s) { return !s.done; });
                return next ? next.label : 'All complete';
            },
        },
        methods: {
            fmt0: function (n) { var f = parseFloat(n); if (!isFinite(f)) f = 0; return f.toLocaleString('en-US', { maximumFractionDigits: 0 }); },
            stageLabel: function (s) { return STAGE_LABEL[s] || s; },
            statusLabel: function (s) { return STATUS_LABEL[s] || s; },
            statusBadgeStyle: function (s) { return STATUS_STYLE[s] || STATUS_STYLE.LOST; },
            categoryLabel: function (k) { return ALL_CAT_LABELS[k] || k; },
            categoriesForStatus: function (status) { return REASON_CATS[status] || []; },
            // Slice 8X · handover chip appearance (done = sage, current = tan, future = grey)
            handoverChipStyle: function (s, i) {
                var firstUndoneIdx = this.handoverSteps.findIndex(function (x) { return !x.done; });
                var isCurrent = (i === firstUndoneIdx);
                var base = 'font-size:.72rem;font-weight:500;text-transform:capitalize;padding:.45rem .7rem;line-height:1.3;';
                if (s.done)          return base + 'background:#EAF2E8;color:#3F5C43;border:1px solid #7A9E7E;';
                if (isCurrent)       return base + 'background:#FEF3E7;color:#8B6914;border:1px solid #D4A574;';
                return base + 'background:#F1F5F9;color:#94A3B8;border:1px solid #E2E8F0;';
            },
            handoverChipIcon: function (s, i) {
                if (s.done) return 'fa-check';
                // Icon per index — mirrors the PHP mapping on the Contract Signing tab.
                var icons = ['fa-flag-checkered','fa-user-tie','fa-file-contract','fa-users','fa-paper-plane','fa-check-double','fa-user-check','fa-signature'];
                return icons[i] || 'fa-circle';
            },
            onStatusChange: function () {
                // If category doesn't match new status prefix, clear it.
                if (this.draft.reason_category && !this.draft.reason_category.startsWith(this.draft.result_status + '_')) {
                    this.draft.reason_category = '';
                }
                // Auto-populate winner + amount on WON if fields are empty/zero.
                if (this.draft.result_status === 'WON') {
                    if (this.ourBidderName && !(this.draft.winning_bidder || '').trim()) {
                        this.draft.winning_bidder = this.ourBidderName;
                        this.winnerFilledFromProfile = true;
                    }
                    if (this.ourSubAmount > 0 && (parseFloat(this.draft.winning_amount) || 0) === 0) {
                        this.draft.winning_amount = this.ourSubAmount;
                        this.amountFilledFromSubmission = true;
                    }
                } else {
                    this.winnerFilledFromProfile = false;
                    this.amountFilledFromSubmission = false;
                }
            },
            saveResult: function () {
                var self = this; self.busySave = true;
                $.post(PROOT + 'Tenders/recordResultAj', {
                    tender_id:       TID,
                    result_status:   self.draft.result_status,
                    result_date:     self.draft.result_date,
                    winning_bidder:  self.draft.winning_bidder,
                    winning_amount:  self.draft.winning_amount || '',
                    reason:          self.draft.reason,
                    reason_category: self.draft.reason_category,
                    lessons:         self.draft.lessons,
                }, null, 'json')
                    .always(function () { self.busySave = false; })
                    .done(function (res) {
                        if (res && res.ok) {
                            rsToast('Result saved.', 'success');
                            self.result = res.result || self.result;
                            if (res.tender_stage)  self.tenderStage  = res.tender_stage;
                            if (res.tender_status) self.tenderStatus = res.tender_status;
                        } else rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                    })
                    .fail(function () { rsToast('Network error saving result.', 'error'); });
            },
            advanceStage: function () {
                var self = this; if (!self.nextStage) return;
                self.busyAdvance = true;
                $.post(PROOT + 'Tenders/advanceStageAj', {
                    tender_id: TID, stage: self.nextStage, notes: self.advanceNotes || '',
                }, null, 'json')
                    .always(function () { self.busyAdvance = false; })
                    .done(function (res) {
                        if (res && res.ok) {
                            rsToast('Advanced to ' + self.stageLabel(self.nextStage) + '.', 'success');
                            self.tenderStage = self.nextStage;
                            self.advanceNotes = '';
                        } else rsToast('Advance failed: ' + (res && res.msg || 'unknown'), 'error', 5000);
                    })
                    .fail(function () { rsToast('Network error advancing stage.', 'error'); });
            },
        },
        // Fire status-change logic once on mount so an existing WON result with empty winner still gets the hint.
        mounted: function () { this.onStatusChange(); },
    });

    $(document).ready(function () {
        if (typeof Vue === 'undefined') {
            $('#tab_awarded_root').removeAttr('v-cloak').css('display','block');
            $('#tab_awarded_root').prepend('<div class="alert alert-warning small">Awarded UI could not initialise (Vue failed to load). Refresh the page.</div>');
            return;
        }
        if (document.getElementById('tab_awarded_root')) {
            try { app.mount('#tab_awarded_root'); }
            catch (e) {
                console.error('[awarded-vue] mount threw:', e);
                $('#tab_awarded_root').removeAttr('v-cloak').css('display','block');
                $('#tab_awarded_root').prepend('<div class="alert alert-danger small">Awarded UI failed to mount: ' + (e && e.message || e) + ' — see console.</div>');
            }
        }
    });
})();
</script>

<!-- Slice 8Z-q · Bonds & Receipts tracker + FM verification attachments · Vue 3 Options API root -->
<script>
(function () {
    var TID   = <?= (int)$t['c0d']; ?>;
    var PROOT = <?= json_encode(PROOT); ?>;
    var bootBonds        = <?= json_encode($this->data['contract_bonds']        ?? [], JSON_UNESCAPED_SLASHES); ?>;
    var bootFmAttach     = <?= json_encode($this->data['fm_verify_attachments'] ?? [], JSON_UNESCAPED_SLASHES); ?>;
    var bootCanBondWrite  = <?= UserGroups::can('Tenders','bondSaveAj')       ? 'true' : 'false'; ?>;
    var bootCanFmAttWrite = <?= UserGroups::can('Tenders','fmAttachUploadAj') ? 'true' : 'false'; ?>;

    if (typeof Vue === 'undefined') {
        $('#ct_fm_root').removeAttr('v-cloak').css('display','block');
        $('#ct_fm_root').prepend('<div class="alert alert-warning small">Bonds + FM attachments UI could not initialise (Vue failed to load).</div>');
        return;
    }

    var app = Vue.createApp({
        data: function () {
            return {
                PROOT: PROOT, TID: TID,
                bonds:         (bootBonds || []).slice(),
                fmAttach:      (bootFmAttach || []).slice(),
                canBondWrite:  bootCanBondWrite,
                canFmAttWrite: bootCanFmAttWrite,
                bondTypeLabels: {
                    'CLIENT_ADVANCE'      : 'Client advance received',
                    'APG'                 : 'Advance Payment Guarantee',
                    'PERFORMANCE_BOND'    : 'Performance bond',
                    'RETENTION_BOND'      : 'Retention bond',
                    'INSURANCE_CERT'      : 'Insurance certificate',
                    'TAX_CLEARANCE'       : 'TRA tax clearance',
                    'VAT_EXEMPTION_CERT'  : 'VAT exemption certificate',
                    'OTHER_GUARANTEE'     : 'Other guarantee'
                },
                statusColors:  { 'PENDING':'#D4A574', 'RECEIVED':'#7A9E7E', 'NA':'#94A3B8', 'EXPIRED':'#C48579' },
                expiryColors:  { 'OK':'#94A3B8', 'DUE_SOON':'#D4A574', 'OVERDUE':'#C48579' },
                bondStatuses:  ['PENDING','RECEIVED','NA','EXPIRED'],
                fmSubtypes: [
                    ['COVER_MEMO',               'FM cover memo',            true],
                    ['CASH_FLOW',                'Cash-flow projection',     true],
                    ['PROFITABILITY_MODEL',      'Profitability model',      true],
                    ['BANK_FACILITY_LETTER',     'Bank facility letter',     false],
                    ['CREDIT_ASSESSMENT',        'Client credit assessment', false],
                    ['FX_HEDGING_MEMO',          'FX hedging memo',          false],
                    ['INSURANCE_CHECKLIST',      'Insurance checklist',      false],
                    ['RELATED_PARTY_DISCLOSURE', 'Related-party disclosure', false],
                    ['OTHER',                    'Other',                    false]
                ]
            };
        },
        computed: {
            mandatoryTotal: function () { return this.fmSubtypes.filter(function (s) { return s[2]; }).length; },
            presentSubtypes: function () {
                var s = {};
                this.fmAttach.forEach(function (a) { s[a.subtype] = true; });
                return s;
            },
            mandatoryDone: function () {
                var present = this.presentSubtypes;
                return this.fmSubtypes.filter(function (s) { return s[2] && present[s[0]]; }).length;
            },
            missingLabels: function () {
                var present = this.presentSubtypes;
                return this.fmSubtypes.filter(function (s) { return s[2] && !present[s[0]]; }).map(function (s) { return s[1]; });
            },
            mandatoryOk: function () { return this.missingLabels.length === 0; }
        },
        methods: {
            fmtAmt: function (n) { var v = parseFloat(n); return isFinite(v) ? v.toLocaleString('en-US', { maximumFractionDigits: 0 }) : ''; },
            fmtKb:  function (b) { var v = parseFloat(b); return isFinite(v) ? (v/1024).toFixed(1) : '0.0'; },
            fmtWhen: function (iso) {
                if (!iso) return '';
                var d = new Date(iso.replace(' ', 'T'));
                if (isNaN(d.getTime())) return iso;
                var M = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
                return d.getDate() + ' ' + M[d.getMonth()] + ' · ' + String(d.getHours()).padStart(2,'0') + ':' + String(d.getMinutes()).padStart(2,'0');
            },
            statusColor: function (s) { return this.statusColors[s] || '#94A3B8'; },
            expiryColor: function (c) { return this.expiryColors[c] || '#94A3B8'; },
            subtypeLabel: function (k) {
                var m = this.fmSubtypes.find(function (s) { return s[0] === k; });
                return m ? m[1] : k;
            },
            isMandatorySubtype: function (k) {
                var m = this.fmSubtypes.find(function (s) { return s[0] === k; });
                return m ? m[2] : false;
            },

            // Re-fetch both lists from the server so expiry_chip stays accurate.
            // Also ping the Contract-signing completeness gate so the "Before handing off, fill"
            // yellow list + the Verify button both refresh in-place — FM attachment changes affect it.
            refresh: function () {
                var self = this;
                $.post(PROOT + 'Tenders/bondsListAj',    { tender_id: TID }, 'json').done(function (res) {
                    if (res && res.ok) self.bonds = res.rows || [];
                });
                $.post(PROOT + 'Tenders/fmAttachListAj', { tender_id: TID }, 'json').done(function (res) {
                    if (res && res.ok) self.fmAttach = res.rows || [];
                });
                if (typeof window.rsRefreshContractCompleteness === 'function') window.rsRefreshContractCompleteness();
            },

            /* ── Bonds ──────────────────────────────────────────────── */
            bondFormHtml: function (b) {
                b = b || {};
                var typeOptions = '', statusOptions = '', curOptions = '';
                var bt = b.bond_type || 'PERFORMANCE_BOND';
                for (var k in this.bondTypeLabels) {
                    typeOptions += '<option value="' + k + '"' + (k === bt ? ' selected' : '') + '>' + this.bondTypeLabels[k] + '</option>';
                }
                var bs = b.status || 'PENDING';
                this.bondStatuses.forEach(function (s) {
                    statusOptions += '<option value="' + s + '"' + (s === bs ? ' selected' : '') + '>' + s + '</option>';
                });
                var bc = b.currency || 'TZS';
                ['TZS','USD','EUR','GBP'].forEach(function (c) {
                    curOptions += '<option value="' + c + '"' + (c === bc ? ' selected' : '') + '>' + c + '</option>';
                });
                var esc = function (s) { return String(s || '').replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;'); };
                return ''
                  + '<div class="mb-2"><label class="form-label small text-muted" style="font-size:.68rem;">Type</label>'
                  + '<select id="bond_type" class="form-select form-select-sm">' + typeOptions + '</select></div>'
                  + '<div class="row g-2"><div class="col-4"><label class="form-label small text-muted" style="font-size:.68rem;">Status</label>'
                  + '<select id="bond_status" class="form-select form-select-sm">' + statusOptions + '</select></div>'
                  + '<div class="col-4"><label class="form-label small text-muted" style="font-size:.68rem;">Received</label>'
                  + '<input type="date" id="bond_recv" class="form-control form-control-sm" value="' + esc(b.received_date) + '"></div>'
                  + '<div class="col-4"><label class="form-label small text-muted" style="font-size:.68rem;">Valid until</label>'
                  + '<input type="date" id="bond_valid" class="form-control form-control-sm" value="' + esc(b.validity_until) + '"></div></div>'
                  + '<div class="row g-2 mt-1"><div class="col-6"><label class="form-label small text-muted" style="font-size:.68rem;">Reference no</label>'
                  + '<input type="text" id="bond_ref" class="form-control form-control-sm" value="' + esc(b.reference_no) + '"></div>'
                  + '<div class="col-6"><label class="form-label small text-muted" style="font-size:.68rem;">Issuer</label>'
                  + '<input type="text" id="bond_issuer" class="form-control form-control-sm" placeholder="e.g. CRDB Bank" value="' + esc(b.issuer) + '"></div></div>'
                  + '<div class="row g-2 mt-1"><div class="col-6"><label class="form-label small text-muted" style="font-size:.68rem;">Amount</label>'
                  + '<input type="number" step="0.01" id="bond_amt" class="form-control form-control-sm" value="' + esc(b.amount) + '"></div>'
                  + '<div class="col-6"><label class="form-label small text-muted" style="font-size:.68rem;">Currency</label>'
                  + '<select id="bond_cur" class="form-select form-select-sm">' + curOptions + '</select></div></div>'
                  + '<div class="mt-2"><label class="form-label small text-muted" style="font-size:.68rem;">Remarks</label>'
                  + '<textarea id="bond_rem" class="form-control form-control-sm" rows="2">' + esc(b.remarks) + '</textarea></div>';
            },
            collectBondPayload: function () {
                return {
                    tender_id:      this.TID,
                    bond_type:      $('#bond_type').val(),
                    status:         $('#bond_status').val(),
                    reference_no:   $('#bond_ref').val(),
                    issuer:         $('#bond_issuer').val(),
                    amount:         $('#bond_amt').val(),
                    currency:       $('#bond_cur').val(),
                    received_date:  $('#bond_recv').val(),
                    validity_until: $('#bond_valid').val(),
                    remarks:        $('#bond_rem').val()
                };
            },
            openBondAdd: function () {
                var self = this;
                $.confirm({
                    title: 'Add bond / receipt', content: self.bondFormHtml({}),
                    columnClass: 'medium', type: 'blue',
                    buttons: {
                        save: { text: 'Save', btnClass: 'btn-primary', action: function () {
                            $.post(PROOT + 'Tenders/bondSaveAj', self.collectBondPayload(), 'json').done(function (res) {
                                if (res && res.ok) { if (window.rsToast) rsToast('Bond added.', 'success'); self.refresh(); }
                                else if (window.rsToast) rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            openBondEdit: function (b) {
                var self = this;
                $.confirm({
                    title: 'Edit bond / receipt', content: self.bondFormHtml(b),
                    columnClass: 'medium', type: 'blue',
                    buttons: {
                        save: { text: 'Save', btnClass: 'btn-primary', action: function () {
                            var p = self.collectBondPayload();
                            p.c0d = b.c0d;
                            $.post(PROOT + 'Tenders/bondSaveAj', p, 'json').done(function (res) {
                                if (res && res.ok) { if (window.rsToast) rsToast('Bond saved.', 'success'); self.refresh(); }
                                else if (window.rsToast) rsToast('Save failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            deleteBond: function (b) {
                var self = this;
                $.confirm({
                    title: 'Remove this bond?',
                    content: 'The bond row will be soft-deleted; the file (if any) is removed from disk. Audit history survives.',
                    type: 'orange',
                    buttons: {
                        yes: { text: 'Remove', btnClass: 'btn-warning', action: function () {
                            $.post(PROOT + 'Tenders/bondRemoveAj', { bond_id: b.c0d }, 'json').done(function (res) {
                                if (res && res.ok) {
                                    if (window.rsToast) rsToast('Removed.', 'success');
                                    self.bonds = self.bonds.filter(function (x) { return x.c0d !== b.c0d; });
                                } else if (window.rsToast) rsToast('Remove failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            openBondUpload: function (b) {
                var self = this;
                $.confirm({
                    title: 'Upload document for this bond',
                    content: '<input type="file" id="bond_upload_file" class="form-control form-control-sm" accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.zip">'
                           + '<div class="small text-muted mt-2" style="font-size:.66rem;">PDF, image, DOC/DOCX, XLS/XLSX, ZIP. Max 10 MB. Replaces the existing doc if any.</div>',
                    type: 'blue',
                    buttons: {
                        upload: { text: 'Upload', btnClass: 'btn-primary', action: function () {
                            var f = document.getElementById('bond_upload_file');
                            if (!f || !f.files || !f.files[0]) { if (window.rsToast) rsToast('Pick a file first.', 'warning'); return false; }
                            var fd = new FormData();
                            fd.append('bond_id',   b.c0d);
                            fd.append('bond_file', f.files[0]);
                            $.ajax({
                                url: PROOT + 'Tenders/bondDocUploadAj', type: 'POST',
                                data: fd, contentType: false, processData: false, dataType: 'json'
                            }).done(function (res) {
                                if (res && res.ok) { if (window.rsToast) rsToast('Document uploaded.', 'success'); self.refresh(); }
                                else if (window.rsToast) rsToast('Upload failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },

            /* ── FM verification attachments ────────────────────────── */
            openFmUpload: function () {
                var self = this;
                var opts = '';
                self.fmSubtypes.forEach(function (s) {
                    opts += '<option value="' + s[0] + '">' + s[1] + (s[2] ? ' *' : '') + '</option>';
                });
                $.confirm({
                    title: 'Upload FM verification document',
                    content: '<div class="mb-2"><label class="form-label small text-muted" style="font-size:.68rem;">Subtype (starred = mandatory before Approve)</label>'
                           + '<select id="fmatt_subtype" class="form-select form-select-sm">' + opts + '</select></div>'
                           + '<div class="mb-2"><label class="form-label small text-muted" style="font-size:.68rem;">Label (optional)</label>'
                           + '<input type="text" id="fmatt_label" class="form-control form-control-sm" placeholder="Leave blank for default"></div>'
                           + '<div class="mb-2"><input type="file" id="fmatt_file" class="form-control form-control-sm" accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.zip,.txt"></div>'
                           + '<div class="small text-muted mt-1" style="font-size:.66rem;">PDF, image, DOC/DOCX, XLS/XLSX, ZIP. Max 10 MB.</div>',
                    type: 'blue', columnClass: 'medium',
                    buttons: {
                        upload: { text: 'Upload', btnClass: 'btn-primary', action: function () {
                            var f = document.getElementById('fmatt_file');
                            if (!f || !f.files || !f.files[0]) { if (window.rsToast) rsToast('Pick a file first.', 'warning'); return false; }
                            var fd = new FormData();
                            fd.append('tender_id', TID);
                            fd.append('subtype',   $('#fmatt_subtype').val());
                            fd.append('label',     $('#fmatt_label').val());
                            fd.append('fm_file',   f.files[0]);
                            $.ajax({
                                url: PROOT + 'Tenders/fmAttachUploadAj', type: 'POST',
                                data: fd, contentType: false, processData: false, dataType: 'json'
                            }).done(function (res) {
                                if (res && res.ok) { if (window.rsToast) rsToast('Uploaded.', 'success'); self.refresh(); }
                                else if (window.rsToast) rsToast('Upload failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            },
            deleteFmAttach: function (a) {
                var self = this;
                $.confirm({
                    title: 'Remove this attachment?',
                    content: 'File is removed from disk. Audit row survives (deleted=1).',
                    type: 'orange',
                    buttons: {
                        yes: { text: 'Remove', btnClass: 'btn-warning', action: function () {
                            $.post(PROOT + 'Tenders/fmAttachRemoveAj', { attachment_id: a.c0d }, 'json').done(function (res) {
                                if (res && res.ok) {
                                    if (window.rsToast) rsToast('Removed.', 'success');
                                    self.fmAttach = self.fmAttach.filter(function (x) { return x.c0d !== a.c0d; });
                                    // Deleting a mandatory subtype may re-block the Verify button.
                                    if (typeof window.rsRefreshContractCompleteness === 'function') window.rsRefreshContractCompleteness();
                                } else if (window.rsToast) rsToast('Remove failed: ' + (res && res.msg || 'unknown'), 'error');
                            });
                        }},
                        cancel: { text: 'Cancel', btnClass: 'btn-light' }
                    }
                });
            }
        }
    });

    $(document).ready(function () {
        if (document.getElementById('ct_fm_root')) {
            try { app.mount('#ct_fm_root'); }
            catch (e) {
                console.error('[ct-fm-vue] mount threw:', e);
                $('#ct_fm_root').removeAttr('v-cloak').css('display','block');
                $('#ct_fm_root').prepend('<div class="alert alert-danger small">Bonds + FM UI failed to mount: ' + (e && e.message || e) + ' — see console.</div>');
            }
        }
    });
})();
</script>
<?php $this->end(); ?>
