<script lang="ts">
  import { flip } from "svelte/animate";
  import { onMount, onDestroy } from "svelte";
  import { createEventDispatcher } from "svelte";
  import { beforeNavigate } from "$app/navigation";
  import type { OpportunityProduct } from "../types";
  import { formatCurrency } from "../types";
  import { optima } from "$lib";
  import NoResultsMonkey from "../../../../../components/NoResultsMonkey.svelte";
  import AddProductModal from "../../../../../components/AddProductModal.svelte";
  import InventoryPopover from "../../../../../components/InventoryPopover.svelte";
  import type { CatalogItem } from "$lib/optima-api/modules/procurement";
  import type {
    AddProductBody,
    AddLaborBody,
    CancelOpportunityProductBody,
    LaborCustomerType,
    LaborStyle,
    SpecialOrderBody,
  } from "$lib/optima-api/modules/sales";
  import type { PermissionMap } from "$lib/permissions";

  export let products: OpportunityProduct[];
  export let accessToken: string | null;
  export let opportunityId: string;
  export let productSequence: number[] | null = null;
  export let initialProductId: number | null = null;
  export let permissions: PermissionMap = {} as PermissionMap;
  export let isClosedOpportunity: boolean = false;
  export let salesTaxRate: number | null = null;
  export let taxCodeDescription: string | null = null;

  $: canViewMargin = permissions["sales.opportunity.view_margin"] !== false;
  $: canViewCost = permissions["sales.opportunity.view_cost"] !== false;
  $: canViewProfit = permissions["sales.opportunity.view_profit"] !== false;

  const dispatch = createEventDispatcher<{
    sequenceSaved: number[];
    productsChanged: OpportunityProduct[];
  }>();

  let showAddProductModal = false;

  let isAddingProduct = false;
  let addProductError = "";

  function buildProductBody(item: CatalogItem): AddProductBody {
    const body: AddProductBody = {};

    // For catalog items with a CW catalog ID, link them
    if (item.cwCatalogId) {
      body.catalogItem = { id: item.cwCatalogId };
    }

    // Use description for forecast/product description
    if (item.description) {
      body.forecastDescription = item.description;
      // When linking to a catalog item, use its default product name
      if (!item.cwCatalogId) {
        body.productDescription = item.description;
      }
    }

    if (item.customerDescription) {
      body.customerDescription = item.customerDescription;
    }

    if (item.procurementNotes) {
      body.procurementNotes = item.procurementNotes;
    }

    if (item.productNarrative) {
      body.productNarrative = item.productNarrative;
    }

    // Default quantity of 1
    const qty = item.quantity && item.quantity > 0 ? item.quantity : 1;
    body.quantity = qty;

    // Use the raw catalog unit price/cost — not adjusted by cancellations
    // CW expects revenue/cost as totals (unit × quantity)
    if (item.price != null) body.revenue = item.price * qty;
    if (item.cost != null) body.cost = item.cost * qty;

    if (item.taxableFlag != null) {
      body.taxableFlag = item.taxableFlag;
    }

    return body;
  }

  async function refreshProducts() {
    if (!accessToken) return;
    try {
      const result = await optima.sales.fetchProducts(
        accessToken,
        opportunityId
      );
      if (result?.data) {
        products = result.data;
        dispatch("productsChanged", products);
      }
    } catch (err) {
      console.error("[Products] Failed to refresh:", err);
    }
  }

  async function handleProductSelected(incoming: CatalogItem | CatalogItem[]) {
    if (!accessToken) return;
    const items = Array.isArray(incoming) ? incoming : [incoming];
    if (items.length === 0) return;

    const laborItems = items.filter((item) => item.identifier === "LABOR");
    const specialOrderItems = items.filter(
      (item) => item.identifier === "SPECIAL-ORDER"
    );
    const standardItems = items.filter(
      (item) =>
        item.identifier !== "SPECIAL-ORDER" && item.identifier !== "LABOR"
    );

    isAddingProduct = true;
    addProductError = "";
    try {
      const newProducts: OpportunityProduct[] = [];

      // Add standard catalog items through generic endpoint
      if (standardItems.length > 0) {
        const results = await Promise.all(
          standardItems.map((item) =>
            optima.sales.addProduct(
              accessToken!,
              opportunityId,
              buildProductBody(item)
            )
          )
        );
        for (const result of results) {
          if (result?.data) {
            const items = Array.isArray(result.data)
              ? result.data
              : [result.data];
            newProducts.push(...items);
          }
        }
      }

      if (laborItems.length > 0) {
        const payload: AddLaborBody[] = laborItems.map((item) => {
          const laborStyle = (item.laborStyle ?? "field") as LaborStyle;
          const customerType = (item.customerType ??
            "corporate") as LaborCustomerType;
          const hours =
            typeof item.hours === "number"
              ? item.hours
              : item.quantity && item.quantity > 0
                ? item.quantity
                : 1;
          const ppu = typeof item.ppu === "number" ? item.ppu : item.price;
          const cpu = typeof item.cpu === "number" ? item.cpu : item.cost;
          const rate = typeof item.rate === "number" ? item.rate : ppu;

          return {
            laborStyle,
            customerType,
            hours,
            taxable: item.taxableFlag,
            rate,
            ppu,
            cpu,
            description: item.description,
            customerDescription: item.customerDescription,
            procurementNotes: item.procurementNotes,
            productNarrative: item.productNarrative,
          };
        });

        const results = await Promise.all(
          payload.map((body) =>
            optima.sales.addLabor(accessToken!, opportunityId, body)
          )
        );
        for (const result of results) {
          const d = result?.data;
          if (d) {
            const revenue = d.revenue ?? 0;
            const cost = d.cost ?? 0;
            newProducts.push({
              id: d.forecastDetailId ?? d.id,
              forecastDescription: d.description,
              productDescription: d.description,
              productClass: "Service",
              forecastType: "Product",
              quantity: d.quantity,
              revenue,
              cost,
              margin: revenue - cost,
              catalogItem: d.catalogItem,
              taxableFlag: d.taxableFlag,
              customerDescription: d.customerDescription,
              procurementNotes: d.procurementNotes,
              productNarrative: d.productNarrative,
            });
          }
        }
      }

      // Add special-order items through dedicated endpoint
      if (specialOrderItems.length > 0) {
        const payload: SpecialOrderBody[] = specialOrderItems.map((item) => ({
          desc: item.description ?? "Special Order",
          customerDesc: item.customerDescription,
          qty: item.quantity && item.quantity > 0 ? item.quantity : 1,
          price: item.price ?? 0,
          cost: item.cost,
          taxable: item.taxableFlag,
          procurementNotes: item.procurementNotes,
          productNarrative: item.productNarrative,
        }));

        const results = await Promise.all(
          payload.map((body) =>
            optima.sales.addSpecialOrder(accessToken!, opportunityId, body)
          )
        );
        for (const result of results) {
          const items = Array.isArray(result?.data)
            ? result.data
            : result?.data
              ? [result.data]
              : [];
          for (const d of items) {
            const revenue = d.revenue ?? d.price ?? 0;
            const cost = d.cost ?? 0;
            newProducts.push({
              id: d.forecastDetailId ?? d.id,
              forecastDescription: d.description,
              productDescription: d.productDescription ?? d.description,
              quantity: d.quantity,
              revenue,
              cost,
              margin: revenue - cost,
              taxableFlag: d.taxableFlag,
              customerDescription: d.customerDescription,
              procurementNotes: d.procurementNotes,
              productNarrative: d.productNarrative,
            });
          }
        }
      }

      // Append newly created products to the list immediately
      if (newProducts.length > 0) {
        products = [...products, ...newProducts];
        dispatch("productsChanged", products);
      }

      showAddProductModal = false;
    } catch (err) {
      addProductError =
        err instanceof Error ? err.message : "Failed to add product";
      console.error("[AddProduct] Failed:", err);
    } finally {
      isAddingProduct = false;
    }
  }

  let selectedProduct: OpportunityProduct | null = null;
  let isClosing = false;
  let showPanel = false;
  let showCancelled = false;
  let viewMode: "cards" | "compact" = "cards";

  // ── Edit mode state ──
  export let isEditing = false;
  let showActionMenu = false;
  let isSavingEdit = false;
  let editSaveError = "";
  let showCancelModal = false;
  let isSavingCancellation = false;
  let cancellationSaveError = "";
  let showDeleteModal = false;
  let isDeletingProduct = false;
  let deleteProductError = "";

  $: canDeleteProduct =
    !isClosedOpportunity &&
    permissions["sales.opportunity.product.delete"] !== false;
  $: canUpdateProduct =
    !isClosedOpportunity &&
    permissions["sales.opportunity.product.update"] !== false;
  let cancellationForm = {
    quantityCancelled: "0",
    cancellationReason: "",
  };
  let editForm: {
    unitPrice: string;
    unitCost: string;
    quantity: string;
    description: string;
    productNarrative: string;
    procurementNotes: string;
    taxableFlag: boolean;
  } = {
    unitPrice: "",
    unitCost: "",
    quantity: "",
    description: "",
    productNarrative: "",
    procurementNotes: "",
    taxableFlag: false,
  };

  function enterEditMode() {
    if (!selectedProduct) return;
    const up = unitPrice(selectedProduct);
    const uc = unitCost(selectedProduct);
    editForm = {
      unitPrice: up != null ? up.toFixed(2) : "",
      unitCost: uc != null ? uc.toFixed(2) : "",
      quantity: selectedProduct.quantity?.toString() ?? "",
      description: selectedProduct.productDescription ?? "",
      productNarrative: selectedProduct.productNarrative ?? "",
      procurementNotes: selectedProduct.procurementNotes ?? "",
      taxableFlag: selectedProduct.taxableFlag ?? false,
    };
    isEditing = true;
    editSaveError = "";
    showActionMenu = false;
  }

  function cancelEdit() {
    isEditing = false;
    editSaveError = "";
  }

  function hasCancellation(p: OpportunityProduct): boolean {
    return !!(
      p.cancelled ||
      p.cancellationType ||
      (p.quantityCancelled ?? 0) > 0
    );
  }

  function maxCancellationQty(p: OpportunityProduct): number {
    const qty = Math.floor(p.quantity ?? 0);
    return qty > 0 ? qty : 0;
  }

  function openCancellationModal() {
    if (!selectedProduct) return;
    const maxQty = maxCancellationQty(selectedProduct);
    const initialQty = Math.min(
      Math.max(
        selectedProduct.quantityCancelled ??
          (selectedProduct.cancellationType === "full" ? maxQty : 0),
        0
      ),
      maxQty
    );

    cancellationForm = {
      quantityCancelled: String(initialQty),
      cancellationReason: selectedProduct.cancelledReason ?? "",
    };
    cancellationSaveError = "";
    showActionMenu = false;
    showCancelModal = true;
  }

  function closeCancellationModal() {
    if (isSavingCancellation) return;
    showCancelModal = false;
    cancellationSaveError = "";
  }

  async function saveCancellation() {
    if (!selectedProduct || !accessToken || isSavingCancellation) return;

    const maxQty = maxCancellationQty(selectedProduct);
    const parsedQty = Number.parseInt(cancellationForm.quantityCancelled, 10);
    const quantityCancelled = Number.isFinite(parsedQty)
      ? Math.min(Math.max(parsedQty, 0), maxQty)
      : 0;
    const reason = cancellationForm.cancellationReason.trim();

    const payload: CancelOpportunityProductBody = {
      quantityCancelled,
      cancellationReason: quantityCancelled > 0 ? reason || null : null,
    };

    isSavingCancellation = true;
    cancellationSaveError = "";
    try {
      await optima.sales.cancelProduct(
        accessToken,
        opportunityId,
        selectedProduct.id,
        payload
      );
      await refreshProducts();
      selectedProduct =
        products.find((p) => p.id === selectedProduct?.id) ?? null;
      showCancelModal = false;
      cancellationSaveError = "";
    } catch (err) {
      console.error("[CancelProduct] Failed:", err);
      cancellationSaveError =
        err instanceof Error ? err.message : "Failed to update cancellation";
    } finally {
      isSavingCancellation = false;
    }
  }

  function openDeleteProductModal() {
    if (!selectedProduct) return;
    showActionMenu = false;
    deleteProductError = "";
    showDeleteModal = true;
  }

  function closeDeleteProductModal() {
    if (isDeletingProduct) return;
    showDeleteModal = false;
    deleteProductError = "";
  }

  async function executeDeleteProduct() {
    if (!selectedProduct || !accessToken || isDeletingProduct) return;

    isDeletingProduct = true;
    deleteProductError = "";
    const deletedId = selectedProduct.id;
    try {
      await optima.sales.deleteProduct(
        accessToken,
        opportunityId,
        deletedId
      );
      products = products.filter((p) => p.id !== deletedId);
      dispatch("productsChanged", products);
      showDeleteModal = false;
      selectedProduct = null;
      showPanel = false;
      isClosing = false;
    } catch (err) {
      console.error("[DeleteProduct] Failed:", err);
      deleteProductError =
        err instanceof Error ? err.message : "Failed to delete product";
    } finally {
      isDeletingProduct = false;
    }
  }

  async function saveEdit() {
    if (!selectedProduct || !accessToken || isSavingEdit) return;

    const qty = parseFloat(editForm.quantity) || selectedProduct.quantity || 1;
    const up = parseFloat(editForm.unitPrice);
    const uc = parseFloat(editForm.unitCost);

    const updates: {
      quantity: number;
      productDescription: string;
      productNarrative: string | null;
      procurementNotes: string | null;
      unitPrice?: number;
      unitCost?: number;
      taxableFlag: boolean;
    } = {
      quantity: qty,
      productDescription: editForm.description,
      productNarrative: editForm.productNarrative || null,
      procurementNotes: editForm.procurementNotes || null,
      taxableFlag: editForm.taxableFlag,
    };

    if (!isNaN(up)) {
      updates.unitPrice = up;
    }
    if (!isNaN(uc)) {
      updates.unitCost = uc;
    }

    console.log(
      "[EditProduct] Description payload:",
      updates.productDescription
    );

    isSavingEdit = true;
    editSaveError = "";
    try {
      await optima.sales.editProduct(
        accessToken,
        opportunityId,
        selectedProduct.id,
        updates
      );
      await refreshProducts();
      selectedProduct =
        products.find((p) => p.id === selectedProduct?.id) ?? null;
      isEditing = false;
      editSaveError = "";
    } catch (err) {
      console.error("[EditProduct] Failed:", err);
      editSaveError =
        err instanceof Error ? err.message : "Failed to update product";
    } finally {
      isSavingEdit = false;
    }
  }

  // ── Unsaved changes guard ──
  function handleBeforeUnload(e: BeforeUnloadEvent) {
    if (isEditing || hasChanges) {
      e.preventDefault();
    }
  }

  onMount(() => {
    window.addEventListener("beforeunload", handleBeforeUnload);
  });

  onDestroy(() => {
    window.removeEventListener("beforeunload", handleBeforeUnload);
  });

  beforeNavigate(({ cancel }) => {
    if (isEditing || hasChanges) {
      if (
        !confirm("You have unsaved changes. Are you sure you want to leave?")
      ) {
        cancel();
      }
    }
  });

  function toggleActionMenu() {
    showActionMenu = !showActionMenu;
  }

  function closeActionMenu() {
    showActionMenu = false;
  }

  // Auto-select a product when initialProductId changes
  $: if (initialProductId != null) {
    const target = products.find((p) => p.id === initialProductId);
    if (target) {
      selectedProduct = target;
      showPanel = true;
      isClosing = false;
    }
  }

  // ── Drag-and-drop state ──
  let orderedProducts: OpportunityProduct[] = [];
  let originalOrderIds: number[] = [];
  let dragIndex: number | null = null;
  let hasChanges = false;
  let isSaving = false;
  let saveError = "";

  function isCancelled(p: OpportunityProduct): boolean {
    return p.cancellationType === "full";
  }

  function isPartiallyCancelled(p: OpportunityProduct): boolean {
    return p.cancellationType === "partial";
  }

  function effectiveQty(p: OpportunityProduct): number | undefined {
    if (p.quantity == null) return undefined;
    return p.quantity - (p.quantityCancelled ?? 0);
  }

  function hasInventory(p: OpportunityProduct): boolean {
    const cls = p.productClass?.toLowerCase() ?? "";
    return cls !== "service" && cls !== "non-inventory";
  }

  /** Use effectiveQty so unit price / cost stay stable during partial cancellations */
  function unitPrice(p: OpportunityProduct): number | undefined {
    const qty = effectiveQty(p);
    return qty ? (p.revenue ?? 0) / qty : p.revenue;
  }

  function unitCost(p: OpportunityProduct): number | undefined {
    const qty = effectiveQty(p);
    return qty ? (p.cost ?? 0) / qty : p.cost;
  }

  function unitMargin(p: OpportunityProduct): number {
    const qty = effectiveQty(p);
    const margin = (p.revenue ?? 0) - (p.cost ?? 0);
    return qty ? margin / qty : margin;
  }

  // Split into active vs cancelled, each sorted by sequenceNumber
  let activeProducts: OpportunityProduct[] = [];
  let lastProductsRef: OpportunityProduct[] | null = null;

  // Cancelled products are derived directly from the prop
  $: cancelledProducts = [...products]
    .filter((p) => isCancelled(p))
    .sort(
      (a, b) => (a.sequenceNumber ?? Infinity) - (b.sequenceNumber ?? Infinity)
    );

  // Initialize when the products prop changes (but NOT when activeProducts is reassigned by drag)
  function initProducts(incoming: OpportunityProduct[]) {
    resetDragState();
    let sorted: OpportunityProduct[];
    if (productSequence && productSequence.length > 0) {
      // Use the locally-stored product sequence for ordering
      const idxMap = new Map(productSequence.map((id, i) => [id, i]));
      sorted = [...incoming].sort((a, b) => {
        const ai = idxMap.get(a.id);
        const bi = idxMap.get(b.id);
        // Items not in the sequence go to the end, ordered by CW sequenceNumber
        if (ai == null && bi == null)
          return (
            (a.sequenceNumber ?? Infinity) - (b.sequenceNumber ?? Infinity)
          );
        if (ai == null) return 1;
        if (bi == null) return -1;
        return ai - bi;
      });
    } else {
      // Fallback: CW sequenceNumber ordering
      sorted = [...incoming].sort(
        (a, b) =>
          (a.sequenceNumber ?? Infinity) - (b.sequenceNumber ?? Infinity)
      );
    }
    orderedProducts = sorted;
    activeProducts = sorted.filter((p) => !isCancelled(p));
    originalOrderIds = activeProducts.map((p) => p.id);
    hasChanges = false;
    saveError = "";
  }

  // Only re-init when the products prop reference actually changes
  $: if (products !== lastProductsRef) {
    lastProductsRef = products;
    initProducts(products);
  }

  // ── Computed totals ──
  $: totalRevenue = activeProducts.reduce(
    (sum, p) => sum + (p.revenue ?? 0),
    0
  );
  $: totalCost = activeProducts.reduce((sum, p) => sum + (p.cost ?? 0), 0);
  $: totalMargin = activeProducts.reduce((sum, p) => sum + (p.margin ?? 0), 0);
  $: totalProfit = activeProducts.reduce((sum, p) => sum + (p.profit ?? 0), 0);
  $: markupPct = totalCost > 0 ? (totalMargin / totalCost) * 100 : 0;
  $: marginPct = totalRevenue > 0 ? (totalMargin / totalRevenue) * 100 : 0;
  $: taxRate = (salesTaxRate ?? 0) / 100;
  $: taxLabel =
    taxCodeDescription != null
      ? salesTaxRate && salesTaxRate > 0
        ? `Tax (${taxCodeDescription} ${salesTaxRate.toFixed(2)}%)`
        : `Tax (${taxCodeDescription})`
      : salesTaxRate
        ? `Tax (${salesTaxRate.toFixed(2)}%)`
        : "Tax";
  $: taxableRevenue = activeProducts
    .filter((p) => p.taxableFlag)
    .reduce((sum, p) => sum + (p.revenue ?? 0), 0);
  $: totalTax = taxRate > 0 ? taxableRevenue * taxRate : 0;
  $: grandTotal = totalRevenue + totalTax;

  /** Markup % = (price - cost) / cost × 100 */
  function markupHealthColor(revenue?: number, margin?: number): string {
    const cost = (revenue ?? 0) - (margin ?? 0);
    if (!cost || cost <= 0) return "neutral";
    const pct = ((margin ?? 0) / cost) * 100;
    if (pct < 0) return "negative";
    if (pct >= 30) return "healthy";
    if (pct >= 15) return "moderate";
    return "low";
  }

  function markupBarWidthPct(revenue?: number, margin?: number): number {
    const cost = (revenue ?? 0) - (margin ?? 0);
    if (!cost || cost <= 0) return 0;
    const pct = ((margin ?? 0) / cost) * 100;
    return Math.min(Math.abs(pct), 100);
  }

  function rawMarkupPct(revenue?: number, margin?: number): number {
    const cost = (revenue ?? 0) - (margin ?? 0);
    if (!cost || cost <= 0) return 0;
    return ((margin ?? 0) / cost) * 100;
  }

  function isNegativeMarkup(revenue?: number, margin?: number): boolean {
    const cost = (revenue ?? 0) - (margin ?? 0);
    if (!cost || cost <= 0) return false;
    return ((margin ?? 0) / cost) * 100 < 0;
  }

  /** Margin % = (price - cost) / price × 100 */
  function marginHealthColor(revenue?: number, margin?: number): string {
    const rev = revenue ?? 0;
    if (!rev || rev <= 0) return "neutral";
    const pct = ((margin ?? 0) / rev) * 100;
    if (pct < 0) return "negative";
    if (pct >= 25) return "healthy";
    if (pct >= 12) return "moderate";
    return "low";
  }

  function marginBarWidthPct(revenue?: number, margin?: number): number {
    const rev = revenue ?? 0;
    if (!rev || rev <= 0) return 0;
    const pct = ((margin ?? 0) / rev) * 100;
    return Math.min(Math.abs(pct), 100);
  }

  function rawMarginPct(revenue?: number, margin?: number): number {
    const rev = revenue ?? 0;
    if (!rev || rev <= 0) return 0;
    return ((margin ?? 0) / rev) * 100;
  }

  function tierWidth(rawPct: number, tierStart: number): number {
    return Math.min(Math.max(rawPct - tierStart, 0), 100);
  }

  function isNegativeMargin(revenue?: number, margin?: number): boolean {
    const rev = revenue ?? 0;
    if (!rev || rev <= 0) return false;
    return ((margin ?? 0) / rev) * 100 < 0;
  }

  function checkForChanges() {
    hasChanges = activeProducts.some((p, i) => p.id !== originalOrderIds[i]);
    if (hasChanges && !isEditing) isEditing = true;
  }

  // ── Drag handlers (HTML5 Drag and Drop API) ──
  let dragOverIndex: number | null = null;
  let lastSwapTime = 0;

  function resetDragState() {
    dragIndex = null;
    dragOverIndex = null;
    lastSwapTime = 0;
  }

  function handleDragStart(e: DragEvent, index: number) {
    console.log("[DnD] dragstart", index, e);
    dragIndex = index;
    if (e.dataTransfer) {
      e.dataTransfer.effectAllowed = "move";
      e.dataTransfer.setData("text/plain", String(index));
      // Use a transparent 1x1 image so the default drag ghost doesn't show
      const img = new Image();
      img.src =
        "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
      e.dataTransfer.setDragImage(img, 0, 0);
    }
    // Apply dragging class after a tick so the browser captures the element first
    requestAnimationFrame(() => {
      dragIndex = index;
    });
  }

  function handleDragOver(e: DragEvent, index: number) {
    e.preventDefault(); // REQUIRED: allows drop
    if (e.dataTransfer) {
      e.dataTransfer.dropEffect = "move";
    }
    if (dragIndex === null || index === dragIndex) return;

    // Throttle swaps to avoid thrashing during rapid dragover
    const now = Date.now();
    if (now - lastSwapTime < 150) return;
    lastSwapTime = now;

    console.log("[DnD] dragover swap", dragIndex, "->", index);
    dragOverIndex = index;
    const items = [...activeProducts];
    const [moved] = items.splice(dragIndex, 1);
    items.splice(index, 0, moved);
    activeProducts = items;
    dragIndex = index;
    checkForChanges();
  }

  function handleDrop(e: DragEvent) {
    console.log("[DnD] drop");
    e.preventDefault();
  }

  function handleDragEnd() {
    console.log("[DnD] dragend");
    resetDragState();
  }

  function handleGlobalDragFinish() {
    if (dragIndex != null || dragOverIndex != null) {
      resetDragState();
    }
  }

  // ── Save / Discard ──
  async function saveSequence() {
    if (!accessToken || isSaving) return;
    resetDragState();
    isSaving = true;
    saveError = "";
    try {
      const orderedIds = activeProducts.map((p) => p.id);
      const result = await optima.sales.sequenceProducts(
        accessToken,
        opportunityId,
        orderedIds
      );

      const idMap: Record<string, number> | undefined = result?.data?.idMap;

      // Only update the IDs — no other product values should change
      if (idMap) {
        activeProducts = activeProducts.map((p) => {
          const newId = idMap[String(p.id)];
          return newId != null ? { ...p, id: newId } : p;
        });
      }

      // Update sequence numbers locally to reflect the new order
      activeProducts = activeProducts.map((p, i) => ({
        ...p,
        sequenceNumber: i + 1,
      }));

      originalOrderIds = activeProducts.map((p) => p.id);
      hasChanges = false;
      isEditing = false;
      dispatch("sequenceSaved", originalOrderIds);
    } catch (err: unknown) {
      saveError =
        err instanceof Error ? err.message : "Failed to save sequence";
    } finally {
      resetDragState();
      isSaving = false;
    }
  }

  function discardChanges() {
    resetDragState();
    const sorted = [...products].sort(
      (a, b) => (a.sequenceNumber ?? Infinity) - (b.sequenceNumber ?? Infinity)
    );
    activeProducts = sorted.filter((p) => !isCancelled(p));
    originalOrderIds = activeProducts.map((p) => p.id);
    hasChanges = false;
    isEditing = false;
    saveError = "";
  }

  function selectProduct(p: OpportunityProduct) {
    if (selectedProduct?.id === p.id && !isClosing) {
      closeDetail();
      return;
    }
    if (isEditing) {
      if (!confirm("You have unsaved changes. Discard and switch products?")) {
        return;
      }
      isEditing = false;
      showActionMenu = false;
    }
    isClosing = false;
    showCancelModal = false;
    showDeleteModal = false;
    cancellationSaveError = "";
    deleteProductError = "";
    selectedProduct = p;
    showPanel = true;
  }

  function closeDetail() {
    if (isEditing) {
      if (!confirm("You have unsaved changes. Discard and close?")) {
        return;
      }
    }
    isEditing = false;
    showActionMenu = false;
    showCancelModal = false;
    showDeleteModal = false;
    cancellationSaveError = "";
    deleteProductError = "";
    isClosing = true;
    setTimeout(() => {
      selectedProduct = null;
      showPanel = false;
      isClosing = false;
    }, 250);
  }

  function handleKeydown(e: KeyboardEvent) {
    if (e.key === "Escape") {
      if (showDeleteModal) {
        closeDeleteProductModal();
        return;
      }
      if (showCancelModal) {
        closeCancellationModal();
        return;
      }
      if (showActionMenu) {
        showActionMenu = false;
        return;
      }
      if (isEditing) {
        cancelEdit();
        return;
      }
      if (selectedProduct) {
        closeDetail();
      }
    }
  }

  function formatDate(dateStr?: string | null): string {
    if (!dateStr) return "—";
    try {
      return new Date(dateStr).toLocaleDateString("en-US", {
        month: "short",
        day: "numeric",
        year: "numeric",
        hour: "numeric",
        minute: "2-digit",
      });
    } catch {
      return "—";
    }
  }
