<script lang="ts">
  import { cwMembers } from "$lib/stores/cwMembers";
  import { goto } from "$app/navigation";
  import { createEventDispatcher, onMount, tick } from "svelte";
  import { clientFetch } from "$lib/client-fetch";
  import type {
    SalesOpportunity,
    WorkflowStatusResponse,
    OpportunityType,
  } from "$lib/optima-api/modules/sales";
  import {
    WORKFLOW_STATUS_LABELS,
    STATUS_ID_TO_KEY,
    TERMINAL_STATUSES,
  } from "$lib/optima-api/modules/sales";
  import type { CWMember } from "$lib/optima-api/modules/cw";
  import type { PermissionMap } from "$lib/permissions";
  import { optima } from "$lib";
  import EmailText from "../../../../../components/EmailText.svelte";
  import EditGuard from "../../../../../components/EditGuard.svelte";
  import {
    statusColorClass,
    statusLabel,
    isEquivalencyStatus,
    originalStatusName,
    formatDate,
  } from "../types";

  const dispatch = createEventDispatcher();

  $: daysUntilClose = (() => {
    if (!opportunity?.expectedCloseDate || isClosedOpportunity) return null;
    const raw = opportunity.expectedCloseDate;
    const dateOnly = raw.split("T")[0];
    const close = new Date(dateOnly + "T00:00:00");
    const now = new Date();
    const closeDay = new Date(
      close.getFullYear(),
      close.getMonth(),
      close.getDate()
    );
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    return Math.round(
      (closeDay.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)
    );
  })();

  export let opportunity: SalesOpportunity | null;
  export let isMobile: boolean;
  export let mobileActiveTab: string | null;
  export let permissions: PermissionMap = {};
  export let accessToken: string | null = null;
  export let isClosedOpportunity: boolean = false;
  export let workflowStatus: WorkflowStatusResponse | null = null;
  export let opportunityTypes: OpportunityType[] = [];

  // Workflow-derived status for badge
  $: wfStatusKey = workflowStatus
    ? (STATUS_ID_TO_KEY[workflowStatus.currentStatusId] ?? null)
    : null;
  $: wfStatusLabel = wfStatusKey
    ? WORKFLOW_STATUS_LABELS[wfStatusKey]
    : (workflowStatus?.currentStatus ?? null);
  $: wfIsTerminal = wfStatusKey ? TERMINAL_STATUSES.has(wfStatusKey) : false;
  $: wfIsOptima = workflowStatus?.isOptimaStage ?? false;
  $: wfIsCold = workflowStatus?.coldCheck?.isCold ?? false;
  $: wfIsPending =
    wfStatusKey === "PendingWon" ||
    wfStatusKey === "PendingLost" ||
    wfStatusKey === "PendingSent" ||
    wfStatusKey === "PendingRevision" ||
    wfStatusKey === "ReadyToSend" ||
    wfStatusKey === "PendingNew";

  /** CSS class for the workflow status badge */
  function workflowStatusClass(key: string | null): string {
    if (!key) return "wf-status-default";
    const map: Record<string, string> = {
      PendingNew: "wf-status-pending-new",
      New: "wf-status-new",
      InternalReview: "wf-status-review",
      QuoteSent: "wf-status-quote-sent",
      ConfirmedQuote: "wf-status-quote-confirmed",
      Active: "wf-status-active",
      ReadyToSend: "wf-status-ready-to-send",
      PendingSent: "wf-status-pending-sent",
      PendingRevision: "wf-status-pending-revision",
      PendingWon: "wf-status-pending-won",
      Won: "wf-status-won",
      PendingLost: "wf-status-pending-lost",
      Lost: "wf-status-lost",
      Canceled: "wf-status-canceled",
    };
    return map[key] ?? "wf-status-default";
  }

  $: canEdit =
    !isClosedOpportunity && permissions["sales.opportunity.update"] !== false;
  $: canDelete = permissions["sales.opportunity.delete"] === true;

  // Edit mode state
  let isEditing = false;
  let isDirty = false;
  let isSaving = false;

  let mounted = false;
  onMount(() => {
    mounted = true;
  });

  // Delete state
  let showDeleteConfirm = false;
  let isDeleting = false;
  let deleteError = "";

  function openDeleteConfirm() {
    showDeleteConfirm = true;
    deleteError = "";
  }

  function cancelDelete() {
    showDeleteConfirm = false;
    deleteError = "";
  }

  async function executeDelete() {
    if (!opportunity) return;
    isDeleting = true;
    deleteError = "";
    try {
      await clientFetch(`/sales/opportunity/${opportunity.cwOpportunityId}`, {
        method: "DELETE",
      });
      goto("/sales");
    } catch (err) {
      deleteError =
        err instanceof Error ? err.message : "Failed to delete opportunity";
      isDeleting = false;
    }
  }
  let editName = "";
  let editDescription = "";
  let editCustomerPO = "";
  let editExpectedCloseDate = "";

  // Rep dropdown state
  let membersLoading = false;
  let editRepId: number | null = null;

  // Secondary rep dropdown state
  let editSecRepId: number | null = null;
  let editSecRepName = "";
  let secRepDropdownOpen = false;
  let secRepSearchQuery = "";
  $: filteredSecRepMembers = secRepSearchQuery
    ? $cwMembers.filter((m) => {
        const q = secRepSearchQuery.toLowerCase();
        return (
          m.name.toLowerCase().includes(q) ||
          (m.identifier && m.identifier.toLowerCase().includes(q))
        );
      })
    : $cwMembers;

  // Contact dropdown state
  interface EditContact {
    cwId?: number;
    firstName?: string;
    lastName?: string;
    inactive?: boolean;
    title?: string;
    phone?: string;
    email?: string;
  }
  let editContactId: number | null = null;
  let editContactName = "";
  let contactDropdownOpen = false;
  let contactSearchQuery = "";
  let editContacts: EditContact[] = [];
  let contactsLoading = false;
  $: activeEditContacts = editContacts.filter((c) => !c.inactive);
  $: filteredEditContacts = contactSearchQuery
    ? activeEditContacts.filter((c) => {
        const q = contactSearchQuery.toLowerCase();
        const name = `${c.firstName ?? ""} ${c.lastName ?? ""}`.toLowerCase();
        return (
          name.includes(q) || (c.email && c.email.toLowerCase().includes(q))
        );
      })
    : activeEditContacts;

  // Site edit state
  interface EditSite {
    id: number;
    name: string;
    address?: {
      line1?: string;
      line2?: string | null;
      city?: string;
      state?: string | null;
      zip?: string;
    };
    primaryAddressFlag?: boolean;
  }
  let editSiteId: number | string | null = null;
  let editSiteName = "";
  let siteDropdownOpen = false;
  let siteSearchQuery = "";
  let editSites: EditSite[] = [];
  let sitesLoading = false;

  // Type dropdown state
  let editTypeId: number | null = null;
  let editTypeName = "";
  let typeDropdownOpen = false;
  let typeSearchQuery = "";
  $: filteredTypes = typeSearchQuery
    ? opportunityTypes.filter((t) =>
        t.name.toLowerCase().includes(typeSearchQuery.toLowerCase())
      )
    : opportunityTypes;

  // Display-mode contact details (fetched from company details API)
  let displayContacts: EditContact[] = [];
  let displayContactsCompanyId: string | null = null;
  let displayContactsLoading = false;
  $: filteredEditSites = siteSearchQuery
    ? editSites.filter((s) => {
        const q = siteSearchQuery.toLowerCase();
        return s.name.toLowerCase().includes(q);
      })
    : editSites;

  // Dropdown positioning (fixed so it escapes overflow containers)
  let companyTriggerEl: HTMLElement | null = null;
  let repTriggerEl: HTMLElement | null = null;
  let secRepTriggerEl: HTMLElement | null = null;
  let contactTriggerEl: HTMLElement | null = null;
  let siteTriggerEl: HTMLElement | null = null;
  let typeTriggerEl: HTMLElement | null = null;
  let dropdownPos = { top: 0, left: 0, width: 280 };

  function positionDropdown(triggerEl: HTMLElement | null) {
    if (!triggerEl) return;
    const rect = triggerEl.getBoundingClientRect();
    dropdownPos = {
      top: rect.bottom + 4,
      left: rect.left,
      width: Math.max(rect.width, 280),
    };
  }
  let editRepName = "";
  let repDropdownOpen = false;
  let repSearchQuery = "";
  $: filteredMembers = repSearchQuery
    ? $cwMembers.filter((m) => {
        const q = repSearchQuery.toLowerCase();
        return (
          m.name.toLowerCase().includes(q) ||
          (m.identifier && m.identifier.toLowerCase().includes(q))
        );
      })
    : $cwMembers;

  // Company dropdown state
  let editCompanyId: number | null = null;
  let editCompanyName = "";
  let companyDropdownOpen = false;
  let companySearchQuery = "";
  type CompanySearchResult = {
    id: string;
    name: string;
    cw_CompanyId?: number;
  };
  let companyResults: CompanySearchResult[] = [];
  let companySearchLoading = false;
  let companySearchTimer: ReturnType<typeof setTimeout> | null = null;

  async function loadCWMembers() {
    const hasInvalidIds = $cwMembers.some((m) => {
      const id = Number((m as { id: unknown }).id);
      return !Number.isFinite(id);
    });

    if (hasInvalidIds) {
      cwMembers.reset();
    }

    if ($cwMembers.length > 0 && !hasInvalidIds) return;
    membersLoading = true;
    try {
      await cwMembers.load();
    } catch (err) {
      console.error("[OpportunitySidebar] Failed to load CW members:", err);
    } finally {
      membersLoading = false;
    }
  }

  function searchCompanies(query: string) {
    if (companySearchTimer) clearTimeout(companySearchTimer);
    if (!query || query.length < 2) {
      companyResults = [];
      companySearchLoading = false;
      return;
    }
    companySearchLoading = true;
    companySearchTimer = setTimeout(async () => {
      try {
        const json = await clientFetch<{ data: CompanySearchResult[] }>(
          `/api/companies/search?search=${encodeURIComponent(query)}&rpp=15`
        );
        companyResults = json.data ?? [];
      } catch (err) {
        console.error("[OpportunitySidebar] Company search failed:", err);
        companyResults = [];
      } finally {
        companySearchLoading = false;
      }
    }, 300);
  }

  function selectRep(member: CWMember) {
    const parsed = Number(member.id);
    editRepId = Number.isFinite(parsed) ? parsed : null;
    editRepName = member.name;
    repDropdownOpen = false;
    repSearchQuery = "";
    isDirty = true;
  }

  function selectSecRep(member: CWMember) {
    const parsed = Number(member.id);
    editSecRepId = Number.isFinite(parsed) ? parsed : null;
    editSecRepName = member.name;
    secRepDropdownOpen = false;
    secRepSearchQuery = "";
    isDirty = true;
  }

  function clearSecRep() {
    editSecRepId = null;
    editSecRepName = "";
    secRepDropdownOpen = false;
    secRepSearchQuery = "";
    isDirty = true;
  }

  function selectContact(c: EditContact) {
    editContactId = c.cwId ?? null;
    editContactName = `${c.firstName ?? ""} ${c.lastName ?? ""}`.trim();
    contactDropdownOpen = false;
    contactSearchQuery = "";
    isDirty = true;
  }

  function clearContact() {
    editContactId = null;
    editContactName = "";
    contactDropdownOpen = false;
    contactSearchQuery = "";
    isDirty = true;
  }

  function clearSite() {
    editSiteId = null;
    editSiteName = "";
    siteDropdownOpen = false;
    siteSearchQuery = "";
    isDirty = true;
  }

  function selectSite(s: EditSite) {
    editSiteId = s.id;
    editSiteName = s.name;
    siteDropdownOpen = false;
    siteSearchQuery = "";
    isDirty = true;
  }

  function selectType(t: OpportunityType) {
    editTypeId = t.id;
    editTypeName = t.name;
    typeDropdownOpen = false;
    typeSearchQuery = "";
    isDirty = true;
  }

  type CompanySite = EditSite;
  async function loadEditSites() {
    const companyOptimaId = opportunity?.company?.id;
    if (!companyOptimaId) return;
    sitesLoading = true;
    try {
      const json = await clientFetch<{ data: CompanySite[] }>(
        `/api/companies/${companyOptimaId}/sites`
      );
      editSites = json.data ?? [];
    } catch (err) {
      console.error("[OpportunitySidebar] Failed to load sites:", err);
      editSites = [];
    } finally {
      sitesLoading = false;
    }
  }

  type CompanyContact = EditContact;
  async function loadEditContacts() {
    // First try allContacts already on the opportunity
    const existing = opportunity?.company?.cw_Data?.allContacts ?? [];
    if (existing.length > 0) {
      editContacts = existing;
      return;
    }
    // Otherwise fetch from company details API
    const companyOptimaId = opportunity?.company?.id;
    if (!companyOptimaId) return;
    contactsLoading = true;
    try {
      const json = await clientFetch<{
        data: { cw_Data?: { allContacts?: CompanyContact[] } };
      }>(`/api/companies/${companyOptimaId}/details`);
      editContacts = json.data?.cw_Data?.allContacts ?? [];
    } catch (err) {
      console.error("[OpportunitySidebar] Failed to load contacts:", err);
      editContacts = [];
    } finally {
      contactsLoading = false;
    }
  }

  async function loadDisplayContacts() {
    const companyOptimaId = opportunity?.company?.id;
    if (!companyOptimaId) {
      displayContacts = [];
      displayContactsCompanyId = null;
      return;
    }
    if (
      displayContactsCompanyId === companyOptimaId &&
      displayContacts.length > 0
    ) {
      return;
    }
    displayContactsLoading = true;
    try {
      const json = await clientFetch<{
        data: { cw_Data?: { allContacts?: CompanyContact[] } };
      }>(`/api/companies/${companyOptimaId}/details`);
      displayContacts = json.data?.cw_Data?.allContacts ?? [];
      displayContactsCompanyId = companyOptimaId;
    } catch (err) {
      console.error(
        "[OpportunitySidebar] Failed to load display contacts:",
        err
      );
      displayContacts = [];
      displayContactsCompanyId = companyOptimaId;
    } finally {
      displayContactsLoading = false;
    }
  }

  function selectCompany(co: {
    id: string;
    name: string;
    cw_CompanyId?: number;
  }) {
    editCompanyId = co.cw_CompanyId ?? null;
    editCompanyName = co.name;
    companyDropdownOpen = false;
    companySearchQuery = "";
    companyResults = [];
    isDirty = true;
  }

  function handleRepBlur(e: FocusEvent) {
    const related = e.relatedTarget as HTMLElement | null;
    if (related?.closest(".opp-edit-dropdown")) return;
    setTimeout(() => {
      repDropdownOpen = false;
    }, 150);
  }

  function handleSecRepBlur(e: FocusEvent) {
    const related = e.relatedTarget as HTMLElement | null;
    if (related?.closest(".opp-edit-dropdown")) return;
    setTimeout(() => {
      secRepDropdownOpen = false;
    }, 150);
  }

  function handleCompanyBlur(e: FocusEvent) {
    const related = e.relatedTarget as HTMLElement | null;
    if (related?.closest(".opp-edit-dropdown")) return;
    setTimeout(() => {
      companyDropdownOpen = false;
    }, 150);
  }

  /** Close dropdowns when clicking outside */
  function handleWindowClick(e: MouseEvent) {
    const target = e.target as HTMLElement;
    if (!target.closest(".opp-edit-dropdown")) {
      repDropdownOpen = false;
      companyDropdownOpen = false;
      secRepDropdownOpen = false;
      contactDropdownOpen = false;
      siteDropdownOpen = false;
      typeDropdownOpen = false;
    }
  }

  /** Close dropdowns on Escape */
  function handleKeydown(e: KeyboardEvent) {
    if (
      e.key === "Escape" &&
      (repDropdownOpen ||
        companyDropdownOpen ||
        secRepDropdownOpen ||
        contactDropdownOpen ||
        siteDropdownOpen ||
        typeDropdownOpen)
    ) {
      repDropdownOpen = false;
      companyDropdownOpen = false;
      secRepDropdownOpen = false;
      contactDropdownOpen = false;
      siteDropdownOpen = false;
      typeDropdownOpen = false;
      e.stopPropagation();
    }
  }

  // Ensure display-mode contact details are loaded whenever company changes.
  $: if (mounted && opportunity?.company?.id) {
    void loadDisplayContacts();
  }

  async function startEditing() {
    if (!opportunity) return;
    editName = opportunity.name ?? "";
    editDescription = opportunity.description ?? "";
    editCustomerPO = opportunity.customerPO ?? "";
    if (opportunity.expectedCloseDate) {
      const normalized = opportunity.expectedCloseDate.includes("T")
        ? opportunity.expectedCloseDate
        : opportunity.expectedCloseDate + "T00:00:00";
      const d = new Date(normalized);
      const yyyy = d.getFullYear();
      const mm = String(d.getMonth() + 1).padStart(2, "0");
      const dd = String(d.getDate()).padStart(2, "0");
      editExpectedCloseDate = `${yyyy}-${mm}-${dd}`;
    } else {
      editExpectedCloseDate = "";
    }

    // Initialize rep selection
    {
      const parsed = Number(opportunity.primarySalesRep?.id);
      editRepId = Number.isFinite(parsed) ? parsed : null;
    }
    editRepName = opportunity.primarySalesRep?.name ?? "";
    repSearchQuery = "";
    repDropdownOpen = false;

    // Initialize secondary rep selection
    {
      const parsed = Number(opportunity.secondarySalesRep?.id);
      editSecRepId = Number.isFinite(parsed) ? parsed : null;
    }
    editSecRepName = opportunity.secondarySalesRep?.name ?? "";
    secRepSearchQuery = "";
    secRepDropdownOpen = false;

    // Initialize contact selection
    editContactId = (opportunity.contact?.id as number) ?? null;
    editContactName = opportunity.contact?.name ?? "";
    contactSearchQuery = "";
    contactDropdownOpen = false;
    editContacts = [];

    // Initialize site selection
    editSiteId = opportunity.site?.id ?? null;
    editSiteName = opportunity.site?.name ?? "";
    siteSearchQuery = "";
    siteDropdownOpen = false;
    editSites = [];

    // Initialize company selection
    editCompanyId = opportunity.company?.cw_CompanyId ?? null;
    editCompanyName = opportunity.company?.name ?? "";
    companySearchQuery = "";
    companyDropdownOpen = false;
    companyResults = [];

    // Initialize type selection
    editTypeId = (opportunity.type?.id as number) ?? null;
    editTypeName = opportunity.type?.name ?? "";
    typeDropdownOpen = false;
    typeSearchQuery = "";

    isEditing = true;
    loadCWMembers();
    loadEditContacts();
    loadEditSites();
  }

  function cancelEditing() {
    isEditing = false;
    isDirty = false;
  }

  async function saveEdits() {
    if (!opportunity || !accessToken) return;
    const identifier = opportunity.cwOpportunityId
      ? String(opportunity.cwOpportunityId)
      : opportunity.id;

    const body: Record<string, unknown> = {};
    if (editName !== (opportunity.name ?? "")) body.name = editName;
    if (editDescription !== (opportunity.description ?? ""))
      body.notes = editDescription;
    if (editCustomerPO !== (opportunity.customerPO ?? ""))
      body.customerPO = editCustomerPO || null;

    // Compare close date using local-timezone-aware formatting
    const origCloseDate = (() => {
      if (!opportunity.expectedCloseDate) return "";
      const src = opportunity.expectedCloseDate.includes("T")
        ? opportunity.expectedCloseDate
        : opportunity.expectedCloseDate + "T00:00:00";
      const d = new Date(src);
      const yyyy = d.getFullYear();
      const mm = String(d.getMonth() + 1).padStart(2, "0");
      const dd = String(d.getDate()).padStart(2, "0");
      return `${yyyy}-${mm}-${dd}`;
    })();
    if (editExpectedCloseDate !== origCloseDate)
      body.expectedCloseDate = editExpectedCloseDate || null;

    // Compare primary sales rep
    const origRepId = (() => {
      const parsed = Number(opportunity.primarySalesRep?.id);
      return Number.isFinite(parsed) ? parsed : null;
    })();
    if (editRepId !== origRepId && editRepId !== null)
      body.primarySalesRep = { id: Number(editRepId) };

    // Compare secondary sales rep
    const origSecRepId = (() => {
      const parsed = Number(opportunity.secondarySalesRep?.id);
      return Number.isFinite(parsed) ? parsed : null;
    })();
    if (editSecRepId !== origSecRepId) {
      body.secondarySalesRep =
        editSecRepId !== null ? { id: Number(editSecRepId) } : null;
    }

    // Compare contact
    const origContactId = (opportunity.contact?.id as number) ?? null;
    if (editContactId !== origContactId) {
      body.contact = editContactId !== null ? { id: editContactId } : null;
    }

    // Compare site
    const origSiteId = opportunity.site?.id ?? null;
    if (editSiteId !== origSiteId) {
      body.site = editSiteId !== null ? { id: Number(editSiteId) } : null;
    }

    // Compare company
    const origCompanyId = opportunity.company?.cw_CompanyId ?? null;
    if (editCompanyId !== origCompanyId && editCompanyId !== null)
      body.company = { id: editCompanyId };

    // Compare type
    const origTypeId = (opportunity.type?.id as number) ?? null;
    if (editTypeId !== origTypeId && editTypeId !== null)
      body.type = { id: editTypeId };

    if (Object.keys(body).length === 0) {
      isEditing = false;
      isDirty = false;
      return;
    }

    isSaving = true;
    try {
      await optima.sales.updateOpportunity(accessToken, identifier, body);
      isEditing = false;
      isDirty = false;
      dispatch("updated");
    } catch (err) {
      console.error("[OpportunitySidebar] Failed to update:", err);
    } finally {
      isSaving = false;
    }
  }

  // Use site address first (more specific), fall back to company address
  $: address =
    opportunity?.site?.address ?? opportunity?.company?.cw_Data?.address;
  function getOpportunityContactField(field: string): string | null {
    const contact = opportunity?.contact as Record<string, unknown> | undefined;
    const value = contact?.[field];
    return typeof value === "string" && value.trim().length > 0 ? value : null;
  }
  // Find the matching contact in allContacts for phone/email
  $: allContacts =
    displayContacts.length > 0
      ? displayContacts
      : (opportunity?.company?.cw_Data?.allContacts ?? []);
  $: matchedContact = opportunity?.contact?.id
    ? (allContacts.find(
        (c) => String(c.cwId) === String(opportunity?.contact?.id)
      ) ?? allContacts[0])
    : (allContacts[0] ?? null);
  $: contactPhone =
    matchedContact?.phone ??
    getOpportunityContactField("phone") ??
    getOpportunityContactField("phoneNumber") ??
    opportunity?.site?.phoneNumber ??
    null;
  $: contactEmail =
    matchedContact?.email ?? getOpportunityContactField("email") ?? null;
  $: contactDisplayName =
    opportunity?.contact?.name ??
    [matchedContact?.firstName, matchedContact?.lastName]
      .filter(Boolean)
      .join(" ") ??
    "";
  $: hasContactSectionData =
    !!contactDisplayName ||
    !!matchedContact ||
    !!contactPhone ||
    !!contactEmail;
  $: closedByDisplay = formatClosedBy(opportunity?.closedBy);
  $: if (opportunity?.closedBy != null) {
    console.log("[OpportunitySidebar] closedBy raw:", opportunity.closedBy);
  }

  function formatPhone(phone: string): string {
    const digits = phone.replace(/\D/g, "");
    if (digits.length === 10) {
      return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
    }
    if (digits.length === 11 && digits[0] === "1") {
      return `(${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
    }
    return phone;
  }

  function formatClosedBy(
    closedBy: SalesOpportunity["closedBy"] | undefined
  ): string | null {
    if (!closedBy) return null;
    if (typeof closedBy === "string") return closedBy;
    return closedBy.name ?? closedBy.identifier ?? String(closedBy.id ?? "");
  }

  /** Map rating name to a heat tier for visual styling */
  function ratingHeatClass(name: string | undefined): string {
    if (!name) return "heat-neutral";
    const n = name.toLowerCase();
    if (n.includes("hot")) return "heat-hot";
    if (n.includes("warm") || n.includes("medium")) return "heat-warm";
    if (n.includes("cold") || n.includes("cool")) return "heat-cold";
    return "heat-neutral";
  }

  /** Map rating name to a thermometer icon fill level (0-3) */
  function ratingHeatLevel(name: string | undefined): number {
    if (!name) return 0;
    const n = name.toLowerCase();
    if (n.includes("hot")) return 3;
    if (n.includes("warm") || n.includes("medium")) return 2;
    if (n.includes("cold") || n.includes("cool")) return 1;
    return 0;
  }
  /** Get the filled dot color for a rating heat tier */
  function heatDotColor(name: string | undefined): string {
    if (!name) return "rgba(128,128,128,0.4)";
    const n = name.toLowerCase();
    if (n.includes("hot")) return "#ef4444";
    if (n.includes("warm") || n.includes("medium")) return "#f59e0b";
    if (n.includes("cold") || n.includes("cool")) return "#38bdf8";
    return "rgba(128,128,128,0.4)";
  }
  /** Build the complete inline style for a heat dot */
  function getDotStyle(level: number, ratingName: string | undefined): string {
    const lvl = ratingHeatLevel(ratingName);
    const filled = level <= lvl;
    if (!filled)
      return "background: rgba(128,128,128,0.25); width: 8px; height: 8px; border-radius: 50%; display: inline-block;";
    const color = heatDotColor(ratingName);
    const heat = ratingHeatClass(ratingName);
    let s = `background: ${color}; width: 8px; height: 8px; border-radius: 50%; display: inline-block;`;
    if (heat === "heat-hot") s += " box-shadow: 0 0 4px rgba(239,68,68,0.6);";
    return s;
  }

  function repDisplayName(
    rep?: {
      name?: string;
      identifier?: string;
    } | null
  ): string | null {
    if (!rep) return null;
    return rep.name || rep.identifier || null;
  }

  function repInitial(
    rep?: { name?: string; identifier?: string } | null
  ): string {
    const display = repDisplayName(rep);
    return display ? display.charAt(0).toUpperCase() : "?";
  }
  /** Map probability percent to a tier for styling */
  function probabilityTier(percent: number): string {
    if (percent >= 75) return "prob-high";
    if (percent >= 40) return "prob-mid";
    return "prob-low";
  }
</script>

<svelte:window on:mousedown={handleWindowClick} on:keydown={handleKeydown} />

<div
  class="opportunity-detail-left"
  class:mobile-collapsed={isMobile && mobileActiveTab !== null}
>
  <div class="opp-sidebar">
    {#if isEditing && opportunity}
      <!-- ═══════════════════════════════════════
           EDIT MODE — dedicated editing layout
           ═══════════════════════════════════════ -->
      <EditGuard {isDirty} onDiscard={cancelEditing} let:guardClose>
        <div class="opp-edit-panel">
          <div class="opp-edit-header">
            <button
              class="back-btn"
              on:click={guardClose}
              aria-label="Cancel editing"
              disabled={isSaving}
            >
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                width="16"
                height="16"
              >
                <path d="M19 12H5M12 19l-7-7 7-7" />
              </svg>
            </button>
            <div class="opp-edit-header-center">
              <h3 class="opp-edit-title">Edit Opportunity</h3>
              {#if opportunity.cwOpportunityId}
                <span class="opp-edit-subtitle"
                  >#{opportunity.cwOpportunityId}</span
                >
              {/if}
            </div>
            <button
              class="opp-edit-save-btn"
              on:click={saveEdits}
              disabled={isSaving}
              aria-label="Save changes"
            >
              {#if isSaving}
                <svg
                  class="opp-edit-spinner"
                  viewBox="0 0 24 24"
                  width="14"
                  height="14"
                >
                  <circle
                    cx="12"
                    cy="12"
                    r="10"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2.5"
                    opacity="0.2"
                  />
                  <path
                    d="M12 2a10 10 0 019.95 9"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2.5"
                    stroke-linecap="round"
                  />
                </svg>
              {:else}
                Save
              {/if}
            </button>
          </div>

          <!-- Scrollable form body -->
          <div class="opp-edit-body">
            <!-- Name (always first — most important) -->
            <div class="opp-edit-group">
              <label class="opp-edit-label" for="edit-name">Name</label>
              <input
                id="edit-name"
                type="text"
                class="opp-edit-input"
                bind:value={editName}
                on:input={() => (isDirty = true)}
                placeholder="Opportunity name"
              />
            </div>

            <!-- Company & Rep — side by side, right after name -->
            <div class="opp-edit-row">
              <div class="opp-edit-group">
                <span class="opp-edit-label">Company</span>
                <div class="opp-edit-dropdown" data-dropdown-id="company">
                  <button
                    type="button"
                    class="opp-edit-dropdown-trigger"
                    bind:this={companyTriggerEl}
                    on:click={() => {
                      companyDropdownOpen = !companyDropdownOpen;
                      repDropdownOpen = false;
                      if (companyDropdownOpen)
                        positionDropdown(companyTriggerEl);
                    }}
                    disabled={isSaving}
                  >
                    <span
                      class="opp-edit-dropdown-value"
                      class:placeholder={!editCompanyName}
                    >
                      {editCompanyName || "Select…"}
                    </span>
                    <svg
                      class="opp-edit-dropdown-chevron"
                      class:open={companyDropdownOpen}
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <polyline points="6 9 12 15 18 9" />
                    </svg>
                  </button>
                  {#if companyDropdownOpen}
                    <div
                      class="opp-edit-dropdown-panel"
                      style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                    >
                      <div class="opp-edit-dropdown-search-wrap">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="12"
                          height="12"
                        >
                          <circle cx="11" cy="11" r="8" /><line
                            x1="21"
                            y1="21"
                            x2="16.65"
                            y2="16.65"
                          />
                        </svg>
                        <input
                          type="text"
                          class="opp-edit-dropdown-search"
                          placeholder="Search companies…"
                          bind:value={companySearchQuery}
                          on:input={() => searchCompanies(companySearchQuery)}
                          on:click|stopPropagation
                        />
                      </div>
                      <div class="opp-edit-dropdown-options">
                        {#if companySearchLoading}
                          <div class="opp-edit-dropdown-empty">Searching…</div>
                        {:else if companySearchQuery.length > 0 && companySearchQuery.length < 2}
                          <div class="opp-edit-dropdown-empty">
                            Type 2+ characters
                          </div>
                        {:else if companySearchQuery.length >= 2 && companyResults.length === 0}
                          <div class="opp-edit-dropdown-empty">No results</div>
                        {:else}
                          {#each companyResults as co (co.id)}
                            <button
                              type="button"
                              class="opp-edit-dropdown-item"
                              class:selected={editCompanyId === co.cw_CompanyId}
                              on:mousedown|preventDefault={() =>
                                selectCompany(co)}
                            >
                              <span class="opp-edit-dropdown-item-label"
                                >{co.name}</span
                              >
                              {#if editCompanyId === co.cw_CompanyId}
                                <svg
                                  viewBox="0 0 24 24"
                                  fill="none"
                                  stroke="currentColor"
                                  stroke-width="2.5"
                                  width="13"
                                  height="13"
                                  ><polyline points="20 6 9 17 4 12" /></svg
                                >
                              {/if}
                            </button>
                          {/each}
                        {/if}
                      </div>
                    </div>
                  {/if}
                </div>
              </div>

              <div class="opp-edit-group">
                <span class="opp-edit-label">Primary Rep</span>
                <div class="opp-edit-dropdown" data-dropdown-id="rep">
                  <button
                    type="button"
                    class="opp-edit-dropdown-trigger"
                    bind:this={repTriggerEl}
                    on:click={() => {
                      repDropdownOpen = !repDropdownOpen;
                      companyDropdownOpen = false;
                      if (repDropdownOpen) positionDropdown(repTriggerEl);
                    }}
                    disabled={isSaving}
                  >
                    <span
                      class="opp-edit-dropdown-value"
                      class:placeholder={!editRepName}
                    >
                      {editRepName || "Select…"}
                    </span>
                    <svg
                      class="opp-edit-dropdown-chevron"
                      class:open={repDropdownOpen}
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <polyline points="6 9 12 15 18 9" />
                    </svg>
                  </button>
                  {#if repDropdownOpen}
                    <div
                      class="opp-edit-dropdown-panel"
                      style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                    >
                      <div class="opp-edit-dropdown-search-wrap">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="12"
                          height="12"
                        >
                          <circle cx="11" cy="11" r="8" /><line
                            x1="21"
                            y1="21"
                            x2="16.65"
                            y2="16.65"
                          />
                        </svg>
                        <input
                          type="text"
                          class="opp-edit-dropdown-search"
                          placeholder="Search members…"
                          bind:value={repSearchQuery}
                          on:click|stopPropagation
                        />
                      </div>
                      <div class="opp-edit-dropdown-options">
                        {#if membersLoading}
                          <div class="opp-edit-dropdown-empty">Loading…</div>
                        {:else if filteredMembers.length === 0}
                          <div class="opp-edit-dropdown-empty">
                            No members found
                          </div>
                        {:else}
                          {#each filteredMembers as member (member.id)}
                            <button
                              type="button"
                              class="opp-edit-dropdown-item"
                              class:selected={editRepId === member.id}
                              on:mousedown|preventDefault={() =>
                                selectRep(member)}
                            >
                              <span class="opp-edit-dropdown-item-label"
                                >{member.name}</span
                              >
                              {#if editRepId === member.id}
                                <svg
                                  viewBox="0 0 24 24"
                                  fill="none"
                                  stroke="currentColor"
                                  stroke-width="2.5"
                                  width="13"
                                  height="13"
                                  ><polyline points="20 6 9 17 4 12" /></svg
                                >
                              {/if}
                            </button>
                          {/each}
                        {/if}
                      </div>
                    </div>
                  {/if}
                </div>
              </div>
            </div>

            <!-- Close Date & Secondary Rep — side by side -->
            <div class="opp-edit-row">
              <div class="opp-edit-group">
                <label class="opp-edit-label" for="edit-close-date"
                  >Close Date</label
                >
                <input
                  id="edit-close-date"
                  type="date"
                  class="opp-edit-input"
                  bind:value={editExpectedCloseDate}
                  on:change={() => (isDirty = true)}
                />
              </div>

              <div class="opp-edit-group">
                <span class="opp-edit-label">Secondary Rep</span>
                <div class="opp-edit-dropdown" data-dropdown-id="sec-rep">
                  <button
                    type="button"
                    class="opp-edit-dropdown-trigger"
                    bind:this={secRepTriggerEl}
                    on:click={() => {
                      secRepDropdownOpen = !secRepDropdownOpen;
                      repDropdownOpen = false;
                      companyDropdownOpen = false;
                      if (secRepDropdownOpen) positionDropdown(secRepTriggerEl);
                    }}
                    disabled={isSaving}
                  >
                    <span
                      class="opp-edit-dropdown-value"
                      class:placeholder={!editSecRepName}
                    >
                      {editSecRepName || "None"}
                    </span>
                    <svg
                      class="opp-edit-dropdown-chevron"
                      class:open={secRepDropdownOpen}
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <polyline points="6 9 12 15 18 9" />
                    </svg>
                  </button>
                  {#if secRepDropdownOpen}
                    <div
                      class="opp-edit-dropdown-panel"
                      style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                    >
                      <div class="opp-edit-dropdown-search-wrap">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="12"
                          height="12"
                        >
                          <circle cx="11" cy="11" r="8" /><line
                            x1="21"
                            y1="21"
                            x2="16.65"
                            y2="16.65"
                          />
                        </svg>
                        <input
                          type="text"
                          class="opp-edit-dropdown-search"
                          placeholder="Search members…"
                          bind:value={secRepSearchQuery}
                          on:click|stopPropagation
                        />
                      </div>
                      <div class="opp-edit-dropdown-options">
                        {#if membersLoading}
                          <div class="opp-edit-dropdown-empty">Loading…</div>
                        {:else}
                          <!-- Clear / None option -->
                          <button
                            type="button"
                            class="opp-edit-dropdown-item"
                            class:selected={editSecRepId === null}
                            on:mousedown|preventDefault={clearSecRep}
                          >
                            <span
                              class="opp-edit-dropdown-item-label opp-edit-dropdown-item-none"
                              >None (clear)</span
                            >
                            {#if editSecRepId === null}
                              <svg
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                stroke-width="2.5"
                                width="13"
                                height="13"
                                ><polyline points="20 6 9 17 4 12" /></svg
                              >
                            {/if}
                          </button>
                          {#if filteredSecRepMembers.length === 0}
                            <div class="opp-edit-dropdown-empty">
                              No members found
                            </div>
                          {:else}
                            {#each filteredSecRepMembers as member (member.id)}
                              <button
                                type="button"
                                class="opp-edit-dropdown-item"
                                class:selected={editSecRepId === member.id}
                                on:mousedown|preventDefault={() =>
                                  selectSecRep(member)}
                              >
                                <span class="opp-edit-dropdown-item-label"
                                  >{member.name}</span
                                >
                                {#if editSecRepId === member.id}
                                  <svg
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="2.5"
                                    width="13"
                                    height="13"
                                    ><polyline points="20 6 9 17 4 12" /></svg
                                  >
                                {/if}
                              </button>
                            {/each}
                          {/if}
                        {/if}
                      </div>
                    </div>
                  {/if}
                </div>
              </div>
            </div>

            <!-- Contact & Site — side by side -->
            <div class="opp-edit-row">
              <div class="opp-edit-group">
                <span class="opp-edit-label">Contact</span>
                <div class="opp-edit-dropdown" data-dropdown-id="contact">
                  <button
                    type="button"
                    class="opp-edit-dropdown-trigger"
                    bind:this={contactTriggerEl}
                    on:click={() => {
                      contactDropdownOpen = !contactDropdownOpen;
                      repDropdownOpen = false;
                      companyDropdownOpen = false;
                      secRepDropdownOpen = false;
                      if (contactDropdownOpen)
                        positionDropdown(contactTriggerEl);
                    }}
                    disabled={isSaving}
                  >
                    <span
                      class="opp-edit-dropdown-value"
                      class:placeholder={!editContactName}
                    >
                      {editContactName || "None"}
                    </span>
                    <svg
                      class="opp-edit-dropdown-chevron"
                      class:open={contactDropdownOpen}
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <polyline points="6 9 12 15 18 9" />
                    </svg>
                  </button>
                  {#if contactDropdownOpen}
                    <div
                      class="opp-edit-dropdown-panel"
                      style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                    >
                      <div class="opp-edit-dropdown-search-wrap">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="12"
                          height="12"
                        >
                          <circle cx="11" cy="11" r="8" /><line
                            x1="21"
                            y1="21"
                            x2="16.65"
                            y2="16.65"
                          />
                        </svg>
                        <input
                          type="text"
                          class="opp-edit-dropdown-search"
                          placeholder="Search contacts…"
                          bind:value={contactSearchQuery}
                          on:click|stopPropagation
                        />
                      </div>
                      <div class="opp-edit-dropdown-options">
                        {#if contactsLoading}
                          <div class="opp-edit-dropdown-empty">Loading…</div>
                        {:else}
                          <!-- Clear / None option -->
                          <button
                            type="button"
                            class="opp-edit-dropdown-item"
                            class:selected={editContactId === null}
                            on:mousedown|preventDefault={clearContact}
                          >
                            <span
                              class="opp-edit-dropdown-item-label opp-edit-dropdown-item-none"
                              >None (clear)</span
                            >
                            {#if editContactId === null}
                              <svg
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                stroke-width="2.5"
                                width="13"
                                height="13"
                                ><polyline points="20 6 9 17 4 12" /></svg
                              >
                            {/if}
                          </button>
                          {#if filteredEditContacts.length === 0 && !contactSearchQuery}
                            <div class="opp-edit-dropdown-empty">
                              No contacts available
                            </div>
                          {:else if filteredEditContacts.length === 0}
                            <div class="opp-edit-dropdown-empty">
                              No contacts found
                            </div>
                          {:else}
                            {#each filteredEditContacts as contact (contact.cwId)}
                              <button
                                type="button"
                                class="opp-edit-dropdown-item"
                                class:selected={editContactId === contact.cwId}
                                on:mousedown|preventDefault={() =>
                                  selectContact(contact)}
                              >
                                <div class="opp-edit-dropdown-item-stack">
                                  <span class="opp-edit-dropdown-item-label"
                                    >{contact.firstName ?? ""}
                                    {contact.lastName ?? ""}</span
                                  >
                                  {#if contact.title}
                                    <span class="opp-edit-dropdown-item-sub"
                                      >{contact.title}</span
                                    >
                                  {/if}
                                </div>
                                {#if editContactId === contact.cwId}
                                  <svg
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="2.5"
                                    width="13"
                                    height="13"
                                    ><polyline points="20 6 9 17 4 12" /></svg
                                  >
                                {/if}
                              </button>
                            {/each}
                          {/if}
                        {/if}
                      </div>
                    </div>
                  {/if}
                </div>
              </div>

              <div class="opp-edit-group">
                <span class="opp-edit-label">Site</span>
                <div class="opp-edit-dropdown" data-dropdown-id="site">
                  <button
                    type="button"
                    class="opp-edit-dropdown-trigger"
                    bind:this={siteTriggerEl}
                    on:click={() => {
                      siteDropdownOpen = !siteDropdownOpen;
                      contactDropdownOpen = false;
                      repDropdownOpen = false;
                      companyDropdownOpen = false;
                      secRepDropdownOpen = false;
                      if (siteDropdownOpen) positionDropdown(siteTriggerEl);
                    }}
                    disabled={isSaving}
                  >
                    <span
                      class="opp-edit-dropdown-value"
                      class:placeholder={!editSiteName}
                    >
                      {editSiteName || "None"}
                    </span>
                    <svg
                      class="opp-edit-dropdown-chevron"
                      class:open={siteDropdownOpen}
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <polyline points="6 9 12 15 18 9" />
                    </svg>
                  </button>
                  {#if siteDropdownOpen}
                    <div
                      class="opp-edit-dropdown-panel"
                      style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                    >
                      <div class="opp-edit-dropdown-search-wrap">
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="12"
                          height="12"
                        >
                          <circle cx="11" cy="11" r="8" /><line
                            x1="21"
                            y1="21"
                            x2="16.65"
                            y2="16.65"
                          />
                        </svg>
                        <input
                          type="text"
                          class="opp-edit-dropdown-search"
                          placeholder="Search sites…"
                          bind:value={siteSearchQuery}
                          on:click|stopPropagation
                        />
                      </div>
                      <div class="opp-edit-dropdown-options">
                        {#if sitesLoading}
                          <div class="opp-edit-dropdown-empty">Loading…</div>
                        {:else}
                          <!-- Clear / None option -->
                          <button
                            type="button"
                            class="opp-edit-dropdown-item"
                            class:selected={editSiteId === null}
                            on:mousedown|preventDefault={clearSite}
                          >
                            <span
                              class="opp-edit-dropdown-item-label opp-edit-dropdown-item-none"
                              >None (clear)</span
                            >
                            {#if editSiteId === null}
                              <svg
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                stroke-width="2.5"
                                width="13"
                                height="13"
                                ><polyline points="20 6 9 17 4 12" /></svg
                              >
                            {/if}
                          </button>
                          {#if filteredEditSites.length === 0 && !siteSearchQuery}
                            <div class="opp-edit-dropdown-empty">
                              No sites available
                            </div>
                          {:else if filteredEditSites.length === 0}
                            <div class="opp-edit-dropdown-empty">
                              No sites found
                            </div>
                          {:else}
                            {#each filteredEditSites as site (site.id)}
                              <button
                                type="button"
                                class="opp-edit-dropdown-item"
                                class:selected={editSiteId === site.id}
                                on:mousedown|preventDefault={() =>
                                  selectSite(site)}
                              >
                                <div class="opp-edit-dropdown-item-stack">
                                  <span class="opp-edit-dropdown-item-label"
                                    >{site.name}</span
                                  >
                                  {#if site.address?.line1}
                                    <span class="opp-edit-dropdown-item-sub">
                                      {site.address.line1}{site.address.city
                                        ? `, ${site.address.city}`
                                        : ""}
                                    </span>
                                  {/if}
                                </div>
                                {#if site.primaryAddressFlag}
                                  <span class="opp-edit-dropdown-item-badge"
                                    >Primary</span
                                  >
                                {/if}
                                {#if editSiteId === site.id}
                                  <svg
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="2.5"
                                    width="13"
                                    height="13"
                                    ><polyline points="20 6 9 17 4 12" /></svg
                                  >
                                {/if}
                              </button>
                            {/each}
                          {/if}
                        {/if}
                      </div>
                    </div>
                  {/if}
                </div>
              </div>
            </div>

            <!-- Customer PO -->
            <div class="opp-edit-group">
              <label class="opp-edit-label" for="edit-po">Customer PO</label>
              <input
                id="edit-po"
                type="text"
                class="opp-edit-input"
                bind:value={editCustomerPO}
                on:input={() => (isDirty = true)}
                placeholder="—"
              />
            </div>

            <!-- Type dropdown -->
            <div class="opp-edit-group">
              <span class="opp-edit-label">Opportunity Type</span>
              <div class="opp-edit-dropdown" data-dropdown-id="type">
                <button
                  type="button"
                  class="opp-edit-dropdown-trigger"
                  bind:this={typeTriggerEl}
                  on:click={() => {
                    typeDropdownOpen = !typeDropdownOpen;
                    repDropdownOpen = false;
                    companyDropdownOpen = false;
                    secRepDropdownOpen = false;
                    contactDropdownOpen = false;
                    siteDropdownOpen = false;
                    if (typeDropdownOpen) positionDropdown(typeTriggerEl);
                  }}
                  disabled={isSaving}
                >
                  <span
                    class="opp-edit-dropdown-value"
                    class:placeholder={!editTypeName}
                  >
                    {editTypeName || "Select type…"}
                  </span>
                  <svg
                    class="opp-edit-dropdown-chevron"
                    class:open={typeDropdownOpen}
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    width="12"
                    height="12"
                  >
                    <polyline points="6 9 12 15 18 9" />
                  </svg>
                </button>
                {#if typeDropdownOpen}
                  <div
                    class="opp-edit-dropdown-panel"
                    style="position:fixed; top:{dropdownPos.top}px; left:{dropdownPos.left}px; width:{dropdownPos.width}px;"
                  >
                    <div class="opp-edit-dropdown-search-wrap">
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        width="12"
                        height="12"
                      >
                        <circle cx="11" cy="11" r="8" /><line
                          x1="21"
                          y1="21"
                          x2="16.65"
                          y2="16.65"
                        />
                      </svg>
                      <input
                        type="text"
                        class="opp-edit-dropdown-search"
                        placeholder="Search types…"
                        bind:value={typeSearchQuery}
                        on:click|stopPropagation
                      />
                    </div>
                    <div class="opp-edit-dropdown-options">
                      {#if opportunityTypes.length === 0}
                        <div class="opp-edit-dropdown-empty">No types available</div>
                      {:else if filteredTypes.length === 0}
                        <div class="opp-edit-dropdown-empty">No types found</div>
                      {:else}
                        {#each filteredTypes as t (t.id)}
                          <button
                            type="button"
                            class="opp-edit-dropdown-item"
                            class:selected={editTypeId === t.id}
                            on:mousedown|preventDefault={() => selectType(t)}
                          >
                            <span class="opp-edit-dropdown-item-label">{t.name}</span>
                            {#if editTypeId === t.id}
                              <svg
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                stroke-width="2.5"
                                width="13"
                                height="13"
                                ><polyline points="20 6 9 17 4 12" /></svg
                              >
                            {/if}
                          </button>
                        {/each}
                      {/if}
                    </div>
                  </div>
                {/if}
              </div>
            </div>

            <!-- Description (large textarea at bottom — takes remaining space) -->
            <div class="opp-edit-group opp-edit-group-grow">
              <label class="opp-edit-label" for="edit-description"
                >Description</label
              >
              <textarea
                id="edit-description"
                class="opp-edit-textarea"
                bind:value={editDescription}
                on:input={() => (isDirty = true)}
                placeholder="Add a description…"
              ></textarea>
            </div>

            <!-- Read-only context at very bottom -->
            {#if opportunity.source}
              <div class="opp-edit-readonly-strip">
                {#if opportunity.source}
                  <div class="opp-edit-readonly">
                    <span class="opp-edit-readonly-label">Source</span>
                    <span class="opp-edit-readonly-value"
                      >{opportunity.source}</span
                    >
                  </div>
                {/if}
              </div>
            {/if}
          </div>

          <!-- Sticky footer -->
          <div class="opp-edit-footer">
            <button
              class="opp-edit-cancel-btn"
              on:click={guardClose}
              disabled={isSaving}
            >
              Discard Changes
            </button>
          </div>
        </div>
      </EditGuard>
    {:else}
      <!-- ═══════════════════════════════════════
           VIEW MODE — normal sidebar
           ═══════════════════════════════════════ -->
      <div class="opp-sidebar-header">
        <button
          class="back-btn"
          on:click={() => goto("/sales")}
          aria-label="Back to sales"
        >
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="16"
            height="16"
          >
            <path d="M19 12H5M12 19l-7-7 7-7" />
          </svg>
        </button>
        <div class="opp-sidebar-header-actions">
          {#if canDelete}
            <button
              class="opp-delete-btn"
              on:click={openDeleteConfirm}
              aria-label="Delete opportunity"
              title="Delete"
            >
              <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>
            </button>
          {/if}
          {#if canEdit}
            <button
              class="opp-edit-btn"
              on:click={startEditing}
              aria-label="Edit opportunity"
              title="Edit"
            >
              <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>
            </button>
          {/if}
        </div>
      </div>
      {#if opportunity}
        <!-- ── Headline ── -->
        <div class="opp-headline">
          <h3 class="opp-name">{opportunity.name}</h3>
          <div class="opp-meta-row">
            {#if opportunity.cwOpportunityId}
              <span class="opp-number">#{opportunity.cwOpportunityId}</span>
            {/if}
            {#if wfIsOptima && wfStatusLabel}
              <span
                class="wf-status-badge {workflowStatusClass(wfStatusKey)}"
                class:wf-pending={wfIsPending}
                class:wf-terminal={wfIsTerminal}
              >
                {#if wfIsTerminal}
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    width="12"
                    height="12"
                  >
                    <rect
                      x="3"
                      y="11"
                      width="18"
                      height="11"
                      rx="2"
                      ry="2"
                    /><path d="M7 11V7a5 5 0 0110 0v4" />
                  </svg>
                {/if}
                {wfStatusLabel}
              </span>
              {#if wfIsCold}
                <span
                  class="wf-cold-badge"
                  title="This opportunity has gone cold — no recent activity"
                >
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    width="12"
                    height="12"
                  >
                    <path d="M12 2v20M17 7l-5 5-5-5M2 12h20M7 17l5-5 5 5" />
                  </svg>
                  Cold
                </span>
              {/if}
            {:else if opportunity.status}
              <span
                class="opp-status-badge {statusColorClass(opportunity)}"
                class:status-equiv={isEquivalencyStatus(opportunity)}
                data-tooltip={isEquivalencyStatus(opportunity)
                  ? `Original: ${originalStatusName(opportunity)}`
                  : undefined}
              >
                {statusLabel(opportunity)}
              </span>
            {/if}
            {#if opportunity.type?.name}
              <span class="opp-type-badge">{opportunity.type.name}</span>
            {/if}
            {#if opportunity.type?.wonFlag || opportunity.type?.lostFlag}
              <span
                class="opp-outcome-badge {opportunity.type.wonFlag
                  ? 'outcome-won'
                  : 'outcome-lost'}"
              >
                {opportunity.type.wonFlag ? "Won" : "Lost"}
              </span>
            {/if}
            {#if opportunity.interest && !isClosedOpportunity && !opportunity.status?.name
                ?.toLowerCase()
                .includes("cancel")}
              <span
                class="opp-rating-badge {ratingHeatClass(opportunity.interest)}"
              >
                <span class="opp-heat-dots">
                  {#each [1, 2, 3] as level}
                    <span style={getDotStyle(level, opportunity.interest)}
                    ></span>
                  {/each}
                </span>
                {opportunity.interest}
              </span>
            {/if}
            {#if opportunity.probability?.percent != null}
              <span
                class="opp-probability-badge {probabilityTier(
                  opportunity.probability.percent
                )}"
              >
                <svg
                  viewBox="0 0 20 20"
                  width="10"
                  height="10"
                  class="opp-prob-ring"
                >
                  <circle
                    cx="10"
                    cy="10"
                    r="8"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2.5"
                    opacity="0.15"
                  />
                  <circle
                    cx="10"
                    cy="10"
                    r="8"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2.5"
                    stroke-dasharray={`${opportunity.probability.percent * 0.5027} 50.27`}
                    stroke-linecap="round"
                    transform="rotate(-90 10 10)"
                  />
                </svg>
                {opportunity.probability.percent}%
              </span>
            {/if}
          </div>
        </div>

        <!-- ── Days to Close ── -->
        {#if daysUntilClose !== null}
          <div
            class="opp-close-countdown"
            class:overdue={daysUntilClose < 0}
            class:soon={daysUntilClose >= 0 && daysUntilClose <= 14}
          >
            <span class="opp-close-number">{Math.abs(daysUntilClose)}</span>
            <span class="opp-close-unit">
              {daysUntilClose < 0
                ? `day${Math.abs(daysUntilClose) !== 1 ? "s" : ""} overdue`
                : `day${daysUntilClose !== 1 ? "s" : ""} to close`}
            </span>
          </div>
        {/if}

        <!-- ── Byline (Sales Rep) ── -->
        <div class="opp-byline">
          <div class="opp-byline-rep">
            <div class="opp-byline-avatar">
              {repInitial(opportunity.primarySalesRep)}
            </div>
            <div class="opp-byline-info">
              <span class="opp-byline-name"
                >{repDisplayName(opportunity.primarySalesRep) ?? "—"}</span
              >
              <span class="opp-byline-role">Primary Rep</span>
            </div>
          </div>
          {#if repDisplayName(opportunity.secondarySalesRep)}
            <div class="opp-byline-rep">
              <div class="opp-byline-avatar secondary">
                {repInitial(opportunity.secondarySalesRep)}
              </div>
              <div class="opp-byline-info">
                <span class="opp-byline-name"
                  >{repDisplayName(opportunity.secondarySalesRep)}</span
                >
                <span class="opp-byline-role">Secondary Rep</span>
              </div>
            </div>
          {/if}
        </div>

        <div class="opp-sidebar-divider"></div>

        <div class="opp-sidebar-info">
          <!-- ── Company ── -->
          {#if opportunity.company?.name}
            <a
              href="/companies/{opportunity.company.id}"
              class="opp-info-row opp-info-row-link"
            >
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                class="opp-info-icon"
              >
                <rect x="2" y="7" width="20" height="14" rx="2" ry="2" /><path
                  d="M16 3h-8l-2 4h12z"
                />
              </svg>
              <div class="opp-info-content">
                <span class="opp-info-label">Company</span>
                <span class="opp-info-value">{opportunity.company.name}</span>
              </div>
              <svg
                class="opp-info-arrow"
                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>
            </a>
          {/if}

          <!-- ── Address / Site ── -->
          {#if address || opportunity.site?.name}
            <div class="opp-info-row">
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                class="opp-info-icon"
              >
                <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" /><circle
                  cx="12"
                  cy="10"
                  r="3"
                />
              </svg>
              <div class="opp-info-content">
                {#if opportunity.site?.name}
                  <span class="opp-info-label">{opportunity.site.name}</span>
                {:else}
                  <span class="opp-info-label">Address</span>
                {/if}
                {#if address}
                  <span class="opp-info-value">
                    {#if address.line1}{address.line1}<br />{/if}
                    {#if address.line2}{address.line2}<br />{/if}
                    {#if address.city || address.state || address.zip}
                      {[address.city, address.state]
                        .filter(Boolean)
                        .join(", ")}{address.zip ? ` ${address.zip}` : ""}
                    {/if}
                  </span>
                {:else}
                  <span class="opp-info-muted">No address on file</span>
                {/if}
              </div>
            </div>
          {/if}

          <!-- ── Contact ── -->
          {#if hasContactSectionData}
            <div class="opp-info-row">
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                class="opp-info-icon"
              >
                <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" /><circle
                  cx="12"
                  cy="7"
                  r="4"
                />
              </svg>
              <div class="opp-info-content">
                <span class="opp-info-label">Contact</span>
                <span class="opp-info-value">
                  {contactDisplayName || "\u2014"}
                </span>
                {#if matchedContact?.title}
                  <span class="opp-info-sub">{matchedContact.title}</span>
                {/if}
                {#if contactPhone}
                  <a href="tel:{contactPhone}" class="opp-info-phone">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="14"
                      height="14"
                    >
                      <path
                        d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z"
                      />
                    </svg>
                    {formatPhone(contactPhone)}
                  </a>
                {/if}
                {#if contactEmail}
                  <EmailText email={contactEmail} />
                {/if}
              </div>
            </div>
          {/if}

          <!-- ── Description ── -->
          {#if opportunity.description}
            <div class="opp-desc-section">
              <div class="opp-desc-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" />
                </svg>
                <span class="opp-desc-label">Description</span>
              </div>
              <div class="opp-desc-card">
                <p class="opp-desc-text">{opportunity.description}</p>
              </div>
            </div>
          {/if}
        </div>

        <!-- ── Details Footer ── -->
        <div class="opp-sidebar-footer">
          {#if opportunity.cwOpportunityId}
            <span class="opp-footer-item"
              >CW #{opportunity.cwOpportunityId}</span
            >
          {/if}
          {#if opportunity.customerPO}
            <span class="opp-footer-item">PO: {opportunity.customerPO}</span>
          {/if}
          {#if opportunity.location?.name}
            <span class="opp-footer-item">{opportunity.location.name}</span>
          {/if}
          {#if opportunity.department?.name}
            <span class="opp-footer-item">{opportunity.department.name}</span>
          {/if}
          {#if opportunity.campaign}
            <span class="opp-footer-item">{opportunity.campaign}</span>
          {/if}
          {#if closedByDisplay}
            <span class="opp-footer-item">Closed by {closedByDisplay}</span>
          {/if}
          {#if opportunity.cwLastUpdated}
            <span class="opp-footer-item"
              >Synced {formatDate(opportunity.cwLastUpdated)}</span
            >
          {/if}
        </div>
      {:else}
        <div class="opp-sidebar-empty">
          <p>Opportunity not found.</p>
        </div>
      {/if}
    {/if}
  </div>
</div>

<!-- Delete confirmation modal -->
{#if showDeleteConfirm}
  <!-- svelte-ignore a11y-click-events-have-key-events -->
  <div class="opp-delete-overlay" on:click={cancelDelete} role="presentation">
    <!-- svelte-ignore a11y-interactive-supports-focus -->
    <div
      class="opp-delete-modal"
      on:click|stopPropagation
      role="dialog"
      aria-modal="true"
      aria-labelledby="delete-opp-title"
    >
      <h4 class="opp-delete-title" id="delete-opp-title">Delete Opportunity</h4>
      <p class="opp-delete-msg">
        Are you sure you want to delete <strong
          >{opportunity?.name ?? "this opportunity"}</strong
        >? This will also remove it from ConnectWise. This action cannot be
        undone.
      </p>
      {#if deleteError}
        <p class="opp-delete-error">{deleteError}</p>
      {/if}
      <div class="opp-delete-actions">
        <button
          class="opp-edit-cancel-btn"
          on:click={cancelDelete}
          disabled={isDeleting}
        >
          Cancel
        </button>
        <button
          class="opp-delete-confirm-btn"
          on:click={executeDelete}
          disabled={isDeleting}
        >
          {#if isDeleting}
            Deleting…
          {:else}
            Delete
          {/if}
        </button>
      </div>
    </div>
  </div>
{/if}
