{{--
    Create Sales Order terminal — see App\Filament\Resources\SalesOrderResource\Pages\CreateSalesOrder.

    A copy of the POS terminal (resources/views/filament/pages/pos.blade.php)
    adjusted for the sales order requirements. Same full-height two-panel layout
    (products left, order panel right), same category/subcategory filters, same
    image product cards, same per-line quantity/discount controls — but:

      * No till --- open/close session, cash movements, held sales, amend and
        the exchange/fix sheet are all gone: an order is a promise, money and
        stock only move at the "Invoice this order" action after conversion.
      * A customer is mandatory (no walk-in mode); the branch is picked per
        device on the order desk (no till to inherit it from).
      * The order's own header lives on the panel: order date, delivery
        deadline, sales rep, status and note.
      * Instead of a checkout sheet there are optional advance payments
        (methods, credit notes, reference/cheque/custom fields), capped at the
        order total; nothing has to be paid now.
      * No vouchers, no loyalty, no serial tracking, no bundles: none of those
        are recorded on an order.
      * Out-of-stock catalog items still go on the cart — a sales order is a
        promise about the future — via the virtual quotation lot
        (SalesOrderCatalogService), priced from the last receipt.
      * Made-to-order lines have their own "custom item" builder: described in
        words, priced as quoted, no stock at all.

    Cart state (lines, quantities, discounts, advances) is ENTIRELY client-side
    Alpine, same as the POS terminal. Server calls happen only at real
    boundaries: branch changes, customer credit-note lookup, and createOrder().

    Display state (expanded vs. minimized) is a persisted client-side flag in
    localStorage, identical to the POS terminal's.
--}}
<x-filament-panels::page>
    <div
        wire:ignore
        x-data="salesOrderTerminal({
            products: @js($products),
            customers: @js($customers),
            salesReps: @js($salesReps),
            statuses: @js($statuses),
            defaultStatus: @js($defaultStatus),
            branches: @js($branches),
            selectedBranchId: @js($selectedBranchId),
            branchRequired: @js($branchRequired),
            serverPaymentMethods: @js($paymentMethods),
            canDiscount: @js($canDiscount),
            canOverrideBatch: @js($canOverrideBatch),
            vatEnabled: @js($vatEnabled),
            businessName: @js($businessName),
            autoInvoice: @js($autoInvoice),
            today: @js($today),
            labelPrefix: @js($labelPrefix),
        })"
        class="fi-pos fi-create-sales-order"
    >
        <div
            :class="expanded ? 'fixed inset-0 z-50 h-full w-full rounded-none shadow-none' : 'h-[calc(100dvh-10.5rem)] min-h-[30rem] rounded-xl shadow-sm'"
            class="flex overflow-hidden border border-gray-200 bg-white dark:border-white/10 dark:bg-gray-900"
        >
            {{-- ── Products panel ─────────────────────────────────────────── --}}
            <div
                :class="cartExpanded ? 'w-1/2 shrink-0' : 'flex-1'"
                class="flex min-w-0 flex-col border-r border-gray-200 dark:border-white/10"
            >
                <div class="shrink-0 border-b border-gray-200 dark:border-white/10">
                    <div class="p-3 pb-2">
                        <div class="flex gap-2">
                            <div class="relative flex-1">
                                <x-filament::icon icon="heroicon-m-magnifying-glass" class="pointer-events-none absolute inset-y-0 start-3 my-auto h-4 w-4 text-gray-400" />
                                <input
                                    x-ref="searchInput"
                                    type="search"
                                    x-model="search"
                                    x-on:keydown.enter="scanAdd()"
                                    placeholder="Search or scan barcode… (F2)"
                                    class="fi-input w-full rounded-lg border-gray-300 ps-9 dark:bg-gray-800"
                                    {{-- This box already owns Enter (scanAdd() above) — the
                                         page-wide scan listener must stay out of its way. See
                                         resources/views/filament/partials/scan-capture-script.blade.php. --}}
                                    data-scan-ignore
                                >
                            </div>
                            <button
                                type="button"
                                x-on:click="openCustom()"
                                class="inline-flex shrink-0 items-center justify-center gap-2 rounded-lg border border-dashed border-primary-400 bg-primary-50 px-4 py-2 text-sm font-semibold text-primary-700 transition hover:bg-primary-100 dark:border-primary-500/50 dark:bg-primary-500/10 dark:text-primary-400 dark:hover:bg-primary-500/20"
                            >
                                <x-filament::icon icon="heroicon-m-sparkles" class="h-4 w-4" />
                                Add custom item
                            </button>
                        </div>
                    </div>
                    <div class="flex gap-2 px-3 pb-3">
                        <div class="relative flex-1" x-data="alpineCombobox({
                                get options() { return mainCatOptions },
                                get value() { return mainCat },
                                placeholder: 'Category',
                                searchPlaceholder: 'Search categories…',
                                onchange: (id) => setMainCat(id),
                            })" x-on:click.outside="open = false">
                            <button
                                type="button"
                                x-on:click="toggle"
                                class="flex h-9 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 text-sm text-gray-700 shadow-sm hover:border-primary-400 dark:border-white/10 dark:bg-gray-800 dark:text-gray-200"
                            >
                                <span class="truncate text-gray-500 dark:text-gray-400" x-text="selected ? selected.name : placeholder"></span>
                                <x-filament::icon icon="heroicon-m-chevron-up-down" class="ms-2 h-4 w-4 shrink-0 text-gray-400" />
                            </button>
                            <div x-show="open" x-cloak class="absolute start-0 end-0 top-[calc(100%+4px)] z-30 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-lg dark:border-white/10 dark:bg-gray-900">
                                <div class="flex items-center gap-2 border-b border-gray-100 px-3 py-2 dark:border-white/10">
                                    <x-filament::icon icon="heroicon-m-magnifying-glass" class="h-4 w-4 shrink-0 text-gray-400" />
                                    <input
                                        x-ref="search"
                                        type="text"
                                        x-model="query"
                                        x-on:keydown.enter="select(filtered[highlighted] ?? null)"
                                        x-on:keydown.arrow-down.prevent="highlighted = Math.min(highlighted + 1, filtered.length - 1)"
                                        x-on:keydown.arrow-up.prevent="highlighted = Math.max(highlighted - 1, 0)"
                                        x-on:keydown.escape="open = false"
                                        :placeholder="searchPlaceholder"
                                        class="flex-1 bg-transparent text-sm outline-none"
                                        autocomplete="off"
                                    >
                                </div>
                                <div class="max-h-56 overflow-y-auto py-1">
                                    <template x-if="filtered.length === 0">
                                        <p class="px-3 py-2 text-center text-sm text-gray-500">No results found.</p>
                                    </template>
                                    <template x-for="(option, i) in filtered" :key="option.id">
                                        <button
                                            type="button"
                                            role="option"
                                            x-on:mousedown.prevent
                                            x-on:click="select(option)"
                                            x-on:mouseenter="highlighted = i"
                                            class="flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-gray-50 dark:hover:bg-white/5"
                                            :class="highlighted === i ? 'bg-gray-50 dark:bg-white/5' : ''"
                                        >
                                            <x-filament::icon icon="heroicon-m-check" class="h-4 w-4 shrink-0" x-bind:class="selected && String(option.id) === String(selected.id) ? '' : 'opacity-0'" />
                                            <span x-text="option.name"></span>
                                        </button>
                                    </template>
                                </div>
                            </div>
                        </div>
                        <div class="relative flex-1" x-data="alpineCombobox({
                                get options() { return subCatOptions },
                                get value() { return subCat },
                                placeholder: 'Subcategory',
                                searchPlaceholder: 'Search subcategories…',
                                onchange: (id) => setSubCat(id),
                            })" x-on:click.outside="open = false">
                            <button
                                type="button"
                                x-on:click="toggle"
                                :disabled="! mainCat"
                                class="flex h-9 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 text-sm text-gray-700 shadow-sm hover:border-primary-400 disabled:cursor-not-allowed disabled:opacity-50 dark:border-white/10 dark:bg-gray-800 dark:text-gray-200"
                            >
                                <span class="truncate text-gray-500 dark:text-gray-400" x-text="selected ? selected.name : placeholder"></span>
                                <x-filament::icon icon="heroicon-m-chevron-up-down" class="ms-2 h-4 w-4 shrink-0 text-gray-400" />
                            </button>
                            <div x-show="open" x-cloak class="absolute start-0 end-0 top-[calc(100%+4px)] z-30 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-lg dark:border-white/10 dark:bg-gray-900">
                                <div class="flex items-center gap-2 border-b border-gray-100 px-3 py-2 dark:border-white/10">
                                    <x-filament::icon icon="heroicon-m-magnifying-glass" class="h-4 w-4 shrink-0 text-gray-400" />
                                    <input
                                        x-ref="search"
                                        type="text"
                                        x-model="query"
                                        x-on:keydown.enter="select(filtered[highlighted] ?? null)"
                                        x-on:keydown.arrow-down.prevent="highlighted = Math.min(highlighted + 1, filtered.length - 1)"
                                        x-on:keydown.arrow-up.prevent="highlighted = Math.max(highlighted - 1, 0)"
                                        x-on:keydown.escape="open = false"
                                        :placeholder="searchPlaceholder"
                                        class="flex-1 bg-transparent text-sm outline-none"
                                        autocomplete="off"
                                    >
                                </div>
                                <div class="max-h-56 overflow-y-auto py-1">
                                    <template x-if="filtered.length === 0">
                                        <p class="px-3 py-2 text-center text-sm text-gray-500">No results found.</p>
                                    </template>
                                    <template x-for="(option, i) in filtered" :key="option.id">
                                        <button
                                            type="button"
                                            role="option"
                                            x-on:mousedown.prevent
                                            x-on:click="select(option)"
                                            x-on:mouseenter="highlighted = i"
                                            class="flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-gray-50 dark:hover:bg-white/5"
                                            :class="highlighted === i ? 'bg-gray-50 dark:bg-white/5' : ''"
                                        >
                                            <x-filament::icon icon="heroicon-m-check" class="h-4 w-4 shrink-0" x-bind:class="selected && String(option.id) === String(selected.id) ? '' : 'opacity-0'" />
                                            <span x-text="option.name"></span>
                                        </button>
                                    </template>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <template x-if="! branchRequired && products.length === 0">
                    <div class="flex min-h-48 flex-1 items-center justify-center p-8 text-center">
                        <div>
                            <div class="text-sm font-semibold text-gray-700 dark:text-gray-200">No products to quote</div>
                            <div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
                                This branch has no active products in the catalog.
                            </div>
                        </div>
                    </div>
                </template>

                <div class="min-h-0 flex-1 overflow-y-auto">
                    <div class="grid grid-cols-2 gap-3 p-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
                        <template x-for="p in filteredProducts" :key="'p' + p.id">
                            @include('filament.pos.product-card', [
                                'dimClass' => "cartQtyFor(p) > 0 ? 'ring-2 ring-primary-500' : 'cursor-pointer hover:shadow-md'",
                                'showSku' => true,
                                'noLotExpr' => "p.lot_count === 0",
                            ])
                        </template>
                        <template x-if="filteredProducts.length === 0">
                            <div class="col-span-full py-12 text-center text-sm text-gray-500">No products found</div>
                        </template>
                    </div>
                </div>
            </div>

            {{-- ── Order panel ─────────────────────────────────────────────── --}}
            <div
                :class="cartExpanded ? 'w-1/2' : 'w-72 xl:w-80'"
                class="flex shrink-0 flex-col bg-gray-50/50 dark:bg-gray-950/30"
            >
                <div class="shrink-0 border-b border-gray-200 bg-white px-3 py-2 dark:border-white/10 dark:bg-gray-900">
                    <div class="truncate text-center text-sm font-bold text-gray-800 dark:text-gray-100" x-text="businessName || 'Sales Order'"></div>
                </div>

                {{-- Branch section ── --}}
                <div class="shrink-0 border-b border-gray-200 bg-gray-100/50 px-3 py-2 dark:border-white/10 dark:bg-white/5">
                    <div class="mb-1 flex items-center gap-1.5">
                        <x-filament::icon icon="heroicon-m-building-library" class="h-3.5 w-3.5 text-gray-500 dark:text-gray-400" />
                        <span class="flex-1 text-xs font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Branch</span>
                        <button
                            type="button"
                            x-on:click="toggleCartExpanded()"
                            :title="cartExpanded ? 'Switch to compact order list' : 'Switch to full table view'"
                            class="flex h-8.5 w-9 items-center justify-center rounded border transition-colors"
                            :class="cartExpanded
                                ? 'border-primary-500 bg-primary-500/10 text-primary-600 dark:border-primary-400/40 dark:text-primary-400'
                                : 'border-gray-300 text-gray-500 hover:bg-gray-200 dark:border-white/10 dark:text-gray-400 dark:hover:bg-white/10'"
                        >
                            <x-filament::icon icon="heroicon-m-table-cells" class="h-4 w-4" />
                        </button>
                        <button
                            type="button"
                            x-on:click="toggleExpanded()"
                            :title="expanded ? 'Exit fullscreen' : 'Enter fullscreen'"
                            class="flex h-8.5 w-9 items-center justify-center rounded border border-red-500 bg-red-500/10 text-red-400 hover:bg-red-500/20 dark:border-red-400/40 dark:text-red-400 dark:hover:bg-red-500/20"
                        >
                            <x-filament::icon x-show="!expanded" icon="heroicon-m-arrows-pointing-out" class="h-4 w-4" />
                            <x-filament::icon x-show="expanded" icon="heroicon-m-arrows-pointing-in" class="h-4 w-4" />
                        </button>
                    </div>
                    <template x-if="! branchRequired && branches.length > 1">
                        <select
                            class="fi-input h-7 w-full rounded-md border-gray-300 text-xs dark:bg-gray-800"
                            :value="selectedBranchId ?? ''"
                            x-on:change="switchBranch($event.target.value)"
                        >
                            <option value="" x-text="selectedBranchId ? branches.find(b => b.id === selectedBranchId)?.name ?? 'Branch' : 'Select branch…'"></option>
                            <template x-for="branch in branches" :key="branch.id">
                                <option :value="branch.id" x-text="branch.name"></option>
                            </template>
                        </select>
                    </template>
                    <template x-if="! branchRequired && branches.length <= 1">
                        <div class="text-xs font-medium" x-text="branches.find(b => b.id === selectedBranchId)?.name ?? 'No branch assigned'"></div>
                    </template>
                </div>

                {{-- Order header section ── --}}
                <div class="shrink-0 space-y-2 border-b border-gray-200 bg-gray-100/50 px-3 py-2 dark:border-white/10 dark:bg-white/5">
                    <div class="grid grid-cols-2 gap-2">
                        <div>
                            <label class="mb-1 block text-[10px] font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Order date</label>
                            <input type="date" x-model="orderDate" class="fi-input h-7 w-full rounded-md border-gray-300 text-xs dark:bg-gray-800">
                        </div>
                        <div>
                            <label class="mb-1 block text-[10px] font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Delivery deadline</label>
                            <input type="date" :min="orderDate" x-model="deadlineDate" class="fi-input h-7 w-full rounded-md border-gray-300 text-xs dark:bg-gray-800">
                        </div>
                        <div>
                            <label class="mb-1 block text-[10px] font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Sales rep</label>
                            <select x-model="salesRepId" class="fi-input h-7 w-full rounded-md border-gray-300 text-xs dark:bg-gray-800">
                                <option :value="null">None</option>
                                <template x-for="rep in salesReps" :key="rep.id">
                                    <option :value="rep.id" x-text="rep.full_name"></option>
                                </template>
                            </select>
                        </div>
                        <div>
                            <label class="mb-1 block text-[10px] font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Status</label>
                            <select x-model="statusCode" class="fi-input h-7 w-full rounded-md border-gray-300 text-xs dark:bg-gray-800">
                                <template x-for="status in statuses" :key="status.code">
                                    <option :value="status.code" x-text="status.name"></option>
                                </template>
                            </select>
                        </div>
                    </div>
                    <div>
                        <label class="mb-1 block text-[10px] font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">Note (optional)</label>
                        <textarea
                            x-model="orderNotes"
                            rows="1"
                            placeholder="Add a note to this order…"
                            class="fi-input w-full resize-none rounded-md border-gray-300 text-xs dark:bg-gray-800"
                        ></textarea>
                    </div>
                </div>

                {{-- Customer section (mandatory) ── --}}
                <div class="shrink-0 border-b border-gray-200 bg-gray-100/50 px-3 py-2 dark:border-white/10 dark:bg-white/5">
                    <div class="mb-1 flex items-center gap-2">
                        <span
                            class="min-w-0 flex-1 truncate text-sm font-semibold"
                            x-text="selectedCustomer?.business_name ?? &quot;Customer's Name&quot;"
                        ></span>

                        <template x-if="customerId">
                            <button
                                type="button"
                                class="shrink-0 text-xs text-primary-600 hover:underline dark:text-primary-400"
                                x-on:click="selectCustomer('')"
                            >
                                Change
                            </button>
                        </template>

                        <button
                            type="button"
                            wire:click="mountAction('newCustomer')"
                            class="flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-primary-500 bg-primary-50 text-primary-600 transition hover:bg-primary-100 dark:border-primary-400/50 dark:bg-primary-500/10 dark:text-primary-400 dark:hover:bg-primary-500/20"
                            title="Add new customer"
                        >
                            <x-filament::icon icon="heroicon-m-plus" class="h-4 w-4" />
                        </button>
                    </div>
                    <div class="relative" x-data="alpineCombobox({
                            get options() { return customers.map(c => ({ id: c.id, name: c.business_name, phone: c.phone, nic: c.nic })) },
                            get value() { return customerId },
                            placeholder: 'Select customer',
                            searchPlaceholder: 'Search customers…',
                            onchange: (id) => selectCustomer(id),
                        })" x-on:click.outside="open = false">
                        <button
                            type="button"
                            x-on:click="toggle"
                            class="flex h-7 w-full items-center justify-between rounded-md border border-gray-300 bg-white px-2 text-xs shadow-sm hover:border-primary-400 dark:border-white/10 dark:bg-gray-800"
                        >
                            <span class="truncate text-gray-500 dark:text-gray-400" x-text="selected ? selected.name : placeholder"></span>
                            <x-filament::icon icon="heroicon-m-chevron-up-down" class="ms-2 h-3.5 w-3.5 shrink-0 text-gray-400" />
                        </button>
                        <div x-show="open" x-cloak class="absolute start-0 end-0 top-[calc(100%+4px)] z-30 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-lg dark:border-white/10 dark:bg-gray-900">
                            <div class="flex items-center gap-2 border-b border-gray-100 px-3 py-2 dark:border-white/10">
                                <x-filament::icon icon="heroicon-m-magnifying-glass" class="h-4 w-4 shrink-0 text-gray-400" />
                                <input
                                    x-ref="search"
                                    type="text"
                                    x-model="query"
                                    x-on:keydown.enter="select(filtered[highlighted] ?? null)"
                                    x-on:keydown.arrow-down.prevent="highlighted = Math.min(highlighted + 1, filtered.length - 1)"
                                    x-on:keydown.arrow-up.prevent="highlighted = Math.max(highlighted - 1, 0)"
                                    x-on:keydown.escape="open = false"
                                    :placeholder="searchPlaceholder"
                                    class="flex-1 bg-transparent text-sm outline-none"
                                    autocomplete="off"
                                >
                            </div>
                            <div class="max-h-56 overflow-y-auto py-1">
                                <template x-if="filtered.length === 0">
                                    <p class="px-3 py-2 text-center text-sm text-gray-500">No results found.</p>
                                </template>
                                <template x-for="(option, i) in filtered" :key="option.id">
                                    <button
                                        type="button"
                                        role="option"
                                        x-on:mousedown.prevent
                                        x-on:click="select(option)"
                                        x-on:mouseenter="highlighted = i"
                                        class="flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-gray-50 dark:hover:bg-white/5"
                                        :class="highlighted === i ? 'bg-gray-50 dark:bg-white/5' : ''"
                                    >
                                        <x-filament::icon icon="heroicon-m-check" class="h-4 w-4 shrink-0" x-bind:class="selected && String(option.id) === String(selected.id) ? '' : 'opacity-0'" />
                                        <span x-text="option.name"></span>
                                    </button>
                                </template>
                            </div>
                        </div>
                    </div>
                </div>

                {{-- Cart lines ── --}}
                <div class="min-h-0 flex-1 overflow-y-auto">
                    <template x-if="cart.length === 0">
                        <div class="py-12 text-center text-sm text-gray-500">No Item Selected</div>
                    </template>

                    {{-- Compact card view (default, narrow column) ── --}}
                    <template x-if="! cartExpanded">
                    <div>
                    <template x-for="line in cart" :key="line.key">
                        <div class="border-b border-gray-200 px-3 py-2 hover:bg-gray-100/50 dark:border-white/10 dark:hover:bg-white/5">
                            <div>
                                <div class="flex items-center gap-2">
                                    <div class="min-w-0 flex-1">
                                        <div class="flex items-center gap-1.5">
                                            <template x-if="line.is_custom">
                                                <x-filament::icon icon="heroicon-m-sparkles" class="h-3.5 w-3.5 shrink-0 text-primary-600 dark:text-primary-400" />
                                            </template>
                                            <div class="line-clamp-2 text-sm leading-snug font-medium" x-text="line.name"></div>
                                        </div>
                                        <div class="flex items-center gap-1.5">
                                            <template x-if="lineDiscount(line) > 0">
                                                <div class="flex items-center gap-1.5">
                                                    <span class="text-xs text-gray-500 line-through" x-text="money(lineGross(line))"></span>
                                                    <span class="text-sm font-semibold text-green-700 tabular-nums dark:text-green-400" x-text="money(lineNet(line))"></span>
                                                </div>
                                            </template>
                                            <template x-if="! (lineDiscount(line) > 0)">
                                                <span class="text-sm font-semibold text-primary-600 tabular-nums dark:text-primary-400" x-text="money(line.unit_price)"></span>
                                            </template>
                                        </div>
                                    </div>
                                    <div class="flex shrink-0 flex-col items-center gap-0.5">
                                        <div class="flex items-center gap-1">
                                            <button type="button" x-on:click="bump(line, -1)" class="flex h-9 w-9 items-center justify-center rounded border border-gray-300 text-gray-500 hover:bg-gray-200 dark:border-white/10 dark:hover:bg-white/10">
                                                <x-filament::icon icon="heroicon-m-minus" class="h-4 w-4" />
                                            </button>
                                            <input
                                                type="text" inputmode="decimal"
                                                :value="line.quantity"
                                                x-on:input="line._qtyText = $event.target.value"
                                                x-on:change="setQty(line, $event.target.value)"
                                                x-on:blur="line._qtyText = null"
                                                class="fi-input h-9 w-14 rounded-md border-gray-300 py-0 px-1 text-center text-sm tabular-nums dark:bg-gray-800"
                                            >
                                            <button type="button" x-on:click="bump(line, 1)" class="flex h-9 w-9 items-center justify-center rounded border border-gray-300 text-gray-500 hover:bg-gray-200 dark:border-white/10 dark:hover:bg-white/10">
                                                <x-filament::icon icon="heroicon-m-plus" class="h-4 w-4" />
                                            </button>
                                        </div>
                                        <span x-show="line.base_unit" class="text-[9px] leading-none text-gray-500 dark:text-gray-400" x-text="line.base_unit?.code || line.base_unit?.name"></span>
                                    </div>
                                    <button type="button" x-on:click="removeItem(line)" class="flex h-8 w-8 shrink-0 items-center justify-center text-red-600 hover:opacity-70 dark:text-red-400">
                                        <x-filament::icon icon="heroicon-m-trash" class="h-4 w-4" />
                                    </button>
                                </div>

                                <div class="mt-1 flex items-center gap-2">
                                    <template x-if="canDiscount">
                                        <div class="relative inline-block" x-data="discountPopover({
                                                get type() { return line.discount_type },
                                                get value() { return line.discount_value },
                                                onapply: (type, value) => { line.discount_type = type; line.discount_value = value },
                                                onclear: () => { line.discount_type = null; line.discount_value = 0 },
                                            })">
                                            <button
                                                type="button"
                                                x-on:click="toggle"
                                                class="rounded border px-2 py-1 text-xs font-medium transition-colors"
                                                :class="hasDiscount ? 'border-green-600 bg-green-600/10 text-green-700' : 'text-gray-500 hover:bg-gray-200 dark:text-gray-400 dark:hover:bg-white/10'"
                                            >
                                                <span x-text="hasDiscount ? (type === 'percentage' ? '-' + value + '%' : '-' + money(value) + '/u') : 'Discount'"></span>
                                            </button>
                                            <div x-show="open" x-cloak class="absolute z-30 mt-1 w-56 space-y-2 rounded-lg border border-gray-200 bg-white p-3 shadow-lg dark:border-white/10 dark:bg-gray-900">
                                                <div class="text-xs font-semibold">Discount per unit</div>
                                                <p class="text-[10px] leading-snug text-gray-400 dark:text-gray-500">Rs. applies to each unit — total off = Rs. × quantity</p>
                                                <div class="flex gap-1">
                                                    <div class="flex shrink-0 overflow-hidden rounded-md border border-gray-300 dark:border-white/10">
                                                        <button
                                                            type="button"
                                                            x-on:click="draftType = 'fixed'"
                                                            class="px-2 py-1 text-xs font-semibold"
                                                            :class="draftType === 'fixed' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'"
                                                        >Rs.</button>
                                                        <button
                                                            type="button"
                                                            x-on:click="draftType = 'percentage'"
                                                            class="px-2 py-1 text-xs font-semibold"
                                                            :class="draftType === 'percentage' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'"
                                                        >%</button>
                                                    </div>
                                                    <input
                                                        type="number" min="0" x-model="draftValue"
                                                        x-on:keydown.enter="apply"
                                                        class="fi-input h-7 flex-1 rounded-md border-gray-300 py-0 text-sm dark:bg-gray-800"
                                                        placeholder="0.00"
                                                    >
                                                </div>
                                                <div class="flex justify-end gap-1.5">
                                                    <template x-if="hasDiscount">
                                                        <button type="button" x-on:click="clear()" class="rounded-md px-2 py-1 text-xs text-gray-500 hover:bg-gray-100 dark:hover:bg-white/10">Remove</button>
                                                    </template>
                                                    <button type="button" x-on:click="apply" class="rounded-md bg-primary-600 px-3 py-1 text-xs font-medium text-white hover:bg-primary-500">Apply</button>
                                                </div>
                                            </div>
                                        </div>
                                    </template>

                                    {{-- Lot — the consignment the line quotes from, changeable when several --}}
                                    <template x-if="! line.is_custom && line.lot">
                                        <div class="flex min-w-0 items-center gap-1.5 rounded border border-gray-200 bg-gray-100/60 p-1.5 text-[11px] dark:border-white/10 dark:bg-white/5">
                                            <span class="min-w-0 flex-1 truncate text-gray-600 dark:text-gray-400" :title="lotTitle(line)">
                                                <span class="font-semibold text-gray-800 dark:text-gray-200" x-text="lotNumber(line)"></span>
                                                <template x-if="line.lot.expiry"> · exp <span x-text="line.lot.expiry"></span></template>
                                                <template x-if="line.lot.is_quote_only"> · <span class="font-medium text-amber-600">quote only</span></template>
                                            </span>
                                            <button
                                                type="button"
                                                x-on:click="openLotLine(line)"
                                                :disabled="lotProduct && lotProduct.lots && lotProduct.lots.length < 2"
                                                class="shrink-0 rounded-md bg-primary-600 px-2 py-0.5 font-medium text-white hover:bg-primary-500 disabled:opacity-50"
                                                x-show="lotProductFor(line)?.lots?.length > 1"
                                            >Change lot</button>
                                        </div>
                                    </template>
                                    <template x-if="! line.is_custom && ! line.lot">
                                        <div class="flex min-w-0 items-center gap-1.5 rounded border border-gray-200 bg-gray-100/60 p-1.5 text-[11px] dark:border-white/10 dark:bg-white/5">
                                            <span class="min-w-0 flex-1 truncate text-gray-600 dark:text-gray-400">Quoted from last receipt — fulfilment lot resolved at conversion</span>
                                            <button
                                                type="button"
                                                x-on:click="openLotLine(line)"
                                                class="shrink-0 rounded-md bg-primary-600 px-2 py-0.5 font-medium text-white hover:bg-primary-500"
                                            >Pick lot</button>
                                        </div>
                                    </template>

                                    {{-- Custom line spec --}}
                                    <template x-if="line.is_custom && line.custom_description">
                                        <div class="min-w-0 flex-1 truncate text-[11px] text-gray-500 dark:text-gray-400">
                                            <span x-text="line.custom_description"></span>
                                        </div>
                                    </template>
                                    <template x-if="line.is_custom">
                                        <button
                                            type="button"
                                            x-on:click="editCustom(line)"
                                            class="shrink-0 rounded border border-gray-200 px-2 py-1 text-[11px] text-gray-500 hover:bg-gray-100 dark:border-white/10 dark:text-gray-400 dark:hover:bg-white/5"
                                        >
                                            Edit
                                        </button>
                                    </template>
                                </div>
                            </div>
                        </div>
                    </template>
                    </div>
                    </template>

                    {{-- Expanded table view — 50/50 layout, columns matching
                         the POS terminal's table view (item / qty / price /
                         discount / net amount). Every control here is the
                         same client-side mutation the card view uses
                         (bump/setQty/discountPopover/removeItem/openLotLine/
                         editCustom), just laid out horizontally — nothing
                         here is read-only.

                         table-fixed + an explicit <colgroup> is deliberate —
                         see the POS terminal's table view for why: without
                         it a sticky <thead> can size its columns
                         independently of the <tbody> in some browsers. ── --}}
                    <template x-if="cartExpanded && cart.length > 0">
                        <table class="w-full table-fixed border-collapse text-sm">
                            <colgroup>
                                <col style="width: 30%">
                                <col style="width: 15%">
                                <col style="width: 13%">
                                <col style="width: 14%">
                                <col style="width: 20%">
                                <col style="width: 8%">
                            </colgroup>
                            <thead class="sticky top-0 z-10 bg-gray-100 dark:bg-gray-900">
                                <tr class="border-b-2 border-gray-200 text-start text-[11px] font-semibold tracking-wide text-gray-500 uppercase dark:border-white/10 dark:text-gray-400">
                                    <th class="px-3 py-2.5 text-start">Item</th>
                                    <th class="px-3 py-2.5 text-center">Qty</th>
                                    <th class="px-3 py-2.5 text-end">Price</th>
                                    <th class="px-3 py-2.5 text-end">Discount</th>
                                    <th class="px-3 py-2.5 text-end">Net Amount</th>
                                    <th class="px-3 py-2.5"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <template x-for="line in cart" :key="line.key">
                                    <tr class="border-b border-gray-200 odd:bg-white even:bg-gray-50/60 hover:bg-primary-50/40 dark:border-white/10 dark:odd:bg-gray-900 dark:even:bg-white/[0.03] dark:hover:bg-white/5">
                                        {{-- Item ── --}}
                                        <td class="px-3 py-2.5 align-top">
                                            <div>
                                                <div class="flex items-center gap-1.5">
                                                    <template x-if="line.is_custom">
                                                        <x-filament::icon icon="heroicon-m-sparkles" class="h-3.5 w-3.5 shrink-0 text-primary-600 dark:text-primary-400" />
                                                    </template>
                                                    <div class="line-clamp-2 leading-snug font-medium" x-text="line.name"></div>
                                                </div>

                                                {{-- Lot — same whole-row-clickable control as the
                                                     card view (see the POS table view's comment for
                                                     why): a real <button> spanning the row width. --}}
                                                <template x-if="! line.is_custom && line.lot">
                                                    <button
                                                        type="button"
                                                        x-on:click="openLotLine(line)"
                                                        :disabled="lotProductFor(line)?.lots?.length < 2"
                                                        class="mt-1 flex w-full items-center gap-1.5 rounded border px-1.5 py-1 text-start text-[10px] transition-colors disabled:cursor-not-allowed disabled:opacity-50"
                                                        :class="'border-gray-200 bg-gray-100/60 hover:border-primary-400 hover:bg-primary-50 dark:border-white/10 dark:bg-white/5 dark:hover:border-primary-500/40 dark:hover:bg-primary-500/10'"
                                                    >
                                                        <span class="min-w-0 flex-1 truncate text-gray-600 dark:text-gray-400" :title="lotTitle(line)">
                                                            <span class="font-semibold text-gray-800 dark:text-gray-200" x-text="lotNumber(line)"></span>
                                                            <template x-if="line.lot.expiry"> · exp <span x-text="line.lot.expiry"></span></template>
                                                            <template x-if="line.lot.is_quote_only"> · <span class="font-medium text-amber-600">quote only</span></template>
                                                        </span>
                                                        <span x-show="lotProductFor(line)?.lots?.length > 1" class="flex shrink-0 items-center gap-0.5 font-semibold text-primary-600 dark:text-primary-400">
                                                            Change
                                                            <x-filament::icon icon="heroicon-m-chevron-right" class="h-3 w-3" />
                                                        </span>
                                                    </button>
                                                </template>
                                                <template x-if="! line.is_custom && ! line.lot">
                                                    <button
                                                        type="button"
                                                        x-on:click="openLotLine(line)"
                                                        class="mt-1 flex w-full items-center gap-1.5 rounded border border-amber-400/60 bg-amber-50 px-1.5 py-1 text-start text-[10px] transition-colors hover:bg-amber-100 dark:border-amber-400/30 dark:bg-amber-400/10 dark:hover:bg-amber-400/20"
                                                    >
                                                        <span class="min-w-0 flex-1 truncate font-medium text-amber-700 dark:text-amber-400">Quoted from last receipt</span>
                                                        <span class="flex shrink-0 items-center gap-0.5 font-semibold text-primary-600 dark:text-primary-400">
                                                            Pick lot
                                                            <x-filament::icon icon="heroicon-m-chevron-right" class="h-3 w-3" />
                                                        </span>
                                                    </button>
                                                </template>

                                                {{-- Custom line spec --}}
                                                <template x-if="line.is_custom">
                                                    <div class="mt-1 flex items-center gap-1.5">
                                                        <template x-if="line.custom_description">
                                                            <div class="min-w-0 flex-1 truncate text-[11px] text-gray-500 dark:text-gray-400" x-text="line.custom_description"></div>
                                                        </template>
                                                        <button
                                                            type="button"
                                                            x-on:click="editCustom(line)"
                                                            class="shrink-0 rounded border border-gray-200 px-2 py-1 text-[11px] text-gray-500 hover:bg-gray-100 dark:border-white/10 dark:text-gray-400 dark:hover:bg-white/5"
                                                        >
                                                            Edit
                                                        </button>
                                                    </div>
                                                </template>
                                            </div>
                                        </td>

                                        {{-- Qty ── --}}
                                        <td class="px-3 py-2.5 align-top">
                                            <div class="flex flex-col items-center gap-0.5">
                                                <div class="flex items-center gap-1">
                                                    <button type="button" x-on:click="bump(line, -1)" class="flex h-7 w-7 shrink-0 items-center justify-center rounded border border-gray-300 text-gray-500 hover:bg-gray-200 dark:border-white/10 dark:hover:bg-white/10">
                                                        <x-filament::icon icon="heroicon-m-minus" class="h-3.5 w-3.5" />
                                                    </button>
                                                    <input
                                                        type="text" inputmode="decimal"
                                                        :value="line.quantity"
                                                        x-on:input="line._qtyText = $event.target.value"
                                                        x-on:change="setQty(line, $event.target.value)"
                                                        x-on:blur="line._qtyText = null"
                                                        class="fi-input h-7 w-10 min-w-0 rounded border-gray-300 px-0.5 py-0 text-center text-xs tabular-nums dark:bg-gray-800"
                                                    >
                                                    <button type="button" x-on:click="bump(line, 1)" class="flex h-7 w-7 shrink-0 items-center justify-center rounded border border-gray-300 text-gray-500 hover:bg-gray-200 dark:border-white/10 dark:hover:bg-white/10">
                                                        <x-filament::icon icon="heroicon-m-plus" class="h-3.5 w-3.5" />
                                                    </button>
                                                </div>
                                                <span x-show="line.base_unit" class="text-[9px] leading-none text-gray-500 dark:text-gray-400" x-text="line.base_unit?.code || line.base_unit?.name"></span>
                                            </div>
                                        </td>

                                        {{-- Price ── --}}
                                        <td class="px-3 py-2.5 text-end align-top whitespace-nowrap font-semibold tabular-nums text-primary-600 dark:text-primary-400" x-text="money(line.unit_price)"></td>

                                        {{-- Discount ── --}}
                                        <td class="px-3 py-2.5 text-end align-top">
                                            <template x-if="canDiscount">
                                                <div class="relative inline-block" x-data="discountPopover({
                                                        get type() { return line.discount_type },
                                                        get value() { return line.discount_value },
                                                        onapply: (type, value) => { line.discount_type = type; line.discount_value = value },
                                                        onclear: () => { line.discount_type = null; line.discount_value = 0 },
                                                    })">
                                                    <button
                                                        type="button"
                                                        x-on:click="toggle"
                                                        class="whitespace-nowrap rounded border px-2 py-1 text-xs font-medium transition-colors"
                                                        :class="hasDiscount ? 'border-green-600 bg-green-600/10 text-green-700' : 'text-gray-500 hover:bg-gray-200 dark:text-gray-400 dark:hover:bg-white/10'"
                                                    >
                                                        <span x-text="hasDiscount ? (type === 'percentage' ? '-' + value + '%' : '-' + money(value) + '/u') : 'Discount'"></span>
                                                    </button>
                                                    <div x-show="open" x-cloak class="absolute end-0 z-30 mt-1 w-56 space-y-2 rounded-lg border border-gray-200 bg-white p-3 text-start shadow-lg dark:border-white/10 dark:bg-gray-900">
                                                        <div class="text-xs font-semibold">Discount per unit</div>
                                                        <div class="flex gap-1">
                                                            <div class="flex shrink-0 overflow-hidden rounded-md border border-gray-300 dark:border-white/10">
                                                                <button type="button" x-on:click="draftType = 'fixed'" class="px-2 py-1 text-xs font-semibold" :class="draftType === 'fixed' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'">Rs.</button>
                                                                <button type="button" x-on:click="draftType = 'percentage'" class="px-2 py-1 text-xs font-semibold" :class="draftType === 'percentage' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'">%</button>
                                                            </div>
                                                            <input type="number" min="0" x-model="draftValue" x-on:keydown.enter="apply" class="fi-input h-7 flex-1 rounded-md border-gray-300 py-0 text-sm dark:bg-gray-800" placeholder="0.00">
                                                        </div>
                                                        <div class="flex justify-end gap-1.5">
                                                            <template x-if="hasDiscount">
                                                                <button type="button" x-on:click="clear()" class="rounded-md px-2 py-1 text-xs text-gray-500 hover:bg-gray-100 dark:hover:bg-white/10">Remove</button>
                                                            </template>
                                                            <button type="button" x-on:click="apply" class="rounded-md bg-primary-600 px-3 py-1 text-xs font-medium text-white hover:bg-primary-500">Apply</button>
                                                        </div>
                                                    </div>
                                                </div>
                                            </template>
                                            <template x-if="! canDiscount">
                                                <span class="text-gray-400">—</span>
                                            </template>
                                        </td>

                                        {{-- Net Amount ── --}}
                                        <td class="px-3 py-2.5 text-end align-top">
                                            <div class="text-base font-bold tabular-nums" x-text="money(lineNet(line))"></div>
                                            <template x-if="lineDiscount(line) > 0">
                                                <div class="mt-0.5 text-[11px] text-gray-500 line-through dark:text-gray-400" x-text="money(lineGross(line))"></div>
                                            </template>
                                        </td>

                                        {{-- Actions ── --}}
                                        <td class="px-2 py-2.5 align-top">
                                            <div class="flex items-center justify-end">
                                                <button type="button" x-on:click="removeItem(line)" class="flex h-7 w-7 shrink-0 items-center justify-center text-red-600 hover:opacity-70 dark:text-red-400" title="Remove">
                                                    <x-filament::icon icon="heroicon-m-trash" class="h-3.5 w-3.5" />
                                                </button>
                                            </div>
                                        </td>
                                    </tr>
                                </template>
                            </tbody>
                        </table>
                    </template>
                </div>

                {{-- Totals + actions ── --}}
                <div class="shrink-0 space-y-2 border-t border-gray-200 p-3 dark:border-white/10">
                    <div class="flex justify-between text-lg">
                        <span class="text-gray-500 dark:text-gray-400">Subtotal</span>
                        <span class="font-medium tabular-nums" x-text="money(grossSubtotal)"></span>
                    </div>
                    <template x-if="lineDiscountTotal > 0">
                        <div class="flex justify-between text-lg text-green-700 dark:text-green-400">
                            <span>Line discounts</span>
                            <span class="font-medium tabular-nums" x-text="'-' + money(lineDiscountTotal)"></span>
                        </div>
                    </template>
                    <template x-if="canDiscount">
                        <div class="flex items-center justify-between gap-2">
                            <span class="text-base text-gray-500 dark:text-gray-400">Order discount</span>
                            <div class="relative inline-block shrink-0" x-data="discountPopover({
                                    get type() { return discountType },
                                    get value() { return discountValue },
                                    onapply: (type, value) => { discountType = type; discountValue = value },
                                    onclear: () => { discountType = 'fixed'; discountValue = 0 },
                                })">
                                <button
                                    type="button"
                                    x-on:click="toggle"
                                    class="rounded border px-1.5 py-0.5 text-[11px] font-medium transition-colors"
                                    :class="hasDiscount ? 'border-green-600 bg-green-600/10 text-green-700' : 'text-gray-500 hover:bg-gray-200 dark:text-gray-400 dark:hover:bg-white/10'"
                                >
                                    <span x-text="hasDiscount ? (type === 'percentage' ? '-' + value + '%' : '-' + money(value)) : 'Discount'"></span>
                                </button>
                                <div x-show="open" x-cloak class="absolute end-0 bottom-full z-30 mb-1 w-56 space-y-2 rounded-lg border border-gray-200 bg-white p-3 shadow-lg dark:border-white/10 dark:bg-gray-900">
                                    <div class="text-xs font-semibold">Order discount</div>
                                    <div class="flex gap-1">
                                        <div class="flex shrink-0 overflow-hidden rounded-md border border-gray-300 dark:border-white/10">
                                            <button
                                                type="button"
                                                x-on:click="draftType = 'fixed'"
                                                class="px-2 py-1 text-xs font-semibold"
                                                :class="draftType === 'fixed' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'"
                                            >Rs.</button>
                                            <button
                                                type="button"
                                                x-on:click="draftType = 'percentage'"
                                                class="px-2 py-1 text-xs font-semibold"
                                                :class="draftType === 'percentage' ? 'bg-primary-600 text-white' : 'bg-white text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-white/10'"
                                            >%</button>
                                        </div>
                                        <input
                                            type="number" min="0" x-model="draftValue"
                                            x-on:keydown.enter="apply"
                                            class="fi-input h-7 flex-1 rounded-md border-gray-300 py-0 text-sm dark:bg-gray-800"
                                            placeholder="0.00"
                                        >
                                    </div>
                                    <div class="flex justify-end gap-1.5">
                                        <template x-if="hasDiscount">
                                            <button type="button" x-on:click="clear()" class="rounded-md px-2 py-1 text-xs text-gray-500 hover:bg-gray-100 dark:hover:bg-white/10">Remove</button>
                                        </template>
                                        <button type="button" x-on:click="apply" class="rounded-md bg-primary-600 px-3 py-1 text-xs font-medium text-white hover:bg-primary-500">Apply</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </template>
                    <div class="flex justify-between text-gray-500 dark:text-gray-400" x-show="vatEnabled">
                        <span>VAT</span>
                        <span class="tabular-nums" x-text="money(vatTotal)"></span>
                    </div>
                    <div class="flex items-baseline justify-between gap-2 border-t border-gray-200 pt-2 dark:border-white/10">
                        <span class="shrink-0 text-lg font-bold tracking-wide text-gray-500 uppercase dark:text-gray-400">Total</span>
                        <span class="whitespace-nowrap text-2xl font-bold tabular-nums text-primary-600 dark:text-primary-400" x-text="money(netTotal)"></span>
                    </div>

                    {{-- Advances ── --}}
                    <template x-if="advancePaid > 0">
                        <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400">
                            <span>Advance paid</span>
                            <span class="font-semibold text-green-700 tabular-nums dark:text-green-400" x-text="money(advancePaid)"></span>
                        </div>
                    </template>
                    <template x-if="balance > 0">
                        <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400">
                            <span>Balance on order</span>
                            <span class="font-semibold tabular-nums" x-text="money(balance)"></span>
                        </div>
                    </template>
                    <template x-if="payments.length > 0">
                        <div class="space-y-1 rounded-lg border border-gray-200 bg-gray-100/60 p-2 dark:border-white/10 dark:bg-white/5">
                            <template x-for="(payment, i) in payments" :key="i">
                                <div class="flex items-center gap-2 text-xs">
                                    <span class="min-w-0 flex-1 truncate" x-text="methodLabel(payment.method)"></span>
                                    <span class="font-semibold tabular-nums" x-text="money(payment.amount)"></span>
                                    <button type="button" x-on:click="payments.splice(i, 1)" class="text-red-600 hover:opacity-70 dark:text-red-400">
                                        <x-filament::icon icon="heroicon-m-x-mark" class="h-3.5 w-3.5" />
                                    </button>
                                </div>
                            </template>
                        </div>
                    </template>
                    <button
                        type="button"
                        x-on:click="openAdvance()"
                        class="w-full rounded-lg border border-dashed border-primary-400 bg-primary-500/5 py-2 text-sm font-semibold text-primary-600 hover:bg-primary-500/10 dark:border-primary-500/50 dark:text-primary-400"
                    >
                        Record advance payment
                    </button>

                    <template x-if="errors.length > 0">
                        <ul class="rounded-lg bg-red-50 p-3 text-sm text-red-700 dark:bg-red-500/10">
                            <template x-for="error in errors" :key="error"><li x-text="error"></li></template>
                        </ul>
                    </template>

                    <button
                        type="button"
                        x-on:click="placeOrder()"
                        :disabled="! canSubmit"
                        class="w-full rounded-lg bg-primary-600 py-3.5 text-sm font-semibold text-white hover:bg-primary-500 disabled:cursor-not-allowed disabled:opacity-50"
                    >
                        <span x-text="submitting ? 'Placing order…' : 'Place Order'"></span>
                    </button>
                    <template x-if="autoInvoice">
                        <p class="text-center text-[10px] text-gray-400 dark:text-gray-500">
                            Auto-invoicing is on — this order will be billed immediately.
                        </p>
                    </template>
                    <div class="flex gap-2">
                        <button
                            type="button"
                            x-on:click="resetCart()"
                            :disabled="cart.length === 0"
                            class="flex flex-1 items-center justify-center gap-1 rounded-lg border-2 border-purple-600 bg-purple-100 py-3 text-sm font-semibold text-purple-700 transition hover:bg-purple-200 disabled:cursor-not-allowed disabled:opacity-100 dark:border-purple-400 dark:bg-purple-500/15 dark:text-purple-300 dark:hover:bg-purple-500/25 dark:disabled:opacity-50"
                        >
                            <x-filament::icon icon="heroicon-m-x-mark" class="h-4 w-4" />
                            Clear Order
                        </button>
                    </div>
                </div>
            </div>
        </div>

        {{-- ── Branch picker (blocking: no branch, no quoting) ─────────────
             A sales order, its lot quotes and its advances all belong to
             exactly one branch, so the desk is inert until one is chosen.
             Never rendered when the user has a single branch (it was selected
             automatically server-side). --}}
        <template x-if="branchRequired">
            <div class="fixed inset-0 z-[70] flex items-center justify-center bg-gray-900/60 p-4 backdrop-blur-sm">
                <div class="w-full max-w-sm rounded-xl bg-white p-6 shadow-xl dark:bg-gray-900">
                    <div class="mb-4 flex items-center gap-2">
                        <x-filament::icon icon="heroicon-m-building-library" class="h-5 w-5 text-primary-600 dark:text-primary-400" />
                        <h3 class="text-lg font-semibold">Select a branch</h3>
                    </div>
                    <p class="mb-4 text-sm text-gray-500 dark:text-gray-400">
                        Sales orders quote against one branch. Choose which branch you are taking this order in.
                    </p>
                    <div class="space-y-2">
                        <template x-for="branch in branches" :key="branch.id">
                            <button
                                type="button"
                                x-on:click="chooseBranch(branch.id)"
                                :disabled="submitting"
                                class="flex w-full items-center justify-between rounded-lg border border-gray-300 px-4 py-3 text-start text-sm font-medium hover:border-primary-500 hover:bg-primary-50 disabled:opacity-50 dark:border-white/10 dark:hover:bg-primary-500/10"
                            >
                                <span x-text="branch.name"></span>
                                <x-filament::icon icon="heroicon-m-chevron-right" class="h-4 w-4 text-gray-400" />
                            </button>
                        </template>
                        <template x-if="branches.length === 0">
                            <p class="rounded-lg bg-amber-50 p-3 text-sm text-amber-700 dark:bg-amber-500/10 dark:text-amber-400">
                                You have no branch access. Ask an administrator to assign you to a branch before taking orders.
                            </p>
                        </template>
                        <template x-if="errors.length">
                            <ul class="rounded-lg bg-red-50 p-3 text-sm text-red-700 dark:bg-red-500/10">
                                <template x-for="error in errors" :key="error"><li x-text="error"></li></template>
                            </ul>
                        </template>
                    </div>
                </div>
            </div>
        </template>

        {{-- ── Advance payment sheet ─────────────────────────────────────────
             Optional: an order can be taken with nothing paid and invoiced
             later. Advances are capped at the order total (the service refuses
             the excess at save — an invoice can never settle more than the
             order is worth). --}}
        <div x-show="advanceOpen" x-cloak class="fixed inset-0 z-[60] flex justify-end bg-gray-900/60 backdrop-blur-sm">
            <div x-on:click.outside="advanceOpen = false" class="flex h-full w-full max-w-xl flex-col bg-white shadow-xl dark:bg-gray-900">
                <div class="flex items-center justify-between border-b border-gray-200 px-5 py-4 dark:border-white/10">
                    <h3 class="text-lg font-semibold">Record advance payment</h3>
                    <button type="button" class="text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100" x-on:click="advanceOpen = false">
                        <x-filament::icon icon="heroicon-m-x-mark" class="h-5 w-5" />
                    </button>
                </div>

                <div class="flex-1 space-y-4 overflow-y-auto p-5">
                    <template x-if="errors.length">
                        <ul class="rounded-lg bg-red-50 p-3 text-sm text-red-700 dark:bg-red-500/10">
                            <template x-for="error in errors" :key="error"><li x-text="error"></li></template>
                        </ul>
                    </template>

                    <div class="grid grid-cols-4 gap-1.5">
                        <template x-for="method in paymentMethods" :key="method.code">
                            <button
                                type="button"
                                x-on:click="activeMethod = method.code; customFieldValues = {}; creditNoteId = null"
                                class="flex flex-col items-center gap-1 rounded-lg border px-2 py-3 text-xs font-medium transition-colors"
                                :class="activeMethod === method.code ? 'border-green-600 bg-green-700/10 text-green-700' : 'border-gray-200 text-gray-500 hover:bg-gray-50 dark:border-white/10 dark:text-gray-400 dark:hover:bg-white/5'"
                            >
                                <span class="flex items-center">
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-banknotes'" icon="heroicon-m-banknotes" class="h-4 w-4" />
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-credit-card'" icon="heroicon-m-credit-card" class="h-4 w-4" />
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-building-library'" icon="heroicon-m-building-library" class="h-4 w-4" />
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-document-text'" icon="heroicon-m-document-text" class="h-4 w-4" />
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-wallet'" icon="heroicon-m-wallet" class="h-4 w-4" />
                                    <x-filament::icon x-show="method.icon === 'heroicon-m-document-check'" icon="heroicon-m-document-check" class="h-4 w-4" />
                                </span>
                                <span x-text="method.label"></span>
                            </button>
                        </template>
                    </div>

                    <div class="space-y-3 rounded-lg border border-gray-200 bg-gray-50/60 p-4 dark:border-white/10 dark:bg-white/5">
                        <template x-if="activeMethod === 'credit'">
                            <div>
                                <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                    Credit note <span class="text-red-600">*</span>
                                </label>
                                <select
                                    x-model="creditNoteId"
                                    x-on:change="applyCreditNote(creditNoteId)"
                                    class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800"
                                >
                                    <option :value="null">Select a credit note…</option>
                                    <template x-for="cn in creditNotes" :key="cn.id">
                                        <option :value="cn.id" x-text="cn.cn_number + ' — ' + money(cn.amount)"></option>
                                    </template>
                                </select>
                                <template x-if="selectedCustomer && creditNotes.length === 0">
                                    <p class="mt-1 text-xs text-amber-600">No issued credit notes for this customer.</p>
                                </template>
                                <template x-if="! selectedCustomer">
                                    <p class="mt-1 text-xs text-amber-600">Select a customer first — a credit note can only be applied to its own customer's order.</p>
                                </template>
                            </div>
                        </template>
                        <template x-if="activeMethod === 'cheque'">
                            <div class="grid grid-cols-2 gap-3">
                                <div>
                                    <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                        Cheque No.
                                        <template x-if="activeMethodConfig?.requiresChequeFields"><span class="text-red-600"> *</span></template>
                                    </label>
                                    <input x-model="pmChequeNumber" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                                </div>
                                <div>
                                    <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                        Bank
                                        <template x-if="activeMethodConfig?.requiresChequeFields"><span class="text-red-600"> *</span></template>
                                    </label>
                                    <input x-model="pmChequeBank" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                                </div>
                                <div>
                                    <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">Branch</label>
                                    <input x-model="pmChequeBranch" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                                </div>
                                <div>
                                    <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                        Maturity Date
                                        <template x-if="activeMethodConfig?.requiresChequeFields"><span class="text-red-600"> *</span></template>
                                    </label>
                                    <input type="date" x-model="pmChequeDate" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                                </div>
                            </div>
                        </template>
                        <template x-if="activeMethod === 'card' || activeMethod === 'bank_transfer' || (activeMethodConfig?.requiresReference && activeMethod !== 'cheque' && activeMethod !== 'credit')">
                            <div>
                                <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                    Reference / Transaction ID
                                    <template x-if="activeMethodConfig?.requiresReference"><span class="text-red-600"> *</span></template>
                                </label>
                                <input x-model="pmReference" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                            </div>
                        </template>
                        <template x-if="activeCustomMethod">
                            <template x-for="field in activeCustomMethod.fields ?? []" :key="field.key">
                                <div>
                                    <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">
                                        <span x-text="field.label"></span>
                                        <template x-if="field.required"><span class="text-red-600"> *</span></template>
                                    </label>
                                    <template x-if="field.type === 'dropdown'">
                                        <select x-model="customFieldValues[field.key]" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                                            <option value="">Select…</option>
                                            <template x-for="opt in field.options ?? []" :key="opt">
                                                <option :value="opt" x-text="opt"></option>
                                            </template>
                                        </select>
                                    </template>
                                    <template x-if="field.type !== 'dropdown' && field.type !== 'file'">
                                        <input
                                            :type="field.type === 'number' ? 'number' : 'text'"
                                            x-model="customFieldValues[field.key]"
                                            class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800"
                                        >
                                    </template>
                                    <template x-if="field.type === 'file'">
                                        <p class="text-xs text-gray-400">File attachments are captured at the POS, not the order desk.</p>
                                    </template>
                                </div>
                            </template>
                        </template>
                        <div>
                            <label class="mb-1 block text-xs text-gray-500 dark:text-gray-400">Received on</label>
                            <input type="date" x-model="pmReceivedAt" class="fi-input w-full rounded border-gray-300 px-2 py-1.5 text-sm dark:bg-gray-800">
                        </div>
                        <div class="rounded-xl border-2 border-green-600 bg-green-50 p-4 dark:border-green-950/30">
                            <div class="mb-2 flex items-center gap-2">
                                <x-filament::icon icon="heroicon-m-banknotes" class="h-5 w-5 shrink-0 text-green-700 dark:text-green-400" />
                                <label class="text-base font-black tracking-wide text-green-800 uppercase dark:text-green-400">Enter Amount</label>
                            </div>
                            <input
                                type="number" min="0.01" step="0.01"
                                x-model="pmAmount"
                                x-ref="paymentAmountInput"
                                :max="netTotal"
                                :readonly="activeMethod === 'credit'"
                                :placeholder="netTotal.toFixed(2)"
                                x-on:wheel="$event.target.blur()"
                                class="w-full rounded-lg border-2 border-green-600 bg-white px-4 py-4 text-center text-3xl font-black tabular-nums text-gray-900 shadow-sm outline-none placeholder:text-gray-300 focus:ring-4 focus:ring-green-600/30 dark:bg-gray-800 dark:border-green-500 dark:text-gray-100"
                            >
                            <div class="mt-2 flex items-center justify-between gap-2">
                                <span class="text-sm font-bold text-green-800 dark:text-green-400">
                                    Order total:
                                    <span class="tabular-nums" x-text="money(netTotal)"></span>
                                </span>
                                <button
                                    type="button"
                                    x-on:click="pmAmount = balance.toFixed(2)"
                                    x-show="activeMethod !== 'credit'"
                                    class="rounded-md border-2 border-green-600 bg-white px-4 py-1.5 text-xs font-bold text-green-700 hover:bg-green-100 dark:border-green-400 dark:bg-gray-800 dark:text-green-400 dark:hover:bg-white/10"
                                >
                                    Balance
                                </button>
                            </div>
                        </div>
                        <button
                            type="button"
                            x-on:click="addPayment()"
                            :disabled="! advanceCanAdd"
                            class="flex w-full items-center justify-center gap-2 rounded-lg border border-gray-300 bg-white py-3 text-sm font-medium hover:bg-gray-100 disabled:opacity-40 dark:border-white/10 dark:bg-gray-800 dark:hover:bg-white/5"
                        >
                            <span class="flex items-center">
                                <x-filament::icon x-show="activeMethod === 'credit'" icon="heroicon-m-document-check" class="h-4 w-4" />
                                <x-filament::icon x-show="activeMethod !== 'credit'" icon="heroicon-m-plus-circle" class="h-4 w-4" />
                            </span>
                            <span x-text="'Add ' + methodLabel(activeMethod) + ' advance'"></span>
                        </button>
                    </div>
                    <p class="text-center text-xs text-gray-500 dark:text-gray-400">
                        Advances bank against the order when it is invoiced. Nothing is paid now.
                    </p>
                </div>
            </div>
        </div>

        {{-- ── Custom item builder ────────────────────────────────────────── --}}
        <div x-show="customOpen" x-cloak class="fixed inset-0 z-[60] flex items-center justify-center bg-gray-900/60 p-4 backdrop-blur-sm">
            <div x-on:click.outside="closeCustom()" class="max-h-[90vh] w-full max-w-md overflow-y-auto rounded-xl bg-white p-6 shadow-xl dark:bg-gray-900">
                <div class="mb-4 flex items-center justify-between">
                    <h3 class="flex items-center gap-2 text-lg font-semibold">
                        <x-filament::icon icon="heroicon-m-sparkles" class="h-5 w-5 text-primary-600 dark:text-primary-400" />
                        <span x-text="editingCustomIndex === null ? 'New custom item' : 'Edit custom item'"></span>
                    </h3>
                    <button type="button" x-on:click="closeCustom()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200">
                        <x-filament::icon icon="heroicon-m-x-mark" class="h-5 w-5" />
                    </button>
                </div>

                <div class="space-y-3">
                    <div>
                        <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">
                            Item name <span class="text-danger-600">*</span>
                        </label>
                        <input
                            type="text"
                            x-ref="customName"
                            x-model="custom.product_name"
                            x-on:keydown.enter.prevent="saveCustom()"
                            placeholder="e.g. Two-tier birthday cake"
                            maxlength="255"
                            class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800"
                        >
                    </div>
                    <div class="grid grid-cols-2 gap-3">
                        <div>
                            <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">Quantity <span class="text-danger-600">*</span></label>
                            <input type="number" min="0.01" step="any" x-model.number="custom.quantity" class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800">
                        </div>
                        <div>
                            <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">Unit price (Rs.) <span class="text-danger-600">*</span></label>
                            <input type="number" min="0" step="0.01" x-model.number="custom.unit_price" class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800">
                        </div>
                        <div class="col-span-2">
                            <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">Description</label>
                            <textarea
                                x-model="custom.custom_description"
                                rows="2"
                                placeholder="What is being made"
                                class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800"
                            ></textarea>
                        </div>
                        <div class="col-span-2">
                            <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">Exact details from the customer</label>
                            <textarea
                                x-model="custom.custom_specification"
                                rows="2"
                                placeholder="Sizes, colours, wording, packaging — anything they specified"
                                class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800"
                            ></textarea>
                        </div>
                        <div x-show="vatEnabled">
                            <label class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200">VAT rate (%)</label>
                            <input type="number" min="0" max="100" step="0.01" x-model.number="custom.vat_rate" class="fi-input w-full rounded-lg border-gray-300 dark:bg-gray-800">
                        </div>
                        <div class="flex items-end">
                            <p class="text-xs text-gray-500 dark:text-gray-400">
                                Line total<br>
                                <span class="text-sm font-bold text-gray-900 dark:text-white" x-text="money((Number(custom.quantity) || 0) * (Number(custom.unit_price) || 0))"></span>
                            </p>
                        </div>
                    </div>

                    <div class="flex items-center gap-2 pt-2">
                        <button
                            type="button"
                            x-on:click="saveCustom()"
                            x-bind:disabled="! customIsValid()"
                            class="inline-flex items-center gap-1.5 rounded-lg bg-primary-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-primary-500 disabled:cursor-not-allowed disabled:opacity-40"
                        >
                            <x-filament::icon icon="heroicon-m-check" class="h-4 w-4" />
                            <span x-text="editingCustomIndex === null ? 'Add to order' : 'Save changes'"></span>
                        </button>
                        <button
                            type="button"
                            x-on:click="closeCustom()"
                            class="rounded-lg px-3 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800"
                        >
                            Cancel
                        </button>
                        <p x-show="! customIsValid()" class="text-xs text-gray-400 dark:text-gray-500">
                            A name, a quantity and a price are needed.
                        </p>
                    </div>
                </div>
            </div>
        </div>

        {{-- ── Lot picker — the consignment the line quotes from ───────────
             Same rule as the order-desk grid: one sellable lot → taken
             silently; several → the desk picks; none → the virtual
             quotation lot (priced from the last receipt) is used. --}}
        <div x-show="lotPickerOpen" x-cloak class="fixed inset-0 z-[60] flex items-center justify-center bg-gray-900/60 p-4 backdrop-blur-sm" x-on:keydown.escape="closeLots()">
            <div
                x-on:click.outside="closeLots()"
                class="flex max-h-[85vh] w-full max-w-lg flex-col overflow-hidden rounded-xl bg-white shadow-xl dark:bg-gray-900"
            >
                <div class="flex items-center justify-between gap-3 border-b border-gray-200 px-5 py-4 dark:border-white/10">
                    <div class="min-w-0">
                        <h3 class="text-base font-semibold leading-tight">Pick a lot</h3>
                        <p class="truncate text-sm text-gray-500 dark:text-gray-400" x-text="lotPickerProduct?.name"></p>
                    </div>
                    <button type="button" x-on:click="closeLots()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200">
                        <x-filament::icon icon="heroicon-o-x-mark" class="h-5 w-5" />
                    </button>
                </div>

                <div class="min-h-0 flex-1 overflow-auto p-4">
                    <p x-show="lotPickerError" class="py-3 text-center text-sm text-red-600" x-text="lotPickerError"></p>
                    <template x-for="lot in lotPickerLots" :key="lot.id + ':' + (lot.batch ?? 'quote')">
                        <button
                            type="button"
                            x-on:click="confirmLot(lot)"
                            :disabled="! canOverrideBatch && ! lot.is_fefo_front"
                            :title="(! canOverrideBatch && ! lot.is_fefo_front) ? 'Picking a lot other than the next one to sell (FEFO) needs the override permission.' : null"
                            class="mb-1.5 w-full rounded-lg border border-gray-200 bg-white p-3 text-start transition hover:border-primary-400 hover:bg-primary-50/50 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-gray-200 disabled:hover:bg-white dark:border-white/10 dark:bg-gray-800 dark:hover:border-primary-500/40 dark:hover:bg-white/5 dark:disabled:hover:bg-gray-800"
                        >
                            <div class="flex items-center justify-between gap-2">
                                <span class="font-mono text-sm font-semibold text-gray-800 dark:text-gray-200" x-text="lot.batch ?? 'Last receipt price'"></span>
                                <span class="flex shrink-0 items-center gap-2">
                                    <template x-if="lot.is_quote_only">
                                        <span class="rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-semibold text-amber-700 dark:bg-amber-500/10 dark:text-amber-400">Quote only</span>
                                    </template>
                                    <span x-show="lot.is_fefo_front && ! lot.is_quote_only" class="rounded bg-emerald-100 px-1.5 py-0.5 text-[10px] font-semibold text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400">Next to sell</span>
                                    <span class="text-sm font-bold text-primary-600 tabular-nums dark:text-primary-400" x-text="money(lot.price)"></span>
                                </span>
                            </div>
                            <div class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-gray-500 dark:text-gray-400">
                                <span x-text="formatQty(lot.available) + ' available'"></span>
                                <template x-if="lot.expiry"> · exp <span x-text="lot.expiry"></span></template>
                            </div>
                        </button>
                    </template>
                    <p x-show="lotPickerLots.length === 0 && ! lotPickerError" class="py-8 text-center text-sm text-amber-600">
                        No sellable lot for this product at this branch.
                    </p>
                </div>

                <div class="flex items-center justify-end gap-2 border-t border-gray-200 px-5 py-3 dark:border-white/10">
                    <x-filament::button color="gray" x-on:click="closeLots()">
                        Cancel
                    </x-filament::button>
                </div>
            </div>
        </div>

        {{-- ── Order taken modal ─────────────────────────────────────────── --}}
        <div x-show="orderCompleteOpen" x-cloak class="fixed inset-0 z-[70] flex items-center justify-center bg-gray-900/60 p-4 backdrop-blur-sm">
            <div x-on:click.outside="orderCompleteOpen = false" class="w-full max-w-sm rounded-xl bg-white p-6 shadow-xl dark:bg-gray-900">
                <div class="flex items-center gap-3">
                    <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-green-100 text-green-600 dark:bg-green-500/10 dark:text-green-400">
                        <x-filament::icon icon="heroicon-o-check-circle" class="h-6 w-6" />
                    </span>
                    <div class="min-w-0">
                        <h3 class="text-base font-semibold leading-tight">Order Taken</h3>
                        <span class="truncate font-mono text-sm text-gray-500 dark:text-gray-400" x-text="lastOrder?.order_number"></span>
                    </div>
                </div>
                <template x-if="lastOrder?.auto_invoiced">
                    <p class="mt-3 text-sm text-gray-500 dark:text-gray-400">
                        Auto-invoicing is on — this order was invoiced in the same write.
                    </p>
                </template>
                <div class="mt-5 flex justify-end gap-2">
                    <x-filament::button color="gray" x-on:click="resetCart(); orderCompleteOpen = false">
                        New order
                    </x-filament::button>
                    <x-filament::button x-on:click="lastOrder?.url ? window.location.href = lastOrder.url : orderCompleteOpen = false">
                        <span x-text="lastOrder?.auto_invoiced ? 'View invoice tab' : 'View order'"></span>
                    </x-filament::button>
                </div>
            </div>
        </div>
    </div>

    <style>
        /* fitReceipt() is not used here — no receipt preview on the order
           desk; the ticket-style modal renders inline. */
        .fi-create-sales-order { position: relative; }
    </style>

    @script
    <script>
        // ── Searchable combobox (category / subcategory / customer) ────────
        Alpine.data('alpineCombobox', (config) => ({
            open: false,
            query: '',
            highlighted: -1,

            get placeholder() { return config.placeholder || 'Select…' },
            get searchPlaceholder() { return config.searchPlaceholder || 'Search…' },

            get selected() {
                return (config.options || []).find((o) => String(o.id) === String(config.value)) || null;
            },

            get filtered() {
                const q = this.query.trim().toLowerCase();
                if (! q) return config.options || [];
                return (config.options || []).filter((o) =>
                    String(o.name ?? '').toLowerCase().includes(q)
                    || String(o.phone ?? '').toLowerCase().includes(q)
                    || String(o.nic ?? '').toLowerCase().includes(q)
                );
            },

            toggle() {
                this.open = ! this.open;
                if (this.open) {
                    this.query = '';
                    this.highlighted = -1;
                    this.$nextTick(() => this.$refs.search?.focus());
                }
            },

            select(option) {
                if (! option) return;
                config.onchange?.(option.id);
                this.open = false;
            },
        }));

        // ── Fixed/percentage discount popover (cart lines + order level) ──
        Alpine.data('discountPopover', (config) => ({
            open: false,
            draftType: 'fixed',
            draftValue: '',

            get hasDiscount() { return !! config.type && Number(config.value) > 0 },

            get type() { return config.type },
            get value() { return config.value },

            init() {
                this.$watch('open', (opened) => {
                    if (opened) {
                        this.draftType = config.type || 'fixed';
                        this.draftValue = Number(config.value) > 0 ? String(config.value) : '';
                    }
                });
            },

            toggle() {
                this.open = ! this.open;
            },

            clear() {
                config.onclear?.();
                this.open = false;
            },

            apply() {
                const value = parseFloat(this.draftValue) || 0;
                if (value <= 0) {
                    config.onclear?.();
                } else {
                    config.onapply?.(this.draftType, value);
                }
                this.open = false;
            },
        }));

        // ── Create Sales Order terminal ─────────────────────────────────────
        Alpine.data('salesOrderTerminal', (config) => ({
            ...config,

            // Client-only order state
            cart: [],
            search: '',
            mainCat: null,
            subCat: null,

            // Order header state
            orderDate: config.today,
            deadlineDate: '',
            salesRepId: null,
            statusCode: config.defaultStatus,
            orderNotes: '',
            customerId: null,
            customerContextData: {},

            discountType: 'fixed',
            discountValue: 0,

            // Display state — mirrored from the POS terminal: a persisted CSS
            // overlay flag, not the browser Fullscreen API.
            expanded: false,
            // Order panel layout: true (default) = 50/50 table view, false =
            // narrow card list (see toggleCartExpanded()). Independent of
            // `expanded` (fullscreen) so either can be toggled on its own.
            cartExpanded: true,

            // Advance payment state
            advanceOpen: false,
            payments: [],
            activeMethod: 'cash',
            pmAmount: '',
            pmReference: '',
            pmChequeNumber: '',
            pmChequeBank: '',
            pmChequeBranch: '',
            pmChequeDate: '',
            pmReceivedAt: config.today,
            creditNoteId: null,
            customFieldValues: {},

            // Custom item builder state
            customOpen: false,
            editingCustomIndex: null,
            custom: { product_name: '', custom_description: '', custom_specification: '', quantity: 1, unit_price: 0, vat_rate: 0 },

            // Lot picker state
            lotPickerOpen: false,
            lotPickerProduct: null,
            lotPickerLots: [],
            lotPickerLine: null,
            lotPickerError: '',

            // Branch picker state — the blocking overlay renders off
            // `branchRequired` alone (like the POS terminal); nothing toggles
            // it independently since a blocked desk cannot dismiss the prompt.

            // Lot picker: `lotPickerProduct` is the catalog card being quoted
            // (or re-quoted from the cart); `lotPickerLine` is null when
            // adding a new line and the line object when changing a lot.

            // Order taken modal
            orderCompleteOpen: false,
            lastOrder: null,

            submitting: false,
            errors: [],

            methodIconFor(code) {
                return {
                    cash: 'heroicon-m-banknotes',
                    card: 'heroicon-m-credit-card',
                    bank_transfer: 'heroicon-m-building-library',
                    cheque: 'heroicon-m-document-text',
                    credit: 'heroicon-m-document-check',
                }[code] ?? 'heroicon-m-wallet';
            },

            get paymentMethods() {
                return (this.serverPaymentMethods || []).map((m) => {
                    const isCredit = m.code === 'credit';
                    return {
                        code: m.code,
                        label: isCredit ? 'Credit note' : (m.name || m.code),
                        icon: this.methodIconFor(m.code),
                        isCustom: !! m.is_custom,
                        requiresReference: !! m.requires_reference && ! isCredit,
                        requiresChequeFields: !! m.requires_cheque_fields,
                        fields: m.fields,
                    };
                });
            },

            get activeMethodConfig() {
                return this.paymentMethods.find((m) => m.code === this.activeMethod) ?? null;
            },

            get activeCustomMethod() {
                return this.activeMethodConfig?.isCustom ? this.activeMethodConfig : null;
            },

            methodLabel(code) {
                return this.paymentMethods.find((m) => m.code === code)?.label ?? code;
            },

            methodIcon(code) {
                return this.paymentMethods.find((m) => m.code === code)?.icon ?? 'heroicon-m-wallet';
            },

            init() {
                this.expanded = this.readExpanded();
                this.cartExpanded = this.readCartExpanded();
                window.addEventListener('keydown', this.onKeydown);

                // Page-wide scanner capture (see scan-capture-script.blade.php,
                // rendered into every tenant page): a scan reaches handleScan()
                // no matter what has focus. Declined while a modal owns the
                // screen — a scan mid-checkout or mid-lot-pick must not
                // silently start a second action behind it.
                window.VellixScan?.register(this.$root, (code) => {
                    if (this.lotPickerOpen || this.advanceOpen || this.customOpen || this.orderCompleteOpen) {
                        return true;
                    }

                    this.handleScan(code);

                    return true;
                });

                window.addEventListener(
                    'sales-order-customer-created',
                    (event) => {
                        const customer = event.detail?.customer;

                        if (! customer) {
                            return;
                        }

                        this.customers = [
                            ...(this.customers || []).filter(
                                (c) => String(c.id) !== String(customer.id)
                            ),
                            customer,
                        ];

                        this.selectCustomer(customer.id);
                    }
                );
            },

            readExpanded() {
                try {
                    return localStorage.getItem('create-sales-order.expanded') === '1';
                } catch (e) {
                    return false;
                }
            },

            persistExpanded() {
                try {
                    if (this.expanded) {
                        localStorage.setItem('create-sales-order.expanded', '1');
                    } else {
                        localStorage.removeItem('create-sales-order.expanded');
                    }
                } catch (e) {}
            },

            toggleExpanded() {
                this.expanded = ! this.expanded;
                this.persistExpanded();
            },

            // ── Order table view: switches the order column from the narrow
            // card list to a 50/50 table layout (item / qty / price /
            // discount / net amount columns), mirroring the POS terminal's
            // table view. Table view is the default; absence of a stored
            // value (first run, or a browser predating this feature) means
            // "no choice made yet", which resolves to the default (table
            // view), not to off.
            readCartExpanded() {
                try {
                    const stored = localStorage.getItem('create-sales-order.cartExpanded');
                    return stored === null ? true : stored === '1';
                } catch (e) {
                    return true;
                }
            },

            persistCartExpanded() {
                try {
                    localStorage.setItem('create-sales-order.cartExpanded', this.cartExpanded ? '1' : '0');
                } catch (e) {}
            },

            toggleCartExpanded() {
                this.cartExpanded = ! this.cartExpanded;
                this.persistCartExpanded();
            },

            // ── Keyboard shortcuts: F2 search, F8 advance, Esc close ──
            onKeydown(e) {
                if (e.key === 'F2') {
                    e.preventDefault();
                    this.$refs.searchInput?.focus();
                } else if (e.key === 'F8') {
                    e.preventDefault();
                    this.openAdvance();
                } else if (e.key === 'Escape') {
                    this.advanceOpen = false;
                    this.customOpen = false;
                    this.lotPickerOpen = false;
                    this.orderCompleteOpen = false;
                }
            },

            // ── Derived values (pure client-side, no round-trip) ────────────
            get mainCatOptions() {
                const cats = [...new Set((this.products || []).map((p) => p.main_category).filter(Boolean))].sort();
                return [{ id: '__all__', name: 'All' }, ...cats.map((c) => ({ id: c, name: c }))];
            },

            get subCatOptions() {
                const cats = [...new Set(
                    (this.products || [])
                        .filter((p) => ! this.mainCat || p.main_category === this.mainCat)
                        .map((p) => p.sub_category)
                        .filter(Boolean),
                )].sort();
                return [{ id: '__all__', name: 'All' }, ...cats.map((c) => ({ id: c, name: c }))];
            },

            get filteredProducts() {
                const q = this.search.trim().toLowerCase();
                return (this.products || []).filter((p) => {
                    const matchesMain = ! this.mainCat || p.main_category === this.mainCat;
                    const matchesSub = ! this.subCat || p.sub_category === this.subCat;
                    const matchesSearch = ! q
                        || (p.name || '').toLowerCase().includes(q)
                        || (p.sku || '').toLowerCase().includes(q)
                        || (p.barcode || '').toLowerCase().includes(q)
                        || (p.sub_category || '').toLowerCase().includes(q);
                    return matchesMain && matchesSub && matchesSearch;
                });
            },

            get selectedCustomer() {
                if (! this.customerId) return null;
                return (this.customers || []).find((c) => String(c.id) === String(this.customerId)) ?? null;
            },

            cartLineFor(product) {
                const lines = this.cart.filter((line) => line.product_id === product.id);
                if (! lines.length) return null;
                return { quantity: lines.reduce((sum, line) => sum + Number(line.quantity), 0) };
            },

            tapProduct(product) {
                if (this.branchRequired) {
                    return;
                }
                this.addToCart(product);
            },

            cartQtyFor(product) {
                // A product may sit on the cart once per lot — the badge shows
                // the combined quantity while lines stay (product, lot) apart.
                return this.cart
                    .filter((line) => ! line.is_custom && line.product_id === product.id)
                    .reduce((sum, line) => sum + (Number(line.quantity) || 0), 0);
            },

            get cartCount() {
                return this.cart.reduce((sum, line) => sum + (Number(line.quantity) || 0), 0);
            },

            stepFor(line) {
                return line.base_unit?.is_fractional ? 0.1 : 1;
            },

            lineGross(line) {
                return (Number(line.quantity) || 0) * (Number(line.unit_price) || 0);
            },

            // Mirrors SalesOrderService::lineDiscount(): a fixed discount is
            // per-unit (value × quantity), a percentage is of the gross.
            lineDiscount(line) {
                const gross = this.lineGross(line);
                const value = Number(line.discount_value) || 0;
                if (! line.discount_type || value <= 0 || gross <= 0) return 0;
                const amount = line.discount_type === 'percentage'
                    ? gross * (value / 100)
                    : value * (Number(line.quantity) || 0);
                return Math.min(Math.max(amount, 0), gross);
            },

            lineNet(line) {
                return this.lineGross(line) - this.lineDiscount(line);
            },

            get grossSubtotal() {
                return this.cart.reduce((sum, line) => sum + this.lineGross(line), 0);
            },

            get lineDiscountTotal() {
                return this.cart.reduce((sum, line) => sum + this.lineDiscount(line), 0);
            },

            // The order-level discount, on the total net of line discounts —
            // the exact base SalesOrderService::recalculate() applies it to.
            get orderDiscountAmount() {
                const base = this.grossSubtotal - this.lineDiscountTotal;
                const value = Number(this.discountValue) || 0;
                if (! this.discountType || value <= 0 || base <= 0) return 0;
                const amount = this.discountType === 'percentage' ? base * (value / 100) : value;
                return Math.round(Math.min(Math.max(amount, 0), base) * 100) / 100;
            },

            // VAT on each line's NET (after line discount) — matching
            // SalesOrderService::shapeLine(): vat_amount on line_total.
            get vatTotal() {
                if (! this.vatEnabled) return 0;
                return this.cart.reduce((sum, line) => sum + this.lineNet(line) * ((Number(line.vat_rate) || 0) / 100), 0);
            },

            get netTotal() {
                return Math.max(0, this.grossSubtotal - this.lineDiscountTotal - this.orderDiscountAmount + this.vatTotal);
            },

            get advancePaid() {
                return this.payments.reduce((sum, p) => sum + (Number(p.amount) || 0), 0);
            },

            get balance() {
                return Math.max(0, this.netTotal - this.advancePaid);
            },

            get creditNotes() {
                return this.customerContextData.credit_notes ?? [];
            },

            get missingRequiredMethodFields() {
                const cfg = this.activeMethodConfig;
                if (! cfg || this.activeMethod === 'credit') return false;

                if (cfg.requiresReference && ! String(this.pmReference || '').trim()) return true;

                if (cfg.requiresChequeFields && this.activeMethod === 'cheque') {
                    if (! String(this.pmChequeNumber || '').trim()) return true;
                    if (! String(this.pmChequeBank || '').trim()) return true;
                    if (! String(this.pmChequeDate || '').trim()) return true;
                }

                return false;
            },

            get missingRequiredCustomField() {
                return this.activeCustomMethod?.fields?.some(
                    (f) => f.required && f.type !== 'file' && ! String(this.customFieldValues[f.key] ?? '').trim(),
                ) ?? false;
            },

            get advanceCanAdd() {
                const amount = this.activeMethod === 'credit'
                    ? Number(this.selectedCreditNote?.amount ?? this.pmAmount) || 0
                    : Number(this.pmAmount);
                return amount > 0
                    && amount <= this.netTotal + 0.001
                    && ! this.missingRequiredMethodFields
                    && ! this.missingRequiredCustomField
                    && (this.activeMethod !== 'credit' || !! this.creditNoteId);
            },

            get selectedCreditNote() {
                return this.creditNotes.find((cn) => String(cn.id) === String(this.creditNoteId)) ?? null;
            },

            money(value) {
                return 'Rs. ' + (Number(value) || 0).toFixed(2);
            },

            // The card's price caption: one figure, or the min–max range when
            // the product has several priced consignments at this branch.
            priceLabel(product) {
                const min = Number(product.price_min);
                const max = Number(product.price_max);
                const count = Number(product.lot_count) || 0;
                if (! count || ! (min > 0)) return '—';
                if (count === 1 || min === max) return this.money(min);
                return 'Rs. ' + min.toFixed(2) + ' – ' + max.toFixed(2);
            },

            formatQty(value) {
                const n = Number(value) || 0;
                return Number.isInteger(n) ? String(n) : n.toFixed(3);
            },

            formatQtyWithUnit(value, unit) {
                const qty = this.formatQty(value);
                const label = unit?.code || unit?.name;
                return label ? qty + ' ' + label : qty;
            },

            // ── Cart mutations (client-only) ────────────────────────────────
            // The lot IS the price, but unlike the POS there is no FEFO-front
            // auto-take: the payload carries every sellable lot (plus the
            // virtual quotation lot when out of stock), so one lot is taken
            // silently and several open the picker. The client never asks the
            // server — SalesOrderService::quoteLot() re-resolves and reprices
            // server-side when the order is actually saved.
            addToCart(product) {
                if (! product) return;

                const lots = product.lots ?? [];

                if (lots.length === 0) {
                    this.pushLine(product, {
                        id: null,
                        is_quote_only: true,
                        price: Number(product.quote_price ?? product.price_min ?? 0),
                        batch: 'To be received',
                        available: 0,
                    });

                    return;
                }

                if (product.is_batch_tracked === false || lots.length === 1) {
                    this.pushLine(product, lots[0]);
                    return;
                }

                this.openLotPicker(product, null);
            },

            lineFor(productId, batchId) {
                return this.cart.find((line) => ! line.is_custom && line.product_id === productId && line.batch_id === batchId);
            },

            pushLine(product, lot) {
                const batchId = lot.is_quote_only ? null : lot.id;

                const existing = this.lineFor(product.id, batchId);
                if (existing) {
                    existing.quantity = Math.round((Number(existing.quantity) + this.stepFor(existing)) * 100) / 100;
                    return;
                }

                this.cart.push({
                    key: 'p' + product.id + '-' + (batchId ?? 'q') + '-' + Date.now(),
                    product_id: product.id,
                    is_custom: false,
                    name: product.name,
                    unit_price: Number(lot.price) || 0,
                    vat_rate: Number(product.vat_rate) || 0,
                    quantity: this.stepFor({ base_unit: product.base_unit, product_id: product.id }),
                    discount_type: null,
                    discount_value: 0,
                    batch_id: batchId,
                    lot: {
                        id: lot.id,
                        number: lot.batch,
                        expiry: lot.expiry ?? null,
                        available: Number(lot.available) || 0,
                        cost: lot.cost !== null && lot.cost !== undefined
                            ? Number(lot.cost)
                            : null,
                        is_quote_only: !! lot.is_quote_only,
                    },
                    base_unit: product.base_unit ?? null,
                });
            },

            // Enter in the search box, driven by a barcode scanner (scan →
            // Enter) or a rep who typed the full SKU/barcode. Clears the box
            // first, then hands off to handleScan() — the same entry point the
            // page-wide scan listener uses (see
            // resources/views/filament/partials/scan-capture-script.blade.php),
            // so a scan works identically whether or not this box has focus.
            async scanAdd() {
                const q = this.search.trim();
                this.search = '';
                if (q) await this.handleScan(q);
            },

            // The one place a scanned (or typed-then-Enter'd) code becomes an
            // order line.
            //
            // Exact code match wins over an ambiguous text search; otherwise
            // the scan does nothing unless the current filter has already
            // narrowed to exactly one product.
            //
            // A product match is handed to addToCart() — the SAME path a
            // manual card tap takes: zero lots quotes ("to be received"), one
            // lot (or batch tracking off) adds straight through, more than one
            // active lot always opens the lot picker. A scan used to skip that
            // picker and take lots[0] silently; it no longer does — which
            // consignment gets promised is always the rep's call, never the
            // scanner's.
            async handleScan(code) {
                // A label the shop printed itself is not a product identifier
                // but a whole line — product, lot and quantity, decided when
                // the label was made. Recognised by prefix so an ordinary
                // SKU/barcode scan never pays for the lookup.
                if (await this.scanPrintedLabel(code)) return;

                const q = code.trim().toLowerCase();
                if (! q) return;

                const exact = (this.products || []).find((p) =>
                    (p.barcode && p.barcode.toLowerCase() === q) || (p.sku && p.sku.toLowerCase() === q)
                );
                const target = exact || (this.filteredProducts.length === 1 ? this.filteredProducts[0] : null);
                if (! target) return;

                this.addToCart(target);
            },

            // A scan of one of our own printed labels. Returns true when the
            // scan was handled here — whether a line was added or the label was
            // refused — so scanAdd() knows not to also try it as a product code.
            async scanPrintedLabel(code) {
                const prefix = this.labelPrefix || '';
                if (! prefix || ! code.toUpperCase().startsWith(prefix.toUpperCase())) return false;

                this.search = '';

                let result;
                try {
                    result = await $wire.resolveScan(code, this.selectedBranchId);
                } catch (e) {
                    new FilamentNotification()
                        .title('Could not read that label')
                        .body('Check the connection and scan again.')
                        .danger()
                        .send();

                    return true;
                }

                if (! result?.ok) {
                    new FilamentNotification()
                        .title('Label not usable')
                        .body(result?.message ?? 'That label could not be resolved.')
                        .danger()
                        .send();

                    return true;
                }

                this.addLabelLine(result);

                return true;
            },

            // Puts a resolved label straight on the order. An order records no
            // serials (which physical unit ships is settled at invoicing), so
            // only the product, the lot and the quantity carry over.
            addLabelLine(label) {
                const product = (this.products || []).find((p) => p.id === label.product_id) ?? null;
                const lot = label.lot;

                const existing = this.lineFor(label.product_id, lot.id);
                if (existing) {
                    existing.quantity = Math.round((Number(existing.quantity) + Number(label.quantity)) * 10000) / 10000;

                    return;
                }

                this.cart.push({
                    key: 'p' + label.product_id + '-' + lot.id + '-' + Date.now(),
                    product_id: label.product_id,
                    is_custom: false,
                    name: product?.name ?? label.product_name,
                    unit_price: Number(lot.sale_price) || 0,
                    vat_rate: Number(product?.vat_rate) || 0,
                    quantity: Number(label.quantity) || 1,
                    discount_type: null,
                    discount_value: 0,
                    batch_id: lot.id,
                    lot: {
                        id: lot.id,
                        number: lot.internal_batch_number,
                        expiry: lot.expiry_date ?? null,
                        available: Number(lot.available_quantity) || 0,
                        is_quote_only: false,
                    },
                    base_unit: product?.base_unit ?? null,
                });
            },

            bump(line, delta) {
                this.setQty(line, (Number(line.quantity) || 0) + delta * this.stepFor(line));
            },

            setQty(line, raw) {
                const parsed = parseFloat(raw);
                let qty = (! raw || isNaN(parsed)) ? 0 : parsed;
                qty = Math.max(qty, 0);

                if (qty <= 0) {
                    this.removeItem(line);
                    return;
                }

                line.quantity = Math.round(qty * 100) / 100;
            },

            removeItem(line) {
                this.cart = this.cart.filter((l) => l.key !== line.key);
            },

            // ── Lot picker ──────────────────────────────────────────────────
            lotProductFor(line) {
                return (this.products || []).find((p) => p.id === line.product_id) ?? null;
            },

            lotTitle(line) {
                const parts = [this.lotNumber(line)];
                if (line.lot?.expiry) parts.push('exp ' + line.lot.expiry);
                if (line.lot?.is_quote_only) parts.push('quote only');
                return parts.join(' · ');
            },

            lotNumber(line) {
                return line.lot?.number ?? ('Lot #' + line.batch_id);
            },

            openLotPicker(product, line) {
                this.lotPickerProduct = product;
                this.lotPickerLine = line ?? null;
                // The catalog already orders each product's lots sell-order
                // first (FEFO for expiry-tracked products, FIFO otherwise —
                // see SalesOrderCatalog) — the same order SalesOrderService
                // ::quoteLot() draws from when no batch_id is submitted. Index
                // 0 IS the front lot; no separate server flag is needed to say
                // so, only to remember it once the list is mapped below.
                this.lotPickerLots = (product.lots ?? []).map((lot, index) => ({
                    id: lot.id,
                    batch: lot.batch,
                    price: Number(lot.price) || 0,
                    expiry: lot.expiry ?? null,
                    available: Number(lot.available) || 0,
                    is_quote_only: !! lot.is_quote_only,
                    is_fefo_front: index === 0,
                }));
                this.lotPickerError = '';
                this.lotPickerOpen = true;
            },

            openLotLine(line) {
                const product = this.lotProductFor(line);
                if (! product) return;
                this.openLotPicker(product, line);
            },

            confirmLot(lot) {
                if (! this.lotPickerProduct) return;
                if (! this.canOverrideBatch && ! lot.is_fefo_front) return; // server enforces too

                if (this.lotPickerLine) {
                    // Re-quote an existing line to a different lot.
                    const line = this.lotPickerLine;
                    line.batch_id = lot.is_quote_only ? null : lot.id;
                    line.unit_price = Number(lot.price) || 0;
                    line.lot = {
                        id: lot.id,
                        number: lot.batch,
                        expiry: lot.expiry ?? null,
                        available: Number(lot.available) || 0,
                        is_quote_only: !! lot.is_quote_only,
                    };
                } else {
                    this.pushLine(this.lotPickerProduct, lot);
                }

                this.closeLots();
            },

            closeLots() {
                this.lotPickerOpen = false;
                this.lotPickerProduct = null;
                this.lotPickerLots = [];
                this.lotPickerLine = null;
                this.lotPickerError = '';
            },

            // ── Custom (made-to-order) items ────────────────────────────────
            openCustom() {
                this.editingCustomIndex = null;
                this.custom = { product_name: '', custom_description: '', custom_specification: '', quantity: 1, unit_price: 0, vat_rate: 0 };
                this.customOpen = true;
                this.$nextTick(() => this.$refs.customName?.focus());
            },

            editCustom(line) {
                this.editingCustomIndex = line;
                this.custom = {
                    product_name: line.name,
                    custom_description: line.custom_description ?? '',
                    custom_specification: line.custom_specification ?? '',
                    quantity: Number(line.quantity),
                    unit_price: Number(line.unit_price),
                    vat_rate: Number(line.vat_rate) || 0,
                };
                this.customOpen = true;
                this.$nextTick(() => this.$refs.customName?.focus());
            },

            closeCustom() {
                this.customOpen = false;
                this.editingCustomIndex = null;
            },

            customIsValid() {
                return String(this.custom.product_name || '').trim().length > 0
                    && Number(this.custom.quantity) > 0
                    && Number(this.custom.unit_price) >= 0;
            },

            saveCustom() {
                if (! this.customIsValid()) return;

                const payload = {
                    name: String(this.custom.product_name).trim(),
                    custom_description: this.custom.custom_description || null,
                    custom_specification: this.custom.custom_specification || null,
                    quantity: Number(this.custom.quantity),
                    unit_price: Number(this.custom.unit_price),
                    vat_rate: Number(this.custom.vat_rate) || 0,
                };

                if (this.editingCustomIndex === null) {
                    this.cart.push({
                        key: 'c' + Date.now(),
                        product_id: null,
                        is_custom: true,
                        ...payload,
                        discount_type: null,
                        discount_value: 0,
                        batch_id: null,
                        lot: null,
                        base_unit: null,
                    });
                } else {
                    const line = this.editingCustomIndex;
                    Object.assign(line, payload);
                }

                this.closeCustom();
            },

            // ── Customer context (issued credit notes, fetched once) ───────
            async selectCustomer(id) {
                this.customerId = id ? String(id) : '';
                this.customFieldValues = {};
                this.pmAmount = '';
                if (! this.pmReceivedAt) this.pmReceivedAt = this.today;
                if (! this.customerId) {
                    this.customerContextData = {};
                    return;
                }
                const data = await $wire.customerContext(Number(this.customerId));
                if (data) {
                    this.customerContextData = data;
                }
            },

            // ── Advance payments ────────────────────────────────────────────
            openAdvance() {
                this.errors = [];
                this.advanceOpen = true;
                if (! this.paymentMethods.some((m) => m.code === this.activeMethod)) {
                    this.activeMethod = this.paymentMethods[0]?.code ?? this.activeMethod;
                }
                this.$nextTick(() => this.$refs.paymentAmountInput?.focus());
            },

            applyCreditNote(id) {
                const note = this.creditNotes.find((cn) => String(cn.id) === String(id)) ?? null;
                this.pmAmount = note ? Number(note.amount) : '';
            },

            addPayment() {
                if (! this.advanceCanAdd) return;

                const payment = {
                    method: this.activeMethod,
                    amount: Math.round(Number(this.pmAmount) * 100) / 100,
                    received_at: this.pmReceivedAt,
                };

                if (this.activeMethod === 'credit') {
                    payment.credit_note_id = this.creditNoteId;
                }

                if (this.activeMethod === 'cheque') {
                    payment.cheque_number = this.pmChequeNumber;
                    payment.cheque_bank = this.pmChequeBank;
                    payment.cheque_branch = this.pmChequeBranch;
                    payment.cheque_date = this.pmChequeDate;
                }

                if (this.activeMethod === 'card' || this.activeMethod === 'bank_transfer' || this.activeMethodConfig?.requiresReference) {
                    payment.reference = this.pmReference;
                }

                if (this.activeCustomMethod) {
                    payment.custom_fields = this.customFieldValues;
                }

                this.payments.push(payment);
                this.pmAmount = '';
                this.pmReference = '';
                this.pmChequeNumber = '';
                this.pmChequeBank = '';
                this.pmChequeBranch = '';
                this.pmChequeDate = '';
                this.creditNoteId = null;
                this.customFieldValues = {};
                this.advanceOpen = false;
            },

            // ── Branch switching ────────────────────────────────────────────
            switchBranch(branchId) {
                if (! branchId) return;
                const url = new URL(window.location.href);
                url.searchParams.set('branch_id', String(branchId));
                window.location.href = url.toString();
            },

            async chooseBranch(branchId) {
                if (! branchId || this.submitting) return;
                this.submitting = true;
                this.errors = [];
                const result = await $wire.selectBranch(branchId);
                if (! result?.ok) {
                    this.submitting = false;
                    this.errors = result?.errors ?? ['Could not select that branch.'];
                    return;
                }
                window.location.reload();
            },

            // ── The one server boundary ─────────────────────────────────────
            get canSubmit() {
                return ! this.submitting
                    && ! this.branchRequired
                    && this.cart.length > 0
                    && !! this.selectedCustomer;
            },

            cartPayload() {
                return this.cart.map((line) => line.is_custom ? {
                    is_custom: true,
                    product_id: null,
                    product_name: line.name,
                    custom_description: line.custom_description ?? null,
                    custom_specification: line.custom_specification ?? null,
                    quantity: Number(line.quantity),
                    unit_price: Number(line.unit_price),
                    vat_rate: Number(line.vat_rate) || 0,
                    discount_type: line.discount_type ?? null,
                    discount_value: Number(line.discount_value) || 0,
                } : {
                    is_custom: false,
                    product_id: line.product_id,
                    quantity: Number(line.quantity),
                    unit_price: Number(line.unit_price),
                    vat_rate: Number(line.vat_rate) || 0,
                    batch_id: line.batch_id ?? null,
                    discount_type: line.discount_type ?? null,
                    discount_value: Number(line.discount_value) || 0,
                });
            },

            paymentsPayload() {
                return this.payments.map((p) => {
                    const payload = {
                        method: p.method,
                        amount: Number(p.amount),
                        received_at: p.received_at ?? this.today,
                    };
                    if (p.reference) payload.reference = p.reference;
                    if (p.cheque_number) payload.cheque_number = p.cheque_number;
                    if (p.cheque_bank) payload.cheque_bank = p.cheque_bank;
                    if (p.cheque_branch) payload.cheque_branch = p.cheque_branch;
                    if (p.cheque_date) payload.cheque_date = p.cheque_date;
                    if (p.credit_note_id) payload.credit_note_id = p.credit_note_id;
                    if (p.custom_fields) payload.custom_fields = p.custom_fields;
                    return payload;
                });
            },

            async placeOrder() {
                if (! this.canSubmit) {
                    this.errors = [this.branchRequired
                        ? 'Select a branch first.'
                        : (this.selectedCustomer ? '' : 'Select a customer — orders are recorded against one.')
                        || (this.cart.length === 0 ? 'Add at least one line.' : '')].filter(Boolean);
                    if (this.errors.length) return;
                }

                this.submitting = true;
                this.errors = [];

                const result = await $wire.createOrder({
                    branch_id: this.selectedBranchId,
                    customer_id: Number(this.customerId),
                    sales_rep_id: this.salesRepId ? Number(this.salesRepId) : null,
                    order_date: this.orderDate || this.today,
                    deadline_date: this.deadlineDate || null,
                    status_code: this.statusCode,
                    note: this.orderNotes.trim() || null,
                    discount_type: this.discountType,
                    discount_value: Number(this.discountValue) || 0,
                    items: this.cartPayload(),
                    payments: this.paymentsPayload(),
                });

                this.submitting = false;

                if (! result?.ok) {
                    this.errors = result?.errors ?? ['Could not take the order.'];
                    return;
                }

                this.lastOrder = {
                    order_number: result.order_number,
                    url: result.url,
                    auto_invoiced: !! result.auto_invoiced,
                };
                this.resetCart();
                this.orderCompleteOpen = true;
            },

            resetCart() {
                this.cart = [];
                this.payments = [];
                this.discountType = 'fixed';
                this.discountValue = 0;
                this.orderNotes = '';
                this.customerId = null;
                this.customerContextData = {};
                this.errors = [];
                this.orderDate = this.today;
                this.deadlineDate = '';
                this.salesRepId = null;
                this.statusCode = this.defaultStatus;
            },
        }));
    </script>
    @endscript
</x-filament-panels::page>