</script>

<svelte:window
  on:keydown={handleKeydown}
  on:dragend={handleGlobalDragFinish}
  on:drop={handleGlobalDragFinish}
/>

<div class="products-tab" class:has-detail={showPanel}>
  {#if products.length === 0}
    <div class="tab-empty">
      <div class="tab-empty-content">
        <NoResultsMonkey message="No products on this opportunity" />
        {#if !isClosedOpportunity}
          <button
            class="toolbar-add-btn empty-add-btn"
            type="button"
            disabled={hasChanges}
            on:click={() => (showAddProductModal = true)}
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="15"
              height="15"
            >
              <line x1="12" y1="5" x2="12" y2="19" /><line
                x1="5"
                y1="12"
                x2="19"
                y2="12"
              />
            </svg>
            Add Product
          </button>
        {/if}
      </div>
    </div>
  {:else}
    <!-- ═══ Financial KPI Strip ═══ -->
    <div class="kpi-strip">
      <div class="kpi-card">
        <div class="kpi-icon revenue">
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="16"
            height="16"
          >
            <line x1="12" y1="1" x2="12" y2="23" /><path
              d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"
            />
          </svg>
        </div>
        <div class="kpi-content">
          <span class="kpi-label">Revenue</span>
          <span class="kpi-value">{formatCurrency(totalRevenue)}</span>
        </div>
      </div>
      {#if canViewCost}
        <div class="kpi-card">
          <div class="kpi-icon cost">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="16"
              height="16"
            >
              <path d="M2 20h20" /><path d="M5 20V10l4-6 4 6v10" /><path
                d="M19 20V4l-4 4"
              />
            </svg>
          </div>
          <div class="kpi-content">
            <span class="kpi-label">Cost</span>
            <span class="kpi-value">{formatCurrency(totalCost)}</span>
          </div>
        </div>
      {/if}
      {#if canViewMargin}
        <div class="kpi-card">
          <div class="kpi-icon margin">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="16"
              height="16"
            >
              <polyline points="23 6 13.5 15.5 8.5 10.5 1 18" /><polyline
                points="17 6 23 6 23 12"
              />
            </svg>
          </div>
          <div class="kpi-content">
            <span class="kpi-label">Margin</span>
            <span class="kpi-value">{formatCurrency(totalMargin)}</span>
          </div>
          <span
            class="kpi-badge {marginPct >= 25
              ? 'healthy'
              : marginPct >= 12
                ? 'moderate'
                : marginPct >= 0
                  ? 'low'
                  : 'negative'}"
            title="Margin: (price − cost) ÷ price"
          >
            {marginPct.toFixed(1)}%
          </span>
        </div>
      {/if}
      {#if canViewProfit}
        <div class="kpi-card">
          <div class="kpi-icon profit">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="16"
              height="16"
            >
              <rect x="2" y="7" width="20" height="14" rx="2" ry="2" /><path
                d="M16 21V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v16"
              />
            </svg>
          </div>
          <div class="kpi-content">
            <span class="kpi-label">Profit</span>
            <span class="kpi-value">{formatCurrency(totalProfit)}</span>
          </div>
        </div>
      {/if}
      {#if totalTax > 0}
        <div class="kpi-card">
          <div class="kpi-icon tax">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="16"
              height="16"
            >
              <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
              <polyline points="14 2 14 8 20 8" />
              <line x1="16" y1="13" x2="8" y2="13" />
              <line x1="16" y1="17" x2="8" y2="17" />
              <polyline points="10 9 9 9 8 9" />
            </svg>
          </div>
          <div class="kpi-content">
            <span class="kpi-label">{taxLabel}</span>
            <span class="kpi-value">{formatCurrency(totalTax)}</span>
          </div>
        </div>
        <div class="kpi-card kpi-card--grand-total">
          <div class="kpi-content">
            <span class="kpi-label">Grand Total</span>
            <span class="kpi-value">{formatCurrency(grandTotal)}</span>
          </div>
        </div>
      {/if}
    </div>
    <div class="products-toolbar">
      <div class="toolbar-left">
        {#if !isClosedOpportunity}
          <button
            class="toolbar-add-btn"
            type="button"
            disabled={hasChanges}
            on:click={() => (showAddProductModal = true)}
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="15"
              height="15"
            >
              <line x1="12" y1="5" x2="12" y2="19" /><line
                x1="5"
                y1="12"
                x2="19"
                y2="12"
              />
            </svg>
            Add Product
          </button>
        {/if}
        <button
          class="view-toggle-btn"
          type="button"
          title={viewMode === "cards"
            ? "Switch to compact view"
            : "Switch to card view"}
          on:click={() =>
            (viewMode = viewMode === "cards" ? "compact" : "cards")}
        >
          {#if viewMode === "cards"}
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="15"
              height="15"
            >
              <line x1="3" y1="6" x2="21" y2="6" /><line
                x1="3"
                y1="12"
                x2="21"
                y2="12"
              /><line x1="3" y1="18" x2="21" y2="18" />
            </svg>
          {:else}
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="15"
              height="15"
            >
              <rect x="3" y="3" width="7" height="7" rx="1" /><rect
                x="14"
                y="3"
                width="7"
                height="7"
                rx="1"
              />
              <rect x="3" y="14" width="7" height="7" rx="1" /><rect
                x="14"
                y="14"
                width="7"
                height="7"
                rx="1"
              />
            </svg>
          {/if}
        </button>
      </div>
      {#if hasChanges}
        <div class="toolbar-actions">
          {#if saveError}
            <span class="toolbar-error">{saveError}</span>
          {/if}
          <button
            class="sequence-btn discard"
            on:click={discardChanges}
            disabled={isSaving}
            type="button"
          >
            Discard
          </button>
          <button
            class="sequence-btn save"
            on:click={saveSequence}
            disabled={isSaving}
            type="button"
          >
            {#if isSaving}Saving…{:else}Save Order{/if}
          </button>
        </div>
      {/if}
    </div>

    <!-- ═══ Content row: list + detail side by side ═══ -->
    <div class="products-content-row">
      <!-- Product list -->
      <div class="products-list-pane" class:collapsed={showPanel}>
        <div class="products-scroll">
          <!-- Active product cards -->
          {#if viewMode === "compact"}
            <div class="product-cards compact-cards">
              {#each activeProducts as p, i (p.id)}
                <!-- svelte-ignore a11y_no_static_element_interactions -->
                <!-- svelte-ignore a11y_click_events_have_key_events -->
                <div
                  class="product-card compact"
                  class:selected={selectedProduct?.id === p.id}
                  class:dragging={dragIndex === i}
                  data-drag-index={i}
                  draggable={!isSaving && !isClosedOpportunity}
                  animate:flip={{ duration: 120 }}
                  on:dragstart={(e) => handleDragStart(e, i)}
                  on:dragover={(e) => handleDragOver(e, i)}
                  on:drop={handleDrop}
                  on:dragend={handleDragEnd}
                  on:click={() => selectProduct(p)}
                >
                  <!-- Drag handle -->
                  <div class="card-drag" title="Drag to reorder">
                    <svg
                      viewBox="0 0 24 24"
                      fill="currentColor"
                      width="12"
                      height="12"
                    >
                      <circle cx="9" cy="6" r="1.5" /><circle
                        cx="15"
                        cy="6"
                        r="1.5"
                      />
                      <circle cx="9" cy="12" r="1.5" /><circle
                        cx="15"
                        cy="12"
                        r="1.5"
                      />
                      <circle cx="9" cy="18" r="1.5" /><circle
                        cx="15"
                        cy="18"
                        r="1.5"
                      />
                    </svg>
                  </div>

                  <!-- Card body — single row: qty | identity | metrics | badges -->
                  <div class="card-body">
                    <span
                      class="card-qty"
                      class:partial={isPartiallyCancelled(p)}
                      >x{effectiveQty(p) ?? "—"}</span
                    >
                    <div class="card-identity">
                      <span class="card-name"
                        >{p.productDescription ?? "—"}</span
                      >
                      {#if p.catalogItem?.identifier}
                        <span class="card-catalog"
                          >{p.catalogItem.identifier}</span
                        >
                      {/if}
                      {#if isPartiallyCancelled(p)}
                        <span class="partial-cancelled-flag"
                          >{p.quantityCancelled} cancelled</span
                        >
                      {/if}
                    </div>

                    <div class="card-metrics">
                      <div class="card-metric">
                        <span class="card-metric-label">Unit Price</span>
                        <span class="card-metric-value accent"
                          >{formatCurrency(unitPrice(p))}</span
                        >
                      </div>
                      {#if canViewCost}
                        <div class="card-metric">
                          <span class="card-metric-label">Unit Cost</span>
                          <span class="card-metric-value"
                            >{formatCurrency(unitCost(p))}</span
                          >
                        </div>
                      {/if}
                      {#if canViewMargin}
                        <div class="card-metric">
                          <span class="card-metric-label">Margin</span>
                          <span class="card-metric-value"
                            >{formatCurrency(unitMargin(p))}</span
                          >
                        </div>
                      {/if}
                    </div>

                    <div class="card-badges">
                      <span
                        class="product-class-badge"
                        class:service={p.productClass === "Service"}
                        class:agreement={p.productClass === "Agreement"}
                      >
                        {p.productClass ?? "—"}
                      </span>
                      {#if hasInventory(p) && p.onHand != null}
                        <span
                          class="stock-badge"
                          class:stock-none={p.onHand === 0}
                          class:stock-low={p.onHand >= 1 && p.onHand <= 5}
                          class:stock-good={p.onHand > 5}
                        >
                          {p.onHand} on hand
                        </span>
                      {/if}
                    </div>
                  </div>

                  <!-- Chevron -->
                  <div class="card-chevron">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <polyline points="9 18 15 12 9 6" />
                    </svg>
                  </div>
                </div>
              {/each}
            </div>
          {:else}
            <div class="product-cards">
              {#each activeProducts as p, i (p.id)}
                <!-- svelte-ignore a11y_no_static_element_interactions -->
                <!-- svelte-ignore a11y_click_events_have_key_events -->
                <div
                  class="product-card"
                  class:selected={selectedProduct?.id === p.id}
                  class:dragging={dragIndex === i}
                  data-drag-index={i}
                  draggable={!isSaving && !isClosedOpportunity}
                  animate:flip={{ duration: 200 }}
                  on:dragstart={(e) => handleDragStart(e, i)}
                  on:dragover={(e) => handleDragOver(e, i)}
                  on:drop={handleDrop}
                  on:dragend={handleDragEnd}
                  on:click={() => selectProduct(p)}
                >
                  <!-- Drag handle -->
                  <div class="card-drag" title="Drag to reorder">
                    <svg
                      viewBox="0 0 24 24"
                      fill="currentColor"
                      width="14"
                      height="14"
                    >
                      <circle cx="9" cy="6" r="1.5" /><circle
                        cx="15"
                        cy="6"
                        r="1.5"
                      />
                      <circle cx="9" cy="12" r="1.5" /><circle
                        cx="15"
                        cy="12"
                        r="1.5"
                      />
                      <circle cx="9" cy="18" r="1.5" /><circle
                        cx="15"
                        cy="18"
                        r="1.5"
                      />
                    </svg>
                  </div>

                  <!-- Card body -->
                  <div class="card-body">
                    <!-- Top row: qty + name + badges -->
                    <div class="card-top">
                      <span
                        class="card-qty"
                        class:partial={isPartiallyCancelled(p)}
                        >x{effectiveQty(p) ?? "—"}</span
                      >
                      <div class="card-identity">
                        <span class="card-name"
                          >{p.productDescription ?? "—"}</span
                        >
                        {#if p.catalogItem?.identifier}
                          <span class="card-catalog"
                            >{p.catalogItem.identifier}</span
                          >
                        {/if}
                        {#if isPartiallyCancelled(p)}
                          <span class="partial-cancelled-flag"
                            >{p.quantityCancelled} cancelled</span
                          >
                        {/if}
                      </div>
                      <div class="card-badges">
                        <span
                          class="product-class-badge"
                          class:service={p.productClass === "Service"}
                          class:agreement={p.productClass === "Agreement"}
                        >
                          {p.productClass ?? "—"}
                        </span>
                        {#if hasInventory(p) && p.onHand != null}
                          <span
                            class="stock-badge"
                            class:stock-none={p.onHand === 0}
                            class:stock-low={p.onHand >= 1 && p.onHand <= 5}
                            class:stock-good={p.onHand > 5}
                          >
                            {p.onHand} on hand
                          </span>
                        {/if}
                      </div>
                    </div>

                    <!-- Bottom row: per-unit pricing + margin indicator -->
                    <div class="card-metrics">
                      <div class="card-metric">
                        <span class="card-metric-label">Unit Price</span>
                        <span class="card-metric-value accent"
                          >{formatCurrency(unitPrice(p))}</span
                        >
                      </div>
                      {#if canViewCost}
                        <div class="card-metric">
                          <span class="card-metric-label">Unit Cost</span>
                          <span class="card-metric-value"
                            >{formatCurrency(unitCost(p))}</span
                          >
                        </div>
                      {/if}
                      {#if canViewMargin}
                        <div class="card-metric">
                          <span class="card-metric-label">Margin</span>
                          <span class="card-metric-value"
                            >{formatCurrency(unitMargin(p))}</span
                          >
                        </div>
                        <div class="card-bars">
                          <div class="card-bar-row">
                            <span class="card-bar-label">Markup</span>
                            <div class="card-margin-bar">
                              <div
                                class="card-margin-fill {markupHealthColor(
                                  p.revenue,
                                  p.margin
                                )}"
                                class:from-right={isNegativeMarkup(
                                  p.revenue,
                                  p.margin
                                )}
                                style="width: {markupBarWidthPct(
                                  p.revenue,
                                  p.margin
                                )}%"
                              ></div>
                              {#if rawMarkupPct(p.revenue, p.margin) > 100}
                                <div
                                  class="card-margin-fill super-blue"
                                  style="width: {tierWidth(
                                    rawMarkupPct(p.revenue, p.margin),
                                    100
                                  )}%"
                                ></div>
                              {/if}
                              {#if rawMarkupPct(p.revenue, p.margin) > 200}
                                <div
                                  class="card-margin-fill super-indigo"
                                  style="width: {tierWidth(
                                    rawMarkupPct(p.revenue, p.margin),
                                    200
                                  )}%"
                                ></div>
                              {/if}
                              {#if rawMarkupPct(p.revenue, p.margin) > 300}
                                <div
                                  class="card-margin-fill super-violet"
                                  style="width: {tierWidth(
                                    rawMarkupPct(p.revenue, p.margin),
                                    300
                                  )}%"
                                ></div>
                              {/if}
                            </div>
                          </div>
                          <div class="card-bar-row">
                            <span class="card-bar-label">Margin</span>
                            <div class="card-margin-bar">
                              <div
                                class="card-margin-fill {marginHealthColor(
                                  p.revenue,
                                  p.margin
                                )}"
                                class:from-right={isNegativeMargin(
                                  p.revenue,
                                  p.margin
                                )}
                                style="width: {marginBarWidthPct(
                                  p.revenue,
                                  p.margin
                                )}%"
                              ></div>
                              {#if rawMarginPct(p.revenue, p.margin) > 100}
                                <div
                                  class="card-margin-fill super-blue"
                                  style="width: {tierWidth(
                                    rawMarginPct(p.revenue, p.margin),
                                    100
                                  )}%"
                                ></div>
                              {/if}
                              {#if rawMarginPct(p.revenue, p.margin) > 200}
                                <div
                                  class="card-margin-fill super-indigo"
                                  style="width: {tierWidth(
                                    rawMarginPct(p.revenue, p.margin),
                                    200
                                  )}%"
                                ></div>
                              {/if}
                              {#if rawMarginPct(p.revenue, p.margin) > 300}
                                <div
                                  class="card-margin-fill super-violet"
                                  style="width: {tierWidth(
                                    rawMarginPct(p.revenue, p.margin),
                                    300
                                  )}%"
                                ></div>
                              {/if}
                            </div>
                          </div>
                        </div>
                      {/if}
                    </div>
                  </div>

                  <!-- Chevron -->
                  <div class="card-chevron">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="16"
                      height="16"
                    >
                      <polyline points="9 18 15 12 9 6" />
                    </svg>
                  </div>
                </div>
              {/each}
            </div>
          {/if}

          <!-- Cancelled products (collapsible) -->
          {#if cancelledProducts.length > 0}
            <!-- svelte-ignore a11y_no_static_element_interactions -->
            <!-- svelte-ignore a11y_click_events_have_key_events -->
            <div
              class="cancelled-header"
              on:click={() => (showCancelled = !showCancelled)}
            >
              <svg
                class="cancelled-chevron"
                class:open={showCancelled}
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                width="14"
                height="14"
              >
                <polyline points="9 18 15 12 9 6" />
              </svg>
              <span class="cancelled-label">Cancelled</span>
              <span class="cancelled-count">{cancelledProducts.length}</span>
              <div class="cancelled-line"></div>
            </div>

            {#if showCancelled}
              {#if viewMode === "compact"}
                <div class="product-cards cancelled-cards compact-cards">
                  {#each cancelledProducts as p (p.id)}
                    <!-- svelte-ignore a11y_no_static_element_interactions -->
                    <!-- svelte-ignore a11y_click_events_have_key_events -->
                    <div
                      class="product-card cancelled compact"
                      class:selected={selectedProduct?.id === p.id}
                      on:click={() => selectProduct(p)}
                    >
                      <div class="card-drag disabled"></div>
                      <div class="card-body">
                        <span class="card-qty">x{p.quantity ?? "—"}</span>
                        <div class="card-identity">
                          <span class="card-name"
                            >{p.productDescription ?? "—"}</span
                          >
                          {#if p.catalogItem?.identifier}
                            <span class="card-catalog"
                              >{p.catalogItem.identifier}</span
                            >
                          {/if}
                        </div>

                        <div class="card-metrics">
                          <div class="card-metric">
                            <span class="card-metric-label">Unit Price</span>
                            <span class="card-metric-value"
                              >{formatCurrency(unitPrice(p))}</span
                            >
                          </div>
                          {#if canViewCost}
                            <div class="card-metric">
                              <span class="card-metric-label">Unit Cost</span>
                              <span class="card-metric-value"
                                >{formatCurrency(unitCost(p))}</span
                              >
                            </div>
                          {/if}
                          {#if canViewMargin}
                            <div class="card-metric">
                              <span class="card-metric-label">Margin</span>
                              <span class="card-metric-value"
                                >{formatCurrency(unitMargin(p))}</span
                              >
                            </div>
                          {/if}
                        </div>

                        <div class="card-badges">
                          <span
                            class="product-class-badge"
                            class:service={p.productClass === "Service"}
                            class:agreement={p.productClass === "Agreement"}
                          >
                            {p.productClass ?? "—"}
                          </span>
                        </div>
                      </div>
                      <div class="card-chevron">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="14"
                          height="14"
                        >
                          <polyline points="9 18 15 12 9 6" />
                        </svg>
                      </div>
                    </div>
                  {/each}
                </div>
              {:else}
                <div class="product-cards cancelled-cards">
                  {#each cancelledProducts as p (p.id)}
                    <!-- svelte-ignore a11y_no_static_element_interactions -->
                    <!-- svelte-ignore a11y_click_events_have_key_events -->
                    <div
                      class="product-card cancelled"
                      class:selected={selectedProduct?.id === p.id}
                      on:click={() => selectProduct(p)}
                    >
                      <div class="card-drag disabled"></div>
                      <div class="card-body">
                        <div class="card-top">
                          <div class="card-identity">
                            <span class="card-name">
                              {p.productDescription ?? "—"}
                            </span>
                            {#if p.catalogItem?.identifier}
                              <span class="card-catalog"
                                >{p.catalogItem.identifier}</span
                              >
                            {/if}
                          </div>
                          <div class="card-badges">
                            <span class="card-qty">x{p.quantity ?? "—"}</span>
                            <span
                              class="product-class-badge"
                              class:service={p.productClass === "Service"}
                              class:agreement={p.productClass === "Agreement"}
                            >
                              {p.productClass ?? "—"}
                            </span>
                          </div>
                        </div>
                        <div class="card-metrics">
                          <div class="card-metric">
                            <span class="card-metric-label">Unit Price</span>
                            <span class="card-metric-value"
                              >{formatCurrency(unitPrice(p))}</span
                            >
                          </div>
                          {#if canViewCost}
                            <div class="card-metric">
                              <span class="card-metric-label">Unit Cost</span>
                              <span class="card-metric-value"
                                >{formatCurrency(unitCost(p))}</span
                              >
                            </div>
                          {/if}
                          {#if canViewMargin}
                            <div class="card-metric">
                              <span class="card-metric-label">Margin</span>
                              <span class="card-metric-value"
                                >{formatCurrency(unitMargin(p))}</span
                              >
                            </div>
                          {/if}
                        </div>
                      </div>
                      <div class="card-chevron">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="16"
                          height="16"
                        >
                          <polyline points="9 18 15 12 9 6" />
                        </svg>
                      </div>
                    </div>
                  {/each}
                </div>
              {/if}
            {/if}
          {/if}
        </div>
      </div>

      <!-- ═══ Slide-over detail panel ═══ -->
      {#if showPanel && selectedProduct}
        <!-- svelte-ignore a11y_no_static_element_interactions -->
        <!-- svelte-ignore a11y_click_events_have_key_events -->
        <div
          class="product-detail-overlay"
          class:closing={isClosing}
          on:click={closeDetail}
        >
          <!-- svelte-ignore a11y_no_static_element_interactions -->
          <!-- svelte-ignore a11y_click_events_have_key_events -->
          <div
            class="product-detail-panel"
            class:closing={isClosing}
            on:click|stopPropagation
          >
            {#key selectedProduct.id}
              <div class="product-detail-content">
                <!-- Header -->
                <div class="detail-header">
                  <div class="detail-header-left">
                    <h3 class="detail-title">
                      {#if isEditing}
                        <textarea
                          class="edit-title-input"
                          bind:value={editForm.description}
                          placeholder="Product description"
                          rows="2"
                        ></textarea>
                      {:else}
                        {selectedProduct.productDescription ?? "Product"}
                      {/if}
                    </h3>
                    <div class="detail-badges">
                      {#if selectedProduct.productClass}
                        <span
                          class="product-class-badge"
                          class:service={selectedProduct.productClass ===
                            "Service"}
                          class:agreement={selectedProduct.productClass ===
                            "Agreement"}
                        >
                          {selectedProduct.productClass}
                        </span>
                      {/if}
                    </div>
                  </div>
                  <div class="detail-header-actions">
                    {#if !isClosedOpportunity}
                      {#if isEditing}
                        <button
                          class="detail-action-btn cancel-btn"
                          on:click={cancelEdit}
                          type="button"
                          title="Discard changes"
                          disabled={isSavingEdit}
                        >
                          Cancel
                        </button>
                        <button
                          class="detail-action-btn save-btn"
                          on:click={saveEdit}
                          type="button"
                          title="Save changes"
                          disabled={isSavingEdit}
                        >
                          {isSavingEdit ? "Saving..." : "Save"}
                        </button>
                      {:else}
                        {#if canUpdateProduct}
                          <button
                            class="detail-action-btn cancel-state-btn"
                            class:active={hasCancellation(selectedProduct)}
                            on:click={openCancellationModal}
                            type="button"
                            title={hasCancellation(selectedProduct)
                              ? "Edit cancellation"
                              : "Cancel product"}
                            disabled={maxCancellationQty(selectedProduct) <= 0}
                          >
                            {hasCancellation(selectedProduct)
                              ? "Edit Cancellation"
                              : "Cancel"}
                          </button>
                        {/if}
                        <div class="detail-menu-wrap">
                          <button
                            class="detail-menu-btn"
                            on:click={toggleActionMenu}
                            type="button"
                            aria-label="Product actions"
                            title="Actions"
                          >
                            <svg
                              viewBox="0 0 24 24"
                              fill="currentColor"
                              width="18"
                              height="18"
                            >
                              <circle cx="12" cy="5" r="1.5" />
                              <circle cx="12" cy="12" r="1.5" />
                              <circle cx="12" cy="19" r="1.5" />
                            </svg>
                          </button>
                          {#if showActionMenu}
                            <!-- svelte-ignore a11y_no_static_element_interactions -->
                            <!-- svelte-ignore a11y_click_events_have_key_events -->
                            <div
                              class="detail-action-menu"
                              on:click|stopPropagation
                            >
                              {#if canUpdateProduct}
                                <button
                                  class="detail-action-menu-item"
                                  on:click={enterEditMode}
                                  type="button"
                                >
                                  <svg
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="2"
                                    width="14"
                                    height="14"
                                  >
                                    <path
                                      d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"
                                    />
                                    <path
                                      d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"
                                    />
                                  </svg>
                                  Edit Product
                                </button>
                              {/if}
                              {#if canDeleteProduct}
                                <button
                                  class="detail-action-menu-item danger"
                                  on:click={openDeleteProductModal}
                                  type="button"
                                >
                                  <svg
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="2"
                                    width="14"
                                    height="14"
                                  >
                                    <polyline points="3 6 5 6 21 6" />
                                    <path
                                      d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"
                                    />
                                    <line x1="10" y1="11" x2="10" y2="17" />
                                    <line x1="14" y1="11" x2="14" y2="17" />
                                  </svg>
                                  Delete Product
                                </button>
                              {/if}
                            </div>
                          {/if}
                        </div>
                      {/if}
                    {/if}
                    <button
                      class="detail-close"
                      on:click={closeDetail}
                      aria-label="Close detail"
                      type="button"
                    >
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="18"
                        height="18"
                      >
                        <path d="M18 6L6 18M6 6l12 12" />
                      </svg>
                    </button>
                  </div>
                </div>

                {#if isEditing && editSaveError}
                  <div class="detail-inline-error">{editSaveError}</div>
                {/if}

                <!-- Cancelled alert (hidden during edit) -->
                {#if !isEditing && (selectedProduct.cancelled || selectedProduct.cancellationType || (selectedProduct.quantityCancelled != null && selectedProduct.quantityCancelled > 0))}
                  <div
                    class="detail-cancelled-card"
                    class:partial={selectedProduct.cancellationType ===
                      "partial"}
                  >
                    <div class="detail-cancelled-banner">
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="16"
                        height="16"
                      >
                        <circle cx="12" cy="12" r="10" /><path
                          d="M15 9l-6 6M9 9l6 6"
                        />
                      </svg>
                      <span class="detail-cancelled-title">
                        {selectedProduct.cancellationType === "partial"
                          ? "Partially Cancelled"
                          : "Cancelled"}
                      </span>
                    </div>
                    {#if selectedProduct.quantityCancelled || selectedProduct.cancelledReason || selectedProduct.cancelledDate}
                      <div class="detail-cancelled-meta">
                        {#if selectedProduct.quantityCancelled}
                          <div class="detail-cancelled-item">
                            <span>Qty Cancelled</span><span
                              >{selectedProduct.quantityCancelled}{#if selectedProduct.quantity}<span
                                  class="detail-cancelled-of"
                                  >&nbsp;of {selectedProduct.quantity}</span
                                >{/if}</span
                            >
                          </div>
                        {/if}
                        {#if selectedProduct.cancelledReason}
                          <div class="detail-cancelled-item">
                            <span>Reason</span><span
                              >{selectedProduct.cancelledReason}</span
                            >
                          </div>
                        {/if}
                        {#if selectedProduct.cancelledDate}
                          <div class="detail-cancelled-item">
                            <span>Date</span><span
                              >{formatDate(selectedProduct.cancelledDate)}</span
                            >
                          </div>
                        {/if}
                      </div>
                    {/if}
                  </div>
                {/if}

                <!-- Section: Identity -->
                <div class="detail-section">
                  <div class="detail-section-header">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <path
                        d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"
                      /><circle cx="12" cy="7" r="4" />
                    </svg>
                    Identity
                  </div>
                  {#if selectedProduct.catalogItem?.identifier}
                    <div class="detail-field">
                      <span class="detail-field-label">Product ID</span>
                      <span class="detail-field-value mono"
                        >{selectedProduct.catalogItem.identifier}</span
                      >
                    </div>
                  {/if}
                  {#if selectedProduct.forecastDescription}
                    <div class="detail-field">
                      <span class="detail-field-label"
                        >Forecast Description</span
                      >
                      <span class="detail-field-value"
                        >{selectedProduct.forecastDescription}</span
                      >
                    </div>
                  {/if}
                  {#if selectedProduct.forecastType}
                    <div class="detail-field">
                      <span class="detail-field-label">Forecast Type</span>
                      <span class="detail-field-value"
                        >{selectedProduct.forecastType}</span
                      >
                    </div>
                  {/if}
                  <div class="detail-field">
                    <span class="detail-field-label">Quantity</span>
                    {#if isEditing}
                      <input
                        class="edit-input"
                        type="number"
                        min="0"
                        step="1"
                        bind:value={editForm.quantity}
                        placeholder="Qty"
                      />
                    {:else}
                      <span class="detail-field-value"
                        >{selectedProduct.quantity ?? "—"}</span
                      >
                    {/if}
                  </div>
                </div>

                <!-- Section: Financials -->
                <div class="detail-section">
                  <div class="detail-section-header">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <line x1="12" y1="1" x2="12" y2="23" /><path
                        d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"
                      />
                    </svg>
                    Financials
                  </div>

                  <!-- Unit Pricing -->
                  <div class="detail-unit-pricing">
                    <span class="detail-unit-pricing-label">Unit Pricing</span>
                    <div class="detail-unit-pricing-grid">
                      <div class="detail-field">
                        <span class="detail-field-label">Unit Price</span>
                        {#if isEditing}
                          <input
                            class="edit-input"
                            type="number"
                            min="0"
                            step="0.01"
                            bind:value={editForm.unitPrice}
                            placeholder="0.00"
                          />
                        {:else}
                          <span class="detail-field-value"
                            >{formatCurrency(unitPrice(selectedProduct))}</span
                          >
                        {/if}
                      </div>
                      {#if canViewCost}
                        <div class="detail-field">
                          <span class="detail-field-label">Unit Cost</span>
                          {#if isEditing}
                            <input
                              class="edit-input"
                              type="number"
                              min="0"
                              step="0.01"
                              bind:value={editForm.unitCost}
                              placeholder="0.00"
                            />
                          {:else}
                            <span class="detail-field-value"
                              >{formatCurrency(unitCost(selectedProduct))}</span
                            >
                          {/if}
                        </div>
                      {/if}
                      {#if canViewMargin}
                        <div class="detail-field">
                          <span class="detail-field-label">Unit Margin</span>
                          <span class="detail-field-value"
                            >{#if isEditing}
                              {formatCurrency(
                                (parseFloat(editForm.unitPrice) || 0) -
                                  (parseFloat(editForm.unitCost) || 0)
                              )}
                            {:else}
                              {formatCurrency(unitMargin(selectedProduct))}
                            {/if}</span
                          >
                        </div>
                      {/if}
                    </div>
                  </div>

                  <div class="detail-finance-grid">
                    <div class="detail-finance-card rev">
                      <span class="detail-finance-label">Revenue</span>
                      <span class="detail-finance-value"
                        >{formatCurrency(selectedProduct.revenue)}</span
                      >
                    </div>
                    {#if canViewCost}
                      <div class="detail-finance-card">
                        <span class="detail-finance-label">Cost</span>
                        <span class="detail-finance-value"
                          >{formatCurrency(selectedProduct.cost)}</span
                        >
                      </div>
                    {/if}
                    {#if canViewMargin}
                      <div class="detail-finance-card">
                        <span class="detail-finance-label">Margin</span>
                        <span class="detail-finance-value"
                          >{formatCurrency(selectedProduct.margin)}</span
                        >
                      </div>
                    {/if}
                    {#if canViewProfit}
                      <div class="detail-finance-card">
                        <span class="detail-finance-label">Profit</span>
                        <span class="detail-finance-value"
                          >{formatCurrency(selectedProduct.profit)}</span
                        >
                      </div>
                    {/if}
                  </div>

                  {#if canViewMargin}
                    <div class="detail-field-row">
                      <div class="detail-field">
                        <span class="detail-field-label">Markup %</span>
                        <span class="detail-field-value">
                          {selectedProduct.cost
                            ? (
                                ((selectedProduct.margin ?? 0) /
                                  selectedProduct.cost) *
                                100
                              ).toFixed(1) + "%"
                            : "—"}
                        </span>
                      </div>
                      <div class="detail-field">
                        <span class="detail-field-label">Margin %</span>
                        <span class="detail-field-value">
                          {selectedProduct.revenue
                            ? (
                                ((selectedProduct.margin ?? 0) /
                                  selectedProduct.revenue) *
                                100
                              ).toFixed(1) + "%"
                            : "—"}
                        </span>
                      </div>
                    </div>
                    <!-- Markup health bar -->
                    <div class="detail-margin-bar-wrap">
                      <span class="detail-bar-label">Markup</span>
                      <div class="detail-margin-bar">
                        <div
                          class="detail-margin-fill {markupHealthColor(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}"
                          class:from-right={isNegativeMarkup(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}
                          style="width: {markupBarWidthPct(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}%"
                        ></div>
                        {#if rawMarkupPct(selectedProduct.revenue, selectedProduct.margin) > 100}
                          <div
                            class="detail-margin-fill super-blue"
                            style="width: {tierWidth(
                              rawMarkupPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              100
                            )}%"
                          ></div>
                        {/if}
                        {#if rawMarkupPct(selectedProduct.revenue, selectedProduct.margin) > 200}
                          <div
                            class="detail-margin-fill super-indigo"
                            style="width: {tierWidth(
                              rawMarkupPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              200
                            )}%"
                          ></div>
                        {/if}
                        {#if rawMarkupPct(selectedProduct.revenue, selectedProduct.margin) > 300}
                          <div
                            class="detail-margin-fill super-violet"
                            style="width: {tierWidth(
                              rawMarkupPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              300
                            )}%"
                          ></div>
                        {/if}
                      </div>
                      <span class="detail-margin-pct">
                        {selectedProduct.cost
                          ? (
                              ((selectedProduct.margin ?? 0) /
                                selectedProduct.cost) *
                              100
                            ).toFixed(1) + "%"
                          : "—"}
                      </span>
                    </div>
                    <!-- Margin health bar -->
                    <div class="detail-margin-bar-wrap">
                      <span class="detail-bar-label">Margin</span>
                      <div class="detail-margin-bar">
                        <div
                          class="detail-margin-fill {marginHealthColor(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}"
                          class:from-right={isNegativeMargin(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}
                          style="width: {marginBarWidthPct(
                            selectedProduct.revenue,
                            selectedProduct.margin
                          )}%"
                        ></div>
                        {#if rawMarginPct(selectedProduct.revenue, selectedProduct.margin) > 100}
                          <div
                            class="detail-margin-fill super-blue"
                            style="width: {tierWidth(
                              rawMarginPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              100
                            )}%"
                          ></div>
                        {/if}
                        {#if rawMarginPct(selectedProduct.revenue, selectedProduct.margin) > 200}
                          <div
                            class="detail-margin-fill super-indigo"
                            style="width: {tierWidth(
                              rawMarginPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              200
                            )}%"
                          ></div>
                        {/if}
                        {#if rawMarginPct(selectedProduct.revenue, selectedProduct.margin) > 300}
                          <div
                            class="detail-margin-fill super-violet"
                            style="width: {tierWidth(
                              rawMarginPct(
                                selectedProduct.revenue,
                                selectedProduct.margin
                              ),
                              300
                            )}%"
                          ></div>
                        {/if}
                      </div>
                      <span class="detail-margin-pct">
                        {selectedProduct.revenue
                          ? (
                              ((selectedProduct.margin ?? 0) /
                                selectedProduct.revenue) *
                              100
                            ).toFixed(1) + "%"
                          : "—"}
                      </span>
                    </div>
                  {/if}
                </div>

                <!-- Section: Details (text fields) -->
                <div class="detail-section">
                  <div class="detail-section-header">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <path
                        d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"
                      />
                      <polyline points="14 2 14 8 20 8" />
                      <line x1="16" y1="13" x2="8" y2="13" />
                      <line x1="16" y1="17" x2="8" y2="17" />
                      <polyline points="10 9 9 9 8 9" />
                    </svg>
                    Details
                  </div>
                  <div class="detail-field">
                    <span class="detail-field-label">Product Narrative</span>
                    {#if isEditing}
                      <textarea
                        class="edit-textarea"
                        bind:value={editForm.productNarrative}
                        placeholder="Product narrative…"
                        rows="3"
                      ></textarea>
                    {:else}
                      <span
                        class="detail-field-value"
                        style="white-space: pre-wrap;"
                        >{selectedProduct.productNarrative || "—"}</span
                      >
                    {/if}
                  </div>
                  <div class="detail-field">
                    <span class="detail-field-label">Procurement Notes</span>
                    {#if isEditing}
                      <textarea
                        class="edit-textarea"
                        bind:value={editForm.procurementNotes}
                        placeholder="Procurement notes…"
                        rows="3"
                      ></textarea>
                    {:else}
                      <span
                        class="detail-field-value"
                        style="white-space: pre-wrap;"
                        >{selectedProduct.procurementNotes || "—"}</span
                      >
                    {/if}
                  </div>
                </div>

                <!-- Section: Flags & Settings -->
                <div class="detail-section">
                  <div class="detail-section-header">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <path
                        d="M12.22 2h-.44a2 2 0 00-2 2v.18a2 2 0 01-1 1.73l-.43.25a2 2 0 01-2 0l-.15-.08a2 2 0 00-2.73.73l-.22.38a2 2 0 00.73 2.73l.15.1a2 2 0 011 1.72v.51a2 2 0 01-1 1.74l-.15.09a2 2 0 00-.73 2.73l.22.38a2 2 0 002.73.73l.15-.08a2 2 0 012 0l.43.25a2 2 0 011 1.73V20a2 2 0 002 2h.44a2 2 0 002-2v-.18a2 2 0 011-1.73l.43-.25a2 2 0 012 0l.15.08a2 2 0 002.73-.73l.22-.39a2 2 0 00-.73-2.73l-.15-.08a2 2 0 01-1-1.74v-.5a2 2 0 011-1.74l.15-.09a2 2 0 00.73-2.73l-.22-.38a2 2 0 00-2.73-.73l-.15.08a2 2 0 01-2 0l-.43-.25a2 2 0 01-1-1.73V4a2 2 0 00-2-2z"
                      />
                      <circle cx="12" cy="12" r="3" />
                    </svg>
                    Flags &amp; Settings
                  </div>
                  <div class="detail-flags">
                    <div
                      class="detail-flag"
                      class:active={selectedProduct.includeFlag}
                    >
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="13"
                        height="13"
                      >
                        {#if selectedProduct.includeFlag}<path
                            d="M20 6L9 17l-5-5"
                          />{:else}<path d="M18 6L6 18M6 6l12 12" />{/if}
                      </svg>
                      Included
                    </div>
                    <div
                      class="detail-flag"
                      class:active={selectedProduct.linkFlag}
                    >
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="13"
                        height="13"
                      >
                        {#if selectedProduct.linkFlag}<path
                            d="M20 6L9 17l-5-5"
                          />{:else}<path d="M18 6L6 18M6 6l12 12" />{/if}
                      </svg>
                      Linked
                    </div>
                    <div
                      class="detail-flag"
                      class:active={isEditing
                        ? editForm.taxableFlag
                        : selectedProduct.taxableFlag}
                      class:editable={isEditing}
                      role={isEditing ? "button" : undefined}
                      tabindex={isEditing ? 0 : undefined}
                      on:click={() => {
                        if (isEditing)
                          editForm.taxableFlag = !editForm.taxableFlag;
                      }}
                      on:keydown={(e) => {
                        if (isEditing && (e.key === "Enter" || e.key === " ")) {
                          e.preventDefault();
                          editForm.taxableFlag = !editForm.taxableFlag;
                        }
                      }}
                    >
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="13"
                        height="13"
                      >
                        {#if isEditing ? editForm.taxableFlag : selectedProduct.taxableFlag}<path
                            d="M20 6L9 17l-5-5"
                          />{:else}<path d="M18 6L6 18M6 6l12 12" />{/if}
                      </svg>
                      Taxable
                    </div>
                    <div
                      class="detail-flag"
                      class:active={selectedProduct.recurringFlag}
                    >
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="13"
                        height="13"
                      >
                        {#if selectedProduct.recurringFlag}<path
                            d="M20 6L9 17l-5-5"
                          />{:else}<path d="M18 6L6 18M6 6l12 12" />{/if}
                      </svg>
                      Recurring
                    </div>
                  </div>

                  {#if selectedProduct.recurringFlag}
                    <div class="detail-recurring-grid">
                      <div class="detail-field">
                        <span class="detail-field-label">Recurring Revenue</span
                        >
                        <span class="detail-field-value"
                          >{formatCurrency(
                            selectedProduct.recurringRevenue
                          )}</span
                        >
                      </div>
                      {#if canViewCost}
                        <div class="detail-field">
                          <span class="detail-field-label">Recurring Cost</span>
                          <span class="detail-field-value"
                            >{formatCurrency(
                              selectedProduct.recurringCost
                            )}</span
                          >
                        </div>
                      {/if}
                      <div class="detail-field">
                        <span class="detail-field-label">Cycles</span>
                        <span class="detail-field-value"
                          >{selectedProduct.cycles ?? "—"}</span
                        >
                      </div>
                    </div>
                  {/if}
                </div>

                <!-- Section: Inventory -->
                {#if hasInventory(selectedProduct)}
                  <div class="detail-section">
                    <div class="detail-section-header">
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="14"
                        height="14"
                      >
                        <path
                          d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"
                        />
                        <polyline points="3.27 6.96 12 12.01 20.73 6.96" /><line
                          x1="12"
                          y1="22.08"
                          x2="12"
                          y2="12"
                        />
                      </svg>
                      Inventory
                    </div>
                    <div class="detail-field-row">
                      <div class="detail-field">
                        <span class="detail-field-label">On Hand</span>
                        <span class="detail-field-value">
                          {#if selectedProduct.catalogItem}
                            <InventoryPopover
                              identifier={String(selectedProduct.catalogItem.id)}
                              onHand={selectedProduct.onHand ?? undefined}
                            />
                          {:else if selectedProduct.onHand != null}
                            <span
                              class="stock-badge"
                              class:stock-none={selectedProduct.onHand === 0}
                              class:stock-low={selectedProduct.onHand >= 1 &&
                                selectedProduct.onHand <= 5}
                              class:stock-good={selectedProduct.onHand > 5}
                              >{selectedProduct.onHand}</span
                            >
                          {:else}
                            —
                          {/if}
                        </span>
                      </div>
                      <div class="detail-field">
                        <span class="detail-field-label">In Stock</span>
                        <span class="detail-field-value">
                          {selectedProduct.inStock == null
                            ? "—"
                            : selectedProduct.inStock
                              ? "Yes"
                              : "No"}
                        </span>
                      </div>
                    </div>
                  </div>
                {/if}

                <!-- Section: History -->
                <div class="detail-section last">
                  <div class="detail-section-header">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <circle cx="12" cy="12" r="10" /><polyline
                        points="12 6 12 12 16 14"
                      />
                    </svg>
                    History
                  </div>
                  <div class="detail-field">
                    <span class="detail-field-label">Last Updated</span>
                    <span class="detail-field-value"
                      >{formatDate(selectedProduct.cwLastUpdated)}</span
                    >
                  </div>
                  {#if selectedProduct.cwUpdatedBy}
                    <div class="detail-field">
                      <span class="detail-field-label">Updated By</span>
                      <span class="detail-field-value"
                        >{selectedProduct.cwUpdatedBy}</span
                      >
                    </div>
                  {/if}
                </div>
              </div>
            {/key}
          </div>
        </div>
      {/if}
    </div>
  {/if}
</div>

{#if showCancelModal && selectedProduct}
  <!-- svelte-ignore a11y_no_static_element_interactions -->
  <!-- svelte-ignore a11y_click_events_have_key_events -->
  <div class="cancel-modal-overlay" on:click={closeCancellationModal}>
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <!-- svelte-ignore a11y_click_events_have_key_events -->
    <div class="cancel-modal" on:click|stopPropagation>
      <div class="cancel-modal-header">
        <h4>
          {hasCancellation(selectedProduct)
            ? "Edit Cancellation"
            : "Cancel Product"}
        </h4>
        <button
          class="cancel-modal-close"
          type="button"
          on:click={closeCancellationModal}
          aria-label="Close cancellation modal"
          disabled={isSavingCancellation}
        >
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="16"
            height="16"
          >
            <path d="M18 6L6 18M6 6l12 12" />
          </svg>
        </button>
      </div>

      <p class="cancel-modal-copy">
        Set cancelled quantity between 0 and {maxCancellationQty(
          selectedProduct
        )}.
      </p>

      {#if cancellationSaveError}
        <div class="cancel-modal-error">{cancellationSaveError}</div>
      {/if}

      <div class="cancel-modal-field">
        <label for="cancel-qty">Qty Cancelled</label>
        <input
          id="cancel-qty"
          class="edit-input"
          type="number"
          min="0"
          max={maxCancellationQty(selectedProduct)}
          step="1"
          bind:value={cancellationForm.quantityCancelled}
          disabled={isSavingCancellation}
        />
      </div>

      <div class="cancel-modal-field">
        <label for="cancel-reason">Reason</label>
        <textarea
          id="cancel-reason"
          class="edit-textarea"
          rows="3"
          placeholder="Optional cancellation reason"
          bind:value={cancellationForm.cancellationReason}
          disabled={isSavingCancellation}
        ></textarea>
      </div>

      <div class="cancel-modal-actions">
        <button
          class="detail-action-btn cancel-btn"
          type="button"
          on:click={closeCancellationModal}
          disabled={isSavingCancellation}
        >
          Close
        </button>
        <button
          class="detail-action-btn save-btn"
          type="button"
          on:click={saveCancellation}
          disabled={isSavingCancellation}
        >
          {isSavingCancellation ? "Saving..." : "Save Cancellation"}
        </button>
      </div>
    </div>
  </div>
{/if}

{#if showDeleteModal && selectedProduct}
  <!-- svelte-ignore a11y_no_static_element_interactions -->
  <!-- svelte-ignore a11y_click_events_have_key_events -->
  <div class="cancel-modal-overlay" on:click={closeDeleteProductModal}>
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <!-- svelte-ignore a11y_click_events_have_key_events -->
    <div class="cancel-modal" on:click|stopPropagation>
      <div class="cancel-modal-header">
        <h4>Delete Product</h4>
        <button
          class="cancel-modal-close"
          type="button"
          on:click={closeDeleteProductModal}
          aria-label="Close delete modal"
          disabled={isDeletingProduct}
        >
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="16"
            height="16"
          >
            <path d="M18 6L6 18M6 6l12 12" />
          </svg>
        </button>
      </div>

      <p class="cancel-modal-copy">
        Are you sure you want to delete <strong
          >{selectedProduct.productDescription ??
            selectedProduct.forecastDescription ??
            "this product"}</strong
        >? This action cannot be undone.
      </p>

      {#if deleteProductError}
        <div class="cancel-modal-error">{deleteProductError}</div>
      {/if}

      <div class="cancel-modal-actions">
        <button
          class="detail-action-btn cancel-btn"
          type="button"
          on:click={closeDeleteProductModal}
          disabled={isDeletingProduct}
        >
          Cancel
        </button>
        <button
          class="detail-action-btn delete-confirm-btn"
          type="button"
          on:click={executeDeleteProduct}
          disabled={isDeletingProduct}
        >
          {isDeletingProduct ? "Deleting..." : "Delete"}
        </button>
      </div>
    </div>
  </div>
{/if}

<AddProductModal
  bind:isOpen={showAddProductModal}
  accessToken={accessToken ?? ""}
  {opportunityId}
  onSelect={handleProductSelected}
/>

<style>
  /* ═══════════════════════════════════════════════════
     Products Tab — Reimagined
     ═══════════════════════════════════════════════════ */
  .products-tab {
    display: flex;
    flex-direction: column;
    gap: 0;
    min-height: 0;
    flex: 1;
    position: relative;
    overflow: hidden;
    margin: -24px;
    height: calc(100% + 48px);
  }

  /* ═══ KPI Strip ═══ */
  .kpi-strip {
    display: flex;
    align-items: stretch;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    flex-shrink: 0;
    flex-wrap: wrap;
  }

  .kpi-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-radius: 10px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
    min-width: 0;
    flex: 1;
    position: relative;
  }

  .kpi-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    flex-shrink: 0;
  }

  .kpi-icon.revenue {
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
  }

  .kpi-icon.cost {
    background: rgba(239, 68, 68, 0.1);
    color: #ef4444;
  }

  .kpi-icon.margin {
    background: rgba(59, 130, 246, 0.12);
    color: #3b82f6;
  }

  .kpi-icon.profit {
    background: rgba(139, 92, 246, 0.12);
    color: #8b5cf6;
  }

  .kpi-icon.tax {
    background: rgba(245, 158, 11, 0.12);
    color: #f59e0b;
  }

  .kpi-card--grand-total {
    border-color: var(--card-border);
    background: var(--bg-inset);
    font-weight: 700;
  }

  .kpi-card--grand-total .kpi-label {
    font-weight: 600;
  }

  .kpi-card--grand-total .kpi-value {
    font-size: 17px;
  }

  .kpi-content {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
  }

  .kpi-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-faint);
  }

  .kpi-value {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .kpi-badge {
    position: absolute;
    top: 6px;
    right: 8px;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 6px;
    border-radius: 6px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .kpi-badge.healthy {
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
  }

  .kpi-badge.moderate {
    background: rgba(234, 179, 8, 0.12);
    color: #eab308;
  }

  .kpi-badge.low {
    background: rgba(249, 115, 22, 0.12);
    color: #f97316;
  }

  .kpi-badge.negative {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
  }

  .kpi-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    flex-shrink: 0;
    animation: actionsIn 0.2s ease-out;
  }

  .kpi-actions-error {
    font-size: 12px;
    color: var(--status-lost-color, rgb(239, 68, 68));
  }

  /* ═══ Products Toolbar ═══ */
  .products-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 16px;
    border-bottom: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
    flex-shrink: 0;
    gap: 8px;
  }

  .toolbar-left {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .toolbar-add-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    border: 1px dashed var(--border-subtle, rgba(255, 255, 255, 0.15));
    background: transparent;
    color: var(--text-secondary);
    transition:
      background 0.15s,
      color 0.15s,
      border-color 0.15s;
  }

  .toolbar-add-btn:hover:not(:disabled) {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-color: var(--accent, #60a5fa);
  }

  .toolbar-add-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }

  .toolbar-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    animation: actionsIn 0.2s ease-out;
  }

  .toolbar-error {
    font-size: 11px;
    color: var(--status-lost-color, rgb(239, 68, 68));
  }

  @keyframes actionsIn {
    from {
      opacity: 0;
      transform: translateX(8px);
    }
    to {
      opacity: 1;
      transform: translateX(0);
    }
  }

  .sequence-btn {
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition:
      background 0.15s,
      opacity 0.15s,
      transform 0.1s;
  }

  .sequence-btn:active:not(:disabled) {
    transform: scale(0.97);
  }

  .sequence-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .sequence-btn.discard {
    background: var(--bg-muted, rgba(128, 128, 128, 0.1));
    color: var(--text-secondary);
  }

  .sequence-btn.discard:hover:not(:disabled) {
    background: var(--bg-hover);
    color: var(--text-primary);
  }

  .sequence-btn.save {
    background: var(--accent);
    color: #fff;
  }

  .sequence-btn.save:hover:not(:disabled) {
    opacity: 0.9;
  }

  /* ═══ View Toggle Button ═══ */
  .view-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    border-radius: 6px;
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.15));
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition:
      background 0.15s,
      color 0.15s,
      border-color 0.15s;
  }

  .view-toggle-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-color: var(--accent, #60a5fa);
  }

  /* ═══ Compact card modifiers ═══ */
  .compact-cards {
    gap: 3px !important;
  }

  .product-card.compact {
    padding: 5px 8px;
    border-radius: 6px;
    gap: 6px;
    align-items: center;
  }

  .product-card.compact .card-drag {
    width: 14px;
    padding: 0;
  }

  .product-card.compact .card-drag svg {
    width: 10px;
    height: 10px;
  }

  .product-card.compact .card-body {
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 4px 6px;
  }

  .product-card.compact .card-identity {
    width: 240px;
    flex-shrink: 0;
    min-width: 0;
    gap: 1px;
  }

  .product-card.compact .card-name {
    font-size: 12.5px;
    font-weight: 500;
  }

  .product-card.compact .card-catalog {
    font-size: 10px;
  }

  .product-card.compact .card-metrics {
    flex-shrink: 0;
    gap: 16px;
    align-items: flex-end;
  }

  .product-card.compact .card-metric-label {
    font-size: 9px;
  }

  .product-card.compact .card-metric-value {
    font-size: 12px;
  }

  .product-card.compact .card-badges {
    flex-shrink: 0;
    margin-left: auto;
    gap: 4px;
    padding-right: 4px;
  }

  .product-card.compact .card-qty {
    font-size: 10px;
    height: 18px;
    padding: 0 5px;
  }

  .product-card.compact .product-class-badge {
    font-size: 9px;
    height: 18px;
    padding: 0 6px;
  }

  .product-card.compact .card-chevron svg {
    width: 12px;
    height: 12px;
  }

  /* ═══ Content row ═══ */
  .products-content-row {
    display: flex;
    flex-direction: row;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }

  .products-list-pane {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    min-width: 0;
    overflow: hidden;
    transition: flex 0.3s ease;
  }

  .products-list-pane.collapsed {
    flex: 1 1 0%;
  }

  .products-scroll {
    overflow-y: auto;
    flex: 1;
    min-height: 0;
    padding: 12px 16px;
  }

  /* ═══ Product Cards ═══ */
  .product-cards {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .product-card {
    display: flex;
    align-items: stretch;
    border-radius: 10px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
    cursor: grab;
    transition:
      background 0.12s,
      border-color 0.15s,
      box-shadow 0.15s,
      transform 0.12s;
    overflow: hidden;
    user-select: none;
    -webkit-user-select: none;
    -webkit-app-region: no-drag;
  }

  .product-card:active {
    cursor: grabbing;
  }

  .product-card:hover {
    background: var(--bg-hover);
    border-color: var(--border-subtle, rgba(255, 255, 255, 0.12));
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  }

  .product-card.selected {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 5%, var(--bg-surface));
    box-shadow:
      0 0 0 1px var(--accent),
      0 2px 8px rgba(0, 0, 0, 0.08);
  }

  .product-card.dragging {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    transform: scale(1.01);
    z-index: 10;
    position: relative;
    border-color: var(--accent);
    opacity: 0.5;
  }

  .product-card.cancelled {
    opacity: 0.5;
  }

  .product-card.cancelled .card-name {
    text-decoration: line-through;
  }

  /* Drag handle */
  .card-drag {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    flex-shrink: 0;
    cursor: grab;
    color: var(--text-faint);
    opacity: 0.3;
    transition:
      opacity 0.15s,
      background 0.15s;
  }

  .card-drag:active {
    cursor: grabbing;
  }

  .product-card:hover .card-drag:not(.disabled) {
    opacity: 0.7;
    background: var(--bg-hover, rgba(255, 255, 255, 0.03));
  }

  .card-drag.disabled {
    cursor: default;
    opacity: 0;
  }

  /* Card body */
  .card-body {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .card-top {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .card-identity {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }

  .card-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
  }

  .card-catalog {
    font-size: 11px;
    color: var(--text-faint);
    font-family: var(--font-mono, monospace);
    letter-spacing: 0.01em;
  }

  .partial-cancelled-flag {
    font-size: 10px;
    font-weight: 600;
    color: #f59e0b;
    letter-spacing: 0.01em;
  }

  .card-qty.partial {
    background: rgba(245, 158, 11, 0.12);
    border-color: rgba(245, 158, 11, 0.25);
    color: #f59e0b;
  }

  .card-badges {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin-left: auto;
    padding-right: 4px;
  }

  .card-qty {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    padding: 2px 8px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    background: var(--bg-hover, rgba(255, 255, 255, 0.07));
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08));
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    position: relative;
    top: -2px;
    flex-shrink: 0;
  }

  .product-class-badge {
    display: inline-flex;
    align-items: center;
    height: 22px;
    padding: 0 8px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--bg-muted, rgba(128, 128, 128, 0.1));
    color: var(--text-secondary);
  }

  .product-class-badge.service {
    background: rgba(59, 130, 246, 0.1);
    color: rgb(59, 130, 246);
  }

  .product-class-badge.agreement {
    background: rgba(139, 92, 246, 0.1);
    color: rgb(139, 92, 246);
  }

  .stock-badge {
    display: inline-flex;
    align-items: center;
    height: 22px;
    padding: 0 8px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .stock-badge.stock-none {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
  }

  .stock-badge.stock-low {
    background: rgba(245, 158, 11, 0.12);
    color: #f59e0b;
  }

  .stock-badge.stock-good {
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
  }

  /* Card metrics row */
  .card-metrics {
    display: flex;
    align-items: flex-end;
    gap: 16px;
  }

  .card-metric {
    display: flex;
    flex-direction: column;
    gap: 1px;
  }

  .card-metric-label {
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
  }

  .card-metric-value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
  }

  .card-metric-value.accent {
    color: #3498db;
  }

  /* Margin & Markup bars (inline in card) */
  .card-bars {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 1;
    min-width: 60px;
    align-self: center;
  }

  .card-bar-row {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .card-bar-label {
    font-size: 9px;
    font-weight: 600;
    color: var(--text-faint, #888);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    width: 38px;
    flex-shrink: 0;
  }

  .card-margin-bar {
    flex: 1;
    height: 4px;
    border-radius: 2px;
    background: var(--bg-muted, rgba(128, 128, 128, 0.12));
    overflow: hidden;
    min-width: 40px;
    position: relative;
  }

  .card-margin-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    border-radius: 9999px;
    transition: width 0.4s ease;
  }

  .card-margin-fill.from-right {
    left: auto;
    right: 0;
  }

  .card-margin-fill.healthy {
    background: #22c55e;
  }

  .card-margin-fill.moderate {
    background: #eab308;
  }

  .card-margin-fill.low {
    background: #f97316;
  }

  .card-margin-fill.negative {
    background: #ef4444;
  }

  .card-margin-fill.neutral {
    background: var(--text-faint, #888);
  }

  .card-margin-fill.super-blue {
    background: #3b82f6;
  }

  .card-margin-fill.super-indigo {
    background: #6366f1;
  }

  .card-margin-fill.super-violet {
    background: #8b5cf6;
  }

  /* Card chevron */
  .card-chevron {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    flex-shrink: 0;
    color: var(--text-faint);
    opacity: 0;
    transition: opacity 0.15s;
  }

  .product-card:hover .card-chevron,
  .product-card.selected .card-chevron {
    opacity: 1;
  }

  /* ═══ Cancelled Section ═══ */
  .cancelled-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 16px 4px 8px;
    cursor: pointer;
    user-select: none;
  }

  .cancelled-chevron {
    color: var(--text-faint);
    transition: transform 0.2s ease;
    flex-shrink: 0;
  }

  .cancelled-chevron.open {
    transform: rotate(90deg);
  }

  .cancelled-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-faint, #888);
    white-space: nowrap;
  }

  .cancelled-count {
    font-size: 10px;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 6px;
    background: rgba(239, 68, 68, 0.1);
    color: #ef4444;
  }

  .cancelled-line {
    flex: 1;
    height: 1px;
    background: var(--border-subtle);
  }

  .cancelled-cards {
    animation: fadeSlideDown 0.2s ease-out;
  }

  @keyframes fadeSlideDown {
    from {
      opacity: 0;
      transform: translateY(-4px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* ═══════════════════════════════════════════════════
     Detail Panel — Reimagined
     ═══════════════════════════════════════════════════ */
  .product-detail-overlay {
    display: contents;
  }

  .product-detail-panel {
    width: 400px;
    min-width: 340px;
    max-width: 440px;
    border-left: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: slideIn 0.25s ease-out forwards;
  }

  .product-detail-panel.closing {
    animation: slideOut 0.25s ease-in forwards;
  }

  @keyframes slideIn {
    from {
      opacity: 0;
      transform: translateX(20px);
    }
    to {
      opacity: 1;
      transform: translateX(0);
    }
  }

  @keyframes slideOut {
    from {
      opacity: 1;
      transform: translateX(0);
    }
    to {
      opacity: 0;
      transform: translateX(20px);
    }
  }

  .product-detail-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 0;
    overflow-y: auto;
    animation: detailFadeIn 0.25s ease-out;
  }

  @keyframes detailFadeIn {
    from {
      opacity: 0;
      transform: translateY(6px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* Detail header */
  .detail-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 20px 20px 16px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    position: sticky;
    top: 0;
    z-index: 2;
  }

  .detail-header-left {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
  }

  .detail-title {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.3;
  }

  .detail-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }

  .product-status-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--bg-muted, rgba(128, 128, 128, 0.1));
    color: var(--text-secondary);
  }

  .product-status-badge.included {
    background: var(--status-open-bg, rgba(34, 197, 94, 0.1));
    color: var(--status-open-color, rgb(34, 197, 94));
  }

  .detail-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    flex-shrink: 0;
    transition:
      background 0.15s,
      color 0.15s;
  }

  .detail-close:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
  }

  /* Header actions container */
  .detail-header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
  }

  /* Three-dot menu button */
  .detail-menu-wrap {
    position: relative;
  }

  .detail-menu-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition:
      background 0.15s,
      color 0.15s;
  }

  .detail-menu-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
  }

  /* Dropdown menu */
  .detail-action-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 4px;
    min-width: 160px;
    padding: 4px;
    background: var(--bg-surface, #1c1c22);
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    z-index: 10;
  }

  .detail-action-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 12px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition:
      background 0.12s,
      color 0.12s;
    text-align: left;
  }

  .detail-action-menu-item:hover {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
    color: var(--text-primary);
  }

  .detail-action-menu-item.danger {
    color: #ef4444;
  }

  .detail-action-menu-item.danger:hover {
    background: rgba(239, 68, 68, 0.12);
    color: #dc2626;
  }

  .delete-confirm-btn {
    background: #ef4444;
    color: #fff;
  }

  .delete-confirm-btn:hover:not(:disabled) {
    background: #dc2626;
  }

  .delete-confirm-btn:disabled {
    opacity: 0.65;
    cursor: not-allowed;
  }

  /* Edit mode action buttons */
  .detail-action-btn {
    padding: 5px 12px;
    border: none;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    flex-shrink: 0;
    cursor: pointer;
    transition:
      background 0.15s,
      color 0.15s;
  }

  .detail-action-btn:disabled {
    opacity: 0.65;
    cursor: not-allowed;
  }

  .cancel-btn {
    background: transparent;
    color: var(--text-secondary);
  }

  .cancel-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
  }

  .cancel-state-btn {
    background: transparent;
    color: var(--text-secondary);
  }

  .cancel-state-btn:hover {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
  }

  .cancel-state-btn.active {
    background: rgba(245, 158, 11, 0.14);
    color: #d97706;
  }

  .cancel-state-btn.active:hover {
    background: rgba(245, 158, 11, 0.2);
    color: #d97706;
  }

  .save-btn {
    background: var(--accent, #6366f1);
    color: #fff;
  }

  .save-btn:hover {
    background: color-mix(in srgb, var(--accent, #6366f1) 85%, #000);
  }

  .detail-inline-error {
    margin: 10px 18px 0;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid rgba(220, 38, 38, 0.25);
    background: rgba(220, 38, 38, 0.08);
    color: #ef4444;
    font-size: 12px;
    font-weight: 500;
  }

  .cancel-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }

  .cancel-modal {
    width: min(480px, calc(100vw - 40px));
    border-radius: 12px;
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
    background: var(--bg-surface, #1c1c22);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .cancel-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
  }

  .cancel-modal-header h4 {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
  }

  .cancel-modal-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
  }

  .cancel-modal-close:hover {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
    color: var(--text-primary);
  }

  .cancel-modal-copy {
    margin: 0;
    color: var(--text-secondary);
    font-size: 12px;
    line-height: 1.4;
  }

  .cancel-modal-error {
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid rgba(220, 38, 38, 0.25);
    background: rgba(220, 38, 38, 0.08);
    color: #ef4444;
    font-size: 12px;
    font-weight: 500;
  }

  .cancel-modal-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .cancel-modal-field label {
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 600;
  }

  .cancel-modal-actions {
    margin-top: 4px;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }

  /* Edit inputs */
  .edit-input {
    width: 100%;
    padding: 6px 10px;
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
    border-radius: 6px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.04));
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    outline: none;
    transition: border-color 0.15s;
  }

  .edit-input:focus {
    border-color: var(--accent, #6366f1);
  }

  .edit-input[type="number"] {
    font-variant-numeric: tabular-nums;
  }

  .edit-title-input {
    width: 100%;
    font-size: 13px;
    font-weight: 600;
    padding: 6px 8px;
    line-height: 1.4;
    resize: vertical;
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
    border-radius: 6px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.04));
    color: var(--text-primary);
    font-family: inherit;
  }

  .edit-textarea {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
    border-radius: 6px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.04));
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    line-height: 1.5;
    resize: vertical;
    outline: none;
    transition: border-color 0.15s;
  }

  .edit-textarea:focus {
    border-color: var(--accent, #6366f1);
  }

  /* Cancelled card in detail */
  .detail-cancelled-card {
    margin: 16px 20px 0;
    padding: 0;
    background: rgba(239, 68, 68, 0.1);
    border: 1px solid rgba(239, 68, 68, 0.35);
    border-radius: 10px;
    border-left: 3px solid #ef4444;
  }

  /* Partial cancellation — amber variant */
  .detail-cancelled-card.partial {
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-left: 3px solid #f59e0b;
  }

  .detail-cancelled-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    min-height: 38px;
    color: #ef4444;
    font-size: 13px;
    font-weight: 700;
    background: rgba(239, 68, 68, 0.1);
    border-radius: 10px 10px 0 0;
  }

  .detail-cancelled-card.partial .detail-cancelled-banner {
    color: #d97706;
    background: rgba(245, 158, 11, 0.1);
  }

  .detail-cancelled-banner svg {
    flex-shrink: 0;
  }

  .detail-cancelled-title {
    letter-spacing: 0.01em;
  }

  .detail-cancelled-meta {
    padding: 6px 14px 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    border-top: 1px solid rgba(239, 68, 68, 0.15);
  }

  .detail-cancelled-card.partial .detail-cancelled-meta {
    border-top-color: rgba(245, 158, 11, 0.15);
  }

  .detail-cancelled-item {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 3px 0;
    font-size: 12px;
  }

  .detail-cancelled-item span:first-child {
    color: rgba(239, 68, 68, 0.8);
    font-weight: 600;
  }

  .detail-cancelled-card.partial .detail-cancelled-item span:first-child {
    color: rgba(217, 119, 6, 0.8);
  }

  .detail-cancelled-item span:last-child {
    color: var(--text-primary);
  }

  .detail-cancelled-of {
    color: var(--text-faint, #888);
    font-weight: 400;
  }

  /* Detail sections */
  .detail-section {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .detail-section.last {
    border-bottom: none;
  }

  .detail-section-header {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-faint);
    padding-bottom: 4px;
  }

  .detail-section-header svg {
    opacity: 0.6;
  }

  .detail-field {
    display: flex;
    flex-direction: column;
    gap: 3px;
  }

  .detail-field-label {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
  }

  .detail-field-value {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
  }

  .detail-field-value.mono {
    font-family: var(--font-mono, monospace);
    font-size: 13px;
  }

  .detail-field-row {
    display: flex;
    gap: 20px;
  }

  .detail-field-row .detail-field {
    flex: 1;
  }

  /* Finance grid (2x2) */
  .detail-finance-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: 4px;
    padding-top: 10px;
    border-top: 1px dashed var(--border-subtle, rgba(255, 255, 255, 0.06));
  }

  .detail-finance-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border-radius: 8px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.03));
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.05));
  }

  .detail-finance-card.rev {
    border-color: color-mix(in srgb, var(--accent) 30%, transparent);
    background: color-mix(
      in srgb,
      var(--accent) 4%,
      var(--bg-hover, rgba(255, 255, 255, 0.03))
    );
  }

  .detail-finance-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
  }

  .detail-finance-value {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
  }

  .detail-finance-card.rev .detail-finance-value {
    color: var(--accent);
  }

  /* Unit pricing sub-section */
  .detail-unit-pricing {
    margin-top: 4px;
  }

  .detail-unit-pricing-label {
    display: block;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
    margin-bottom: 8px;
  }

  .detail-unit-pricing-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
  }

  .detail-unit-pricing-grid .detail-field {
    padding: 8px 10px;
    border-radius: 6px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.03));
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.05));
  }

  /* Margin/Markup fields row */
  .detail-field-row {
    display: flex;
    gap: 16px;
  }

  .detail-field-row .detail-field {
    flex: 1;
  }

  .detail-bar-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-faint, #888);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    width: 44px;
    flex-shrink: 0;
  }

  /* Margin bar in detail */
  .detail-margin-bar-wrap {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .detail-margin-bar {
    flex: 1;
    height: 6px;
    border-radius: 3px;
    background: var(--bg-muted, rgba(128, 128, 128, 0.12));
    overflow: hidden;
    position: relative;
  }

  .detail-margin-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    border-radius: 9999px;
    transition: width 0.4s ease;
  }

  .detail-margin-fill.from-right {
    left: auto;
    right: 0;
  }

  .detail-margin-fill.healthy {
    background: #22c55e;
  }
  .detail-margin-fill.moderate {
    background: #eab308;
  }
  .detail-margin-fill.low {
    background: #f97316;
  }
  .detail-margin-fill.negative {
    background: #ef4444;
  }
  .detail-margin-fill.neutral {
    background: var(--text-faint, #888);
  }

  .detail-margin-fill.super-blue {
    background: #3b82f6;
  }
  .detail-margin-fill.super-indigo {
    background: #6366f1;
  }
  .detail-margin-fill.super-violet {
    background: #8b5cf6;
  }

  .detail-margin-pct {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    min-width: 48px;
    text-align: right;
  }

  .detail-margin-bar-wrap + .detail-margin-bar-wrap {
    margin-top: 4px;
  }

  /* Flags */
  .detail-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }

  .detail-flag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 500;
    background: var(--bg-muted, rgba(128, 128, 128, 0.08));
    color: var(--text-faint);
    transition:
      background 0.15s,
      color 0.15s;
  }

  .detail-flag.active {
    background: var(--status-open-bg, rgba(34, 197, 94, 0.1));
    color: var(--status-open-color, rgb(34, 197, 94));
  }

  .detail-flag.editable {
    cursor: pointer;
    user-select: none;
    outline: 1.5px dashed var(--border-color, rgba(128, 128, 128, 0.3));
    outline-offset: -1px;
  }

  .detail-flag.editable:hover {
    background: var(--card-hover-bg, rgba(128, 128, 128, 0.12));
  }

  .detail-recurring-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 4px;
  }

  /* ═══════════════════════════════════════════
     Mobile — Bottom sheet
     ═══════════════════════════════════════════ */
  @media (max-width: 768px) {
    .kpi-strip {
      gap: 8px;
      padding: 12px;
    }

    .kpi-card {
      flex: 1 1 calc(50% - 4px);
      min-width: calc(50% - 4px);
      padding: 8px 10px;
    }

    .kpi-icon {
      width: 28px;
      height: 28px;
    }

    .kpi-value {
      font-size: 13px;
    }

    .products-list-pane.collapsed {
      display: none;
    }

    .product-detail-overlay {
      display: flex;
      position: fixed;
      inset: 0;
      z-index: 150;
      align-items: flex-end;
      justify-content: center;
      background: rgba(0, 0, 0, 0.5);
      pointer-events: auto;
      transition: background 0.25s ease;
    }

    .product-detail-overlay.closing {
      background: rgba(0, 0, 0, 0);
    }

    .product-detail-panel {
      width: 100%;
      max-width: 100%;
      min-width: 0;
      height: 85vh;
      max-height: 85vh;
      border-left: none;
      border-radius: 16px 16px 0 0;
      box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.25);
      animation: slideUp 0.3s cubic-bezier(0.32, 0.72, 0, 1) forwards;
    }

    .product-detail-panel.closing {
      animation: slideDown 0.25s ease-in forwards;
    }

    @keyframes slideUp {
      from {
        transform: translateY(100%);
      }
      to {
        transform: translateY(0);
      }
    }

    @keyframes slideDown {
      from {
        transform: translateY(0);
      }
      to {
        transform: translateY(100%);
      }
    }

    .kpi-actions {
      flex-basis: 100%;
      justify-content: flex-end;
    }

    .card-drag {
      opacity: 0.5;
    }

    .card-chevron {
      opacity: 0.5;
    }

    .products-scroll {
      padding: 8px 12px;
    }
  }
</style>
