frappe.pages['receiving'].on_page_load = function(wrapper) {
    var page = frappe.ui.make_app_page({
        parent: wrapper,
        title: 'Receiving',
        single_column: true
    });

    $(wrapper).find('.layout-main-section').html(`
        <div class="receiving-station" style="padding: 20px;">
            <ul class="nav nav-tabs" role="tablist" id="receiving-tabs">
                <li role="presentation" class="active"><span class="stage-tab active" data-target="#stage-a" style="cursor:pointer">📋 Stage A — Schedule Pickup</span></li>
                <li role="presentation"><span class="stage-tab" data-target="#stage-b" style="cursor:pointer">🗺️ Stage B — Route & Dispatch</span></li>
                <li role="presentation"><span class="stage-tab" data-target="#stage-c" style="cursor:pointer">⚖️ Stage C — Load Check-in</span></li>
            </ul>
            <div class="tab-content" style="padding-top: 20px;">
                <div role="tabpanel" class="tab-pane active" id="stage-a">
                    <div class="row">
                        <div class="col-md-3">
                            <div class="panel panel-primary">
                                <div class="panel-heading">📅 Pickup Calendar — Next 30 Days</div>
                                <div class="panel-body" id="pickup-calendar"><div class="text-muted text-center">Loading...</div></div>
                            </div>
                        </div>
                        <div class="col-md-9">
                            <div class="panel panel-default">
                                <div class="panel-heading">
                                    <div class="row">
                                        <div class="col-md-6"><strong>Scheduled Pickups</strong><span id="pickup-count-label" class="text-muted" style="margin-left: 8px;"></span></div>
                                        <div class="col-md-6 text-right">
                                            <button class="btn btn-primary btn-sm" id="btn-new-pickup">+ New Pickup</button>
                                            <input type="date" id="pickup-date-filter" class="form-control input-sm" style="display:inline-block;width:auto;vertical-align:middle;margin-left:8px;">
                                            <button class="btn btn-default btn-sm" id="btn-clear-date" style="margin-left:4px;">Clear</button>
                                        </div>
                                    </div>
                                </div>
                                <div class="panel-body" style="padding: 0; overflow-x: auto;">
                                    <table class="table table-striped table-hover" id="pickup-table" style="font-size: 13px; margin-bottom: 0;">
                                        <thead><tr><th>Date</th><th>Type</th><th>Customer</th><th>Contact</th><th>Address</th><th>Items</th><th>Data</th><th>RED/R2</th><th>Status</th><th>Notes</th></tr></thead>
                                        <tbody id="pickup-tbody"><tr><td colspan="10" class="text-center text-muted">Loading...</td></tr></tbody>
                                    </table>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div role="tabpanel" class="tab-pane" id="stage-b">
                    <div class="row" style="margin-bottom: 16px;"><div class="col-md-12"><div class="btn-group"><input type="date" id="route-date" class="form-control" style="display:inline-block;width:auto;"><button class="btn btn-primary" id="btn-load-routes">Load Pickups</button><button class="btn btn-primary" id="btn-auto-route">🧮 Auto-Route</button><button class="btn btn-success" id="btn-route-sheet">🖨️ Route Sheet</button><button class="btn btn-success" id="btn-green-sheet">📄 Green Sheet</button><button class="btn btn-success" id="btn-labels">🏷️ Labels</button></div></div></div>
                    <div class="row" id="route-columns">
                        <div class="col-md-4"><div class="panel panel-default truck-column" data-truck="Truck 1"><div class="panel-heading">🚛 Truck 1 <span id="truck1-count" class="text-muted"></span></div><div class="panel-body truck-stops" id="truck1-stops"></div></div></div>
                        <div class="col-md-4"><div class="panel panel-default truck-column" data-truck="Truck 2"><div class="panel-heading">🚛 Truck 2 <span id="truck2-count" class="text-muted"></span></div><div class="panel-body truck-stops" id="truck2-stops"></div></div></div>
                        <div class="col-md-4"><div class="panel panel-default truck-column" data-truck="Truck 3"><div class="panel-heading">🚛 Truck 3 <span id="truck3-count" class="text-muted"></span></div><div class="panel-body truck-stops" id="truck3-stops"></div></div></div>
                    </div>
                    <div class="row" style="margin-top: 16px;"><div class="col-md-12"><div class="panel panel-default truck-column" data-truck=""><div class="panel-heading">📋 Unassigned <span id="unassigned-count" class="text-muted"></span></div><div class="panel-body truck-stops" id="unassigned-stops"></div></div></div></div>
                </div>
                <div role="tabpanel" class="tab-pane" id="stage-c">
                    <div class="row" style="margin-bottom: 16px;"><div class="col-md-12"><button class="btn btn-primary" id="btn-new-checkin">+ Check In Load</button><button class="btn btn-success" id="btn-cor-report">📋 CoR Report</button></div></div>
                    <div class="panel panel-default">
                        <div class="panel-heading">Recent Check-ins</div>
                        <div class="panel-body" style="padding: 0; overflow-x: auto;">
                            <table class="table table-striped table-hover" id="checkin-table" style="font-size: 13px; margin-bottom: 0;">
                                <thead><tr><th>Date</th><th>Customer</th><th>Load #</th><th class="text-right">Pallets</th><th class="text-right">Weight</th><th>Contents</th><th>Data Status</th><th>RED/R2</th></tr></thead>
                                <tbody id="checkin-tbody"><tr><td colspan="8" class="text-center text-muted">Loading...</td></tr></tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <style>
            .truck-stops { min-height: 60px; }
            .stop-card { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 6px; padding: 10px 12px; margin: 6px 0; cursor: grab; font-size: 13px; }
            .stop-card:hover { border-color: #2F5496; }
            .stop-card .stop-co { font-weight: 700; color: #2F5496; }
            .stop-card .stop-addr { color: #666; font-size: 12px; margin-top: 2px; }
            .stop-card .stop-meta { display: flex; gap: 8px; margin-top: 4px; font-size: 11px; }
            .stop-card .stop-meta span { background: #D6E4F0; color: #2F5496; padding: 1px 6px; border-radius: 3px; }
            .cal-day { display: inline-block; width: 36px; height: 36px; line-height: 36px; text-align: center; margin: 1px; border-radius: 4px; font-size: 12px; cursor: pointer; }
            .cal-day:hover { background: #D6E4F0; }
            .cal-day.has-pickups { background: #2F5496; color: #fff; font-weight: 700; }
            .stage-tab { display: inline-block; padding: 10px 15px; font-size: 14px; color: #555; } .stage-tab:hover { color: #2F5496; } .stage-tab.active { color: #2F5496; font-weight: 600; border-bottom: 2px solid #2F5496; }
            .cal-day.today { border: 2px solid #C62828; }
            /* Tighten Frappe Section Break bars in dialogs by 2/3 */
            .modal-dialog .section-head { padding-top: 3px !important; padding-bottom: 3px !important; font-size: 12px !important; }
            .modal-dialog .form-section { padding-top: 2px !important; padding-bottom: 2px !important; }
            .modal-dialog .section-desc { font-size: 11px !important; }
        </style>
    `);

    // Tab switching
    $("#receiving-tabs").on("click", ".stage-tab", function() {
        var target = $(this).data("target");
        $("#receiving-tabs li, .stage-tab").removeClass("active");
        $(this).addClass("active").closest("li").addClass("active");
        $(".tab-pane").removeClass("active");
        $(target).addClass("active");
    });

    // ── Stage A: New Pickup DIALOG ──
    $("#btn-new-pickup").on("click", function() {
        var d = new frappe.ui.Dialog({
            title: "New Scheduled Pickup",
            size: "large",
            fields: [
                {fieldtype: "Section Break", label: "📅 Pickup Info"},
                {fieldname: "pickup_date", fieldtype: "Date", label: "Pickup Date", reqd: 1, default: frappe.datetime.nowdate()},
                {fieldname: "pickup_type", fieldtype: "Select", label: "Type", reqd: 1, options: "Pickup\nDrop-off", default: "Pickup"},
                {fieldname: "customer_number", fieldtype: "Link", label: "Customer", options: "Customer", reqd: 1},
                {fieldname: "company_name", fieldtype: "Data", label: "Company Name", read_only: 1},
                {fieldtype: "Column Break"},
                {fieldname: "contact_name", fieldtype: "Data", label: "Contact Name"},
                {fieldname: "contact_phone", fieldtype: "Data", label: "Contact Phone"},
                {fieldname: "contact_email", fieldtype: "Data", label: "Contact Email"},
                {fieldtype: "Section Break", label: "📍 Address"},
                {fieldname: "address_line", fieldtype: "Data", label: "Street Address"},
                {fieldname: "city", fieldtype: "Data", label: "City"},
                {fieldtype: "Column Break"},
                {fieldname: "state", fieldtype: "Data", label: "State", default: "AZ"},
                {fieldname: "zip_code", fieldtype: "Data", label: "ZIP"},
                {fieldname: "hours_of_operation", fieldtype: "Data", label: "Hours of Operation", placeholder: "e.g. Mon-Fri 8am-5pm"},
                {fieldtype: "Section Break", label: "📦 Load Info"},
                {fieldname: "estimated_items", fieldtype: "Int", label: "Estimated Items"},
                {fieldname: "estimated_weight", fieldtype: "Data", label: "Estimated Weight"},
                {fieldname: "load_contents", fieldtype: "Data", label: "Load Contents", placeholder: "Wire, Monitors, Laptops..."},
                {fieldtype: "Column Break"},
                {fieldname: "data_status", fieldtype: "Select", label: "Data Status", options: "\nD0\nD1\nND1\nND2\nND3\nND4"},
                {fieldname: "red_r2", fieldtype: "Select", label: "RED / R2", options: "\nRED\nNIST\nRed+NIST\nR2\nBoth\nNeither"},
                {fieldname: "needs_aor", fieldtype: "Check", label: "Needs AoR"},
                {fieldname: "needs_cod", fieldtype: "Check", label: "Needs CoD"},
                {fieldname: "notes", fieldtype: "Small Text", label: "Notes / Special Handling"},
            ],
            primary_action_label: "Save Pickup",
            primary_action: function(values) {
                if (!values.customer_number) { frappe.msgprint("Select a customer"); return; }
                values.doctype = "Scheduled Pickup";
                values.status = "Scheduled";
                frappe.call({
                    method: "frappe.client.insert",
                    args: { doc: values },
                    callback: function(r) {
                        if (r.message) {
                            frappe.show_alert({message: "Pickup scheduled", indicator: "green"});
                            d.hide();
                            loadPickups();
                        }
                    }
                });
            }
        });

        // Auto-fill customer details on selection
        d.fields_dict.customer_number.$input.on("change", function() {
            var val = d.get_value("customer_number");
            if (!val) return;
            frappe.call({
                method: "frappe.client.get",
                args: { doctype: "Customer", name: val },
                callback: function(r) {
                    if (!r.message) return;
                    var c = r.message;
                    d.set_value("company_name", c.customer_name || "");
                    frappe.call({
                        method: "frappe.client.get_list",
                        args: {
                            doctype: "Address",
                            filters: [["Dynamic Link", "link_name", "=", val]],
                            fields: ["name", "address_line1", "city", "state", "pincode"],
                            limit_page_length: 1
                        },
                        callback: function(ra) {
                            if (ra.message && ra.message.length) {
                                var a = ra.message[0];
                                d.set_value("address_line", a.address_line1 || "");
                                d.set_value("city", a.city || "");
                                d.set_value("state", a.state || "AZ");
                                d.set_value("zip_code", a.pincode || "");
                            }
                        }
                    });
                    frappe.call({
                        method: "frappe.client.get_list",
                        args: {
                            doctype: "Contact",
                            filters: [["Dynamic Link", "link_name", "=", val]],
                            fields: ["first_name", "last_name", "email_id", "phone", "mobile_no"],
                            limit_page_length: 1
                        },
                        callback: function(rc) {
                            if (rc.message && rc.message.length) {
                                var ct = rc.message[0];
                                d.set_value("contact_name", (ct.first_name || "") + " " + (ct.last_name || ""));
                                d.set_value("contact_phone", ct.phone || ct.mobile_no || "");
                                d.set_value("contact_email", ct.email_id || "");
                            }
                        }
                    });
                }
            });
        });

        d.show();
    });

    // ── Stage A: Load Pickups ──
    function loadPickups() {
        var dateFilter = $("#pickup-date-filter").val();
        frappe.call({
            method: "westech_r2.westech_r2.api.receiving_api.get_pickups",
            args: { date: dateFilter || undefined },
            callback: function(r) {
                if (r.message) {
                    renderPickupTable(r.message.pickups || []);
                    renderCalendar(r.message.calendar || []);
                }
            }
        });
    }

    function renderPickupTable(pickups) {
        var tbody = $("#pickup-tbody");
        $("#pickup-count-label").text("(" + pickups.length + ")");
        if (!pickups.length) {
            tbody.html('<tr><td colspan="10" class="text-center text-muted">No pickups found</td></tr>');
            return;
        }
        tbody.html(pickups.map(function(p) {
            return '<tr style="cursor:pointer" data-pickup="' + esc(p.name) + '">' +
                '<td>' + esc(p.pickup_date || "") + '</td>' +
                '<td>' + esc(p.pickup_type || "") + '</td>' +
                '<td><strong>' + esc(p.company_name || p.customer_number || "") + '</strong></td>' +
                '<td>' + esc(p.contact_name || "") + '</td>' +
                '<td style="max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc(p.address_line || "") + (p.city ? ", " + esc(p.city) : "") + '</td>' +
                '<td class="text-right">' + (p.estimated_items || "—") + '</td>' +
                '<td>' + esc(p.data_status || "—") + '</td>' +
                '<td>' + esc(p.red_r2 || "—") + '</td>' +
                '<td>' + esc(p.status || "") + '</td>' +
                '<td style="max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc(p.notes || "") + '</td></tr>';
        }).join(""));
    }

    function renderCalendar(calendar) {
        var el = $("#pickup-calendar");
        if (!calendar.length) { el.html('<div class="text-muted text-center">No data</div>'); return; }
        var todayStr = frappe.datetime.nowdate();
        var html = '<div style="text-align:center;">';
        calendar.forEach(function(d) {
            var cls = "cal-day";
            if (d.count > 0) cls += " has-pickups";
            if (d.date === todayStr) cls += " today";
            var label = d.date.substring(5);
            html += '<div class="' + cls + '" data-date="' + d.date + '" title="' + d.count + ' pickup(s)">' + label + '</div>';
        });
        html += '</div>';
        el.html(html);
    }

    $(document).on("click", ".cal-day.has-pickups", function() {
        $("#pickup-date-filter").val($(this).data("date"));
        loadPickups();
    });

    $("#pickup-date-filter").on("change", loadPickups);
    $("#btn-clear-date").on("click", function() {
        $("#pickup-date-filter").val("");
        loadPickups();
    });

    // ── Stage B: Routing ──
    function loadRoutes() {
        var date = $("#route-date").val() || frappe.datetime.nowdate();
        $("#route-date").val(date);
        frappe.call({
            method: "westech_r2.westech_r2.api.receiving_api.get_pickups",
            args: { date: date },
            callback: function(r) {
                if (r.message) renderRouteColumns(r.message.pickups || []);
            }
        });
    }

    function renderRouteColumns(pickups) {
        var trucks = { "Truck 1": [], "Truck 2": [], "Truck 3": [], "Unassigned": [] };
        pickups.forEach(function(p) {
            var t = p.truck || "";
            if (t && trucks[t]) trucks[t].push(p);
            else trucks["Unassigned"].push(p);
        });
        ["Truck 1", "Truck 2", "Truck 3"].forEach(function(t) {
            var key = t.toLowerCase().replace(/ /g, "");
            $("#" + key + "-count").text("(" + trucks[t].length + " stops)");
            $("#" + key + "-stops").html(trucks[t].map(function(p, i) { return stopCard(p, i + 1); }).join(""));
        });
        $("#unassigned-count").text("(" + trucks["Unassigned"].length + ")");
        $("#unassigned-stops").html(trucks["Unassigned"].map(function(p) { return stopCard(p, 0); }).join(""));
    }

    function stopCard(p, order) {
        var h = '<div class="stop-card" data-pickup="' + esc(p.name) + '">';
        if (order) h += '<div style="font-size:11px;color:#666;margin-bottom:2px">Stop #' + order + '</div>';
        h += '<div class="stop-co">' + esc(p.company_name || p.customer_number || "Unknown") + '</div>';
        h += '<div class="stop-addr">' + esc((p.address_line || "") + (p.city ? ", " + p.city : "")) + '</div>';
        h += '<div class="stop-meta">';
        if (p.estimated_items) h += '<span>' + p.estimated_items + ' items</span>';
        if (p.data_status) h += '<span>' + esc(p.data_status) + '</span>';
        if (p.red_r2) h += '<span>' + esc(p.red_r2) + '</span>';
        if (p.needs_aor) h += '<span>AoR</span>';
        if (p.needs_cod) h += '<span>CoD</span>';
        h += '</div></div>';
        return h;
    }

    $("#btn-load-routes").on("click", loadRoutes);
    $("#btn-auto-route").on("click", function() {
        var date = $("#route-date").val();
        if (!date) { frappe.msgprint("Select a date first"); return; }
        frappe.call({
            method: "westech_r2.westech_r2.api.receiving_api.auto_route",
            args: { date: date },
            callback: function(r) {
                if (r.message && r.message.success) { frappe.show_alert({message: "Routes optimized", indicator: "green"}); loadRoutes(); }
            }
        });
    });
    $("#btn-route-sheet").on("click", function() {
        var date = $("#route-date").val() || frappe.datetime.nowdate();
        window.open("/api/method/westech_r2.westech_r2.api.receiving_api.print_route_sheet?date=" + date, "_blank");
    });
    $("#btn-green-sheet").on("click", function() {
        var date = $("#route-date").val() || frappe.datetime.nowdate();
        window.open("/api/method/westech_r2.westech_r2.api.receiving_api.print_green_sheet?date=" + date, "_blank");
    });
    $("#btn-labels").on("click", function() {
        var date = $("#route-date").val() || frappe.datetime.nowdate();
        window.open("/api/method/westech_r2.westech_r2.api.receiving_api.print_labels?date=" + date, "_blank");
    });

    // ── Stage C: Check-in DIALOG ──
    $("#btn-new-checkin").on("click", function() {
        var d = new frappe.ui.Dialog({
            title: "Load Check-in",
            size: "large",
            fields: [
                {fieldtype: "Section Break", label: "📅 Pickup Reference"},
                {fieldname: "pickup_ref", fieldtype: "Link", label: "Scheduled Pickup", options: "Scheduled Pickup", reqd: 1,
                    get_query: function() { return { filters: [["Scheduled Pickup", "status", "in", ["Scheduled", "Routed", "In Progress"]]] }; }
                },
                {fieldname: "pickup_info", fieldtype: "HTML", label: "Pickup Details"},
                {fieldtype: "Section Break", label: "⚖️ Actual Load"},
                {fieldname: "received_date", fieldtype: "Date", label: "Received Date", reqd: 1, default: frappe.datetime.nowdate()},
                {fieldname: "actual_pallets", fieldtype: "Int", label: "Actual # of Pallets/Gaylords", reqd: 1, default: 1},
                {fieldname: "total_weight", fieldtype: "Data", label: "Total Weight (lbs)"},
                {fieldtype: "Column Break"},
                {fieldname: "load_contents", fieldtype: "Small Text", label: "Load Contents", placeholder: "e.g. 80% wire 20% tablets"},
                {fieldname: "data_status", fieldtype: "Select", label: "Data Status", options: "\nD0\nD1\nND1\nND2\nND3\nND4"},
                {fieldname: "red_r2", fieldtype: "Select", label: "RED / R2", options: "\nRED\nNIST\nRed+NIST\nR2\nBoth\nNeither"},
            ],
            primary_action_label: "✓ Check In Load",
            primary_action: function(values) {
                if (values.actual_pallets < 1) { frappe.msgprint("Enter at least 1 pallet"); return; }
                frappe.confirm("Check in " + values.actual_pallets + " pallet(s) for this load?", function() {
                    frappe.call({
                        method: "westech_r2.westech_r2.api.receiving_api.checkin_load",
                        args: {
                            pickup_name: values.pickup_ref,
                            received_date: values.received_date,
                            actual_pallets: values.actual_pallets,
                            total_weight: values.total_weight,
                            load_contents: values.load_contents,
                            data_status: values.data_status,
                            red_r2: values.red_r2
                        },
                        callback: function(r) {
                            if (r.message && r.message.success) {
                                frappe.show_alert({message: "Load checked in! " + r.message.pallets_created + " pallet(s) in Load " + r.message.load, indicator: "green"});
                                d.hide();
                                loadCheckins();
                                loadPickups();
                            }
                        }
                    });
                });
            }
        });

        // Load pickup details on selection
        d.fields_dict.pickup_ref.$input.on("change", function() {
            var val = d.get_value("pickup_ref");
            if (!val) { d.fields_dict.pickup_info.html(""); return; }
            frappe.call({
                method: "westech_r2.westech_r2.api.receiving_api.get_pickup_details",
                args: { pickup_name: val },
                callback: function(r) {
                    if (!r.message) return;
                    var p = r.message;
                    var html = '<div style="background:#f8f9fa;border:1px solid #ddd;border-radius:4px;padding:10px;">';
                    html += '<div style="font-weight:700;font-size:14px;">' + esc(p.company_name || p.customer_number || "Unknown") + '</div>';
                    html += '<div style="font-size:12px;color:#666;">' + esc((p.address_line || "") + (p.city ? ", " + p.city : "") + (p.state ? ", " + p.state : "") + (p.zip_code ? " " + p.zip_code : "")) + '</div>';
                    html += '<div style="font-size:12px;color:#666;">' + esc((p.contact_name || "") + (p.contact_phone ? " &bull; " + p.contact_phone : "") + (p.contact_email ? " &bull; " + p.contact_email : "")) + '</div>';
                    if (p.red_r2 && p.red_r2 !== "Neither" && p.red_r2 !== "") {
                        html += '<div style="margin-top:8px;padding:6px;background:#FFCDD2;border:1px solid #C62828;border-radius:4px;font-size:12px;"><strong>&#9888; ' + esc(p.red_r2) + '</strong> &mdash; Special handling required' + (p.needs_aor ? ' &bull; AoR &#10003;' : '') + (p.needs_cod ? ' &bull; CoD &#10003;' : '') + '</div>';
                    }
                    if (p.notes) {
                        html += '<div style="margin-top:8px;padding:6px;background:#F5F5F5;border:1px solid #999;border-radius:4px;font-size:12px;"><strong>Notes:</strong> ' + esc(p.notes) + '</div>';
                    }
                    html += '</div>';
                    d.fields_dict.pickup_info.html(html);
                    d.set_value("actual_pallets", p.estimated_items || 1);
                    d.set_value("data_status", p.data_status || "");
                    d.set_value("red_r2", p.red_r2 || "");
                }
            });
        });

        d.show();
    });

    // ── Stage C: Load Checkins ──
    function loadCheckins() {
        frappe.call({
            method: "westech_r2.westech_r2.api.receiving_api.get_checkins",
            callback: function(r) {
                if (r.message) renderCheckinTable(r.message.checkins || []);
            }
        });
    }

    function renderCheckinTable(checkins) {
        var tbody = $("#checkin-tbody");
        if (!checkins.length) {
            tbody.html('<tr><td colspan="8" class="text-center text-muted">No check-ins yet</td></tr>');
            return;
        }
        tbody.html(checkins.map(function(c) {
            return '<tr>' +
                '<td>' + esc(c.incoming_date || "") + '</td>' +
                '<td><strong>' + esc(c.customer_name || c.customer || "") + '</strong></td>' +
                '<td>' + esc(c.name || "") + '</td>' +
                '<td class="text-right">' + (c.pallet_count || 0) + '</td>' +
                '<td class="text-right">' + (c.total_weight || "—") + '</td>' +
                '<td style="max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc(c.data_status || "") + '</td>' +
                '<td>' + esc(c.red_r2 || "—") + '</td>' +
                '<td style="font-size:11px;color:#666;">' + ((c.pallets || []).map(function(p) { return esc(p.pallet_number || p.name); }).join(", ")) + '</td></tr>';
        }).join(""));
    }

    $("#btn-cor-report").on("click", function() {
        window.open("/api/method/westech_r2.westech_r2.api.receiving_api.cor_report", "_blank");
    });

    // ── Helpers ──
    function esc(s) { return s ? String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;") : ""; }

    // ── Init ──
    loadPickups();
    loadCheckins();
};