const { useEffect, useMemo, useRef, useState } = React;
const APP_NAME = "Nex Central";
const APP_VERSION_EVENT = "nex-app-version-stale";
const API_RECONNECT_EVENT = "nex-api-reconnect-needed";
const APP_VERSION_STORAGE_KEY = "nex-central-last-app-version";
const CHAT_UPLOAD_LIMIT_BYTES = 5 * 1024 * 1024;
const CHAT_ALLOWED_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "pdf", "doc", "docx", "xls", "xlsx", "csv"];
const chatEmojiOptions = ["👍", "🔥", "🎉", "🏡", "✅", "🙏", "💯", "🚀", "👏", "❤️"];

function dispatchNexEvent(name, detail = {}) {
  if (typeof window === "undefined") return;
  try {
    window.dispatchEvent(new CustomEvent(name, { detail }));
  } catch (_) {
    try {
      const event = document.createEvent("CustomEvent");
      event.initCustomEvent(name, false, false, detail);
      window.dispatchEvent(event);
    } catch (_) {}
  }
}

function rememberAppVersion(version) {
  if (!version || typeof window === "undefined") return;
  const nextVersion = String(version);
  let storedVersion = "";
  try {
    storedVersion = localStorage.getItem(APP_VERSION_STORAGE_KEY) || "";
  } catch (_) {}
  const currentVersion = window.__NEX_APP_VERSION__ || storedVersion || "";
  if (!currentVersion) {
    window.__NEX_APP_VERSION__ = nextVersion;
    try {
      localStorage.setItem(APP_VERSION_STORAGE_KEY, nextVersion);
    } catch (_) {}
    return;
  }
  if (currentVersion !== nextVersion) {
    if (window.__NEX_LATEST_APP_VERSION__ !== nextVersion) {
      window.__NEX_LATEST_APP_VERSION__ = nextVersion;
      dispatchNexEvent(APP_VERSION_EVENT, { currentVersion, nextVersion });
    }
    try {
      localStorage.setItem(APP_VERSION_STORAGE_KEY, nextVersion);
    } catch (_) {}
    return;
  }
  try {
    localStorage.setItem(APP_VERSION_STORAGE_KEY, nextVersion);
  } catch (_) {}
}

const API = {
  async request(path, options = {}) {
    const { retries = 1, retryDelay = 450, ...fetchOptions } = options;
    let lastError;

    for (let attempt = 0; attempt <= retries; attempt += 1) {
      try {
        const response = await fetch(path, {
          headers: { "Content-Type": "application/json", ...(fetchOptions.headers || {}) },
          credentials: "same-origin",
          cache: "no-store",
          ...fetchOptions
        });
        rememberAppVersion(response.headers.get("x-nex-app-version"));
        if (!response.ok) {
          const error = await response.json().catch(() => ({ error: response.statusText }));
          const requestError = new Error(error.error || "Request failed.");
          requestError.status = response.status;
          throw requestError;
        }
        return response.json();
      } catch (error) {
        lastError = error;
        if (error.status || attempt === retries) {
          if (!error.status && typeof window !== "undefined") {
            dispatchNexEvent(API_RECONNECT_EVENT, { path });
          }
          throw error;
        }
        await new Promise((resolve) => setTimeout(resolve, retryDelay * (attempt + 1)));
      }
    }
    throw lastError;
  }
};

function friendlyNetworkError(error, fallback = "Load failed. Please refresh and try again.") {
  const message = String(error?.message || "");
  if (/load failed|failed to fetch|networkerror|network request failed/i.test(message)) {
    return "Nex Central could not finish loading. Please refresh the page and try again.";
  }
  return message || fallback;
}

const marketingTypes = [
  "Just Listed",
  "Just Sold",
  "Open House",
  "For Rent",
  "Price Improvement",
  "Buyer Education",
  "Seller Lead Generation",
  "Recruiting",
  "Agent Bio",
  "Agent Award / Production Recognition",
  "New Agent Announcement",
  "Quick Video / Reel",
  "Postcard",
  "Business Card",
  "Vendor / Partner"
];

const toneOptions = [
  "Professional",
  "Luxury",
  "Hype / high-energy",
  "Short and punchy",
  "Warm and consumer-friendly",
  "Agent recruiting style"
];

const platformOptions = [
  "Multi-platform",
  "Facebook",
  "Instagram",
  "LinkedIn",
  "Instagram Story",
  "Reel Script",
  "Quick Video",
  "Flyer",
  "Postcard",
  "Business Card",
  "Email",
  "SMS"
];

const businessCardStyles = ["Signature Red", "Executive Black", "Clean White", "Luxury Gold"];
const headshotShapes = ["Square", "Circle", "Arch"];
const headshotFitOptions = ["Cover", "Contain"];
const defaultLogoBlackUrl = "/assets/nex-logo-black.png";
const defaultLogoWhiteUrl = "/assets/nex-logo-white.png";

const studioTemplateDefaults = [
  { id: "just-listed", name: "Just Listed", category: "Listing", headline: "JUST LISTED", badge: "New Listing", accent: "#e30613", style: "classic" },
  { id: "luxury-listing", name: "Luxury Listing", category: "Listing", headline: "LUXURY LISTING", badge: "Private Offering", accent: "#c9a24a", style: "luxury" },
  { id: "modern-open-house", name: "Modern Open House", category: "Event", headline: "OPEN HOUSE", badge: "Tour This Home", accent: "#e30613", style: "magazine" },
  { id: "for-rent", name: "For Rent", category: "Rental", headline: "FOR RENT", badge: "Available Now", accent: "#e30613", style: "classic" },
  { id: "rental-luxe", name: "Rental Spotlight", category: "Rental", headline: "RENTAL SPOTLIGHT", badge: "Lease Today", accent: "#c9a24a", style: "luxury" },
  { id: "just-sold", name: "Just Sold", category: "Listing", headline: "JUST SOLD", badge: "Sold", accent: "#050505", style: "classic" },
  { id: "price-improvement", name: "Price Improvement", category: "Listing", headline: "PRICE IMPROVEMENT", badge: "New Price", accent: "#c9a24a", style: "magazine" },
  { id: "coming-soon", name: "Coming Soon", category: "Listing", headline: "COMING SOON", badge: "First Look", accent: "#050505", style: "magazine" },
  { id: "under-contract", name: "Under Contract", category: "Listing", headline: "UNDER CONTRACT", badge: "Buyer Secured", accent: "#e30613", style: "classic" },
  { id: "buyer-need", name: "Buyer Need", category: "Lead Generation", headline: "BUYER NEED", badge: "Have A Match?", accent: "#050505", style: "clean" },
  { id: "seller-lead-ad", name: "Seller Lead Ad", category: "Lead Generation", headline: "SELL WITH CONFIDENCE", badge: "Home Value", accent: "#e30613", style: "social" },
  { id: "home-value-offer", name: "Home Value Offer", category: "Lead Generation", headline: "WHAT IS YOUR HOME WORTH?", badge: "Free Valuation", accent: "#c9a24a", style: "social" },
  { id: "fsbo-outreach", name: "FSBO Outreach", category: "Lead Generation", headline: "SELLING SOLO?", badge: "Agent Support", accent: "#e30613", style: "clean" },
  { id: "expired-listing", name: "Expired Listing", category: "Lead Generation", headline: "YOUR HOME DESERVES A NEW STRATEGY", badge: "Fresh Plan", accent: "#050505", style: "luxury" },
  { id: "buyer-education", name: "Buyer Education", category: "Education", headline: "BUYER GUIDE", badge: "Smart Moves", accent: "#050505", style: "clean" },
  { id: "seller-guide", name: "Seller Guide", category: "Education", headline: "SELLER GUIDE", badge: "Market Ready", accent: "#050505", style: "clean" },
  { id: "market-update", name: "Market Update", category: "Education", headline: "MARKET UPDATE", badge: "Local Insight", accent: "#c9a24a", style: "clean" },
  { id: "testimonial", name: "Testimonial", category: "Social", headline: "CLIENT SUCCESS STORY", badge: "Five-Star Experience", accent: "#c9a24a", style: "clean" },
  { id: "holiday-social", name: "Holiday / Social Graphic", category: "Social", headline: "FROM NEX REALTY", badge: "Community Moment", accent: "#e30613", style: "social" },
  { id: "new-agent", name: "New Agent Announcement", category: "Agent Marketing", headline: "WELCOME TO NEX REALTY", badge: "New Agent", accent: "#050505", style: "social" },
  { id: "agent-award", name: "Agent Award / Production Recognition", category: "Agent Marketing", headline: "AGENT RECOGNITION", badge: "Top Performance", accent: "#c9a24a", style: "luxury" },
  { id: "agent-spotlight", name: "Agent Spotlight", category: "Agent Marketing", headline: "AGENT SPOTLIGHT", badge: "Nex Realty", accent: "#e30613", style: "magazine" },
  { id: "referral-partner", name: "Referral Partner", category: "Agent Marketing", headline: "TRUSTED PARTNER", badge: "Referral Ready", accent: "#e30613", style: "clean" },
  { id: "recruiting", name: "Recruiting / Join Nex Realty", category: "Recruiting", headline: "JOIN NEX REALTY", badge: "Grow Faster", accent: "#e30613", style: "social" },
  { id: "recruiting-post", name: "Recruiting Post", category: "Recruiting", headline: "READY FOR A BETTER BROKERAGE?", badge: "Join Nex Realty", accent: "#e30613", style: "luxury" },
  { id: "cloud-brokerage", name: "Cloud Brokerage Recruiting", category: "Recruiting", headline: "BUILD WITHOUT LIMITS", badge: "Agent Platform", accent: "#c9a24a", style: "luxury" },
  { id: "business-card", name: "Business Card", category: "Agent Marketing", headline: "NEX REALTY", badge: "Agent Card", accent: "#e30613", style: "classic" },
  { id: "email-header", name: "Email Header", category: "Email", headline: "NEX REALTY UPDATE", badge: "Email Campaign", accent: "#050505", style: "clean" },
  { id: "email-signature", name: "Email Signature", category: "Email", headline: "NEX REALTY", badge: "Email Signature", accent: "#e30613", style: "clean" },
  { id: "story-reel-cover", name: "Story/Reel Cover", category: "Social", headline: "NEW LISTING TOUR", badge: "Watch Now", accent: "#e30613", style: "social" }
];

const marketingStudioToolTabs = [
  ["Templates", "LayoutTemplate"],
  ["AI Create", "Sparkles"],
  ["Styles", "WandSparkles"],
  ["Layers", "Layers3"],
  ["Uploads", "UploadCloud"],
  ["Photos", "Images"],
  ["Text", "Type"],
  ["Elements", "Shapes"],
  ["QR Code", "QrCode"],
  ["Agent Info", "Contact"],
  ["Property Info", "Home"],
  ["Edit", "SlidersHorizontal"],
  ["Brand Kit", "Palette"],
  ["Export", "Send"],
  ["Saved Projects", "FolderOpen"]
];

const leadCtaBlocks = [
  "Schedule a showing",
  "Request home value",
  "Download buyer guide",
  "Get pre-approved",
  "Scan for more info",
  "Contact agent",
  "Join Nex Realty",
  "Book discovery call"
];

const brandTaglines = [
  "Modern brokerage. Bold marketing.",
  "Cloud-based real estate brokerage.",
  "Built for high-performance agents.",
  "Luxury presentation. Local expertise.",
  "Smarter systems. Stronger results."
];

const brandFontPairings = [
  "Bold Sans / Clean Sans",
  "Editorial Serif / Modern Sans",
  "Condensed Display / Neutral Sans"
];

const studioLayerDefinitions = [
  { id: "logo", label: "Logo / brand", icon: "BadgeIcon" },
  { id: "headline", label: "Headline", icon: "Type" },
  { id: "media", label: "Hero photo", icon: "Image" },
  { id: "address", label: "Address", icon: "MapPin" },
  { id: "price", label: "Price", icon: "BadgeDollarSign", visibilityField: "showPrice" },
  { id: "stats", label: "Feature row", icon: "Rows3", visibilityField: "showStats" },
  { id: "body", label: "Body / CTA", icon: "MessageSquareText" },
  { id: "qr", label: "QR code", icon: "QrCode", visibilityField: "showQr" },
  { id: "agent", label: "Agent block", icon: "Contact", visibilityField: "showAgent" },
  { id: "disclaimer", label: "Disclaimer", icon: "ShieldCheck", visibilityField: "showDisclaimer" }
];

const studioStylePresets = [
  { id: "nex-signature", name: "Nex Signature", description: "Red, black, high-impact listing look.", accentColor: "#e30613", backgroundColor: "#ffffff", finish: "red-signature", layout: "classic", photoTreatment: "dramatic-overlay" },
  { id: "luxury-black", name: "Luxury Black", description: "Dark editorial, premium property feel.", accentColor: "#c9a24a", backgroundColor: "#050505", finish: "black-luxury", layout: "luxury", photoTreatment: "dramatic-overlay" },
  { id: "clean-white", name: "Clean White", description: "Bright modern flyer with restrained contrast.", accentColor: "#e30613", backgroundColor: "#ffffff", finish: "clean-white", layout: "clean", photoTreatment: "soft-contrast" },
  { id: "social-hype", name: "Social Hype", description: "Bold campaign energy for social posts.", accentColor: "#e30613", backgroundColor: "#111318", finish: "red-signature", layout: "social", photoTreatment: "full-bleed" },
  { id: "award-gold", name: "Gold Recognition", description: "Premium award, production, or recruiting tone.", accentColor: "#c9a24a", backgroundColor: "#111318", finish: "gold-accent", layout: "magazine", photoTreatment: "gallery-strip" }
];

const copyQuickActions = [
  ["Make it more luxury", "Rewrite this marketing content in a luxury real estate tone."],
  ["Make it more hype", "Rewrite this with high-energy, punchy real estate marketing language."],
  ["Make it shorter", "Make this shorter, sharper, and easier to scan."],
  ["Add emojis", "Add tasteful emojis for social media while keeping it professional."],
  ["Investor-focused", "Rewrite this for real estate investors and ROI-minded buyers."],
  ["Buyer-focused", "Rewrite this for buyers and lifestyle benefits."],
  ["Seller-focused", "Rewrite this for sellers and lead generation."],
  ["Facebook", "Rewrite this as a Facebook post."],
  ["Instagram", "Rewrite this as an Instagram caption with hashtags."],
  ["Email", "Rewrite this as an email blast."],
  ["SMS", "Rewrite this as a short SMS text."]
];

const flyerLayoutOptions = [
  { id: "classic", name: "Classic Listing", icon: "Rows3" },
  { id: "luxury", name: "Luxury Editorial", icon: "Gem" },
  { id: "magazine", name: "Magazine Cover", icon: "BookOpen" },
  { id: "social", name: "Social Ad", icon: "Megaphone" },
  { id: "clean", name: "Clean Guide", icon: "PanelTop" }
];

const flyerFinishOptions = [
  { id: "red-signature", name: "Red Signature" },
  { id: "black-luxury", name: "Black Luxury" },
  { id: "gold-accent", name: "Gold Accent" },
  { id: "clean-white", name: "Clean White" }
];

const photoTreatmentOptions = [
  { id: "full-bleed", name: "Full Bleed" },
  { id: "dramatic-overlay", name: "Dramatic Overlay" },
  { id: "soft-contrast", name: "Soft Contrast" },
  { id: "gallery-strip", name: "Gallery Strip" }
];

const creativeFormatOptions = [
  { id: "letter-flyer", name: "Letter Flyer", icon: "FileText", width: 8.5, height: 11, exportLabel: "8.5 x 11 in" },
  { id: "open-house-flyer", name: "Open House Flyer", icon: "CalendarDays", width: 8.5, height: 11, exportLabel: "8.5 x 11 in" },
  { id: "facebook-post", name: "Facebook Post", icon: "Share2", width: 1200, height: 630, exportLabel: "1200 x 630" },
  { id: "instagram-square", name: "IG Post", icon: "Camera", width: 1080, height: 1080, exportLabel: "1080 x 1080" },
  { id: "instagram-story", name: "IG Story", icon: "Smartphone", width: 1080, height: 1920, exportLabel: "1080 x 1920" },
  { id: "instagram-reel", name: "Reel Cover", icon: "Clapperboard", width: 1080, height: 1920, exportLabel: "1080 x 1920" },
  { id: "linkedin-post", name: "LinkedIn Post", icon: "Linkedin", width: 1200, height: 1200, exportLabel: "1200 x 1200" },
  { id: "youtube-thumbnail", name: "YouTube Thumbnail", icon: "Youtube", width: 1280, height: 720, exportLabel: "1280 x 720" },
  { id: "postcard", name: "Postcard 6 x 4", icon: "Mail", width: 6, height: 4, exportLabel: "6 x 4 in" },
  { id: "postcard-large", name: "Postcard 9 x 6", icon: "Mail", width: 9, height: 6, exportLabel: "9 x 6 in" },
  { id: "horizontal-video", name: "Video Wide", icon: "MonitorPlay", width: 1920, height: 1080, exportLabel: "1920 x 1080" },
  { id: "business-card", name: "Business Card", icon: "Contact", width: 3.5, height: 2, exportLabel: "3.5 x 2 in" },
  { id: "email-header", name: "Email Header", icon: "Mail", width: 1200, height: 400, exportLabel: "1200 x 400" },
  { id: "email-signature", name: "Email Signature", icon: "BadgeCheck", width: 600, height: 220, exportLabel: "600 x 220" },
  { id: "open-house-sign", name: "Open House Sign", icon: "Signpost", width: 18, height: 24, exportLabel: "18 x 24 in" },
  { id: "yard-sign", name: "Yard Sign", icon: "Signpost", width: 24, height: 18, exportLabel: "24 x 18 in" },
  { id: "qr-code-flyer", name: "QR Code Flyer", icon: "QrCode", width: 8.5, height: 11, exportLabel: "8.5 x 11 in" }
];

const studioQuickStarts = [
  { title: "Just Listed Flyer", description: "Print-ready listing flyer", icon: "FileText", templateId: "just-listed", formatId: "letter-flyer", nextTool: "Property Info" },
  { title: "Open House", description: "Flyer or social promo", icon: "CalendarDays", templateId: "modern-open-house", formatId: "letter-flyer", nextTool: "Property Info" },
  { title: "Price Improvement", description: "New price social or flyer", icon: "BadgeDollarSign", templateId: "price-improvement", formatId: "facebook-post", nextTool: "Property Info" },
  { title: "Under Contract", description: "Pending sale announcement", icon: "BadgeCheck", templateId: "under-contract", formatId: "instagram-square", nextTool: "Text" },
  { title: "Just Sold", description: "Closed deal announcement", icon: "PartyPopper", templateId: "just-sold", formatId: "instagram-square", nextTool: "Text" },
  { title: "For Rent", description: "Rental flyer or post", icon: "KeyRound", templateId: "for-rent", formatId: "letter-flyer", nextTool: "Property Info" },
  { title: "Seller Lead Ad", description: "Home value campaign", icon: "Target", templateId: "seller-lead-ad", formatId: "facebook-post", nextTool: "AI Create" },
  { title: "Buyer Lead Ad", description: "Find buyer prospects", icon: "UsersRound", templateId: "buyer-need", formatId: "instagram-square", nextTool: "AI Create" },
  { title: "Recruiting Post", description: "Agent attraction graphic", icon: "Megaphone", templateId: "recruiting-post", formatId: "instagram-square", nextTool: "AI Create" },
  { title: "Business Card", description: "3.5 x 2 agent card", icon: "Contact", templateId: "business-card", formatId: "business-card", nextTool: "Agent Info" },
  { title: "Email Signature", description: "Clean agent email signature", icon: "BadgeCheck", templateId: "email-signature", formatId: "email-signature", nextTool: "Agent Info" },
  { title: "Postcard", description: "6 x 4 direct mail", icon: "Mail", templateId: "home-value-offer", formatId: "postcard", nextTool: "AI Create" },
  { title: "QR Code Flyer", description: "Scan-to-lead handout", icon: "QrCode", templateId: "seller-lead-ad", formatId: "qr-code-flyer", nextTool: "QR Code" },
  { title: "Event/Class Flyer", description: "Class or partner event", icon: "Presentation", templateId: "market-update", formatId: "letter-flyer", nextTool: "AI Create" },
  { title: "Instagram Post", description: "1080 x 1080 social graphic", icon: "Camera", templateId: "just-listed", formatId: "instagram-square", nextTool: "Text" },
  { title: "Reel / Story Cover", description: "Vertical 1080 x 1920", icon: "Clapperboard", templateId: "story-reel-cover", formatId: "instagram-reel", nextTool: "Text" },
  { title: "Facebook Post", description: "Wide feed graphic", icon: "Share2", templateId: "seller-lead-ad", formatId: "facebook-post", nextTool: "Text" }
];

const simpleMarketingWorkflows = [
  {
    id: "listing",
    label: "Listing",
    type: "Just Listed",
    title: "Create Listing Marketing",
    icon: "Home",
    description: "Flyers and social posts for a new listing.",
    templateId: "just-listed",
    defaultPrompt: "Create professional Just Listed marketing for this Nex Realty property.",
    recommendedFormats: ["letter-flyer", "facebook-post", "instagram-square", "instagram-story"],
    fields: ["address", "price", "beds", "baths", "garage", "sqft", "description", "cta", "photos"]
  },
  {
    id: "rental",
    label: "Rental",
    type: "For Rent",
    title: "Create Rental Marketing",
    icon: "KeyRound",
    description: "Rental flyers, social posts, and story graphics.",
    templateId: "for-rent",
    defaultPrompt: "Create clean rental marketing for this Nex Realty rental listing.",
    recommendedFormats: ["letter-flyer", "facebook-post", "instagram-story"],
    fields: ["address", "rent", "beds", "baths", "garage", "sqft", "available", "description", "cta", "photos"]
  },
  {
    id: "open-house",
    label: "Open House",
    type: "Open House",
    title: "Create Open House Marketing",
    icon: "CalendarDays",
    description: "Promote an open house quickly.",
    templateId: "modern-open-house",
    defaultPrompt: "Create modern open house marketing for this Nex Realty property.",
    recommendedFormats: ["open-house-flyer", "instagram-story", "facebook-post", "email-header"],
    fields: ["address", "price", "beds", "baths", "openHouse", "description", "cta", "photos"]
  },
  {
    id: "sold",
    label: "Just Sold",
    type: "Just Sold",
    title: "Create Just Sold Marketing",
    icon: "PartyPopper",
    description: "Celebrate a closing and build social proof.",
    templateId: "just-sold",
    defaultPrompt: "Create polished Just Sold marketing for Nex Realty.",
    recommendedFormats: ["instagram-square", "facebook-post", "instagram-story"],
    fields: ["address", "price", "description", "cta", "photos"]
  },
  {
    id: "recruiting",
    label: "Recruiting",
    type: "Recruiting",
    title: "Create Recruiting Marketing",
    icon: "Megaphone",
    description: "Agent attraction posts and flyers.",
    templateId: "recruiting-post",
    defaultPrompt: "Create a professional Nex Realty recruiting post focused on growth, support, and technology.",
    recommendedFormats: ["facebook-post", "instagram-square", "instagram-story", "letter-flyer"],
    fields: ["message", "plan", "cta"]
  },
  {
    id: "event",
    label: "Event/Class",
    type: "Event / Class",
    title: "Create Event/Class Marketing",
    icon: "Presentation",
    description: "Training, partner, and community event graphics.",
    templateId: "market-update",
    defaultPrompt: "Create a clean Nex Realty event flyer and social post.",
    recommendedFormats: ["letter-flyer", "facebook-post", "instagram-story", "email-header"],
    fields: ["eventTitle", "dateTime", "location", "speaker", "description", "cta", "photos"]
  },
  {
    id: "social",
    label: "Social Post",
    type: "Social Post",
    title: "Create Social Marketing",
    icon: "Share2",
    description: "A quick Nex-branded social graphic.",
    templateId: "seller-lead-ad",
    defaultPrompt: "Create a simple Nex Realty social post that is clean, modern, and easy to read.",
    recommendedFormats: ["instagram-square", "facebook-post", "instagram-story"],
    fields: ["message", "description", "cta", "photos"]
  },
  {
    id: "business-card",
    label: "Business Card",
    type: "Business Card",
    title: "Create Business Card",
    icon: "Contact",
    description: "A print-ready Nex agent card with editable front and back.",
    templateId: "business-card",
    defaultPrompt: "Create a clean print-ready Nex Realty business card for this agent.",
    recommendedFormats: ["business-card"],
    fields: ["agentName", "agentPhone", "agentEmail", "agentWebsite", "agentTitle", "license", "cta"]
  },
  {
    id: "template",
    label: "Start From Template",
    type: "Template",
    title: "Start From Template",
    icon: "LayoutTemplate",
    description: "Open the template browser when you know what you want.",
    templateId: "just-listed",
    defaultPrompt: "Create a Nex Realty marketing piece from the selected template.",
    recommendedFormats: ["letter-flyer", "instagram-square", "facebook-post"],
    fields: ["address", "price", "description", "cta", "photos"],
    advancedDefault: true
  }
];

const videoOrientationOptions = [
  { id: "vertical", name: "Vertical Reel", icon: "Smartphone", width: 1080, height: 1920, label: "9:16 reel/story" },
  { id: "horizontal", name: "Horizontal Video", icon: "MonitorPlay", width: 1920, height: 1080, label: "16:9 wide video" }
];

const defaultFields = {
  agentName: "",
  agentPhone: "",
  agentEmail: "",
  propertyAddress: "",
  city: "",
  state: "",
  zip: "",
  price: "",
  bedrooms: "",
  bathrooms: "",
  garageSpaces: "",
  squareFootage: "",
  lotSize: "",
  propertyType: "",
  status: "For sale",
  openHouseDateTime: "",
  rentalAvailableDate: "",
  propertyHighlights: "",
  mlsRemarks: "",
  cta: "Schedule Your Tour Today",
  marketingType: "Just Listed",
  tone: "Professional",
  platform: "Multi-platform"
};

const localDefaultBrand = {
  companyName: "Nex Realty",
  primaryColor: "#e30613",
  black: "#050505",
  charcoal: "#24272d",
  white: "#ffffff",
  gold: "#c9a24a",
  logoDataUrl: "",
  logoBlackUrl: defaultLogoBlackUrl,
  logoWhiteUrl: defaultLogoWhiteUrl,
  logoBlackDataUrl: "",
  logoWhiteDataUrl: "",
  defaultDisclaimer:
    "Information deemed reliable but not guaranteed. Equal Housing Opportunity. Advertised by Nex Realty. Agent is responsible for verifying all listing and advertising information prior to publication.",
  recruitingDisclaimer:
    "Commission plans, fees, caps, and incentives are subject to change and may vary by agreement. Contact Nex Realty for current details."
};

const defaultFlyerCopy = {
  headline: "JUST LISTED",
  badge: "New Listing",
  body: "Premium Nex Realty marketing copy will appear here after generation.",
  cta: "Schedule Your Tour Today",
  footer: localDefaultBrand.defaultDisclaimer,
  layout: "classic",
  finish: "red-signature",
  photoTreatment: "dramatic-overlay",
  canvasFormat: "letter-flyer",
  videoOrientation: "vertical",
  fontScale: 100,
  fontWeight: 900,
  textAlign: "left",
  showPrice: true,
  showStats: true,
  showAgent: true,
  showDisclaimer: true,
  showQr: false,
  qrUrl: "",
  agentTitle: "Real Estate Professional",
  agentSocial: "@nexrealty",
  businessCardSide: "front",
  headlineOffsetX: 0,
  headlineOffsetY: 0,
  headlineWidth: 360,
  heroHeight: 274,
  addressScale: 100,
  priceScale: 100,
  statsScale: 100,
  bodyScale: 100,
  agentScale: 100,
  disclaimerScale: 100,
  qrScale: 100,
  backgroundColor: "#ffffff",
  backgroundImage: "",
  backgroundImageName: "",
  backgroundOpacity: 12,
  videoMotion: "Subtle zoom",
  videoDuration: 8,
  heroImageFit: "Cover",
  heroImagePosition: "Center"
};

const defaultBusinessCardCopy = {
  style: "Signature Red",
  displayName: "",
  email: "",
  phone: "",
  title: "Real Estate Professional",
  licenseLine: "Advertised by Nex Realty",
  website: "nexrealty.com",
  social: "@nexrealty",
  tagline: "Modern brokerage. Bold marketing. Smarter moves.",
  headshotShape: "Square",
  headshotFit: "Cover",
  headshotZoom: 100,
  headshotX: 0,
  headshotY: 0
};

const MARKETING_MEDIA_LIBRARY_PREFIX = "nex-marketing-studio-media-library";
const MARKETING_HEADSHOT_PREFIX = "nex-marketing-studio-headshot";

function normalizeSvgAttribute(key) {
  return key.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
}

function Icon({ name, size = 18, className = "" }) {
  const node = window.lucide && window.lucide.icons && window.lucide.icons[name];
  if (!node) return <span className={className} aria-hidden="true" />;

  function render(iconNode, index = 0) {
    const [tag, attrs = {}, children = []] = iconNode;
    const normalized = Object.entries(attrs).reduce((next, [key, value]) => {
      next[normalizeSvgAttribute(key)] = value;
      return next;
    }, {});
    if (tag === "svg") {
      normalized.width = size;
      normalized.height = size;
      normalized.className = className;
      normalized["aria-hidden"] = "true";
    }
    return React.createElement(
      tag,
      { ...normalized, key: index },
      children.map((child, childIndex) => render(child, childIndex))
    );
  }

  return render(node);
}

function classNames(...values) {
  return values.filter(Boolean).join(" ");
}

function isAdminRole(role) {
  const value = String(role || "").trim().toLowerCase();
  return value === "admin" || value === "super admin" || value === "superadmin";
}

function money(value) {
  if (!value) return "";
  const number = Number(String(value).replace(/[^0-9.]/g, ""));
  if (!Number.isFinite(number) || number <= 0) return value;
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    maximumFractionDigits: 0
  }).format(number);
}

function titleCaseDate(value) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleString([], {
    weekday: "short",
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit"
  });
}

function dashboardTime(value, fallback = "Live") {
  if (!value) return fallback;
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) return fallback;
  return parsed.toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
}

function slugify(value) {
  return String(value || "")
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/(^-|-$)/g, "");
}

function readableInkColor(value, fallback = "#111318") {
  const hex = String(value || "").trim().replace("#", "");
  const normalized = hex.length === 3 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
  if (!/^[0-9a-f]{6}$/i.test(normalized)) return fallback;
  const red = parseInt(normalized.slice(0, 2), 16);
  const green = parseInt(normalized.slice(2, 4), 16);
  const blue = parseInt(normalized.slice(4, 6), 16);
  const luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255;
  return luminance > 0.58 ? "#111318" : "#ffffff";
}

function makeStudioMediaItem(item = {}, source = "Uploaded") {
  const dataUrl = item.dataUrl || item.url || item.src || "";
  if (!dataUrl) return null;
  const name = item.name || item.title || "Studio image";
  return {
    id: item.id || `${slugify(source)}-${slugify(name)}-${Date.now()}-${Math.round(Math.random() * 10000)}`,
    name,
    title: item.title || name,
    type: item.type || (String(dataUrl).startsWith("data:image/svg") ? "image/svg+xml" : "image/jpeg"),
    source: item.source || source,
    dataUrl,
    savedAt: item.savedAt || new Date().toISOString()
  };
}

function mergeStudioMedia(mediaItems = [], current = [], limit = 24) {
  const seen = new Set();
  return [...mediaItems, ...current]
    .filter(Boolean)
    .filter((item) => {
      const key = item.dataUrl || item.id;
      if (!key || seen.has(key)) return false;
      seen.add(key);
      return true;
    })
    .slice(0, limit);
}

function saveStudioJson(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch {
    // Browser storage can fill up with uploaded data URLs. The project still works without saved media.
  }
}

function mergeTemplates(templateList = []) {
  const byId = new Map(studioTemplateDefaults.map((template) => [template.id, template]));
  for (const template of templateList) {
    if (!template || !template.id) continue;
    byId.set(template.id, { ...(byId.get(template.id) || {}), ...template });
  }
  return Array.from(byId.values());
}

function makeStockVisual({ title, category, colorA, colorB, accent, pattern }) {
  const roof = pattern === "exterior" || pattern === "open-house";
  const skyline = pattern === "skyline" || pattern === "recruiting";
  const interior = pattern === "interior" || pattern === "kitchen";
  const award = pattern === "award";
  const svg = `
    <svg width="1200" height="820" viewBox="0 0 1200 820" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0" stop-color="${colorA}"/>
          <stop offset="1" stop-color="${colorB}"/>
        </linearGradient>
        <linearGradient id="shine" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0" stop-color="#fff" stop-opacity=".18"/>
          <stop offset=".55" stop-color="#fff" stop-opacity=".04"/>
          <stop offset="1" stop-color="#fff" stop-opacity=".22"/>
        </linearGradient>
      </defs>
      <rect width="1200" height="820" fill="url(#bg)"/>
      <rect x="70" y="64" width="1060" height="690" fill="none" stroke="#fff" stroke-opacity=".18" stroke-width="2"/>
      <circle cx="980" cy="150" r="92" fill="${accent}" opacity=".32"/>
      <circle cx="160" cy="700" r="150" fill="#fff" opacity=".08"/>
      ${skyline ? `
        <g fill="#111318" opacity=".62">
          <rect x="126" y="320" width="126" height="330"/>
          <rect x="280" y="244" width="152" height="406"/>
          <rect x="468" y="350" width="118" height="300"/>
          <rect x="622" y="205" width="170" height="445"/>
          <rect x="830" y="290" width="142" height="360"/>
        </g>
        <g fill="#fff" opacity=".32">
          ${Array.from({ length: 38 }, (_, index) => `<rect x="${150 + (index % 10) * 78}" y="${350 + Math.floor(index / 10) * 74}" width="28" height="20"/>`).join("")}
        </g>
      ` : ""}
      ${roof ? `
        <path d="M185 520 L600 190 L1015 520 Z" fill="#ffffff" opacity=".2"/>
        <path d="M270 520 L600 258 L930 520 Z" fill="#111318" opacity=".42"/>
        <rect x="320" y="520" width="560" height="170" fill="#ffffff" opacity=".16"/>
        <rect x="550" y="570" width="104" height="120" fill="${accent}" opacity=".72"/>
        <rect x="390" y="560" width="92" height="72" fill="#fff" opacity=".32"/>
        <rect x="720" y="560" width="92" height="72" fill="#fff" opacity=".32"/>
      ` : ""}
      ${interior ? `
        <rect x="130" y="150" width="940" height="370" fill="#ffffff" opacity=".16"/>
        <rect x="190" y="205" width="260" height="240" fill="#111318" opacity=".34"/>
        <rect x="490" y="205" width="260" height="240" fill="#ffffff" opacity=".22"/>
        <rect x="790" y="205" width="220" height="240" fill="#111318" opacity=".24"/>
        <rect x="250" y="590" width="700" height="72" rx="36" fill="#111318" opacity=".48"/>
        <rect x="354" y="510" width="492" height="114" rx="24" fill="${accent}" opacity=".55"/>
      ` : ""}
      ${award ? `
        <path d="M520 180 H680 L650 480 H550 Z" fill="${accent}" opacity=".72"/>
        <path d="M482 210 C338 226 352 438 536 392" fill="none" stroke="#fff" stroke-opacity=".32" stroke-width="46"/>
        <path d="M718 210 C862 226 848 438 664 392" fill="none" stroke="#fff" stroke-opacity=".32" stroke-width="46"/>
        <rect x="500" y="520" width="200" height="40" fill="#111318" opacity=".62"/>
        <rect x="430" y="560" width="340" height="80" fill="#111318" opacity=".42"/>
      ` : ""}
      <rect x="0" y="0" width="1200" height="820" fill="url(#shine)"/>
      <path d="M80 108 H360" stroke="${accent}" stroke-width="10"/>
      <text x="80" y="702" fill="#fff" fill-opacity=".86" font-family="Arial, sans-serif" font-size="52" font-weight="900" letter-spacing="4">${title.toUpperCase()}</text>
      <text x="82" y="742" fill="#fff" fill-opacity=".62" font-family="Arial, sans-serif" font-size="22" font-weight="700" letter-spacing="5">${category.toUpperCase()}</text>
    </svg>`;
  return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}

const stockPhotoPresets = [
  { id: "luxury-exterior", title: "Luxury Exterior", category: "Luxury", pattern: "exterior", colorA: "#111318", colorB: "#5d6470", accent: "#c9a24a" },
  { id: "modern-interior", title: "Modern Interior", category: "Luxury", pattern: "interior", colorA: "#272c35", colorB: "#b8bdc7", accent: "#e30613" },
  { id: "designer-kitchen", title: "Designer Kitchen", category: "Listing", pattern: "kitchen", colorA: "#111318", colorB: "#ece7dd", accent: "#c9a24a" },
  { id: "open-house", title: "Open House", category: "Open House", pattern: "open-house", colorA: "#17191d", colorB: "#7c1d24", accent: "#e30613" },
  { id: "city-skyline", title: "City Skyline", category: "Listing", pattern: "skyline", colorA: "#08090b", colorB: "#343a46", accent: "#e30613" },
  { id: "rental-lifestyle", title: "Rental Lifestyle", category: "Rental", pattern: "interior", colorA: "#1f2933", colorB: "#6c7887", accent: "#e30613" },
  { id: "seller-consult", title: "Seller Consult", category: "Seller", pattern: "kitchen", colorA: "#111318", colorB: "#755f35", accent: "#c9a24a" },
  { id: "buyer-guide", title: "Buyer Guide", category: "Education", pattern: "interior", colorA: "#f4f5f7", colorB: "#9aa2af", accent: "#e30613" },
  { id: "agent-platform", title: "Agent Platform", category: "Recruiting", pattern: "recruiting", colorA: "#070708", colorB: "#303744", accent: "#e30613" },
  { id: "award-night", title: "Award Night", category: "Recognition", pattern: "award", colorA: "#111318", colorB: "#5a4521", accent: "#c9a24a" }
].map((photo) => ({ ...photo, dataUrl: makeStockVisual(photo) }));

const thirdPartyStockPhotoPresets = [
  {
    id: "stock-bright-exterior",
    title: "Bright Exterior",
    category: "Exterior",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1564013799919-ab600027ffc6?auto=format&fit=crop&w=1400&q=82"
  },
  {
    id: "stock-modern-living",
    title: "Modern Living Room",
    category: "Interior",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=1400&q=82"
  },
  {
    id: "stock-kitchen",
    title: "Luxury Kitchen",
    category: "Interior",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1556911220-bff31c812dba?auto=format&fit=crop&w=1400&q=82"
  },
  {
    id: "stock-open-house",
    title: "Open House Detail",
    category: "Open House",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1560518883-ce09059eeffa?auto=format&fit=crop&w=1400&q=82"
  },
  {
    id: "stock-agent-laptop",
    title: "Agent Workspace",
    category: "Recruiting",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1497366754035-f200968a6e72?auto=format&fit=crop&w=1400&q=82"
  },
  {
    id: "stock-condo-view",
    title: "Condo View",
    category: "Luxury",
    source: "Unsplash stock",
    dataUrl: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?auto=format&fit=crop&w=1400&q=82"
  }
];

const studioStockPhotoPresets = [...thirdPartyStockPhotoPresets, ...stockPhotoPresets];

function getCreativeFormat(id) {
  return creativeFormatOptions.find((option) => option.id === id) || creativeFormatOptions[0];
}

function getRecommendedFormatForTemplate(template = {}) {
  const id = String(template.id || "").toLowerCase();
  const name = String(template.name || "").toLowerCase();
  const category = String(template.category || "").toLowerCase();

  if (id.includes("business-card") || name.includes("business card")) return "business-card";
  if (id.includes("email-signature") || name.includes("email signature")) return "email-signature";
  if (id.includes("email-header") || name.includes("email header") || category === "email") return "email-header";
  if (id.includes("youtube") || name.includes("youtube")) return "youtube-thumbnail";
  if (id.includes("linkedin") || name.includes("linkedin")) return "linkedin-post";
  if (id.includes("story") || name.includes("story")) return "instagram-story";
  if (id.includes("reel") || name.includes("reel")) return "instagram-reel";
  if (id.includes("open-house") || name.includes("open house")) return "open-house-flyer";
  if (category === "social" || id.includes("testimonial") || id.includes("holiday")) return "instagram-square";
  if (id.includes("qr")) return "qr-code-flyer";
  if (id.includes("postcard-large") || name.includes("9 x 6")) return "postcard-large";
  if (id.includes("postcard") || name.includes("postcard")) return "postcard";
  if (id.includes("yard") || name.includes("yard")) return "yard-sign";
  if (id.includes("sign") || name.includes("sign")) return "open-house-sign";
  return template.canvasFormat || template.format || "letter-flyer";
}

function getFormatDefaults(formatId) {
  const shared = {
    showPrice: true,
    showStats: true,
    showAgent: true,
    showDisclaimer: true,
    showQr: false,
    heroImageFit: "Cover",
    textAlign: "left",
    headlineOffsetX: 0,
    headlineOffsetY: 0,
    addressScale: 100,
    priceScale: 100,
    statsScale: 100,
    bodyScale: 100,
    agentScale: 100,
    disclaimerScale: 100,
    qrScale: 100
  };
  if (formatId === "business-card") {
    return {
      ...shared,
      showPrice: false,
      showStats: false,
      showDisclaimer: false,
      showQr: true,
      heroHeight: 160,
      headlineWidth: 280,
      fontScale: 100
    };
  }
  if (formatId === "email-header") {
    return {
      ...shared,
      showPrice: false,
      showStats: false,
      showDisclaimer: false,
      showQr: false,
      heroHeight: 190,
      headlineWidth: 520,
      fontScale: 88
    };
  }
  if (formatId === "email-signature") {
    return {
      ...shared,
      showPrice: false,
      showStats: false,
      showDisclaimer: false,
      showQr: false,
      heroHeight: 160,
      headlineWidth: 420,
      fontScale: 92
    };
  }
  if (["facebook-post", "youtube-thumbnail", "horizontal-video", "postcard", "postcard-large", "yard-sign"].includes(formatId)) {
    return {
      ...shared,
      showDisclaimer: false,
      showQr: false,
      heroHeight: 260,
      headlineWidth: 520,
      fontScale: 82
    };
  }
  if (["instagram-square", "linkedin-post"].includes(formatId)) {
    return {
      ...shared,
      showDisclaimer: false,
      showQr: false,
      heroHeight: 300,
      headlineWidth: 420,
      fontScale: 96
    };
  }
  if (["instagram-story", "instagram-reel"].includes(formatId)) {
    return {
      ...shared,
      showDisclaimer: false,
      showQr: false,
      heroHeight: 420,
      headlineWidth: 320,
      fontScale: 100
    };
  }
  if (formatId === "open-house-sign") {
    return {
      ...shared,
      showDisclaimer: false,
      showQr: true,
      heroHeight: 360,
      headlineWidth: 430,
      fontScale: 112
    };
  }
  if (formatId === "qr-code-flyer") {
    return {
      ...shared,
      showQr: true,
      heroHeight: 260,
      headlineWidth: 390,
      fontScale: 100
    };
  }
  return {
    ...shared,
    heroHeight: 274,
    headlineWidth: 360,
    fontScale: 100
  };
}

function clampStudioNumber(value, min, max) {
  const number = Number(value);
  if (!Number.isFinite(number)) return min;
  return Math.min(Math.max(number, min), max);
}

function layerScaleStyle(flyerCopy, elementId) {
  const scale = clampStudioNumber(flyerCopy[`${elementId}Scale`] || 100, 50, 180) / 100;
  const offsetX = clampStudioNumber(flyerCopy[`${elementId}OffsetX`] || 0, -220, 220);
  const offsetY = clampStudioNumber(flyerCopy[`${elementId}OffsetY`] || 0, -220, 220);
  return { "--layer-scale": scale, "--layer-x": `${offsetX}px`, "--layer-y": `${offsetY}px` };
}

function getQrCodeUrl(value) {
  const target = value || "https://mynexrealty.com";
  return `https://quickchart.io/qr?text=${encodeURIComponent(target)}&size=320&margin=2`;
}

function sortStudioTemplates(templates = [], templateCategory = "All", query = "") {
  const priority = [
    "just-listed",
    "business-card",
    "modern-open-house",
    "story-reel-cover",
    "seller-lead-ad",
    "for-rent",
    "luxury-listing",
    "recruiting-post"
  ];
  if (templateCategory !== "All" || query) return templates;
  return [...templates].sort((a, b) => {
    const aIndex = priority.indexOf(a.id);
    const bIndex = priority.indexOf(b.id);
    if (aIndex !== -1 || bIndex !== -1) {
      return (aIndex === -1 ? 99 : aIndex) - (bIndex === -1 ? 99 : bIndex);
    }
    return String(a.name || "").localeCompare(String(b.name || ""));
  });
}

function getVideoOrientation(id) {
  return videoOrientationOptions.find((option) => option.id === id) || videoOrientationOptions[0];
}

function canvasImage(src) {
  return new Promise((resolve) => {
    if (!src) {
      resolve(null);
      return;
    }
    const image = new Image();
    image.crossOrigin = "anonymous";
    image.onload = () => resolve(image);
    image.onerror = () => resolve(null);
    image.src = src;
  });
}

function drawCoverImage(ctx, image, x, y, width, height, zoom = 1) {
  if (!image) return;
  const imageRatio = image.width / image.height;
  const boxRatio = width / height;
  let sourceWidth = image.width;
  let sourceHeight = image.height;
  if (imageRatio > boxRatio) sourceWidth = image.height * boxRatio;
  else sourceHeight = image.width / boxRatio;
  sourceWidth /= zoom;
  sourceHeight /= zoom;
  const sourceX = (image.width - sourceWidth) / 2;
  const sourceY = (image.height - sourceHeight) / 2;
  ctx.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, x, y, width, height);
}

function drawContainImage(ctx, image, x, y, width, height) {
  if (!image) return;
  const ratio = Math.min(width / image.width, height / image.height);
  const drawWidth = image.width * ratio;
  const drawHeight = image.height * ratio;
  ctx.drawImage(image, x, y + (height - drawHeight) / 2, drawWidth, drawHeight);
}

function drawWrappedText(ctx, text, x, y, maxWidth, lineHeight, maxLines = 4) {
  const words = String(text || "").split(/\s+/).filter(Boolean);
  const lines = [];
  let line = "";
  words.forEach((word) => {
    const testLine = line ? `${line} ${word}` : word;
    if (ctx.measureText(testLine).width > maxWidth && line) {
      lines.push(line);
      line = word;
    } else {
      line = testLine;
    }
  });
  if (line) lines.push(line);
  lines.slice(0, maxLines).forEach((lineText, index) => {
    ctx.fillText(lineText, x, y + index * lineHeight);
  });
}

function downloadBlob(blob, fileName) {
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = fileName;
  link.click();
  setTimeout(() => URL.revokeObjectURL(url), 1200);
}

async function createQuickMarketingVideo({ brand, fields, flyerCopy, propertyPhotos, orientation }) {
  const spec = getVideoOrientation(orientation);
  const canvas = document.createElement("canvas");
  canvas.width = spec.width;
  canvas.height = spec.height;
  const ctx = canvas.getContext("2d");
  if (!ctx || !canvas.captureStream || !window.MediaRecorder) {
    throw new Error("Quick video export requires a browser with canvas video recording support.");
  }

  const imageSource = propertyPhotos[0]?.dataUrl || stockPhotoPresets[0]?.dataUrl;
  const heroImage = await canvasImage(imageSource);
  const logo = await canvasImage(brand.logoWhiteDataUrl || brand.logoWhiteUrl || defaultLogoWhiteUrl);
  const stream = canvas.captureStream(30);
  const mimeType = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"].find((type) => MediaRecorder.isTypeSupported(type)) || "";
  const recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
  const chunks = [];
  const duration = 5200;
  const isVertical = spec.height > spec.width;

  recorder.ondataavailable = (event) => {
    if (event.data && event.data.size) chunks.push(event.data);
  };

  function drawFrame(progress) {
    const width = canvas.width;
    const height = canvas.height;
    const red = brand.primaryColor || "#e30613";
    const gold = brand.gold || "#c9a24a";
    const headline = flyerCopy.headline || fields.marketingType || "Nex Realty";
    const badge = flyerCopy.badge || fields.status || "Featured";
    const address = fields.propertyAddress || "Your next move starts here";
    const price = money(fields.price) || "Contact for details";
    const cta = flyerCopy.cta || fields.cta || "Schedule Your Tour Today";
    const zoom = 1.03 + progress * 0.08;
    ctx.clearRect(0, 0, width, height);

    const background = ctx.createLinearGradient(0, 0, width, height);
    background.addColorStop(0, "#070708");
    background.addColorStop(0.58, "#17191d");
    background.addColorStop(1, red);
    ctx.fillStyle = background;
    ctx.fillRect(0, 0, width, height);

    const photoHeight = isVertical ? height * 0.58 : height;
    drawCoverImage(ctx, heroImage, 0, 0, width, photoHeight, zoom);
    const overlay = ctx.createLinearGradient(0, 0, isVertical ? 0 : width, height);
    overlay.addColorStop(0, "rgba(0,0,0,.25)");
    overlay.addColorStop(isVertical ? 0.58 : 0.42, "rgba(0,0,0,.58)");
    overlay.addColorStop(1, "rgba(0,0,0,.92)");
    ctx.fillStyle = overlay;
    ctx.fillRect(0, 0, width, height);

    const pad = isVertical ? 78 : 86;
    if (logo) drawContainImage(ctx, logo, pad, pad, isVertical ? 230 : 250, isVertical ? 92 : 100);
    else {
      ctx.fillStyle = "#ffffff";
      ctx.font = `900 ${isVertical ? 42 : 46}px Arial`;
      ctx.fillText("NEX REALTY", pad, pad + 44);
    }

    ctx.fillStyle = red;
    ctx.fillRect(pad, isVertical ? height * 0.62 : height * 0.54, isVertical ? 260 : 310, isVertical ? 54 : 58);
    ctx.fillStyle = "#ffffff";
    ctx.font = `900 ${isVertical ? 28 : 31}px Arial`;
    ctx.letterSpacing = "2px";
    ctx.fillText(String(badge).toUpperCase(), pad + 22, (isVertical ? height * 0.62 : height * 0.54) + (isVertical ? 36 : 39));

    ctx.fillStyle = "#ffffff";
    ctx.font = `900 ${isVertical ? 80 : 84}px Arial`;
    drawWrappedText(ctx, String(headline).toUpperCase(), pad, isVertical ? height * 0.71 : height * 0.67, width - pad * 2, isVertical ? 86 : 90, isVertical ? 4 : 3);

    ctx.fillStyle = gold;
    ctx.font = `900 ${isVertical ? 34 : 36}px Arial`;
    drawWrappedText(ctx, address, pad, isVertical ? height - 265 : height - 190, width - pad * 2, 42, 2);

    ctx.fillStyle = "#ffffff";
    ctx.font = `900 ${isVertical ? 42 : 44}px Arial`;
    ctx.fillText(price, pad, isVertical ? height - 178 : height - 116);

    ctx.fillStyle = red;
    ctx.fillRect(pad, height - (isVertical ? 120 : 74), isVertical ? width - pad * 2 : 520, isVertical ? 62 : 52);
    ctx.fillStyle = "#ffffff";
    ctx.font = `900 ${isVertical ? 27 : 24}px Arial`;
    ctx.fillText(String(cta).toUpperCase().slice(0, 42), pad + 24, height - (isVertical ? 80 : 40));
  }

  return new Promise((resolve, reject) => {
    recorder.onerror = () => reject(new Error("Could not render the quick video."));
    recorder.onstop = () => resolve(new Blob(chunks, { type: mimeType || "video/webm" }));
    recorder.start();
    const start = performance.now();
    function tick(now) {
      const progress = Math.min(1, (now - start) / duration);
      drawFrame(progress);
      if (progress < 1) requestAnimationFrame(tick);
      else setTimeout(() => recorder.stop(), 260);
    }
    requestAnimationFrame(tick);
  });
}

const promptStarters = [
  { label: "Luxury listing campaign", prompt: "Create a luxury listing caption, flyer copy, email blast, and SMS for this property." },
  { label: "Open house push", prompt: "Create an open house promo with Facebook copy, Instagram caption, flyer text, email invitation, and SMS invite." },
  { label: "Seller lead ad", prompt: "Create a seller lead generation ad for homeowners considering selling this year." },
  { label: "Recruiting post", prompt: "Make a high-energy recruiting post for agents considering Nex Realty." }
];

const portalPages = [
  ["Dashboard", "LayoutDashboard"],
  ["Activity", "Activity"],
  ["Agent Intelligence", "BrainCircuit"],
  ["Communication Center", "BellRing"],
  ["Marketing Studio", "Sparkles"],
  ["Bulletin Board", "Megaphone"],
  ["Quick Links", "PanelsTopLeft"],
  ["Directory", "ContactRound"],
  ["My Website", "Globe2"],
  ["Nex Intelligent Assistant", "Bot"],
  ["Nex Chat", "MessagesSquare"],
  ["Nex CRM", "UsersRound"],
  ["Nex Leads", "Route"],
  ["Production Tracker", "Calculator"],
  ["Calculators", "ReceiptText"],
  ["Commission Tracker", "BadgeDollarSign"],
  ["Nex PowerShare", "Network"],
  ["Transactions", "FileCheck2"],
  ["Documents", "FolderKanban"],
  ["Nex LaunchPad", "Rocket"],
  ["NexU / Training Center", "GraduationCap"],
  ["Transaction Help Center", "ClipboardList"],
  ["Support Desk", "LifeBuoy"],
  ["Recruiting SEO", "SearchCheck"],
  ["Admin Panel", "ShieldCheck"]
];

const marketingStudioPages = [
  ["Chat Marketing Assistant", "MessageSquare", "Generate complete campaign copy"],
  ["Flyer Builder", "FileText", "Build branded PDF and PNG flyers"],
  ["Quick Video Builder", "Clapperboard", "Create vertical reels or horizontal videos"],
  ["Business Card Builder", "Contact", "Create print-ready business cards"],
  ["Social Media Generator", "Megaphone", "Captions, hashtags, stories, and reels"],
  ["Email/SMS Generator", "Mail", "Email blasts and text scripts"],
  ["Saved Projects", "FolderOpen", "Reload saved marketing work"],
  ["Template Library", "LayoutTemplate", "Manage design templates"]
];

const announcementCategories = ["Training", "Compliance", "Marketing", "Operations", "Events", "Recruiting", "General"];
const supportCategories = ["Transaction/compliance", "Brokermint", "CRM", "Marketing", "Commission/CDA", "Tech support", "Listing support", "General question"];
const supportUrgencies = ["Normal", "High", "Urgent"];
const ticketStatuses = ["Open", "In Progress", "Waiting on Agent", "Closed"];
const COMMISSION_PLAN_RULES = {
  "Nex Premium": {
    label: "Nex Premium",
    shortLabel: "Premium",
    tagline: "Independent 100% Plan",
    type: "transaction-fee",
    splitLabel: "100% Commission | No Cap",
    monthlyFee: 99,
    joinFee: 0,
    fee: 595,
    luxuryThreshold: 1000000,
    luxuryCommissionRate: 0.05,
    capAmount: null,
    capDeals: null,
    powerShare: "NPS not included",
    bestFor: "Best for independent agents focused on a 100% structure"
  },
  "Nex Premium.1": {
    label: "Nex Premium.1",
    shortLabel: "Premium.1",
    tagline: "Grandfathered 100% Plan",
    type: "capped-transaction-fee",
    splitLabel: "100% Commission | $5,400 Cap",
    monthlyFee: null,
    joinFee: null,
    fee: 450,
    capAmount: 5400,
    capDeals: 12,
    grandfathered: true,
    powerShare: "NPS not included",
    bestFor: "Grandfathered plan for existing agents already assigned to Premium.1"
  },
  "Nex Level": {
    label: "Nex Level",
    shortLabel: "Level",
    tagline: "Growth Plan",
    type: "split-cap",
    splitLabel: "80/20 Split | $20,000 Cap",
    splitRate: 0.2,
    capAmount: 20000,
    monthlyFee: 0,
    joinFee: 99,
    fee: 295,
    powerShare: "Nex PowerShare eligible",
    bestFor: "Best for agents who want multiple revenue opportunities"
  },
  "Nex Elite": {
    label: "Nex Elite",
    shortLabel: "Elite",
    tagline: "Leadership & Teams",
    type: "split-cap",
    splitLabel: "90/10 Split | $18,000 Cap",
    splitRate: 0.1,
    capAmount: 18000,
    monthlyFee: 59,
    joinFee: 0,
    fee: 295,
    powerShare: "Individual-agent NPS eligible",
    teamEligibility: "Team-start eligibility subject to approval",
    bestFor: "Best for leaders, teams, and growth-focused agents"
  }
};

const commissionPlanOptions = Object.keys(COMMISSION_PLAN_RULES);
const directoryTypeOptions = ["Agent", "Staff"];
const npsTierRates = [
  { level: 1, label: "Direct Recruit", rate: 0.1 },
  { level: 2, label: "Level 2", rate: 0.05 },
  { level: 3, label: "Level 3", rate: 0.03 },
  { level: 4, label: "Level 4", rate: 0.02 },
  { level: 5, label: "Level 5", rate: 0.01 },
  { level: 6, label: "Level 6", rate: 0.005 },
  { level: 7, label: "Level 7", rate: 0.0025 }
];
const npsPerformanceRewards = [
  ["First Closed Deal with Nex", 200],
  ["Hit Annual Cap", 2000],
  ["Education Completion", 100],
  ["Promote the Company", 100],
  ["Community Leader Award", 100],
  ["Brand Ambassador Award", 300],
  ["First Listing Taken", 100],
  ["First Buyer Under Contract", 100],
  ["5 Closed Transactions", 250],
  ["10 Closed Transactions", 500],
  ["20 Closed Transactions", 1000],
  ["Perfect Compliance File Award", 50]
];
const npsRewardTypes = ["Growth Credit", "Performance Credit", "Bonus", "Adjustment", "Manual Credit"];
const npsRewardStatuses = ["Pending", "Approved", "Paid", "Held", "Removed"];
const trainingCategories = [
  "Internal Office Documents",
  "Documents and Addendas",
  "Lead Generation",
  "Working with buyers",
  "Working with Sellers",
  "Social Media",
  "Nex Level Learning"
];
const documentSections = [
  { id: "Agent Learning", label: "Agent Learning", icon: "GraduationCap", description: "Office guides, onboarding files, and agent education PDFs or graphics." },
  { id: "Buyer Marketing Docs", label: "Buyer Marketing Docs", icon: "Home", description: "Buyer guides, checklists, open house handouts, and buyer-facing assets." },
  { id: "Seller Marketing Docs", label: "Seller Marketing Docs", icon: "BadgeDollarSign", description: "Seller guides, home value assets, listing prep documents, and net-sheet handouts." },
  { id: "Recruiting Docs", label: "Recruiting Docs", icon: "UsersRound", description: "Agent attraction PDFs, recruiting images, and Nex Realty presentation material." }
];
const documentAcceptedTypes = ".pdf,.jpg,.jpeg,.png";
const documentTypeByExtension = {
  pdf: "application/pdf",
  jpg: "image/jpeg",
  jpeg: "image/jpeg",
  png: "image/png"
};
const WOLK_PREAPPROVAL_URL = "https://2668282.my1003app.com/2027707/register?time=1749573415357";
const WOLK_MORTGAGE_PARTNER = {
  name: "Matthew Wolk",
  preferredName: "Matt",
  title: "Broker, Wolk Mortgage",
  company: "Wolk Mortgage",
  email: "mwolk@wolkmortgage.com",
  phone: "608 354 8521",
  phoneHref: "tel:+16083548521",
  nmls: "2668282",
  individualNmls: "2027707",
  address: "2315 West N A St, Unit 3, Tampa, FL 33609",
  logoUrl: "/assets/wolk-mortgage.png",
  cardImageUrl: "/assets/matthew-wolk-mortgage-card.png",
  preapprovalUrl: WOLK_PREAPPROVAL_URL
};
const NEXU_URL = "https://sites.google.com/mynexrealty.com/nexu/home?authuser=2";
const agentAssistDisclaimer =
  "NIA provides Nex brokerage workflow guidance and support. Always confirm compliance, legal, MLS, and transaction-specific questions with the broker or appropriate professional.";
const agentAssistStarters = [
  "What should I do next on this file?",
  "Help me with buyer paperwork.",
  "Draft a client follow-up.",
  "Create a support ticket summary."
];

const legacyTrainingCategoryMap = {
  "Getting Started": "Nex Level Learning",
  "Buyer Process": "Working with buyers",
  "Seller Process": "Working with Sellers",
  Rentals: "Documents and Addendas",
  Contracts: "Documents and Addendas",
  Compliance: "Internal Office Documents",
  Brokermint: "Internal Office Documents",
  Marketing: "Social Media",
  Recruiting: "Nex Level Learning",
  "Advanced Agent Training": "Nex Level Learning"
};

function normalizeTrainingCategory(category) {
  const value = String(category || "").trim();
  if (!value) return trainingCategories[0];
  return legacyTrainingCategoryMap[value] || value;
}

function trainingResourceUrl(resource) {
  const url = String(resource?.url || "").trim();
  return url && url !== "#" ? url : NEXU_URL;
}

function videoTitleFromUrl(url, fallbackIndex = 1) {
  const text = String(url || "");
  try {
    const parsed = new URL(text);
    const pathname = parsed.pathname
      .split("/")
      .filter(Boolean)
      .slice(-2)
      .join(" ")
      .replace(/[-_]+/g, " ");
    return pathname ? pathname.replace(/\b\w/g, (letter) => letter.toUpperCase()) : `NexU Video ${fallbackIndex}`;
  } catch (error) {
    return `NexU Video ${fallbackIndex}`;
  }
}

function parseBulkTrainingVideoLine(line, index = 1) {
  const text = String(line || "").trim();
  if (!text) return null;
  const parts = text.split("|").map((part) => part.trim()).filter(Boolean);
  if (parts.length >= 2) {
    return { title: parts[0], url: parts.slice(1).join("|") };
  }
  return { title: videoTitleFromUrl(text, index), url: text };
}

function getTrainingEmbedUrl(url) {
  const rawUrl = String(url || "").trim();
  if (!rawUrl || rawUrl === "#") return "";
  try {
    const parsed = new URL(rawUrl);
    const host = parsed.hostname.replace(/^www\./, "").toLowerCase();

    if (host.includes("youtube.com")) {
      let id = "";
      if (parsed.pathname.startsWith("/embed/")) id = parsed.pathname.split("/embed/")[1]?.split("/")[0] || "";
      else if (parsed.pathname.startsWith("/shorts/")) id = parsed.pathname.split("/shorts/")[1]?.split("/")[0] || "";
      else id = parsed.searchParams.get("v") || "";
      return id ? `https://www.youtube.com/embed/${id}` : "";
    }

    if (host === "youtu.be") {
      const id = parsed.pathname.split("/").filter(Boolean)[0];
      return id ? `https://www.youtube.com/embed/${id}` : "";
    }

    if (host.includes("vimeo.com")) {
      const id = parsed.pathname.split("/").filter(Boolean).find((part) => /^\d+$/.test(part));
      return id ? `https://player.vimeo.com/video/${id}` : "";
    }

    if (host.includes("loom.com")) {
      const id = parsed.pathname.split("/").filter(Boolean).pop();
      return id ? `https://www.loom.com/embed/${id}` : "";
    }

    if (host.includes("synthesia.io")) {
      if (parsed.pathname.includes("/embeds/videos/")) return rawUrl;
      const id = parsed.pathname.split("/").filter(Boolean).pop();
      return id ? `https://share.synthesia.io/embeds/videos/${id}` : "";
    }

    if (host.includes("drive.google.com")) {
      const fileId = parsed.pathname.match(/\/file\/d\/([^/]+)/)?.[1] || parsed.searchParams.get("id");
      return fileId ? `https://drive.google.com/file/d/${fileId}/preview` : "";
    }

    if (host.includes("docs.google.com") && rawUrl.includes("/preview")) return rawUrl;
    if (rawUrl.includes("/embed/") || rawUrl.includes("/preview")) return rawUrl;
  } catch (error) {
    return "";
  }
  return "";
}

function isEmbeddableTrainingResource(resource) {
  return Boolean(getTrainingEmbedUrl(trainingResourceUrl(resource)));
}

const transactionGuideEnhancements = {
  "new-listing": {
    overview:
      "Use this guide when a seller is ready to list and the file needs to move from signed paperwork to clean launch. The goal is to confirm authority to market, gather accurate property information, and avoid MLS or advertising issues before anything goes public.",
    reminders: [
      "Verify the seller names, property address, listing dates, compensation terms, and signature pages before building marketing.",
      "Confirm photos, remarks, showing instructions, exclusions, HOA notes, and seller disclosures are consistent before MLS entry.",
      "Start the brokerage file early so admin has time to flag missing paperwork before launch pressure builds."
    ]
  },
  "new-buyer": {
    overview:
      "Use this when a buyer becomes active so the agent has representation, lender readiness, search criteria, and communication expectations organized before showings and offers.",
    reminders: [
      "Confirm whether buyer representation paperwork is required before showings in your market and brokerage workflow.",
      "Ask about financing, proof of funds, timing, must-haves, deal breakers, and communication preferences before touring homes.",
      "Set expectations around inspections, appraisal, financing, escrow deposits, and how quickly decisions may need to happen."
    ]
  },
  "buyer-broker-agreement": {
    overview:
      "Use this right after a buyer broker agreement is signed. The practical goal is to make sure the agreement is complete, stored, and aligned with the buyer’s active search and any future offer paperwork.",
    reminders: [
      "Check names, dates, term length, compensation language, signatures, initials, and any brokerage-required disclosures.",
      "Give the buyer a copy and explain what changes operationally now that representation is confirmed.",
      "Keep CRM notes and transaction files aligned so the agreement can be found quickly when an offer is written."
    ]
  },
  "showing-request": {
    overview:
      "Use this before scheduling a showing so access, buyer readiness, and listing instructions are handled cleanly. The goal is to avoid missed instructions, access issues, or unqualified showing activity.",
    reminders: [
      "Review showing instructions carefully, including appointment windows, lockbox/access rules, pets, alarms, and tenant notice.",
      "Confirm the buyer is available, ready, and understands any listing-specific rules before confirming the appointment.",
      "Capture feedback and next steps immediately after the showing while details are fresh."
    ]
  },
  "offer-submitted": {
    overview:
      "Use this when preparing or sending an offer package. The goal is a complete, clear, timely offer with all supporting documents and a tracked response deadline.",
    reminders: [
      "Review price, deposits, dates, contingencies, financing terms, inclusions, exclusions, and any special clauses with the buyer.",
      "Attach pre-approval or proof of funds and verify addenda are signed or initialed as required.",
      "Track the offer deadline and keep negotiation notes organized so counteroffers are handled quickly."
    ]
  },
  "under-contract": {
    overview:
      "Use this immediately after acceptance. This is the highest-risk handoff point because deadlines begin, escrow instructions matter, and the brokerage file needs to be opened or updated quickly.",
    reminders: [
      "Calendar every contract deadline immediately, then compare those dates against the signed agreement.",
      "Send the buyer a simple next-step summary covering escrow, inspections, lender items, appraisal, title, insurance, and closing.",
      "Use Transactions for buyer/seller deadline tracking and Brokermint for any official compliance file review until Nex Central replaces that workflow."
    ]
  },
  "inspection-period": {
    overview:
      "Use this during the inspection window to keep scheduling, report review, repair negotiations, and contingency timing organized.",
    reminders: [
      "Confirm the inspection deadline before recommending timelines or drafting repair requests.",
      "Encourage buyers to review findings with qualified inspectors and contractors where appropriate.",
      "Get signed written agreements for any negotiated repair, credit, or contingency change before relying on it."
    ]
  },
  "appraisal-issue": {
    overview:
      "Use this when appraisal value, appraisal timing, or lender appraisal conditions could affect the deal. The goal is to slow down, verify the contract terms, and involve the right people before changing deal language.",
    reminders: [
      "Confirm the lender’s exact issue and the contract’s appraisal or financing contingency language before advising next steps.",
      "Loop in broker support before sending sensitive negotiation language or value-related requests.",
      "Document any price change, credit, additional funds, extension, or cancellation path with signed paperwork."
    ]
  },
  "closing-process": {
    overview:
      "Use this as the file approaches closing so title, lender, buyer, seller side, brokerage, and commission details stay aligned.",
    reminders: [
      "Confirm closing date, time, location or remote process, walkthrough, utility planning, wire safety reminders, and cash-to-close review.",
      "Request CDA or commission review early enough for admin and title to process without last-minute pressure.",
      "Upload final signed documents and settlement statements after closing according to brokerage policy."
    ]
  },
  "cda-request": {
    overview:
      "Use this when a commission disbursement authorization is needed. The goal is to make sure admin has a complete file and clear commission instructions before sending anything to title.",
    reminders: [
      "Check final commission terms against the contract, amendments, broker instructions, referral agreements, and team split notes.",
      "Make sure Brokermint is complete enough for admin review before requesting the CDA.",
      "Confirm the CDA was delivered to the correct title or closing contact before closing day."
    ]
  },
  "rental-deal": {
    overview:
      "Use this for lease or rental transactions where application, lease, move-in, and commission details need to be tracked.",
    reminders: [
      "Verify available date, deposit terms, commission arrangement, lease signatures, and any property-management instructions.",
      "Keep tenant, landlord, listing side, and brokerage-required documents organized in the file.",
      "Confirm payment timing and who is responsible for sending commission or referral instructions."
    ]
  },
  "referral-deal": {
    overview:
      "Use this before and after referring a client so the referral agreement, receiving brokerage details, and commission terms are documented.",
    reminders: [
      "Get the referral agreement signed before the client is formally handed off when brokerage policy requires it.",
      "Confirm receiving agent, brokerage, license/contact details, referral percentage, payment trigger, and expiration terms.",
      "Track the client status periodically so the referral does not disappear after the introduction."
    ]
  },
  "cancellation-termination": {
    overview:
      "Use this when a deal may cancel or terminate. This is a broker-review moment because dates, deposits, releases, and contract language can have real consequences.",
    reminders: [
      "Pause before sending cancellation language and confirm the correct form/path with broker support.",
      "Review contract deadlines, contingency status, escrow/deposit handling, and signature requirements.",
      "Upload final signed documents and update file status once the cancellation or release is complete."
    ]
  }
};

const crmLeadTypes = ["Buyer", "Seller", "Renter", "Investor", "Agent Recruit", "Landlord", "Referral Partner", "Past Client", "Vendor", "Sphere", "Other"];
const crmPipelineStageMap = {
  Buyer: ["New Lead", "Attempted Contact", "Spoke", "Buyer Consultation Set", "Buyer Agreement Signed", "Showing Homes", "Offer Submitted", "Under Contract", "Closed", "Nurture", "Lost"],
  Seller: ["New Lead", "Attempted Contact", "Spoke", "Listing Appointment Set", "CMA Sent", "Listing Agreement Sent", "Listed", "Offer Received", "Under Contract", "Closed", "Nurture", "Lost"],
  Renter: ["New Lead", "Attempted Contact", "Spoke", "Showing Scheduled", "Application Sent", "Lease Signed", "Closed", "Nurture", "Lost"],
  "Agent Recruit": ["New Prospect", "Contacted", "Interested", "Discovery Call Booked", "Attended Call", "ICA Sent", "Signed ICA", "Transfer Started", "Active Agent", "Nurture", "Lost"],
  Investor: ["New Lead", "Attempted Contact", "Spoke", "Investor Criteria Set", "Deals Sent", "Offer Submitted", "Under Contract", "Closed", "Nurture", "Lost"]
};
const crmDefaultStages = Array.from(
  new Set([
    ...crmPipelineStageMap.Buyer,
    ...crmPipelineStageMap.Seller,
    ...crmPipelineStageMap.Renter,
    ...crmPipelineStageMap["Agent Recruit"],
    ...crmPipelineStageMap.Investor,
    "Connected",
    "Appointment Set",
    "Active Client",
    "Showing/Consultation",
    "Offer/Negotiation",
    "Lost/Inactive"
  ])
);
const crmTaskStatuses = ["Open", "In Progress", "Completed"];
const crmTaskPriorities = ["Normal", "High", "Urgent"];
const crmTaskTypes = ["Call", "Text", "Email", "Appointment", "CMA", "Showing", "Follow-up", "Note", "Other"];
const crmCommunicationTypes = ["Call", "Text", "Email", "Voicemail", "Appointment", "Note"];
const crmCommunicationOutcomes = ["Connected", "Left Message", "No Answer", "Replied", "Appointment Set", "Needs Follow-Up", "Not Interested"];
const crmLeadSources = ["Website", "Nex Website", "OSI IDX", "IDX Search", "Property Inquiry", "Saved Search", "Showing Request", "Home Valuation", "Agent IDX Page", "Landing Page", "Open House", "QR Code", "Facebook", "Instagram", "Google", "Zillow", "Realtor.com", "Referral", "Sphere", "Past Client", "FSBO", "Expired", "Sign Call", "Walk-In", "Manual Entry", "Imported CSV", "Brokerage Lead", "Agent Generated", "Recruiting", "Other"];
const crmTemperatureOptions = ["All", "Hot", "Warm", "Cold", "Nurture", "Dead/DNC"];
const crmContactMethods = ["Call", "Text", "Email", "Any"];
const crmConsentOptions = ["Unknown", "Opted In", "Verbal Consent", "Website Form", "Open House Form", "Do Not Contact", "Unsubscribed"];
const crmWorkingAgentOptions = ["Unknown", "No", "Yes"];
const crmPreApprovedOptions = ["Unknown", "No", "Yes"];
const crmPages = ["Dashboard", "Leads", "Contacts", "Pipeline", "Smart Lists", "Tasks", "Drips", "NIA Coach", "Import/Export", "Settings"];
const legacyCrmPageName = ["Nex", "lite", "CRM"].join(" ");
const crmDefaultTags = ["Hot Buyer", "Hot Seller", "DPA", "VA", "Investor", "Luxury", "First-Time Buyer", "New Construction", "FSBO", "Expired", "Open House", "Past Client", "Referral", "Recruiting", "Needs Financing", "Cash Buyer"];
const crmSmartPlans = [
  {
    id: "new-buyer-lead",
    name: "New Buyer Lead",
    leadTypes: ["Buyer", "Investor"],
    tasks: [
      [0, "Call immediately", "Call", "Urgent"],
      [0, "Send first buyer text", "Text", "High"],
      [1, "Follow-up call", "Call", "High"],
      [2, "Send buyer needs text", "Text", "Normal"],
      [4, "Email buyer guide", "Email", "Normal"],
      [7, "Follow-up call", "Call", "Normal"],
      [14, "Nurture check-in", "Follow-up", "Normal"],
      [30, "Reconnect and update timeline", "Follow-up", "Normal"]
    ],
    scripts: {
      text: "Hi [Name], this is [Agent] with Nex Realty. I saw you were looking around [Area]. What kind of home would make the move worth it for you?",
      email: "Subject: A simple plan for your home search\n\nHi [Name], I wanted to send a quick next-step plan so your search feels organized. If you send me your must-haves, budget range, and timeline, I can narrow the options and help you avoid wasting time."
    }
  },
  {
    id: "new-seller-lead",
    name: "New Seller Lead",
    leadTypes: ["Seller", "Past Client"],
    tasks: [
      [0, "Call immediately", "Call", "Urgent"],
      [0, "Send home value text", "Text", "High"],
      [1, "Ask property details", "Text", "High"],
      [2, "Offer CMA appointment", "Email", "Normal"],
      [5, "Seller follow-up", "Call", "Normal"],
      [10, "Send seller checklist", "Email", "Normal"],
      [30, "Send market update", "Email", "Normal"]
    ],
    scripts: {
      text: "Hi [Name], this is [Agent] with Nex Realty. I can help you get a realistic read on what your home could sell for in today's market. Want me to put together a quick value range?",
      email: "Subject: Your home value next steps\n\nHi [Name], I can help you understand pricing, prep, timing, and the most likely buyer profile for your property. The best next step is a quick property review."
    }
  },
  {
    id: "open-house-lead",
    name: "Open House Lead",
    leadTypes: ["Buyer", "Seller"],
    tasks: [
      [0, "Text open house thank-you", "Text", "High"],
      [0, "Call after open house", "Call", "High"],
      [1, "Send similar homes or seller value offer", "Email", "Normal"],
      [3, "Follow up on motivation and timeline", "Call", "Normal"],
      [7, "Invite to consult", "Follow-up", "Normal"]
    ],
    scripts: {
      text: "Hi [Name], thanks for stopping by the open house. What did you think of the home compared with what you are really looking for?",
      email: "Subject: Thanks for visiting the open house\n\nHi [Name], thanks for coming by. I can send a few similar homes or help you understand what your own home may be worth."
    }
  },
  {
    id: "agent-recruit-follow-up",
    name: "Agent Recruit Follow-Up",
    leadTypes: ["Agent Recruit"],
    tasks: [
      [0, "Send Nex opportunity text", "Text", "High"],
      [1, "Book discovery call", "Call", "High"],
      [3, "Send Nex model overview", "Email", "Normal"],
      [7, "Follow up on questions", "Call", "Normal"],
      [14, "Invite to leadership call", "Appointment", "Normal"]
    ],
    scripts: {
      text: "Hi [Name], I thought of you because Nex Realty is built for agents who want stronger systems, modern branding, and more leverage. Open to a quick conversation?",
      email: "Subject: A different brokerage model\n\nHi [Name], Nex Realty is building a modern platform for productive agents. If you are evaluating your next move, I would be happy to walk you through it."
    }
  },
  {
    id: "long-term-nurture",
    name: "Long-Term Nurture",
    leadTypes: ["Buyer", "Seller", "Renter", "Investor", "Past Client", "Sphere"],
    tasks: [
      [7, "Send helpful market check-in", "Email", "Normal"],
      [21, "Personal text check-in", "Text", "Normal"],
      [45, "Send value update", "Email", "Normal"],
      [90, "Reconnect call", "Call", "Normal"]
    ],
    scripts: {
      text: "Hi [Name], just checking in. Has anything changed with your real estate plans, timeline, or questions I can help with?",
      email: "Subject: Quick real estate check-in\n\nHi [Name], I wanted to stay in touch and be a resource when the timing is right. If anything has changed, I am happy to help."
    }
  }
];

function recommendedDripCampaignId(contact = {}) {
  const leadType = String(contact.leadType || "").toLowerCase();
  if (leadType.includes("seller")) return "default-seller-365";
  if (leadType.includes("renter")) return "default-renter-180";
  if (leadType.includes("recruit")) return "default-recruit-180";
  if (leadType.includes("past") || String(contact.stage || "").toLowerCase() === "closed") return "default-closed-365";
  return "default-buyer-365";
}

const emptyCrmContact = {
  firstName: "",
  lastName: "",
  email: "",
  phone: "",
  secondaryPhone: "",
  secondaryEmail: "",
  leadType: "Buyer",
  status: "New",
  leadSource: "",
  assignedAgentEmail: "",
  assignedAgentName: "",
  stage: "New Lead",
  preferredContactMethod: "Any",
  budgetRange: "",
  desiredArea: "",
  timeline: "",
  buyingTimeline: "",
  sellingTimeline: "",
  propertyAddress: "",
  bedrooms: "",
  bathrooms: "",
  financingStatus: "",
  preApproved: "Unknown",
  workingWithAnotherAgent: "Unknown",
  consentStatus: "Unknown",
  optInSource: "",
  doNotContact: false,
  birthday: "",
  homeAnniversary: "",
  campaignName: "",
  formName: "",
  utmSource: "",
  utmMedium: "",
  utmCampaign: "",
  referringUrl: "",
  notes: "",
  tags: "",
  lastContactedDate: "",
  nextFollowUpDate: "",
  privateLead: false
};
const buyerStatuses = ["Active", "Closing Soon", "Closed", "Cancelled"];
const buyerTaskPriorities = ["Low", "Normal", "High", "Critical"];
const buyerTrackerTabs = ["Transactions", "Create New Transaction", "Notifications"];
const buyerTrackerDisclaimer =
  "This checklist is an internal organizational tool only and does not replace the purchase contract, brokerage compliance requirements, Brokermint file review, MLS rules, lender/title deadlines, or legal advice. Agents are responsible for verifying all contract deadlines and requirements.";
const transactionTypes = ["Buyer purchase", "Seller listing", "Rental listing", "Tenant representation", "Referral", "Commercial", "Other"];
const transactionStatuses = ["Draft", "Active", "Under Contract", "Submitted for Review", "Pending Broker Review", "Needs Corrections", "Approved", "Closing Soon", "Closed", "Cancelled", "Terminated"];
const transactionTabs = ["Overview", "Workflow", "Contacts", "Dates & Deadlines", "Checklist", "Documents", "Forms", "E-Signature", "Compliance Review", "Commission", "Activity / History", "Notes"];
const transactionDocumentCategories = ["Contract", "Addenda", "Disclosures", "Listing documents", "Buyer documents", "Rental documents", "Commission documents", "EMD", "Inspection", "Appraisal", "Title", "Lender", "Closing documents", "Other"];
const transactionCreateDefaults = {
  title: "",
  propertyAddress: "",
  city: "",
  county: "",
  zip: "",
  mlsNumber: "",
  type: "Buyer purchase",
  clientName: "",
  clientEmail: "",
  clientPhone: "",
  otherPartyName: "",
  otherBrokerage: "",
  titleCompany: "",
  lender: "",
  purchasePrice: "",
  leaseAmount: "",
  commission: "3%",
  closingDate: "",
  effectiveDate: "",
  inspectionDeadline: "",
  financingDeadline: "",
  appraisalDeadline: "",
  emdDeadline: "",
  hoaDeadline: "",
  finalWalkthroughDate: "",
  notes: ""
};
const transactionFoundationDisclaimer =
  "Transactions is a Nex Central workflow foundation. Mock/internal forms are for development and organization only. Official real estate forms must be accessed through approved/licensed forms providers, and agents remain responsible for verifying deadlines, compliance, MLS, legal, lender, title, and brokerage requirements.";
const emptyBuyerTransaction = {
  transactionName: "",
  buyerName: "",
  propertyAddress: "",
  mlsNumber: "",
  effectiveDate: "",
  closingDate: "",
  inspectionPeriodEndDate: "",
  financingPeriodEndDate: "",
  appraisalDeadline: "",
  hoaDeadline: "",
  emdDueDate: "",
  finalWalkthroughDate: "",
  agentName: "",
  agentEmail: "",
  agentPhone: "",
  notes: ""
};
const productionStorageKey = "nex-production-calculator";
const productionTrackerPeriods = ["Daily", "Weekly"];
const productionActivityFields = [
  ["callsMade", "Calls Made", "Phone"],
  ["conversationsHad", "Conversations Had", "MessagesSquare"],
  ["leadsGenerated", "Leads Generated", "UserPlus"],
  ["appointmentsSet", "Appointments Set", "CalendarCheck"],
  ["buyerAgreementsSigned", "Buyer Agreements Signed", "FileSignature"],
  ["listingAgreementsSigned", "Listing Agreements Signed", "Home"],
  ["contractsWritten", "Contracts Written", "PenLine"],
  ["contractsAccepted", "Contracts Accepted", "Handshake"],
  ["closings", "Closings", "BadgeDollarSign"]
];
const productionAssumptionFields = [
  ["callToConversationRate", "Call to conversation rate"],
  ["conversationToLeadRate", "Conversation to lead rate"],
  ["leadToAppointmentRate", "Lead to appointment rate"],
  ["appointmentToSignedClientRate", "Appointment to signed client rate"],
  ["signedClientToContractRate", "Signed client to contract rate"],
  ["contractToCloseRate", "Contract to close rate"]
];
const DEFAULT_PRODUCTION_ASSUMPTIONS = {
  monthlyClosingGoal: 2,
  callToConversationRate: 0.18,
  conversationToLeadRate: 0.3,
  leadToAppointmentRate: 0.25,
  appointmentToSignedClientRate: 0.5,
  signedClientToContractRate: 0.45,
  contractToCloseRate: 0.85,
  prospectingDaysPerMonth: 22,
  prospectingDaysPerWeek: 5,
  callsPerHour: 25,
  averageSalesPrice: 400000,
  averageCommissionRate: 0.025
};
const DEFAULT_ACTIVITY = {
  callsMade: 0,
  textsSent: 0,
  emailsSent: 0,
  socialMessages: 0,
  conversationsHad: 0,
  conversations: 0,
  leadsGenerated: 0,
  leadsCreated: 0,
  appointmentsSet: 0,
  showings: 0,
  openHousesHeld: 0,
  socialPosts: 0,
  networkingEvents: 0,
  paidLeadsReceived: 0,
  followUpsCompleted: 0,
  buyerAgreementsSigned: 0,
  listingAgreementsSigned: 0,
  contractsWritten: 0,
  contractsAccepted: 0,
  closings: 0
};
const DEFAULT_GAME_PLAN_ASSUMPTIONS = {
  incomeGoal: 150000,
  averageSalesPrice: 400000,
  averageCommissionRate: 0.025,
  workingWeeksPerYear: 48,
  prospectingDaysPerWeek: 5,
  callsPerHour: 25,
  textsPerHour: 45,
  emailsPerHour: 35,
  brokerageGeneratedDealShare: 0,
  brokerageLeadFeePercent: 0.15
};
const DEFAULT_GAME_PLAN_CONVERSIONS = {
  callToConversationRate: 0.18,
  textToConversationRate: 0.12,
  emailToConversationRate: 0.06,
  socialToConversationRate: 0.1,
  sphereToConversationRate: 0.35,
  conversationToLeadRate: 0.3,
  leadToAppointmentRate: 0.25,
  appointmentToSignedClientRate: 0.5,
  signedClientToContractRate: 0.45,
  contractToCloseRate: 0.85,
  openHouseVisitors: 8,
  openHouseVisitorToLeadRate: 0.25,
  paidCostPerLead: 65
};
const DEFAULT_GAME_PLAN_CHANNEL_MIX = {
  outbound: 35,
  sphere: 30,
  openHouses: 20,
  paid: 10,
  content: 5
};

function fileToDataUrl(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve({ name: file.name, dataUrl: reader.result, type: file.type || "application/octet-stream", size: file.size || 0 });
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

function resizeImageFileToDataUrl(file, { maxSize = 720, quality = 0.82, maxDataUrlLength = 900000 } = {}) {
  if (!String(file?.type || "").startsWith("image/") || String(file?.type || "").includes("svg")) {
    return fileToDataUrl(file);
  }
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = reject;
    reader.onload = () => {
      const originalDataUrl = String(reader.result || "");
      const image = new Image();
      image.onerror = () => {
        if (originalDataUrl.length <= maxDataUrlLength) resolve({ name: file.name, dataUrl: originalDataUrl, type: file.type || "image/jpeg", size: file.size || 0 });
        else reject(new Error("Could not resize image."));
      };
      image.onload = () => {
        const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");
        const attempts = [
          [maxSize, quality],
          [560, 0.78],
          [420, 0.74],
          [320, 0.7]
        ];
        let output = originalDataUrl;
        for (const [attemptSize, attemptQuality] of attempts) {
          const scale = Math.min(1, attemptSize / Math.max(image.width || attemptSize, image.height || attemptSize));
          canvas.width = Math.max(1, Math.round((image.width || attemptSize) * scale));
          canvas.height = Math.max(1, Math.round((image.height || attemptSize) * scale));
          context.fillStyle = "#ffffff";
          context.fillRect(0, 0, canvas.width, canvas.height);
          context.drawImage(image, 0, 0, canvas.width, canvas.height);
          output = canvas.toDataURL("image/jpeg", attemptQuality);
          if (output.length <= maxDataUrlLength) break;
        }
        resolve({ name: file.name.replace(/\.[^.]+$/, ".jpg"), dataUrl: output, type: "image/jpeg", size: Math.round((output.length * 3) / 4) });
      };
      image.src = originalDataUrl;
    };
    reader.readAsDataURL(file);
  });
}

function copyToClipboard(text, setToast) {
  navigator.clipboard
    .writeText(text)
    .then(() => setToast("Copied to clipboard."))
    .catch(() => setToast("Copy failed. Select the text and copy manually."));
}

function inferDocumentMetaFromUrl(fileUrl) {
  try {
    const url = new URL(String(fileUrl || "").trim());
    if (!["http:", "https:"].includes(url.protocol)) return null;
    const pathname = decodeURIComponent(url.pathname || "");
    const rawName = pathname.split("/").filter(Boolean).pop() || "hosted-document.pdf";
    const cleanName = rawName.includes(".") ? rawName : `${rawName}.pdf`;
    const extension = cleanName.split(".").pop().toLowerCase();
    const type = documentTypeByExtension[extension];
    if (!type) return null;
    return {
      name: cleanName,
      type,
      size: 0,
      fileUrl: url.toString(),
      dataUrl: ""
    };
  } catch {
    return null;
  }
}

function crmContactName(contact) {
  if (!contact) return "Select a contact";
  return [contact.firstName, contact.lastName].filter(Boolean).join(" ").trim() || contact.email || contact.phone || "Unnamed contact";
}

function normalizeEmail(value) {
  return String(value || "").trim().toLowerCase();
}

function normalizeUserDisplayPhone(value) {
  return String(value || "").replace(/\D/g, "");
}

function getUserDedupeKeys(user = {}) {
  const stableId = user.id || user.uid || user.userId || user.docId;
  const email = normalizeEmail(user.email);
  const phone = normalizeUserDisplayPhone(user.phoneMobileE164 || user.phoneMobile || user.phone);
  const primaryKey = stableId ? `id:${stableId}` : email ? `email:${email}` : phone ? `phone:${phone}` : "";
  const keys = primaryKey ? [primaryKey] : [];
  if (stableId && email) keys.push(`email:${email}`);
  if (!email && phone && primaryKey !== `phone:${phone}`) keys.push(`phone:${phone}`);
  return Array.from(new Set(keys));
}

function getUserDedupeKey(user = {}) {
  return getUserDedupeKeys(user)[0] || "";
}

function mergeUserRecords(existing = {}, incoming = {}) {
  const merged = { ...existing };
  Object.entries(incoming || {}).forEach(([key, value]) => {
    if (Array.isArray(value)) {
      if (value.length || !Array.isArray(merged[key])) merged[key] = value;
      return;
    }
    if (value !== undefined && value !== null && value !== "") {
      merged[key] = value;
    } else if (merged[key] === undefined) {
      merged[key] = value;
    }
  });
  return merged;
}

function dedupeUsers(users = []) {
  const seen = new Map();
  const result = [];
  users.forEach((user) => {
    const keys = getUserDedupeKeys(user);
    if (!keys.length) {
      result.push(user);
      return;
    }
    const existingIndex = keys.map((key) => seen.get(key)).find((index) => index !== undefined);
    if (existingIndex !== undefined) {
      result[existingIndex] = mergeUserRecords(result[existingIndex], user);
      getUserDedupeKeys(result[existingIndex]).forEach((key) => seen.set(key, existingIndex));
      return;
    }
    const nextIndex = result.length;
    result.push(user);
    keys.forEach((key) => seen.set(key, nextIndex));
  });
  return result;
}

function sortUsersByName(users = []) {
  return [...(Array.isArray(users) ? users : [])].sort((a, b) =>
    String(a?.name || a?.email || a?.phone || "").localeCompare(String(b?.name || b?.email || b?.phone || ""))
  );
}

function uniqueSortedUsers(users = []) {
  return sortUsersByName(dedupeUsers(Array.isArray(users) ? users : []));
}

function crmTagsText(tags) {
  if (Array.isArray(tags)) return tags.join(", ");
  return tags || "";
}

function crmShortDate(value) {
  if (!value) return "Not set";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleDateString([], { month: "short", day: "numeric", year: "numeric" });
}

function crmIsDue(value) {
  if (!value) return false;
  const due = new Date(`${value}T23:59:59`);
  if (Number.isNaN(due.getTime())) return false;
  return due.getTime() < Date.now();
}

function crmIsDueToday(value) {
  const days = daysUntil(value);
  return days === 0;
}

function crmPipelineStagesForType(type, fallbackStages = crmDefaultStages) {
  const normalized = type === "Recruit" ? "Agent Recruit" : type;
  return crmPipelineStageMap[normalized] || fallbackStages || crmDefaultStages;
}

function crmLeadScore(contact, contactActivity = []) {
  if (!contact) return 0;
  let score = 0;
  const source = String(contact.leadSource || "").toLowerCase();
  const timeline = String(contact.timeline || contact.buyingTimeline || contact.sellingTimeline || "").toLowerCase();
  const tags = crmTagsText(contact.tags).toLowerCase();
  const stage = String(contact.stage || "").toLowerCase();
  const hasFastTimeline = /(0|30|60|90|asap|now|ready|this week|this month|soon)/i.test(timeline);

  if (contact.phone || contact.secondaryPhone) score += 25;
  if (hasFastTimeline) score += 20;
  if ((contact.leadType === "Seller" || contact.sellingTimeline) && contact.propertyAddress) score += 20;
  if (String(contact.preApproved || "").toLowerCase() === "yes") score += 15;
  if (contact.budgetRange) score += 15;
  if (contact.desiredArea) score += 10;
  if (source.includes("open house")) score += 10;
  if (source.includes("home value") || String(contact.campaignName || "").toLowerCase().includes("home value")) score += 10;
  if (contact.lastContactedDate || contact.firstActivityAt || contactActivity.length) score += 10;
  if (stage.includes("appointment") || stage.includes("consultation") || stage.includes("spoke")) score += 10;
  if (stage.includes("under contract")) score += 15;
  if (tags.includes("hot")) score += 12;
  if (contact.doNotContact || String(contact.consentStatus || "").toLowerCase().includes("do not")) score -= 100;
  if (stage.includes("lost") || tags.includes("unresponsive")) score -= 20;

  const activityDate = contact.lastContactedDate || contact.firstActivityAt || contact.updatedAt || contact.createdAt;
  const parsedActivityDate = activityDate ? new Date(String(activityDate).includes("T") ? activityDate : `${activityDate}T00:00:00`) : null;
  const daysSinceActivity = parsedActivityDate && !Number.isNaN(parsedActivityDate.getTime()) ? Math.max(0, Math.round((Date.now() - parsedActivityDate.getTime()) / 86400000)) : null;
  if (!contact.lastContactedDate && daysSinceActivity !== null && daysSinceActivity >= 7) score -= 10;

  return Math.max(-100, Math.min(100, Math.round(score)));
}

function crmTemperature(contact, contactActivity = []) {
  if (!contact) return "Cold";
  const score = typeof contact.leadScore === "number" ? contact.leadScore : crmLeadScore(contact, contactActivity);
  const stage = String(contact.stage || "").toLowerCase();
  if (contact.doNotContact || String(contact.consentStatus || "").toLowerCase().includes("do not") || score <= 0) return "Dead/DNC";
  if (stage.includes("nurture")) return "Nurture";
  if (score >= 70) return "Hot";
  if (score >= 40) return "Warm";
  return "Cold";
}

function crmTemperatureClass(value) {
  return String(value || "Cold").toLowerCase().replace(/[^a-z0-9]+/g, "-");
}

function crmContactActivityItems(contact, notes = [], activity = []) {
  if (!contact) return [];
  return [
    ...notes.filter((note) => note.contactId === contact.id).map((note) => ({ ...note, type: "note", title: "Note", body: note.body })),
    ...activity.filter((item) => item.contactId === contact.id)
  ].sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
}

function crmDaysSinceContact(contact, notes = [], activity = []) {
  const latest = contact?.lastContactedDate || crmContactActivityItems(contact, notes, activity)[0]?.createdAt || contact?.createdAt;
  if (!latest) return null;
  const parsed = new Date(String(latest).includes("T") ? latest : `${latest}T00:00:00`);
  if (Number.isNaN(parsed.getTime())) return null;
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  parsed.setHours(0, 0, 0, 0);
  return Math.max(0, Math.round((today.getTime() - parsed.getTime()) / 86400000));
}

function crmSpeedToLead(contact) {
  if (!contact?.createdAt) return "Not tracked";
  const first = contact.firstActivityAt || contact.lastContactedDate || "";
  if (!first) return "Not contacted";
  const created = new Date(contact.createdAt);
  const contacted = new Date(first.length <= 10 ? `${first}T12:00:00` : first);
  if (Number.isNaN(created.getTime()) || Number.isNaN(contacted.getTime())) return "Tracked";
  const minutes = Math.max(0, Math.round((contacted.getTime() - created.getTime()) / 60000));
  if (minutes <= 5) return "Under 5 min";
  if (minutes <= 15) return "Under 15 min";
  if (minutes <= 60) return "Under 1 hr";
  if (minutes <= 1440) return "Under 24 hr";
  return `${Math.round(minutes / 1440)}d`;
}

function crmSmartListDefinitions(contacts, tasks, notes, activity, permissions = {}) {
  const unassigned = (contact) => !contact.assignedAgentEmail;
  const daysSince = (contact) => crmDaysSinceContact(contact, notes, activity);
  const openTasksFor = (contact) => tasks.filter((task) => task.contactId === contact.id && task.status !== "Completed");
  return [
    { key: "new-not-contacted", label: "New leads not contacted", icon: "Zap", predicate: (contact) => /new lead|new prospect/i.test(contact.stage || "") && !contact.lastContactedDate },
    { key: "hot", label: "Hot leads", icon: "Flame", predicate: (contact) => crmTemperature(contact, crmContactActivityItems(contact, notes, activity)) === "Hot" },
    { key: "due-today", label: "Follow-up due today", icon: "CalendarClock", predicate: (contact) => openTasksFor(contact).some((task) => crmIsDueToday(task.dueDate)) || crmIsDueToday(contact.nextFollowUpDate) },
    { key: "overdue", label: "Overdue follow-ups", icon: "AlarmClock", predicate: (contact) => openTasksFor(contact).some((task) => crmIsDue(task.dueDate)) || crmIsDue(contact.nextFollowUpDate) },
    { key: "no-activity-3", label: "No activity in 3 days", icon: "Clock3", predicate: (contact) => (daysSince(contact) || 0) >= 3 },
    { key: "no-activity-7", label: "No activity in 7 days", icon: "Clock7", predicate: (contact) => (daysSince(contact) || 0) >= 7 },
    { key: "no-activity-14", label: "No activity in 14 days", icon: "CalendarX", predicate: (contact) => (daysSince(contact) || 0) >= 14 },
    { key: "buyers-90", label: "Buyers under 90-day timeline", icon: "Home", predicate: (contact) => contact.leadType === "Buyer" && /(0|30|60|90|asap|soon|ready)/i.test(`${contact.timeline} ${contact.buyingTimeline}`) },
    { key: "sellers-address", label: "Sellers with property address", icon: "MapPinned", predicate: (contact) => contact.leadType === "Seller" && Boolean(contact.propertyAddress) },
    { key: "open-house", label: "Open house leads", icon: "DoorOpen", predicate: (contact) => /open house/i.test(`${contact.leadSource} ${crmTagsText(contact.tags)}`) },
    { key: "website-form", label: "Website/form leads", icon: "Globe2", predicate: (contact) => /website|landing page|form|qr/i.test(`${contact.leadSource} ${contact.formName}`) },
    { key: "osi-idx", label: "New OSI IDX leads", icon: "SearchCheck", predicate: (contact) => /osi idx|idx search|property inquiry|saved search|showing request|agent idx/i.test(`${contact.leadSource} ${contact.formName} ${crmTagsText(contact.tags)} ${contact.notes}`) },
    { key: "sphere", label: "Sphere contacts", icon: "UsersRound", predicate: (contact) => contact.leadType === "Sphere" || /sphere/i.test(`${contact.leadSource} ${crmTagsText(contact.tags)}`) },
    { key: "past-client", label: "Past clients", icon: "HeartHandshake", predicate: (contact) => contact.leadType === "Past Client" },
    { key: "dnc", label: "DNC / do not contact", icon: "Ban", predicate: (contact) => Boolean(contact.doNotContact) || /do not|unsubscribe/i.test(contact.consentStatus || "") },
    { key: "unassigned", label: "Unassigned leads", icon: "UserRoundX", predicate: (contact) => permissions.canViewAll && unassigned(contact) },
    { key: "no-next-follow-up", label: "Leads without next follow-up", icon: "CalendarPlus", predicate: (contact) => !contact.nextFollowUpDate && openTasksFor(contact).length === 0 },
    { key: "agent-recruits", label: "Agent recruits", icon: "BadgePlus", predicate: (contact) => contact.leadType === "Agent Recruit" || contact.leadType === "Recruit" },
    { key: "broker-attention", label: "Leads needing broker attention", icon: "ShieldAlert", predicate: (contact) => /broker|urgent|compliance|issue/i.test(`${contact.notes} ${crmTagsText(contact.tags)}`) }
  ];
}

function addDays(value, days) {
  const start = value ? new Date(`${value}T00:00:00`) : new Date();
  if (Number.isNaN(start.getTime())) return "";
  start.setDate(start.getDate() + Number(days || 0));
  return start.toISOString().slice(0, 10);
}

function dateOnly(value) {
  if (!value) return "";
  const date = new Date(`${value}T00:00:00`);
  if (Number.isNaN(date.getTime())) return "";
  return date.toISOString().slice(0, 10);
}

function daysUntil(value) {
  const dateString = dateOnly(value);
  if (!dateString) return null;
  const due = new Date(`${dateString}T00:00:00`);
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  return Math.round((due.getTime() - today.getTime()) / 86400000);
}

function formatDate(value) {
  if (!value) return "Not set";
  const date = new Date(`${value}T00:00:00`);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleDateString([], { month: "short", day: "numeric", year: "numeric" });
}

function buyerTaskTone(task) {
  if (task.completed) return "complete";
  if (!task.dueDate) return "none";
  const days = daysUntil(task.dueDate);
  if (days === null) return "none";
  if (days < 0) return "overdue";
  if (days === 0) return "today";
  if (days === 1) return "tomorrow";
  if (days <= 3) return "soon";
  return "none";
}

function buyerCompletionPercent(tasks) {
  if (!tasks.length) return 0;
  return Math.round((tasks.filter((task) => task.completed).length / tasks.length) * 100);
}

function nextBuyerDeadline(tasks) {
  return tasks
    .filter((task) => !task.completed && task.dueDate)
    .sort((a, b) => new Date(`${a.dueDate}T00:00:00`) - new Date(`${b.dueDate}T00:00:00`))[0] || null;
}

function buyerOverdueCount(tasks) {
  return tasks.filter((task) => !task.completed && task.dueDate && Number(daysUntil(task.dueDate)) < 0).length;
}

function buyerDisplayStatus(transaction) {
  if (!transaction) return "Active";
  if (transaction.status === "Closed" || transaction.status === "Cancelled") return transaction.status;
  const days = daysUntil(transaction.closingDate);
  if (days !== null && days <= 7 && days >= 0) return "Closing Soon";
  return transaction.status || "Active";
}

function clampRate(value) {
  const number = Number(value);
  if (!Number.isFinite(number)) return 0.01;
  if (number > 1) return Math.min(Math.max(number / 100, 0.01), 1);
  return Math.min(Math.max(number, 0.01), 1);
}

function roundUp(value) {
  return Math.ceil(Number.isFinite(value) ? value : 0);
}

function calculateProductionPlan(input) {
  const monthlyClosings = Math.max(1, Number(input.monthlyClosingGoal) || 1);
  const contractToCloseRate = clampRate(input.contractToCloseRate);
  const signedClientToContractRate = clampRate(input.signedClientToContractRate);
  const appointmentToSignedClientRate = clampRate(input.appointmentToSignedClientRate);
  const leadToAppointmentRate = clampRate(input.leadToAppointmentRate);
  const conversationToLeadRate = clampRate(input.conversationToLeadRate);
  const callToConversationRate = clampRate(input.callToConversationRate);
  const prospectingDaysPerMonth = Math.max(1, Number(input.prospectingDaysPerMonth) || 22);
  const prospectingDaysPerWeek = Math.max(1, Number(input.prospectingDaysPerWeek) || 5);
  const callsPerHour = Math.max(1, Number(input.callsPerHour) || 25);

  const contractsNeeded = monthlyClosings / contractToCloseRate;
  const signedClientsNeeded = contractsNeeded / signedClientToContractRate;
  const appointmentsNeeded = signedClientsNeeded / appointmentToSignedClientRate;
  const leadsNeeded = appointmentsNeeded / leadToAppointmentRate;
  const conversationsNeeded = leadsNeeded / conversationToLeadRate;
  const callsNeeded = conversationsNeeded / callToConversationRate;
  const weeksPerMonth = prospectingDaysPerMonth / prospectingDaysPerWeek;
  const weeklyCallsNeeded = callsNeeded / weeksPerMonth;
  const dailyCallsNeeded = callsNeeded / prospectingDaysPerMonth;
  const dailyHoursNeeded = dailyCallsNeeded / callsPerHour;
  const averageSalesPrice = Math.max(0, Number(input.averageSalesPrice) || 0);
  const averageCommissionRate = clampRate(input.averageCommissionRate || 0.025);
  const estimatedGci = monthlyClosings * averageSalesPrice * averageCommissionRate;

  return {
    monthlyClosings: roundUp(monthlyClosings),
    contractsNeeded: roundUp(contractsNeeded),
    signedClientsNeeded: roundUp(signedClientsNeeded),
    appointmentsNeeded: roundUp(appointmentsNeeded),
    leadsNeeded: roundUp(leadsNeeded),
    conversationsNeeded: roundUp(conversationsNeeded),
    callsNeeded: roundUp(callsNeeded),
    weeklyCallsNeeded: roundUp(weeklyCallsNeeded),
    dailyCallsNeeded: roundUp(dailyCallsNeeded),
    dailyHoursNeeded: Number(dailyHoursNeeded.toFixed(1)),
    estimatedGci: Math.round(estimatedGci)
  };
}

function progressRatio(actual, goal) {
  const safeGoal = Math.max(1, Number(goal) || 1);
  return Math.min((Number(actual) || 0) / safeGoal, 1);
}

function productionPeriodMultiplier(assumptions, period) {
  return period === "Weekly" ? Math.max(1, Number(assumptions.prospectingDaysPerWeek) || 5) : 1;
}

function calculateProductionActivityGoals(required, assumptions = DEFAULT_PRODUCTION_ASSUMPTIONS, period = "Daily") {
  const prospectingDays = Math.max(1, Number(assumptions.prospectingDaysPerMonth) || 22);
  const multiplier = productionPeriodMultiplier(assumptions, period);
  return {
    callsMade: required.dailyCallsNeeded * multiplier,
    conversationsHad: (required.conversationsNeeded / prospectingDays) * multiplier,
    leadsGenerated: (required.leadsNeeded / prospectingDays) * multiplier,
    appointmentsSet: (required.appointmentsNeeded / prospectingDays) * multiplier,
    signedClients: (required.signedClientsNeeded / prospectingDays) * multiplier,
    buyerAgreementsSigned: (required.signedClientsNeeded / prospectingDays) * multiplier,
    listingAgreementsSigned: (required.signedClientsNeeded / prospectingDays) * multiplier,
    contractsWritten: (required.contractsNeeded / prospectingDays) * multiplier,
    contractsAccepted: (required.contractsNeeded / prospectingDays) * multiplier,
    closings: (required.monthlyClosings / prospectingDays) * multiplier
  };
}

function calculateAccountabilityScore(actual, required, assumptions = DEFAULT_PRODUCTION_ASSUMPTIONS, period = "Daily") {
  const goals = calculateProductionActivityGoals(required, assumptions, period);
  const callScore = progressRatio(actual.callsMade, goals.callsMade);
  const conversationScore = progressRatio(actual.conversationsHad, goals.conversationsHad);
  const leadScore = progressRatio(actual.leadsGenerated, goals.leadsGenerated);
  const appointmentScore = progressRatio(actual.appointmentsSet, goals.appointmentsSet);
  const contractScore = progressRatio(actual.contractsAccepted, goals.contractsAccepted);
  const total = callScore * 30 + conversationScore * 20 + leadScore * 15 + appointmentScore * 15 + contractScore * 20;
  return Math.round(Math.min(total, 100));
}

function getAccountabilityStatus(score) {
  if (score >= 90) return "Elite Pace";
  if (score >= 75) return "On Track";
  if (score >= 50) return "Needs Push";
  return "Off Pace";
}

function getProductionPace(actual, goal) {
  const ratio = progressRatio(actual, goal);
  if (ratio >= 1.05) return "Ahead";
  if (ratio >= 0.85) return "On Track";
  return "Behind";
}

function formatCurrency(value) {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    maximumFractionDigits: 0
  }).format(Number(value) || 0);
}

function formatPercent(decimal) {
  return `${Math.round(clampRate(decimal) * 100)}%`;
}

function formatPrecisePercent(decimal) {
  const number = Number(decimal);
  if (!Number.isFinite(number)) return "0%";
  return `${(number * 100).toFixed(number * 100 < 1 ? 2 : 1).replace(/\.0$/, "")}%`;
}

function monthsBetweenDates(startValue, endValue = new Date()) {
  const start = new Date(String(startValue || "").includes("T") ? startValue : `${startValue}T00:00:00`);
  const end = new Date(endValue);
  if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) return 0;
  let months = (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth());
  if (end.getDate() < start.getDate()) months -= 1;
  return Math.max(0, months);
}

function calculateNpsVestingPercentage(agentJoinDate, asOfDate = new Date()) {
  const monthsSinceJoin = monthsBetweenDates(agentJoinDate, asOfDate);
  if (monthsSinceJoin < 12) return 0;
  return Math.min(1, monthsSinceJoin / 36);
}

function npsUserList(currentUser, users = []) {
  const byEmail = new Map();
  [currentUser, ...users].filter(Boolean).forEach((user) => {
    const email = normalizeEmail(user.email);
    if (!email) return;
    byEmail.set(email, {
      ...user,
      email,
      npsJoinDate: user.npsJoinDate || user.anniversaryDate || "",
      npsEligible: user.npsEligible !== false,
      licenseActive: user.licenseActive !== false,
      sponsorEmail: normalizeEmail(user.sponsorEmail || user.sponsorAgentEmail)
    });
  });
  return Array.from(byEmail.values()).sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email));
}

function npsFindUser(users, email) {
  const normalized = normalizeEmail(email);
  return users.find((user) => normalizeEmail(user.email) === normalized) || null;
}

function getNpsSponsorChain(closingAgentEmail, users = []) {
  const chain = [];
  let current = npsFindUser(users, closingAgentEmail);
  const visited = new Set([normalizeEmail(closingAgentEmail)]);
  for (const tier of npsTierRates) {
    const sponsorEmail = normalizeEmail(current?.sponsorEmail || current?.sponsorAgentEmail);
    if (!sponsorEmail || visited.has(sponsorEmail)) break;
    const sponsor = npsFindUser(users, sponsorEmail);
    if (!sponsor) break;
    chain.push({
      ...tier,
      recipient: sponsor,
      directDownline: current
    });
    visited.add(sponsorEmail);
    current = sponsor;
  }
  return chain;
}

function getNpsDirectRecruits(agentEmail, users = []) {
  const normalized = normalizeEmail(agentEmail);
  return users
    .filter((user) => normalizeEmail(user.sponsorEmail || user.sponsorAgentEmail) === normalized)
    .sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email));
}

function npsPlanAllowsParticipation(user = {}) {
  const plan = normalizeCommissionPlanName(user.commissionPlan);
  return plan === "Nex Level" || plan === "Nex Elite";
}

function npsEligibilityStatusText(user = {}) {
  if (user.active === false) return "Inactive";
  if (user.licenseActive === false) return "License inactive";
  if (!npsPlanAllowsParticipation(user)) return "Nex commission plan not eligible";
  if (user.npsEligible === false) return "Admin marked not eligible";
  return "Eligible";
}

function estimateEligibleCompanyRevenue(transaction, commission = {}, closingAgent = {}) {
  const grossCommission = Number(commission.grossCommission || 0) || estimateTransactionGci(transaction, 0.03);
  const plan = normalizeCommissionPlanName(transaction?.commissionPlan || closingAgent?.commissionPlan || "");
  if (plan === "Nex Level") return Math.round(grossCommission * 0.2);
  if (plan === "Nex Elite") return Math.round(grossCommission * 0.1);
  if (plan === "Nex Premium" || plan === "Nex Premium.1") return 0;
  const brokerageFee = Number(commission.brokerageFee || 0) || 0;
  const transactionFee = Number(commission.transactionFee || 0) || 0;
  return Math.max(0, Math.round(brokerageFee + transactionFee || grossCommission * 0.12));
}

function calculateNpsRows({ closingAgentEmail, eligibleCompanyRevenue, closeDate, users }) {
  const chain = getNpsSponsorChain(closingAgentEmail, users);
  return chain.map((tier) => {
    const joinDate = tier.recipient?.npsJoinDate || tier.recipient?.anniversaryDate || "";
    const vestedPercentage = calculateNpsVestingPercentage(joinDate, closeDate || new Date());
    const isEligible = tier.recipient?.active !== false && tier.recipient?.npsEligible !== false && tier.recipient?.licenseActive !== false && npsPlanAllowsParticipation(tier.recipient);
    const grossReward = isEligible ? Number(eligibleCompanyRevenue || 0) * tier.rate : 0;
    const vestedAmount = grossReward * vestedPercentage;
    return {
      ...tier,
      isEligible,
      monthsSinceJoin: monthsBetweenDates(joinDate, closeDate || new Date()),
      vestedPercentage,
      grossReward,
      vestedAmount,
      unvestedAmount: grossReward - vestedAmount,
      status: !isEligible ? "Not Eligible" : vestedPercentage === 0 ? "Earned - Unvested" : vestedPercentage < 1 ? "Vested - Pending Approval" : "Fully Vested"
    };
  });
}

function calculateNpsRewardSummaryForAgent(agent, users = [], transactions = [], commissions = []) {
  const agentEmail = normalizeEmail(agent?.email);
  const allUsers = npsUserList(agent, users);
  const commissionByTransaction = new Map((commissions || []).map((commission) => [commission.transactionId, commission]));
  const rows = [];
  for (const transaction of transactions || []) {
    if (["Cancelled", "Terminated"].includes(transaction.status)) continue;
    const closingAgentEmail = normalizeEmail(transaction.assignedAgentEmail || transaction.createdByEmail);
    const closingAgent = npsFindUser(allUsers, closingAgentEmail);
    const eligibleCompanyRevenue = estimateEligibleCompanyRevenue(transaction, commissionByTransaction.get(transaction.id), closingAgent);
    const closeDate = transaction.closingDate || transaction.updatedAt || new Date();
    const rewardRow = calculateNpsRows({ closingAgentEmail, eligibleCompanyRevenue, closeDate, users: allUsers }).find((row) => normalizeEmail(row.recipient?.email) === agentEmail);
    if (rewardRow) rows.push({ ...rewardRow, transaction });
  }
  const gross = rows.reduce((sum, row) => sum + row.grossReward, 0);
  const vested = rows.reduce((sum, row) => sum + row.vestedAmount, 0);
  const directRecruits = allUsers.filter((user) => normalizeEmail(user.sponsorEmail) === agentEmail);
  return {
    rows,
    gross,
    vested,
    unvested: gross - vested,
    directRecruits,
    directRecruitCount: directRecruits.length
  };
}

function npsRewardIsActive(reward) {
  return !["Removed"].includes(reward.status);
}

function calculatePostedNpsRewardSummary(agent, rewards = []) {
  const agentEmail = normalizeEmail(agent?.email);
  const rows = (rewards || []).filter((reward) => normalizeEmail(reward.recipientEmail) === agentEmail && npsRewardIsActive(reward));
  const paid = rows.filter((reward) => reward.status === "Paid").reduce((sum, reward) => sum + Number(reward.amount || 0), 0);
  const approved = rows.filter((reward) => reward.status === "Approved").reduce((sum, reward) => sum + Number(reward.amount || 0), 0);
  const pending = rows.filter((reward) => reward.status === "Pending").reduce((sum, reward) => sum + Number(reward.amount || 0), 0);
  const held = rows.filter((reward) => reward.status === "Held").reduce((sum, reward) => sum + Number(reward.amount || 0), 0);
  return {
    rows,
    total: rows.reduce((sum, reward) => sum + Number(reward.amount || 0), 0),
    paid,
    approved,
    pending,
    held
  };
}

function defaultNpsRewardDraft(agentEmail = "") {
  return {
    recipientEmail: normalizeEmail(agentEmail),
    sourceAgentEmail: "",
    rewardType: "Growth Credit",
    tierLevel: 1,
    title: "PowerShare Reward",
    amount: "",
    status: "Pending",
    transactionName: "",
    earnedDate: new Date().toISOString().slice(0, 10),
    notes: ""
  };
}

function numericInput(value, fallback = 0) {
  const number = Number(String(value ?? "").replace(/[^0-9.-]/g, ""));
  return Number.isFinite(number) ? number : fallback;
}

function dollars(value) {
  return formatCurrency(Math.round(Number(value) || 0));
}

function floridaStampTax(amount, ratePerHundred) {
  const base = Math.max(0, Number(amount) || 0);
  return Math.ceil(base / 100) * ratePerHundred;
}

function calculateMortgagePayment({ price, downPaymentPercent, interestRate, termYears, annualTaxes, annualInsurance, monthlyHoa, monthlyPmi }) {
  const purchasePrice = Math.max(0, Number(price) || 0);
  const downPayment = purchasePrice * (Math.max(0, Number(downPaymentPercent) || 0) / 100);
  const principal = Math.max(0, purchasePrice - downPayment);
  const monthlyRate = Math.max(0, Number(interestRate) || 0) / 100 / 12;
  const payments = Math.max(1, Number(termYears) || 30) * 12;
  const principalAndInterest = monthlyRate
    ? principal * (monthlyRate * Math.pow(1 + monthlyRate, payments)) / (Math.pow(1 + monthlyRate, payments) - 1)
    : principal / payments;
  const taxes = Math.max(0, Number(annualTaxes) || 0) / 12;
  const insurance = Math.max(0, Number(annualInsurance) || 0) / 12;
  const hoa = Math.max(0, Number(monthlyHoa) || 0);
  const pmi = Math.max(0, Number(monthlyPmi) || 0);
  return {
    purchasePrice,
    downPayment,
    loanAmount: principal,
    principalAndInterest,
    taxes,
    insurance,
    hoa,
    pmi,
    totalMonthlyPayment: principalAndInterest + taxes + insurance + hoa + pmi
  };
}

function calculateBuyerClosingCosts(input) {
  const price = Math.max(0, Number(input.price) || 0);
  const loanAmount = Math.max(0, Number(input.loanAmount) || 0);
  const lenderFees = Math.max(0, Number(input.lenderFees) || 0);
  const titleSettlement = Math.max(0, Number(input.titleSettlement) || 0);
  const appraisal = Math.max(0, Number(input.appraisal) || 0);
  const inspection = Math.max(0, Number(input.inspection) || 0);
  const recording = Math.max(0, Number(input.recording) || 0);
  const prepaidEscrow = Math.max(0, Number(input.prepaidEscrow) || 0);
  const survey = Math.max(0, Number(input.survey) || 0);
  const other = Math.max(0, Number(input.other) || 0);
  const mortgageDocStamps = floridaStampTax(loanAmount, 0.35);
  const intangibleTax = loanAmount * 0.002;
  const estimatedTotal = lenderFees + titleSettlement + appraisal + inspection + recording + prepaidEscrow + survey + other + mortgageDocStamps + intangibleTax;
  return { price, loanAmount, lenderFees, titleSettlement, appraisal, inspection, recording, prepaidEscrow, survey, other, mortgageDocStamps, intangibleTax, estimatedTotal };
}

function calculateSellerNet(input) {
  const price = Math.max(0, Number(input.price) || 0);
  const commissionRate = Math.max(0, Number(input.commissionRate) || 0) / 100;
  const payoff = Math.max(0, Number(input.payoff) || 0);
  const sellerCredits = Math.max(0, Number(input.sellerCredits) || 0);
  const repairs = Math.max(0, Number(input.repairs) || 0);
  const titleSettlement = Math.max(0, Number(input.titleSettlement) || 0);
  const hoaEstoppel = Math.max(0, Number(input.hoaEstoppel) || 0);
  const other = Math.max(0, Number(input.other) || 0);
  const countyRate = input.countyMode === "Miami-Dade Single-Family" ? 0.6 : 0.7;
  const deedDocStamps = floridaStampTax(price, countyRate);
  const commission = price * commissionRate;
  const totalCosts = payoff + sellerCredits + repairs + titleSettlement + hoaEstoppel + other + deedDocStamps + commission;
  return { price, payoff, sellerCredits, repairs, titleSettlement, hoaEstoppel, other, deedDocStamps, commission, totalCosts, estimatedNet: price - totalCosts };
}

const CALCULATOR_ESTIMATE_DISCLAIMER = "This calculator is an estimate for planning and discussion only. Do not rely on it as a final quote, closing statement, loan estimate, tax calculation, legal advice, or financial advice. Actual figures can vary by lender, title company, contract terms, taxes, insurance, HOA, credits, repairs, loan program, rate lock, points, and market conditions. Buyers and sellers should consult the lender, title company, attorney, CPA/tax professional, insurance provider, HOA, and brokerage support as needed before making decisions.";

function calculatorAgentInfo(user = {}) {
  return {
    name: user.name || user.fullName || "Nex Realty Agent",
    email: user.email || "",
    phone: user.phone || user.phoneMobile || user.phone_mobile || "",
    market: user.market || user.region || user.primaryMarketArea || user.city || "Nex Realty",
    license: user.licenseNumber || user.license || "",
    headshotUrl: user.headshotUrl || user.avatarUrl || ""
  };
}

function calculatorSafeImageUrl(src) {
  const value = String(src || "").trim();
  if (!value) return "";
  if (/^data:image\//i.test(value) || value.startsWith("/")) return value;
  if (typeof window !== "undefined" && value.startsWith(window.location.origin)) return value;
  return "";
}

function productionPercentInputValue(value, precision = 0) {
  if (value === "") return "";
  return Number((clampRate(value) * 100).toFixed(precision));
}

function csvEscape(value) {
  const text = Array.isArray(value) ? value.join(", ") : String(value || "");
  if (/[",\n]/.test(text)) return `"${text.replace(/"/g, '""')}"`;
  return text;
}

function parseCsvRows(csvText) {
  const rows = [];
  let current = "";
  let row = [];
  let inQuotes = false;
  const text = String(csvText || "").replace(/\r\n/g, "\n");
  for (let index = 0; index < text.length; index += 1) {
    const char = text[index];
    const next = text[index + 1];
    if (char === '"' && inQuotes && next === '"') {
      current += '"';
      index += 1;
    } else if (char === '"') {
      inQuotes = !inQuotes;
    } else if (char === "," && !inQuotes) {
      row.push(current);
      current = "";
    } else if (char === "\n" && !inQuotes) {
      row.push(current);
      rows.push(row);
      row = [];
      current = "";
    } else {
      current += char;
    }
  }
  if (current || row.length) {
    row.push(current);
    rows.push(row);
  }
  return rows.filter((line) => line.some((cell) => String(cell || "").trim()));
}

function crmContactFromCsvRow(headers, row) {
  const map = {};
  headers.forEach((header, index) => {
    const key = String(header || "").trim().toLowerCase().replace(/[\s_-]+/g, "");
    map[key] = row[index] || "";
  });
  return {
    firstName: map.firstname || map.first || "",
    lastName: map.lastname || map.last || "",
    email: map.email || "",
    phone: map.phone || "",
    secondaryEmail: map.secondaryemail || "",
    secondaryPhone: map.secondaryphone || "",
    leadType: crmLeadTypes.includes(map.leadtype) ? map.leadtype : "Other",
    leadSource: map.leadsource || map.source || "",
    status: map.status || "",
    assignedAgentEmail: map.assignedagentemail || map.assignedagent || "",
    stage: map.stage || map.status || "New Lead",
    budgetRange: map.budgetrange || map.price || map.pricerange || "",
    desiredArea: map.desiredarea || map.area || "",
    timeline: map.timeline || "",
    buyingTimeline: map.buyingtimeline || "",
    sellingTimeline: map.sellingtimeline || "",
    propertyAddress: map.propertyaddress || map.address || "",
    bedrooms: map.bedrooms || map.beds || "",
    bathrooms: map.bathrooms || map.baths || "",
    financingStatus: map.financingstatus || "",
    preApproved: map.preapproved || "",
    workingWithAnotherAgent: map.workingwithanotheragent || "",
    consentStatus: map.consentstatus || "",
    doNotContact: /^(true|yes|1)$/i.test(map.donotcontact || map.dnc || ""),
    campaignName: map.campaignname || "",
    formName: map.formname || "",
    utmSource: map.utmsource || "",
    utmMedium: map.utmmedium || "",
    utmCampaign: map.utmcampaign || "",
    referringUrl: map.referringurl || "",
    notes: map.notes || "",
    tags: map.tags || "",
    lastContactedDate: map.lastcontacteddate || "",
    nextFollowUpDate: map.nextfollowupdate || ""
  };
}

function fallbackGenerate({ fields, brandSettings, prompt }) {
  const brand = brandSettings || localDefaultBrand;
  const marketingType = fields.marketingType || "Just Listed";
  const headline = marketingType.toUpperCase();
  const price = money(fields.price);
  const address = fields.propertyAddress || "the featured property";
  const location = [fields.city, fields.state].filter(Boolean).join(", ");
  const cta = fields.cta || "Schedule your tour today";
  const isRecruiting = marketingType.toLowerCase().includes("recruit");
  const primary = isRecruiting
    ? `${brand.companyName} is built for modern agents who want bold branding, a cleaner cloud-based brokerage model, and the support to grow with confidence.`
    : `${headline}: ${address}${location ? ` in ${location}` : ""}${price ? ` is offered at ${price}` : ""}. ${fields.propertyHighlights || fields.mlsRemarks || "Designed for strong market attention and a polished first impression."} ${cta}.`;
  return {
    id: crypto.randomUUID ? crypto.randomUUID() : String(Date.now()),
    createdAt: new Date().toISOString(),
    marketingType,
    platform: fields.platform,
    tone: fields.tone,
    complianceReminder:
      "Please review all marketing for MLS, brokerage, Fair Housing, advertising, and local/state compliance before publishing.",
    suggestedHeadline: headline,
    suggestedCTA: cta,
    primary,
    shortVersion: `${headline}. ${cta}.`,
    longVersion: `${primary} Contact ${fields.agentName || "your Nex Realty agent"} for details.`,
    flyerReadyCopy: `${fields.propertyHighlights || "Premium Nex Realty marketing for this opportunity."}`,
    emailVersion: `Subject: ${headline}: ${address}\n\n${primary}\n\n${cta}.`,
    smsVersion: `${headline}: ${address}${price ? ` at ${price}` : ""}. ${cta}. Reply for details.`,
    hashtags: ["#NexRealty", "#RealEstate", "#HomeMarketing", "#JustListed"],
    missingSuggestions: prompt ? [] : ["chat request"],
    footerDisclaimer: isRecruiting ? brand.recruitingDisclaimer : brand.defaultDisclaimer
  };
}

function logoSource(brand, variant = "light") {
  if (variant === "dark") {
    return brand.logoWhiteDataUrl || brand.logoWhiteUrl || defaultLogoWhiteUrl;
  }
  return brand.logoBlackDataUrl || brand.logoDataUrl || brand.logoBlackUrl || defaultLogoBlackUrl;
}

function Wordmark({ brand, compact = false, variant = "light", className = "" }) {
  const source = logoSource(brand, variant);
  if (source) {
    return (
      <img
        src={source}
        alt={`${brand.companyName} logo`}
        className={classNames("brand-logo", compact && "brand-logo-compact", variant === "dark" && "brand-logo-white", className)}
        draggable="false"
        decoding="async"
      />
    );
  }
  return (
    <div className={classNames("wordmark", compact && "wordmark-compact")}>
      <span>NEX</span>
      <strong>REALTY</strong>
    </div>
  );
}

function userHeadshotSource(user) {
  return user?.headshotUrl || user?.avatarUrl || defaultLogoBlackUrl;
}

function UserAvatar({ user, size = "md", className = "" }) {
  const label = user?.name || user?.email || "Nex Realty";
  return (
    <span className={classNames("user-avatar", `user-avatar-${size}`, className)}>
      <img src={userHeadshotSource(user)} alt={label} />
    </span>
  );
}

function Sidebar({ activePage, setActivePage, currentUser, onLogout, brand, chatUnreadTotal = 0 }) {
  const role = currentUser?.role || "Agent";
  const adminOnlyPages = new Set(["Admin Panel", "Recruiting SEO", "Agent Intelligence"]);
  const pages = portalPages.filter(([page]) => !adminOnlyPages.has(page) || isAdminRole(role));
  const isMarketingActive = ["Marketing Studio", ...marketingStudioPages.map(([page]) => page)].includes(activePage);

  return (
    <aside className="sidebar">
      <div className="brand-lockup">
        <Wordmark brand={brand} variant="dark" className="platform-logo" />
        <p>{APP_NAME}</p>
      </div>

      <nav className="nav-list" aria-label="Main navigation">
        {pages.map(([page, icon]) => (
          <button
            key={page}
            className={classNames("nav-item", (activePage === page || (page === "Marketing Studio" && isMarketingActive)) && "active")}
            onClick={() => setActivePage(page)}
            title={page}
          >
            <Icon name={icon} size={17} />
            <span>{page}</span>
            {page === "Nex Chat" && chatUnreadTotal > 0 && <em className="nav-unread-badge">{chatUnreadTotal > 99 ? "99+" : chatUnreadTotal}</em>}
          </button>
        ))}
      </nav>

      <div className="role-card">
        <p className="text-xs uppercase tracking-[0.16em] text-white/45">Signed in</p>
        <div className="signed-in-card">
          <UserAvatar user={currentUser} size="sm" />
          <div>
            <strong>{currentUser?.name || currentUser?.email || "Nex Realty user"}</strong>
            <span>{role}</span>
          </div>
        </div>
        <p className="mt-3 text-xs leading-5 text-white/55">{currentUser?.email}</p>
        <button className="logout-btn" onClick={onLogout}>
          <Icon name="LogOut" size={15} />
          <span>Sign Out</span>
        </button>
      </div>
    </aside>
  );
}

function NotificationBell({ notifications = [], onOpenNotifications }) {
  const unread = notifications.filter((notification) => !notification.read).length;
  return (
    <button
      className={classNames("notification-bell", unread > 0 && "has-unread")}
      onClick={onOpenNotifications}
      title="Open notifications"
      aria-label={unread ? `Open notifications, ${unread} unread` : "Open notifications"}
      type="button"
    >
      <span className="notification-bell-icon">
        <Icon name={unread ? "BellRing" : "Bell"} />
        {unread > 0 && <em>{unread > 9 ? "9+" : unread}</em>}
      </span>
      <span className="notification-bell-label">Notifications</span>
    </button>
  );
}

function Header({ activePage, onGenerate, onSaveProject, isGenerating, isMarketingPage, canInstall, onInstall, notifications = [], onOpenNotifications, onRefreshApp, updateAvailable = false }) {
  const hasHeaderActions = canInstall || Boolean(onOpenNotifications) || Boolean(onRefreshApp);
  return (
    <header className="topbar">
      <div>
        <p className="eyebrow">{APP_NAME}</p>
        <h2>{activePage}</h2>
      </div>
      {hasHeaderActions && (
        <div className="topbar-actions">
          {onOpenNotifications && <NotificationBell notifications={notifications} onOpenNotifications={onOpenNotifications} />}
          {onRefreshApp && (
            <button className={classNames("btn secondary app-refresh-btn", updateAvailable && "update-ready")} onClick={onRefreshApp} title="Refresh Nex Central to the newest version">
              <Icon name={updateAvailable ? "RefreshCcw" : "RefreshCw"} />
              <span>{updateAvailable ? "Update app" : "Refresh app"}</span>
            </button>
          )}
          {canInstall && (
            <button className="btn secondary install-app-btn" onClick={onInstall}>
              <Icon name="Smartphone" />
              <span>Install App</span>
            </button>
          )}
        </div>
      )}
    </header>
  );
}

function StatCard({ icon, label, value, tone = "dark" }) {
  return (
    <div className={classNames("stat-card", tone)}>
      <Icon name={icon} size={20} />
      <div>
        <p>{label}</p>
        <strong>{value}</strong>
      </div>
    </div>
  );
}

function dashboardStorageJson(key, fallback) {
  try {
    const saved = localStorage.getItem(key);
    return saved ? JSON.parse(saved) : fallback;
  } catch {
    return fallback;
  }
}

function dashboardDate(value) {
  if (!value) return "";
  const date = new Date(String(value).includes("T") ? value : `${value}T00:00:00`);
  return Number.isNaN(date.getTime()) ? "" : date.toISOString().slice(0, 10);
}

function dashboardCurrentYear(value) {
  const date = dashboardDate(value);
  return Boolean(date && new Date(`${date}T00:00:00`).getFullYear() === new Date().getFullYear());
}

function dashboardMoney(value) {
  return formatCurrency(Math.round(Number(value) || 0));
}

function estimateTransactionGci(transaction, averageCommissionRate = 0.025) {
  const price = Number(transaction?.purchasePrice || transaction?.contractPrice || transaction?.leaseAmount || 0) || 0;
  const commissionValue = numericInput(transaction?.commission, 0);
  if (commissionValue > 0 && commissionValue <= 10 && price) return price * (commissionValue / 100);
  if (commissionValue > 100) return commissionValue;
  return price * clampRate(averageCommissionRate || 0.025);
}

function dashboardDeadlineTone(days) {
  if (days === null) return "later";
  if (days < 0) return "overdue";
  if (days === 0) return "today";
  if (days <= 3) return "soon";
  if (days <= 7) return "upcoming";
  return "later";
}

function dashboardDeadlineLabel(days) {
  if (days === null) return "No date";
  if (days < 0) return `${Math.abs(days)}d overdue`;
  if (days === 0) return "Due today";
  if (days === 1) return "Due tomorrow";
  return `${days} days`;
}

function dashboardDeadlinePriority(days) {
  if (days === null) return 9;
  if (days < 0) return 0;
  if (days === 0) return 1;
  if (days <= 3) return 2;
  if (days <= 7) return 3;
  return 4;
}

function AgentSuccessStat({ label, value, detail, icon, tone = "dark" }) {
  return (
    <article className={classNames("success-stat", tone)}>
      <span><Icon name={icon} size={18} /></span>
      <div>
        <strong>{value}</strong>
        <p>{label}</p>
        {detail && <em>{detail}</em>}
      </div>
    </article>
  );
}

function AgentSuccessWidget({ id, title, eyebrow, action, minimized, onToggle, onOpen = null, children, className = "" }) {
  function handleOpen(event) {
    if (!onOpen) return;
    if (event.target.closest("button, a, input, select, textarea")) return;
    onOpen();
  }

  function handleKeyDown(event) {
    if (!onOpen) return;
    if (event.key !== "Enter" && event.key !== " ") return;
    if (event.target.closest("button, a, input, select, textarea")) return;
    event.preventDefault();
    onOpen();
  }

  return (
    <article
      className={classNames("success-widget", className, minimized && "is-minimized", onOpen && "is-clickable")}
      onClick={handleOpen}
      onKeyDown={handleKeyDown}
      tabIndex={onOpen ? 0 : undefined}
    >
      <div className="success-widget-head">
        <div>
          <p className="eyebrow">{eyebrow}</p>
          <h2>{title}</h2>
        </div>
        <div className="success-widget-actions">
          {action}
          <button className="icon-btn small" onClick={() => onToggle(id)} title={minimized ? "Expand card" : "Minimize card"}>
            <Icon name={minimized ? "Maximize2" : "Minimize2"} size={15} />
          </button>
        </div>
      </div>
      {!minimized && children}
    </article>
  );
}

function Dashboard({ projects, templates, announcements, quickLinks, trainingResources, documents = [], tickets, currentUser, users = [], latestChat, chatUnreadTotal = 0, buyerNotifications = [], setActivePage, setBuyerTrackerStartView, setSelectedTemplateId, setFields, brand, openQuickLink }) {
  const displayName = currentUser?.name || currentUser?.email?.split("@")[0] || "Nex Agent";
  const userEmail = normalizeEmail(currentUser?.email);
  const todayKey = new Date().toISOString().slice(0, 10);
  const productionKey = `${productionStorageKey}:${currentUser?.email || "local"}`;
  const preferencesKey = `nex-success-dashboard-preferences:${currentUser?.email || "local"}`;
  const dismissedMessageKey = `nex-success-dashboard-chat-dismissed:${currentUser?.email || "local"}:${todayKey}`;
  const [dashboardData, setDashboardData] = useState({ loading: true, crm: null, transactions: null, buyer: null, production: null, launchpad: null });
  const [minimizedWidgets, setMinimizedWidgets] = useState(() => dashboardStorageJson(preferencesKey, {}));
  const [messageDismissed, setMessageDismissed] = useState(() => localStorage.getItem(dismissedMessageKey) === "true");

  useEffect(() => {
    let mounted = true;
    Promise.all([
      API.request("/api/crm/bootstrap").catch(() => null),
      API.request("/api/transactions/bootstrap").catch(() => null),
      API.request("/api/buyer-tracker/bootstrap").catch(() => null),
      API.request("/api/production/bootstrap").catch(() => null),
      API.request("/api/launchpad/bootstrap").catch(() => null)
    ]).then(([crm, transactions, buyer, production, launchpad]) => {
      if (!mounted) return;
      setDashboardData({ loading: false, crm, transactions, buyer, production, launchpad });
    });
    return () => {
      mounted = false;
    };
  }, [userEmail]);

  useEffect(() => {
    localStorage.setItem(preferencesKey, JSON.stringify(minimizedWidgets));
  }, [minimizedWidgets, preferencesKey]);

  useEffect(() => {
    if (Number(chatUnreadTotal || 0) > 0) setMessageDismissed(localStorage.getItem(dismissedMessageKey) === "true");
    else setMessageDismissed(false);
  }, [chatUnreadTotal, dismissedMessageKey]);

  function toggleWidget(id) {
    setMinimizedWidgets((current) => ({ ...current, [id]: !current[id] }));
  }

  function dismissMessages() {
    localStorage.setItem(dismissedMessageKey, "true");
    setMessageDismissed(true);
  }

  function openTemplate(template) {
    if (!template) return;
    setSelectedTemplateId(template.id);
    setFields((current) => ({
      ...current,
      marketingType: template.name,
      platform: template.category === "Agent Marketing" || template.category === "Recruiting" ? "Instagram" : current.platform
    }));
    setActivePage("Marketing Studio");
  }

  const productionSaved = dashboardStorageJson(productionKey, {});
  const backendProductionPlan = dashboardData.production?.activePlan || null;
  const backendCalculatedPlan = backendProductionPlan?.calculatedPlan || null;
  const productionAssumptions = backendCalculatedPlan?.assumptions || { ...DEFAULT_PRODUCTION_ASSUMPTIONS, ...(productionSaved.assumptions || {}) };
  const productionActivity = { ...DEFAULT_ACTIVITY, ...(productionSaved.activity || {}) };
  const fallbackProductionPlan = calculateProductionPlan(productionAssumptions);
  const productionPlan = backendCalculatedPlan || fallbackProductionPlan;
  const annualClosingGoal = backendCalculatedPlan?.annualTargets?.requiredClosings || Math.max(1, Number(productionAssumptions.monthlyClosingGoal || 1) * 12);
  const annualVolumeGoal = backendCalculatedPlan?.annualTargets?.requiredVolume || annualClosingGoal * (Number(productionAssumptions.averageSalesPrice || 0) || 0);
  const averageCommissionRate = clampRate(productionAssumptions.averageCommissionRate || 0.025);

  const contacts = dashboardData.crm?.contacts || [];
  const contactTasks = dashboardData.crm?.tasks || [];
  const crmActivity = dashboardData.crm?.activity || [];
  const transactions = dashboardData.transactions?.transactions || [];
  const transactionCommissions = dashboardData.transactions?.commissions || [];
  const transactionActivity = dashboardData.transactions?.activity || [];
  const buyerTransactions = dashboardData.buyer?.transactions || [];
  const buyerTasks = dashboardData.buyer?.tasks || [];
  const launchPadSummary = dashboardData.launchpad?.summary || {};
  const launchPadResumeTarget = dashboardData.launchpad?.resumeTarget || {};
  const launchPadPercent = Math.max(0, Math.min(100, Number(launchPadSummary.percent || 0)));
  const launchPadComplete = launchPadSummary.status === "Completed" || launchPadPercent >= 100;
  const launchPadNextTitle = launchPadResumeTarget.lessonTitle || (launchPadComplete ? "LaunchPad certified" : "Start Day 1");
  const launchPadNextRequirement = launchPadResumeTarget.requirementLabel || (launchPadComplete ? "Certificate ready in Nex Central." : "Open your first required lesson.");
  const unreadChatCount = Number(chatUnreadTotal || 0);
  const latestChatPreview = latestChat?.text || (latestChat?.attachments?.length ? `${latestChat.attachments.length} attachment${latestChat.attachments.length === 1 ? "" : "s"}` : "");

  const activeTransactions = transactions.filter((transaction) => !["Closed", "Cancelled", "Terminated"].includes(transaction.status));
  const closedTransactions = transactions.filter((transaction) => transaction.status === "Closed" && dashboardCurrentYear(transaction.closingDate || transaction.updatedAt));
  const pendingTransactions = transactions.filter((transaction) => /under contract|pending|submitted/i.test(`${transaction.status} ${transaction.complianceStatus}`));
  const listings = transactions.filter((transaction) => /seller|listing/i.test(transaction.type) && !["Closed", "Cancelled", "Terminated"].includes(transaction.status));
  const rentalFiles = transactions.filter((transaction) => /rental|tenant/i.test(transaction.type) && !["Closed", "Cancelled", "Terminated"].includes(transaction.status));
  const activeBuyers = contacts.filter((contact) => contact.leadType === "Buyer" && !/closed|lost|inactive/i.test(contact.stage || contact.status || ""));
  const activeSellers = contacts.filter((contact) => contact.leadType === "Seller" && !/closed|lost|inactive/i.test(contact.stage || contact.status || ""));

  const ytdVolume = closedTransactions.reduce((sum, transaction) => sum + Number(transaction.purchasePrice || 0), 0);
  const pendingVolume = pendingTransactions.reduce((sum, transaction) => sum + Number(transaction.purchasePrice || 0), 0);
  const ytdGci = closedTransactions.reduce((sum, transaction) => sum + estimateTransactionGci(transaction, averageCommissionRate), 0);
  const pendingGci = pendingTransactions.reduce((sum, transaction) => sum + estimateTransactionGci(transaction, averageCommissionRate), 0);
  const ytdClosings = Math.max(Number(productionActivity.closings || 0), closedTransactions.length);
  const goalProgress = Math.min(100, Math.round(((annualVolumeGoal ? ytdVolume / annualVolumeGoal : ytdClosings / annualClosingGoal) || 0) * 100));
  const closingsNeeded = Math.max(0, annualClosingGoal - ytdClosings);
  const monthlyClosingNeed = backendCalculatedPlan?.monthlyTargets?.requiredClosings || productionPlan.monthlyClosings || 1;
  const nextMilestone = closingsNeeded > 0 ? `${Math.min(closingsNeeded, Math.max(1, Math.ceil(monthlyClosingNeed)))} more closing${Math.min(closingsNeeded, Math.max(1, Math.ceil(monthlyClosingNeed))) === 1 ? "" : "s"} keeps the goal moving.` : "Annual closing goal reached.";
  const productionLine = backendProductionPlan?.momentum?.insight ||
    (pendingVolume > 0
    ? `${dashboardMoney(pendingVolume)} pending - keep the deadlines tight.`
    : ytdClosings > 0
      ? `${ytdClosings} closing${ytdClosings === 1 ? "" : "s"} logged this year.`
      : "Build the first lead, then the first appointment, then the first closing.");

  const dashboardCommissionSummary = calculateAgentCommissionSummary(currentUser || {}, transactions, transactionCommissions);
  const dashboardCommissionRule = dashboardCommissionSummary.rule || commissionPlanRule(currentUser?.commissionPlan);
  const closedCommissionYtd = dashboardCommissionSummary.grossCommission || ytdGci;
  const pendingCommission = pendingGci;
  const pendingBrokerageEstimate = dashboardCommissionSummary.plan === "Nex Premium"
    ? pendingTransactions.reduce((sum, transaction) => sum + nexPremiumTransactionFee(transaction, estimateTransactionGci(transaction, averageCommissionRate)), 0)
    : dashboardCommissionSummary.plan === "Nex Premium.1"
      ? Math.min(pendingTransactions.length * dashboardCommissionRule.fee, dashboardCommissionSummary.grandfatheredCapRemaining)
      : dashboardCommissionRule.type === "split-cap"
        ? Math.min(Math.round(pendingCommission * dashboardCommissionRule.splitRate), dashboardCommissionSummary.splitCapRemaining)
        : 0;
  const estimatedAgentNet = dashboardCommissionSummary.agentCommission + Math.max(0, pendingCommission - pendingBrokerageEstimate);
  const capProgress = dashboardCommissionSummary.capProgress;
  const capStatusValue = dashboardCommissionSummary.plan === "Nex Premium"
    ? "No cap"
    : dashboardCommissionSummary.plan === "Nex Premium.1"
      ? `${dashboardCommissionSummary.grandfatheredCapRemainingDeals} deals`
      : dashboardMoney(dashboardCommissionSummary.splitCapRemaining);
  const capStatusLabel = dashboardCommissionSummary.plan === "Nex Premium" ? "Fee status" : "Cap remaining";
  const npsSummary = calculateNpsRewardSummaryForAgent(currentUser, users, transactions, transactionCommissions);

  const followUpDueToday = contactTasks.filter((task) => task.status !== "Completed" && crmIsDueToday(task.dueDate));
  const overdueFollowUps = contactTasks.filter((task) => task.status !== "Completed" && crmIsDue(task.dueDate));
  const newLeads = contacts.filter((contact) => /new lead|new prospect|new/i.test(contact.stage || contact.status || "") && !contact.lastContactedDate);
  const hotLeads = contacts.filter((contact) => crmTemperature(contact, crmContactActivityItems(contact, [], crmActivity)) === "Hot");
  const topFollowUps = [...overdueFollowUps, ...followUpDueToday]
    .filter((task, index, list) => list.findIndex((item) => item.id === task.id) === index)
    .sort((a, b) => String(a.dueDate || "").localeCompare(String(b.dueDate || "")))
    .slice(0, 4);

  const transactionDeadlines = [
    ...transactions.flatMap((transaction) => [
      ["EMD due", transaction.emdDeadline],
      ["Inspection period ends", transaction.inspectionDeadline],
      ["Financing period ends", transaction.financingDeadline],
      ["Appraisal deadline", transaction.appraisalDeadline],
      ["HOA / condo deadline", transaction.hoaDeadline],
      ["Final walkthrough", transaction.finalWalkthroughDate],
      ["Closing", transaction.closingDate],
      transaction.nextDeadline ? [transaction.nextDeadline.label, transaction.nextDeadline.date] : null
    ].filter(Boolean).map(([label, dueDate]) => ({
      id: `${transaction.id}-${label}-${dueDate}`,
      transactionId: transaction.id,
      title: transaction.title || transaction.propertyAddress || "Transaction",
      address: transaction.propertyAddress,
      label,
      dueDate,
      page: "Transactions"
    }))),
    ...buyerTasks
      .filter((task) => !task.completed && task.dueDate)
      .map((task) => {
        const transaction = buyerTransactions.find((item) => item.id === task.transactionId);
        return {
          id: task.id,
          transactionId: task.transactionId,
          title: transaction?.transactionName || transaction?.propertyAddress || "Buyer checklist",
          address: transaction?.propertyAddress || "",
          label: task.taskName,
          dueDate: task.dueDate,
          page: "Transactions"
        };
      })
  ].filter((item) => dashboardDate(item.dueDate));

  const sortedDeadlines = transactionDeadlines
    .map((item) => {
      const days = daysUntil(item.dueDate);
      return { ...item, days, tone: dashboardDeadlineTone(days), statusLabel: dashboardDeadlineLabel(days) };
    })
    .sort((a, b) => dashboardDeadlinePriority(a.days) - dashboardDeadlinePriority(b.days) || String(a.dueDate).localeCompare(String(b.dueDate)))
    .slice(0, 7);

  const recentActivity = [
    latestChat && { type: "Chat", text: latestChatPreview || "New chat activity", time: latestChat.createdAt, page: "Nex Chat" },
    ...crmActivity.slice(0, 3).map((item) => ({ type: item.type || "CRM", text: item.title || item.body || "CRM activity logged", time: item.createdAt, page: "Nex CRM" })),
    ...transactionActivity.slice(0, 3).map((item) => ({ type: "Transaction", text: item.action || item.details?.title || "Transaction activity", time: item.createdAt, page: "Transactions" })),
    ...announcements.slice(0, 2).map((item) => ({ type: item.category || "Bulletin", text: item.title, time: item.createdAt, page: "Bulletin Board" }))
  ].filter(Boolean).sort((a, b) => new Date(b.time || 0) - new Date(a.time || 0)).slice(0, 6);

  const featuredTemplate = templates.find((template) => ["just-listed", "luxury-listing", "modern-open-house"].includes(template.id)) || templates[0];
  const pendingPipelineValue = activeTransactions.reduce((sum, transaction) => sum + Number(transaction.purchasePrice || 0), 0);
  const urgentDeadlineCount = sortedDeadlines.filter((item) => ["overdue", "today"].includes(item.tone)).length;
  const commandSummaryItems = [
    { label: "Overdue follow-ups", value: overdueFollowUps.length, page: "Nex CRM", tone: overdueFollowUps.length ? "hot" : "calm", icon: "Target" },
    { label: "Contract dates", value: urgentDeadlineCount, page: "Transactions", tone: urgentDeadlineCount ? "hot" : "calm", icon: "ClipboardCheck" },
    { label: "Unread chats", value: unreadChatCount, page: "Nex Chat", tone: unreadChatCount ? "live" : "calm", icon: "MessagesSquare" },
    { label: "Pending files", value: pendingTransactions.length, page: "Transactions", tone: pendingTransactions.length ? "active" : "calm", icon: "FileCheck2" }
  ];
  const quickActions = [
    ["Add Lead", "UserPlus", "Nex CRM"],
    ["Create Transaction", "FolderPlus", "Transactions"],
    ["Upload Document", "UploadCloud", "Documents"],
    ["Log Follow-Up", "PhoneCall", "Nex CRM"],
    ["View CRM", "UsersRound", "Nex CRM"],
    ["View Transactions", "FileCheck2", "Transactions"],
    ["Open Nex Chat", "MessagesSquare", "Nex Chat"],
    ["Marketing Studio", "Sparkles", "Marketing Studio"]
  ];
  const hubDate = new Date().toLocaleDateString([], { weekday: "long", month: "short", day: "numeric" });
  const priorityQueueItems = [
    {
      label: "Follow-ups",
      value: overdueFollowUps.length + followUpDueToday.length,
      detail: overdueFollowUps.length ? `${overdueFollowUps.length} overdue. Work these first.` : `${followUpDueToday.length} due today.`,
      page: "Nex CRM",
      icon: "Target",
      tone: overdueFollowUps.length ? "hot" : "clear"
    },
    {
      label: "Contract dates",
      value: urgentDeadlineCount,
      detail: urgentDeadlineCount ? "Deadlines need attention today." : "No urgent contract dates.",
      page: "Transactions",
      icon: "ClipboardCheck",
      tone: urgentDeadlineCount ? "hot" : "clear"
    },
    {
      label: "Unread chats",
      value: unreadChatCount,
      detail: latestChat?.senderName ? `Latest from ${latestChat.senderName}.` : "Stay close to team updates.",
      page: "Nex Chat",
      icon: "MessagesSquare",
      tone: unreadChatCount ? "live" : "clear"
    },
    {
      label: "Active pipeline",
      value: pendingTransactions.length + activeBuyers.length + activeSellers.length,
      detail: pendingPipelineValue ? `${dashboardMoney(pendingPipelineValue)} in active files.` : "Build your next deal flow.",
      page: "Transactions",
      icon: "TrendingUp",
      tone: pendingTransactions.length ? "active" : "clear"
    }
  ];

  return (
    <section className="agent-success-dashboard command-hub-dashboard">
      <div className="success-hero premium-command-hero">
        <div className="success-hero-main">
          <p className="eyebrow">Brokerage Operating System</p>
          <h1>Welcome to Nex Central</h1>
          <p>{displayName}, your brokerage command hub is live. {productionLine} Here is what needs attention today.</p>
          <div className="success-hero-command-row">
            {commandSummaryItems.map((item) => (
              <button key={item.label} type="button" className={item.tone} onClick={() => setActivePage(item.page)}>
                <span className="command-metric-icon"><Icon name={item.icon} size={16} /></span>
                <span className="command-metric-label">{item.label}</span>
                <strong>{item.value}</strong>
              </button>
            ))}
          </div>
          <div className="success-hero-action-strip">
            <button type="button" onClick={() => setActivePage("Nex CRM")}><Icon name="Target" /><span>Work Leads</span></button>
            <button type="button" onClick={() => setActivePage("Transactions")}><Icon name="ClipboardCheck" /><span>Check Files</span></button>
            <button type="button" onClick={() => setActivePage("Production Tracker")}><Icon name="TrendingUp" /><span>Review Pace</span></button>
            <button type="button" onClick={() => setActivePage("Nex Chat")}><Icon name="MessagesSquare" /><span>Open Chat</span></button>
          </div>
        </div>
        <div className="success-hero-status">
          <UserAvatar user={currentUser} size="lg" className="success-hero-avatar" />
          <span><i />Platform live</span>
          <span>{currentUser?.role || "Agent"}</span>
          <span>{hubDate}</span>
          <button type="button" onClick={() => setActivePage("My Website")}>My public profile</button>
        </div>
        <div className="success-hero-market-strip">
          <div className="success-hero-market-head">
            <span><Icon name="Activity" size={15} /> Live Market Pulse</span>
            <button type="button" onClick={() => setActivePage("Calculators")}>Open Calculators</button>
          </div>
          <MarketPulseTicker endpoint="/api/market-data/pulse" variant="central" />
        </div>
      </div>

      <section className="success-priority-strip" aria-label="Today's priority queue">
        <div className="success-section-heading">
          <span>Today&apos;s Priority Queue</span>
          <strong>Start here. These are the moves that matter.</strong>
        </div>
        <div className="success-priority-grid">
          {priorityQueueItems.map((item) => (
            <button key={item.label} type="button" className={classNames("success-priority-card", item.tone)} onClick={() => setActivePage(item.page)}>
              <span className="success-priority-icon"><Icon name={item.icon} size={18} /></span>
              <span className="success-priority-copy">
                <strong>{item.label}</strong>
                <small>{item.detail}</small>
              </span>
              <b>{item.value}</b>
              <Icon name="ArrowUpRight" size={16} />
            </button>
          ))}
        </div>
      </section>

      <section className="nex-dashboard-command-strip success-partner-strip">
        <article className="nex-dashboard-lender-card">
          <img src={WOLK_MORTGAGE_PARTNER.cardImageUrl} alt={`${WOLK_MORTGAGE_PARTNER.name} with ${WOLK_MORTGAGE_PARTNER.company}`} />
          <div>
            <span>Preferred Pre-Approval</span>
            <strong>Matthew Wolk</strong>
            <p>{WOLK_MORTGAGE_PARTNER.email} | {WOLK_MORTGAGE_PARTNER.phone} | NMLS {WOLK_MORTGAGE_PARTNER.nmls}</p>
          </div>
          <div className="nex-dashboard-lender-actions">
            <a className="btn secondary compact" href={`mailto:${WOLK_MORTGAGE_PARTNER.email}`}><Icon name="Mail" /><span>Email Matt</span></a>
            <a className="btn secondary compact" href={WOLK_MORTGAGE_PARTNER.phoneHref}><Icon name="Phone" /><span>Call Matt</span></a>
            <a className="btn primary compact" href={WOLK_MORTGAGE_PARTNER.preapprovalUrl} target="_blank" rel="noreferrer"><Icon name="ExternalLink" /><span>Pre-Approval</span></a>
          </div>
        </article>
      </section>

      {unreadChatCount > 0 && !messageDismissed && (
        <div className="success-message-alert">
          <div>
            <Icon name="MessagesSquare" />
            <div>
              <strong>You have {unreadChatCount} unread message{unreadChatCount === 1 ? "" : "s"}</strong>
              <p>{latestChat?.senderName ? `New message from ${latestChat.senderName}: ` : ""}{latestChatPreview || "Open Nex Chat to catch up."}</p>
            </div>
          </div>
          <button className="btn primary" onClick={() => setActivePage("Nex Chat")}><Icon name="ArrowRight" /><span>Open Messages</span></button>
          <button className="icon-btn small" onClick={dismissMessages} title="Dismiss message alert"><Icon name="X" size={15} /></button>
        </div>
      )}

      <div className="success-stat-row success-performance-strip">
        <AgentSuccessStat label="YTD volume" value={dashboardMoney(ytdVolume)} detail={`${goalProgress}% to annual goal`} icon="TrendingUp" tone="red" />
        <AgentSuccessStat label="Pending volume" value={dashboardMoney(pendingVolume)} detail={`${pendingTransactions.length} pending file${pendingTransactions.length === 1 ? "" : "s"}`} icon="Handshake" tone="dark" />
        <AgentSuccessStat label="Pending GCI" value={dashboardMoney(pendingGci)} detail="Estimated from active files" icon="BadgeDollarSign" tone="gold" />
        <AgentSuccessStat label="Follow-ups today" value={followUpDueToday.length} detail={`${overdueFollowUps.length} overdue`} icon="CalendarClock" tone={overdueFollowUps.length ? "red" : "dark"} />
      </div>

      <div className="success-grid top success-command-grid">
        <AgentSuccessWidget id="production" eyebrow="Production" title="Goal progress" minimized={minimizedWidgets.production} onToggle={toggleWidget}
          className="success-widget-feature"
          onOpen={() => setActivePage("Production Tracker")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Production Tracker")}><Icon name="Calculator" /><span>Tracker</span></button>}>
          <div className="success-progress-main">
            <div>
              <strong>{goalProgress}%</strong>
              <span>to annual goal</span>
            </div>
            <div className="success-progress-track"><i style={{ width: `${goalProgress}%` }} /></div>
          </div>
          <div className="success-kpi-grid">
            <div><span>YTD closings</span><strong>{ytdClosings}</strong></div>
            <div><span>Goal closings</span><strong>{annualClosingGoal}</strong></div>
            <div><span>Active buyers</span><strong>{activeBuyers.length}</strong></div>
            <div><span>Active listings</span><strong>{listings.length}</strong></div>
          </div>
          <p className="success-insight">{nextMilestone}</p>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="launchpad" eyebrow="Nex LaunchPad" title={launchPadComplete ? "Training complete" : "Training progress"} minimized={minimizedWidgets.launchpad} onToggle={toggleWidget}
          className="success-widget-launchpad"
          onOpen={() => setActivePage("Nex LaunchPad")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Nex LaunchPad")}><Icon name="GraduationCap" /><span>Open</span></button>}>
          <div className="dashboard-launchpad-card">
            <div className="dashboard-launchpad-ring" style={{ "--launchpad-progress": `${launchPadPercent}%` }}>
              <strong>{launchPadPercent}%</strong>
              <span>{launchPadComplete ? "complete" : "done"}</span>
            </div>
            <div>
              <span className={classNames("status-pill", launchPadComplete ? "success" : launchPadPercent > 0 ? "warning" : "neutral")}>{launchPadSummary.status || "Not started"}</span>
              <h3>{launchPadNextTitle}</h3>
              <p>{launchPadNextRequirement}</p>
            </div>
          </div>
          <div className="dashboard-launchpad-stats">
            <span><strong>{launchPadSummary.completedChapters || 0}/{launchPadSummary.totalChapters || 33}</strong><em>Lessons</em></span>
            <span><strong>{launchPadSummary.niaScore === null || launchPadSummary.niaScore === undefined ? "Pending" : `${launchPadSummary.niaScore}%`}</strong><em>NIA score</em></span>
            <span><strong>{launchPadMinutes(launchPadSummary.totalTimeMinutes || 0)}</strong><em>Logged time</em></span>
          </div>
          <p className="success-insight">{launchPadComplete ? "Great work. Your LaunchPad completion is saved and certificate status is visible in Nex Central." : "Keep moving through the mastery path. Each completed lesson unlocks the next step."}</p>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="commission" eyebrow="Money Pipeline" title="Commission tracker" minimized={minimizedWidgets.commission} onToggle={toggleWidget}
          className="success-widget-money"
          onOpen={() => setActivePage("Commission Tracker")}
          action={<button className="success-soft-badge" type="button" onClick={() => setActivePage("Commission Tracker")}>Open tracker</button>}>
          <div className="commission-grid">
            <div><span>Pending commission</span><strong>{dashboardMoney(pendingCommission)}</strong></div>
            <div><span>Closed commission YTD</span><strong>{dashboardMoney(closedCommissionYtd)}</strong></div>
            <div><span>Estimated agent net</span><strong>{dashboardMoney(estimatedAgentNet)}</strong></div>
            <div><span>{capStatusLabel}</span><strong>{capStatusValue}</strong></div>
          </div>
          <div className="success-progress-track small"><i style={{ width: `${capProgress}%` }} /></div>
          <p className="success-insight">{dashboardCommissionSummary.plan} is assigned in Admin user settings. Closed transactions update this tracker by anniversary year.</p>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="powershare" eyebrow="Nex PowerShare" title="Growth Credits" minimized={minimizedWidgets.powershare} onToggle={toggleWidget}
          className="success-widget-growth"
          onOpen={() => setActivePage("Nex PowerShare")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Nex PowerShare")}><Icon name="Network" /><span>PowerShare</span></button>}>
          <div className="commission-grid">
            <div><span>Estimated earned</span><strong>{dashboardMoney(npsSummary.gross)}</strong></div>
            <div><span>Vested now</span><strong>{dashboardMoney(npsSummary.vested)}</strong></div>
            <div><span>Unvested</span><strong>{dashboardMoney(npsSummary.unvested)}</strong></div>
            <div><span>Direct recruits</span><strong>{npsSummary.directRecruitCount}</strong></div>
          </div>
          <p className="success-insight">{npsSummary.rows.length ? `${npsSummary.rows.length} PowerShare reward estimate${npsSummary.rows.length === 1 ? "" : "s"} from connected transaction activity.` : "No PowerShare rewards estimated yet. Sponsor assignments and eligible closings will populate this card."}</p>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="pipeline" eyebrow="Pipeline" title="Active business" minimized={minimizedWidgets.pipeline} onToggle={toggleWidget}
          className="success-widget-pipeline"
          onOpen={() => setActivePage("Transactions")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Transactions")}><Icon name="ArrowRight" /><span>Open</span></button>}>
          <div className="pipeline-snapshot">
            <div><strong>{activeBuyers.length}</strong><span>Buyers</span></div>
            <div><strong>{activeSellers.length || listings.length}</strong><span>Sellers/Listings</span></div>
            <div><strong>{pendingTransactions.length}</strong><span>Pending</span></div>
            <div><strong>{rentalFiles.length}</strong><span>Rentals</span></div>
            <div><strong>{closedTransactions.length}</strong><span>Closed YTD</span></div>
          </div>
          <p className="success-insight">{pendingPipelineValue ? `${dashboardMoney(pendingPipelineValue)} in active files.` : "No active transaction volume yet. Create a transaction when your next deal starts."}</p>
        </AgentSuccessWidget>
      </div>

      <div className="success-grid middle success-priority-panels">
        <AgentSuccessWidget id="deadlines" eyebrow="Deadlines" title="Next contract dates" minimized={minimizedWidgets.deadlines} onToggle={toggleWidget}
          className="success-widget-priority"
          onOpen={() => setActivePage("Transactions")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Transactions")}><Icon name="ClipboardCheck" /><span>Tracker</span></button>}>
          <div className="success-deadline-list">
            {sortedDeadlines.map((deadline) => (
              <button key={deadline.id} onClick={() => setActivePage(deadline.page)}>
                <span className={classNames("deadline-dot", deadline.tone)} />
                <div>
                  <strong>{deadline.label}</strong>
                  <p>{deadline.title}{deadline.address ? ` - ${deadline.address}` : ""}</p>
                </div>
                <em className={deadline.tone}>{deadline.statusLabel}<small>{formatDate(deadline.dueDate)}</small></em>
              </button>
            ))}
            {!sortedDeadlines.length && <EmptyState icon="CalendarCheck" title="No transaction deadlines yet" body="Create a buyer or seller transaction to start tracking important dates." />}
          </div>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="followups" eyebrow="Follow-Up" title="Lead attention" minimized={minimizedWidgets.followups} onToggle={toggleWidget}
          className="success-widget-leads"
          onOpen={() => setActivePage("Nex CRM")}
          action={<button className="btn secondary compact" onClick={() => setActivePage("Nex CRM")}><Icon name="UsersRound" /><span>CRM</span></button>}>
          <div className="followup-summary">
            <div><strong>{newLeads.length}</strong><span>New leads</span></div>
            <div><strong>{hotLeads.length}</strong><span>Hot leads</span></div>
            <div><strong>{followUpDueToday.length}</strong><span>Due today</span></div>
            <div><strong>{overdueFollowUps.length}</strong><span>Overdue</span></div>
          </div>
          <div className="followup-list">
            {topFollowUps.map((task) => {
              const contact = contacts.find((item) => item.id === task.contactId);
              return (
                <button key={task.id} onClick={() => setActivePage("Nex CRM")}>
                  <Icon name={crmIsDue(task.dueDate) ? "AlarmClock" : "PhoneCall"} size={16} />
                  <span>{task.title || task.taskType || "Follow up"}</span>
                  <em>{crmContactName(contact)} - {formatDate(task.dueDate)}</em>
                </button>
              );
            })}
            {!topFollowUps.length && <p className="success-empty-line">No follow-ups due today. Protect the pipeline by creating the next follow-up for every active lead.</p>}
          </div>
        </AgentSuccessWidget>
      </div>

      <div className="success-grid lower success-utility-panels">
        <NexChatDashboardWidget
          currentUser={currentUser}
          setActivePage={setActivePage}
          latestChat={latestChat}
          chatUnreadTotal={chatUnreadTotal}
          variant="success"
        />

        <AgentSuccessWidget id="activity" eyebrow="Recent Activity" title="What changed" minimized={minimizedWidgets.activity} onToggle={toggleWidget} onOpen={() => setActivePage("Activity")}>
          <div className="success-activity-list">
            {recentActivity.map((item, index) => (
              <button key={`${item.type}-${index}`} onClick={() => setActivePage(item.page)}>
                <span>{item.type}</span>
                <strong>{item.text}</strong>
                <em>{item.time ? new Date(item.time).toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }) : "Recent"}</em>
              </button>
            ))}
            {!recentActivity.length && <p className="success-empty-line">No recent activity yet. New leads, messages, transaction updates, and announcements will appear here.</p>}
          </div>
        </AgentSuccessWidget>

        <AgentSuccessWidget id="actions" eyebrow="Quick Actions" title="Do the next thing" minimized={minimizedWidgets.actions} onToggle={toggleWidget}
          className="success-widget-command-palette"
          action={featuredTemplate && <button className="btn secondary compact" onClick={() => openTemplate(featuredTemplate)}><Icon name="Sparkles" /><span>Marketing</span></button>}>
          <div className="success-actions-grid">
            {quickActions.map(([label, icon, page]) => (
              <button key={label} onClick={() => setActivePage(page)}>
                <Icon name={icon} />
                <span>{label}</span>
              </button>
            ))}
          </div>
          <p className="success-insight">The full tool library stays in the sidebar. This dashboard keeps only the actions agents need most often.</p>
        </AgentSuccessWidget>
      </div>
    </section>
  );
}

function LegacyDashboard({ projects, templates, announcements, quickLinks, trainingResources, documents = [], tickets, currentUser, latestChat, chatUnreadTotal = 0, buyerNotifications = [], setActivePage, setBuyerTrackerStartView, setSelectedTemplateId, setFields, brand, openQuickLink }) {
  const isAdmin = isAdminRole(currentUser?.role);
  const displayName = currentUser?.name || currentUser?.email?.split("@")[0] || "Nex Agent";
  const todayLabel = new Date().toLocaleDateString([], { weekday: "long", month: "short", day: "numeric" });
  const focusStorageKey = `nex-dashboard-focus-${currentUser?.email || "guest"}-${new Date().toISOString().slice(0, 10)}`;
  const [focusDone, setFocusDone] = useState(() => {
    try {
      return JSON.parse(localStorage.getItem(focusStorageKey) || "{}");
    } catch {
      return {};
    }
  });

  useEffect(() => {
    localStorage.setItem(focusStorageKey, JSON.stringify(focusDone));
  }, [focusDone, focusStorageKey]);

  function openTemplate(template) {
    setSelectedTemplateId(template.id);
    setFields((current) => ({
      ...current,
      marketingType: template.name,
      platform: template.category === "Agent Marketing" || template.category === "Recruiting" ? "Instagram" : current.platform
    }));
    setActivePage("Marketing Studio");
  }

  function openAppTile(tile) {
    if (tile.targetView) setBuyerTrackerStartView(tile.targetView);
    if (tile.externalUrl) {
      window.open(tile.externalUrl, "_blank", "noopener,noreferrer");
      return;
    }
    if (tile.linkTitle) {
      const link = quickLinks.find((item) => item.title === tile.linkTitle);
      if (link) {
        openQuickLink(link);
        return;
      }
    }
    if (tile.templateId) {
      const template = templates.find((item) => item.id === tile.templateId);
      if (template) {
        openTemplate(template);
        return;
      }
    }
    setActivePage(tile.page);
  }

  function runAiPrompt(promptText) {
    if (promptText.startsWith("Open ")) {
      const target = promptText.replace("Open ", "");
      const tile = launchpadTiles.find((item) => item.title.includes(target) || item.page === target);
      if (tile) openAppTile(tile);
      else setActivePage("Nex Intelligent Assistant");
      return;
    }
    setActivePage("Nex Intelligent Assistant");
  }

  function toggleFocus(id) {
    setFocusDone((current) => ({ ...current, [id]: !current[id] }));
  }

  const latest = announcements.slice(0, 5);
  const pinned = announcements.filter((item) => item.pinned || item.urgent).slice(0, 4);
  const featuredTraining = trainingResources.filter((item) => item.featured || item.isNew).slice(0, 4);
  const highlightedTemplates = ["just-listed", "luxury-listing", "modern-open-house", "for-rent", "just-sold", "recruiting-post", "home-value-offer"]
    .map((id) => templates.find((template) => template.id === id))
    .filter(Boolean);
  const openTickets = tickets.filter((ticket) => !["Closed", "Resolved"].includes(ticket.status)).length;
  const waitingTickets = tickets.filter((ticket) => String(ticket.status || "").includes("Waiting")).length;
  const resolvedTickets = tickets.filter((ticket) => ["Closed", "Resolved"].includes(ticket.status)).length;
  const unreadChatCount = Number(chatUnreadTotal || 0);
  const pendingTransactionTasks = buyerNotifications.filter((item) => !item.read).length;
  const newTrainingCount = trainingResources.filter((item) => item.isNew).length;
  const newAnnouncementCount = announcements.filter((item) => item.urgent || item.pinned).length || announcements.length;
  const latestChatText = latestChat?.text || (latestChat?.attachments?.length ? `${latestChat.attachments.length} attachment${latestChat.attachments.length === 1 ? "" : "s"}` : "No chat activity yet.");
  const latestChatTime = latestChat?.createdAt ? dashboardTime(latestChat.createdAt) : "Open chat";
  const trainingProgress = trainingResources.length ? Math.min(92, Math.max(18, Math.round((trainingResources.filter((item) => !item.isNew).length / trainingResources.length) * 100))) : 0;
  const focusItems = (isAdmin
    ? [
        ["tickets", "Review support tickets", "Support Desk"],
        ["agent-questions", "Check unread agent questions", "Nex Chat"],
        ["leads", "Review new leads", "Nex CRM"],
        ["compliance", "Review compliance reminders", "Bulletin Board"],
        ["training", "Check training activity", "NexU / Training Center"],
        ["activity", "Review agent activity", "Admin Panel"]
      ]
    : [
        ["leads", "Follow up with 5 leads", "Nex CRM"],
        ["training", "Complete 1 NexU training", "NexU / Training Center"],
        ["deadlines", "Check transaction deadlines", "Transactions"],
        ["campaign", "Launch 1 marketing campaign", "Marketing Studio"],
        ["chat", "Respond to unread chats", "Nex Chat"],
        ["updates", "Review brokerage updates", "Bulletin Board"]
      ]);
  const focusComplete = focusItems.filter(([id]) => focusDone[id]).length;
  const focusProgress = Math.round((focusComplete / focusItems.length) * 100);

  const metrics = [
    { icon: "Megaphone", label: "New Announcements", value: newAnnouncementCount, status: announcements.some((item) => item.urgent) ? "Urgent" : "Updated", page: "Bulletin Board", tone: "red" },
    { icon: "GraduationCap", label: "New NexU Updates", value: newTrainingCount || trainingResources.length, status: newTrainingCount ? "New" : "Ready", page: "NexU / Training Center", tone: "gold" },
    { icon: "LifeBuoy", label: "Open Support Tickets", value: openTickets, status: openTickets ? "Action Needed" : "Clear", page: "Support Desk", tone: openTickets ? "red" : "dark" },
    { icon: "MessagesSquare", label: "Unread Nex Chat", value: unreadChatCount, status: unreadChatCount ? "Live" : "Synced", page: "Nex Chat", tone: "red" },
    { icon: "FolderKanban", label: "Documents", value: documents.length, status: "Library", page: "Documents", tone: "dark" },
    { icon: "ClipboardCheck", label: "Pending Transaction Tasks", value: pendingTransactionTasks, status: pendingTransactionTasks ? "Due Soon" : "Ready", page: "Transactions", tone: "gold" },
    { icon: "Sparkles", label: "Marketing Projects", value: projects.length, status: projects.length ? "In Progress" : "Launch", page: "Marketing Studio", tone: "red" },
    { icon: "BarChart3", label: "Training Progress", value: `${trainingProgress}%`, status: trainingResources.length ? "Sample" : "Not Started", page: "NexU / Training Center", tone: "gold", sample: true }
  ];

  const launchpadTiles = [
    { title: "Marketing Studio", icon: "Sparkles", body: "Create campaigns, flyers, cards, emails, SMS, and social assets.", status: "Ready", page: "Marketing Studio" },
    { title: "Nex Intelligent Assistant", icon: "Bot", body: "Ask NIA about contracts, marketing, workflows, and brokerage support.", status: "AI Live", page: "Nex Intelligent Assistant" },
    { title: "Nex Chat", icon: "MessagesSquare", body: "Live agent, admin, and support communication.", status: "Live", page: "Nex Chat" },
    { title: "Nex CRM", icon: "UsersRound", body: "Manage leads, follow-ups, tasks, notes, and pipeline activity.", status: "CRM Ready", page: "Nex CRM" },
    { title: "Lead Engine", icon: "Target", body: "Create lead campaigns, QR codes, open house capture, and follow-up assets.", status: "Build Leads", page: "Marketing Studio", templateId: "seller-lead-ad" },
    { title: "Production Tracker", icon: "Calculator", body: "Build an income goal, daily action plan, and NIA coaching path.", status: "Game Plan", page: "Production Tracker" },
    { title: "Calculators", icon: "ReceiptText", body: "Estimate mortgage payments, Florida buyer costs, and seller net proceeds.", status: "Live Rate", page: "Calculators" },
    { title: "Matt Wolk Pre-Approval", icon: "Landmark", body: "Send buyers to Matt Wolk at Wolk Mortgage for pre-approval help.", status: "Preferred Partner", externalUrl: WOLK_MORTGAGE_PARTNER.preapprovalUrl },
    { title: "Transactions", icon: "ClipboardCheck", body: "Create buyer or seller files, track contract deadlines, and manage checklist tasks.", status: "Ready", page: "Transactions" },
    { title: "Documents", icon: "FolderKanban", body: "Open buyer, seller, recruiting, and agent learning document libraries.", status: "Internal", page: "Documents" },
    { title: "NexU", icon: "GraduationCap", body: "Watch internal training and continue agent development.", status: "Updated", page: "NexU / Training Center" },
    { title: "Brokermint", icon: "FileCheck2", body: "Open transaction management and file review resources.", status: "External", page: "Quick Links", linkTitle: "Brokermint" },
    { title: "SoWork", icon: "Building2", body: "Enter the Nex virtual office and collaboration space.", status: "External", page: "Quick Links", linkTitle: "SoWork" },
    { title: "Support Desk", icon: "LifeBuoy", body: "Submit or review brokerage, tech, compliance, and marketing requests.", status: openTickets ? "Action Needed" : "Ready", page: "Support Desk" },
    { title: "Showami", icon: "CalendarClock", body: "Schedule showing help for buyer clients when you need licensed agent coverage.", status: "External", externalUrl: "https://showami.com/how-to-schedule-a-showing" }
  ];

  const activityItems = [
    latestChat && { type: "Chat", tone: "live", user: latestChat.senderName || latestChat.senderEmail || "Nex Chat", text: latestChatText, time: latestChatTime, page: "Nex Chat" },
    ...announcements.slice(0, 2).map((item) => ({ type: item.urgent ? "Urgent" : item.category || "Bulletin", tone: item.urgent ? "urgent" : "normal", user: "Brokerage Bulletin", text: item.title, time: dashboardTime(item.createdAt, "Updated"), page: "Bulletin Board" })),
    ...featuredTraining.slice(0, 2).map((item) => ({ type: "NexU", tone: "new", user: "Training", text: `New training uploaded - ${item.title}`, time: dashboardTime(item.createdAt, "New"), page: "NexU / Training Center" })),
    ...projects.slice(0, 2).map((project) => ({ type: "Marketing", tone: "normal", user: currentUser?.name || "Marketing Studio", text: `${project.title || "New project"} saved`, time: dashboardTime(project.updatedAt || project.createdAt, "Recent"), page: "Saved Projects" })),
    openTickets > 0 && { type: "Support", tone: "urgent", user: "Support Desk", text: `${openTickets} ticket${openTickets === 1 ? "" : "s"} need review`, time: "Action Needed", page: "Support Desk" },
    { type: "Compliance", tone: "normal", user: "Nex Central", text: "Advertising reminder active before publishing marketing.", time: "Live", page: "Bulletin Board" }
  ].filter(Boolean).slice(0, 8);

  const pulseCards = [
    ["Agent activity today", isAdmin ? "Brokerage view" : "Personal view", "Sample until analytics are connected"],
    ["Leads generated this week", "CRM ready", "Connect CRM activity history next"],
    ["Marketing projects created", projects.length, projects.length ? "Live data" : "No saved work yet"],
    ["Training modules completed", `${trainingProgress}%`, "Sample progress until per-user tracking"],
    ["Support response status", openTickets ? `${openTickets} open` : "Clear", waitingTickets ? `${waitingTickets} waiting` : "No waiting items"],
    ["Production activity", "Ready", "Syncs with saved Production Game Plans"],
    ["CRM follow-ups due", "CRM Ready", "Will sync from CRM tasks next"]
  ];

  return (
    <section className="nex-dashboard">
      <section className="nex-hero">
        <div className="nex-hero-glow" />
        <div className="nex-hero-content">
          <div className="nex-hero-copy">
            <p className="eyebrow">Nex Central</p>
            <h1>Welcome back, {displayName}.</h1>
            <p>Your Nex operating system is live - one connected hub for leads, marketing, training, transactions, support, and brokerage growth.</p>
            <div className="nex-status-row">
              {["System Online", "Nex Chat Live", "Marketing Studio Ready", "NexU Updated"].map((status) => (
                <span key={status}><i />{status}</span>
              ))}
            </div>
            <div className="nex-hero-actions">
              <button className="btn primary" onClick={() => setActivePage("Marketing Studio")}><Icon name="Sparkles" /><span>Launch Marketing Studio</span></button>
              <button className="btn light" onClick={() => setActivePage("Nex Intelligent Assistant")}><Icon name="Bot" /><span>Ask NIA</span></button>
              <button className="btn light" onClick={() => openAppTile({ page: "Marketing Studio", templateId: "seller-lead-ad" })}><Icon name="Target" /><span>Create Lead Campaign</span></button>
              <button className="btn light" onClick={() => setActivePage("Nex Chat")}><Icon name="MessagesSquare" /><span>Open Nex Chat</span></button>
              <button className="btn light" onClick={() => setActivePage("Support Desk")}><Icon name="LifeBuoy" /><span>Submit Support Ticket</span></button>
              <button className="btn light" onClick={() => setActivePage("Transactions")}><Icon name="ClipboardCheck" /><span>Start Transaction Checklist</span></button>
            </div>
          </div>
          <aside className="nex-hero-system-card">
            <Wordmark brand={brand} variant="dark" />
            <strong>Nex Central Live</strong>
            <span>{currentUser?.role || "Agent"} access - {todayLabel}</span>
            <div>
              <em><i />Secure login</em>
              <em><i />Agent tools ready</em>
              <em><i />Support active</em>
            </div>
          </aside>
        </div>
      </section>

      <section className="nex-ai-bar">
        <Icon name="Sparkles" />
        <button onClick={() => setActivePage("Nex Intelligent Assistant")}>Ask NIA anything... contracts, marketing, leads, support, training, transactions.</button>
        <div>
          {["What should I work on today?", "Create a seller lead campaign", "Help me with an under-contract checklist", "Draft a follow-up text", "Explain my next transaction step", "Open Marketing Studio", "Show my support tickets"].map((promptText) => (
            <button key={promptText} onClick={() => runAiPrompt(promptText)}>{promptText}</button>
          ))}
        </div>
      </section>

      <section className="nex-dashboard-command-strip">
        <div className="nex-dashboard-command-market">
          <div className="nex-command-strip-head">
            <span><Icon name="Activity" size={15} /> Market Pulse</span>
            <button type="button" onClick={() => setActivePage("Calculators")}>Open Calculators</button>
          </div>
          <MarketPulseTicker endpoint="/api/market-data/pulse" variant="central" />
        </div>
        <article className="nex-dashboard-lender-card">
          <img src={WOLK_MORTGAGE_PARTNER.cardImageUrl} alt={`${WOLK_MORTGAGE_PARTNER.name} with ${WOLK_MORTGAGE_PARTNER.company}`} />
          <div>
            <span>Preferred Pre-Approval</span>
            <strong>Matthew Wolk</strong>
            <p>{WOLK_MORTGAGE_PARTNER.email} | {WOLK_MORTGAGE_PARTNER.phone} | NMLS {WOLK_MORTGAGE_PARTNER.nmls}</p>
          </div>
          <div className="nex-dashboard-lender-actions">
            <a className="btn secondary compact" href={`mailto:${WOLK_MORTGAGE_PARTNER.email}`}><Icon name="Mail" /><span>Email Matt</span></a>
            <a className="btn secondary compact" href={WOLK_MORTGAGE_PARTNER.phoneHref}><Icon name="Phone" /><span>Call Matt</span></a>
            <a className="btn primary compact" href={WOLK_MORTGAGE_PARTNER.preapprovalUrl} target="_blank" rel="noreferrer"><Icon name="ExternalLink" /><span>Pre-Approval</span></a>
          </div>
        </article>
      </section>

      <section className="nex-metrics-row">
        {metrics.map((metric) => (
          <DashboardMetricCard key={metric.label} metric={metric} onClick={() => setActivePage(metric.page)} />
        ))}
      </section>

      <section className="nex-dashboard-grid">
        <article className="nex-widget nex-focus-card">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Today's Nex Focus</p>
              <h2>{focusComplete}/{focusItems.length} complete</h2>
            </div>
            <span>{focusProgress}%</span>
          </div>
          <div className="nex-progress-track"><i style={{ width: `${focusProgress}%` }} /></div>
          <div className="nex-focus-list">
            {focusItems.map(([id, label, page]) => (
              <label key={id} className={focusDone[id] ? "complete" : ""}>
                <input type="checkbox" checked={Boolean(focusDone[id])} onChange={() => toggleFocus(id)} />
                <span>{label}</span>
                <button type="button" onClick={() => setActivePage(page)}>Open</button>
              </label>
            ))}
          </div>
        </article>

        <article className="nex-widget nex-activity-card">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Live Nex Activity</p>
              <h2>Brokerage pulse</h2>
            </div>
            <span className="live-badge"><i />Live</span>
          </div>
          <div className="nex-activity-feed">
            {activityItems.map((item, index) => (
              <button key={`${item.type}-${index}`} onClick={() => setActivePage(item.page)}>
                <em className={item.tone}>{item.type}</em>
                <strong>{item.user}</strong>
                <span>{item.text}</span>
                <small>{item.time}</small>
              </button>
            ))}
          </div>
        </article>
      </section>

      <section className="nex-launchpad">
        <div className="nex-section-head">
          <div>
            <p className="eyebrow">Nex Launchpad</p>
            <h2>Open your agent tech stack</h2>
          </div>
          <button className="btn secondary" onClick={() => setActivePage("Quick Links")}><Icon name="Grid3X3" /><span>All Links</span></button>
        </div>
        <div className="nex-launchpad-grid">
          {launchpadTiles.slice(0, 10).map((tile) => (
            <button key={tile.title} onClick={() => openAppTile(tile)}>
              <Icon name={tile.icon} />
              <span>{tile.status}</span>
              <strong>{tile.title}</strong>
              <p>{tile.body}</p>
            </button>
          ))}
        </div>
      </section>

      <section className="nex-dashboard-grid three">
        <article className="nex-widget nex-pulse-card">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Nex Pulse</p>
              <h2>Platform analytics</h2>
            </div>
            <span>Mixed live + sample</span>
          </div>
          <div className="nex-pulse-grid">
            {pulseCards.map(([label, value, note]) => (
              <div key={label}>
                <span>{label}</span>
                <strong>{value}</strong>
                <em>{note}</em>
              </div>
            ))}
          </div>
        </article>

        <NexChatDashboardWidget
          currentUser={currentUser}
          setActivePage={setActivePage}
          latestChat={latestChat}
          chatUnreadTotal={chatUnreadTotal}
          variant="nex"
        />

        <article className="nex-widget support-snapshot">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Support Center Snapshot</p>
              <h2>{openTickets} open</h2>
            </div>
            {openTickets > 0 && <span className="urgent-pill">Action Needed</span>}
          </div>
          <div className="support-snapshot-grid">
            <div><strong>{openTickets}</strong><span>Open tickets</span></div>
            <div><strong>{waitingTickets}</strong><span>Waiting</span></div>
            <div><strong>{resolvedTickets}</strong><span>Resolved</span></div>
          </div>
          <button className="btn primary" onClick={() => setActivePage("Support Desk")}><Icon name="LifeBuoy" /><span>Open Support Desk</span></button>
        </article>
      </section>

      <section className="nex-dashboard-grid three lower">
        <article className="nex-widget brokerage-bulletin">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Brokerage Bulletin</p>
              <h2>Latest updates</h2>
            </div>
            <button className="icon-btn" onClick={() => setActivePage("Bulletin Board")} title="Open bulletin board"><Icon name="ArrowRight" /></button>
          </div>
          <div className="bulletin-card-list">
            {(pinned.length ? pinned : latest).slice(0, 4).map((item) => (
              <button key={item.id} className={classNames(item.urgent && "urgent")} onClick={() => setActivePage("Bulletin Board")}>
                <span>{item.urgent ? "Urgent" : item.category || "General"}</span>
                <strong>{item.title}</strong>
                <p>{item.body}</p>
                <em>{dashboardTime(item.createdAt, item.pinned ? "Pinned" : "Updated")}</em>
              </button>
            ))}
          </div>
        </article>

        <article className="nex-widget nexu-progress-card">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">NexU Progress</p>
              <h2>{trainingProgress}% learning path</h2>
            </div>
            <span>{newTrainingCount ? `${newTrainingCount} New` : "Ready"}</span>
          </div>
          <div className="nex-progress-track"><i style={{ width: `${trainingProgress}%` }} /></div>
          <div className="nexu-mini-list">
            {(featuredTraining.length ? featuredTraining : trainingResources).slice(0, 3).map((item) => (
              <button key={item.id} onClick={() => setActivePage("NexU / Training Center")}>
                <span>{normalizeTrainingCategory(item.category)}{item.isNew ? " - New" : ""}</span>
                <strong>{item.title}</strong>
              </button>
            ))}
          </div>
          <button className="btn secondary" onClick={() => setActivePage("NexU / Training Center")}><Icon name="PlayCircle" /><span>Continue Learning</span></button>
        </article>

        <article className="nex-widget marketing-momentum">
          <div className="nex-widget-head">
            <div>
              <p className="eyebrow">Marketing Momentum</p>
              <h2>{projects.length} saved projects</h2>
            </div>
            <button className="btn secondary" onClick={() => setActivePage("Marketing Studio")}><Icon name="Sparkles" /><span>Start Design</span></button>
          </div>
          <div className="momentum-template-row">
            {(highlightedTemplates.length ? highlightedTemplates : templates).slice(0, 7).map((template) => (
              <button key={template.id} onClick={() => openTemplate(template)} style={{ "--accent": template.accent || brand.primaryColor }}>
                <span>{template.badge || "Template"}</span>
                <strong>{template.name}</strong>
              </button>
            ))}
          </div>
          <div className="recent-project-mini">
            {projects.slice(0, 3).map((project) => (
              <button key={project.id} onClick={() => setActivePage("Saved Projects")}>
                <span>{project.fields?.marketingType || "Marketing"}</span>
                <strong>{project.title}</strong>
              </button>
            ))}
            {!projects.length && <p>Start in Marketing Studio and your saved campaigns will appear here.</p>}
          </div>
        </article>
      </section>
    </section>
  );
}

function DashboardMetricCard({ metric, onClick }) {
  return (
    <button className={classNames("nex-metric-card", metric.tone, metric.sample && "sample")} onClick={onClick}>
      <span className="metric-icon"><Icon name={metric.icon} /></span>
      <span className="metric-status">{metric.status}</span>
      <strong>{metric.value}</strong>
      <em>{metric.label}</em>
    </button>
  );
}

function NexCentralMarketPulseWidget({ setActivePage }) {
  const [pulse, setPulse] = useState(null);
  const [loading, setLoading] = useState(true);
  const [refreshToken, setRefreshToken] = useState(0);

  useEffect(() => {
    let mounted = true;
    async function loadPulse() {
      setLoading(true);
      try {
        const payload = await API.request(`/api/market-data/pulse?ts=${Date.now()}${refreshToken ? "&refresh=1" : ""}`, { retries: 0 });
        if (mounted) setPulse(payload);
      } catch (error) {
        if (mounted) setPulse({ error: true, items: [], housing: [], disclaimer: "Market Pulse could not load. Check the market data connection." });
      } finally {
        if (mounted) setLoading(false);
      }
    }
    loadPulse();
    const timer = setInterval(loadPulse, 5 * 60 * 1000);
    return () => {
      mounted = false;
      clearInterval(timer);
    };
  }, [refreshToken]);

  const featuredMarketIds = ["30-year-conventional", "10-year-treasury", "mbs-spread-proxy", "cpi-inflation-yoy", "national-inventory-trend"];
  const rateItems = featuredMarketIds
    .map((id) => (pulse?.items || []).find((item) => item.id === id))
    .filter(Boolean)
    .slice(0, 4);
  const housingItems = pulse?.housing || [];
  return (
    <article className="nex-market-pulse-widget nex-market-command-widget">
      <div className="nex-widget-head">
        <div>
          <p className="eyebrow">Market Pulse</p>
          <h2>Real estate finance command strip</h2>
        </div>
        <div className="nex-market-pulse-actions">
          <button className="btn secondary compact" type="button" onClick={() => setRefreshToken((value) => value + 1)} disabled={loading}>
            <Icon name={loading ? "LoaderCircle" : "RefreshCw"} className={loading ? "spin" : ""} />
            <span>{loading ? "Refreshing" : "Refresh"}</span>
          </button>
          <button className="btn primary compact" type="button" onClick={() => setActivePage("Calculators")}>
            <Icon name="Calculator" />
            <span>Calculators</span>
          </button>
        </div>
      </div>
      <div className="nex-market-pulse-body">
        <MarketPulseTicker endpoint="/api/market-data/pulse" variant="central" refreshToken={refreshToken} />
        <div className="nex-market-signal-grid">
          {(rateItems.length ? rateItems : [{ id: "loading", label: "Market data", displayValue: loading ? "Checking" : "Unavailable", note: "Market indicators loading." }]).map((item) => (
            <article key={item.id || item.label}>
              <span>{item.label}</span>
              <strong>{pulseDisplayValue(item)}<em className={classNames("pulse-card-indicator", item.trend)}>{item.indicator}</em></strong>
              <small>{item.changeLabel && <b>{item.changeLabel}</b>} {item.statusLabel && <i>{item.statusLabel}</i>} {item.note || item.source || "Market indicator"}</small>
            </article>
          ))}
        </div>
        <div className="nex-market-housing-row">
          {housingItems.map((item) => (
            <span key={item.id || item.label}>
              <strong>{item.displayValue}</strong>
              <em>{item.label}</em>
            </span>
          ))}
        </div>
        <small className="nex-market-disclaimer">{pulse?.disclaimer || "Market Pulse is informational only. Verify actual rates, APR, fees, and eligibility with a licensed mortgage professional."}</small>
      </div>
    </article>
  );
}

function MarketingStudioHub({
  currentUser,
  setActivePage,
  templates,
  brand,
  selectedTemplateId,
  setSelectedTemplateId,
  fields,
  setFields,
  flyerCopy,
  setFlyerCopy,
  propertyPhotos,
  setPropertyPhotos,
  agentHeadshot,
  setAgentHeadshot,
  flyerRef,
  output,
  setOutput,
  prompt,
  setPrompt,
  isGenerating,
  onGenerate,
  onQuickAction,
  onSaveProject,
  onDuplicateProject,
  onDownloadPdf,
  onDownloadPng,
  onDownloadJpg,
  onPrint,
  onSharePlatform,
  onSaveAsTemplate,
  projects,
  loadProject,
  setToast,
  projectTitle,
  setProjectTitle,
  saveStatus
}) {
  const [studioMode, setStudioMode] = useState("simple");
  const [simpleWorkflowId, setSimpleWorkflowId] = useState("");
  const [simpleGenerated, setSimpleGenerated] = useState(false);
  const [simpleAssets, setSimpleAssets] = useState([]);
  const [activeTool, setActiveTool] = useState("Templates");
  const [templateQuery, setTemplateQuery] = useState("");
  const [templateCategory, setTemplateCategory] = useState("All");
  const [selectedElement, setSelectedElement] = useState("headline");
  const [selectedElements, setSelectedElements] = useState(["headline"]);
  const [canvasZoom, setCanvasZoom] = useState(100);
  const [showSafeGuides, setShowSafeGuides] = useState(false);
  const [showAdvancedControls, setShowAdvancedControls] = useState(false);
  const [aiPrompt, setAiPrompt] = useState("Create a luxury just listed flyer for this property");
  const [aiStyle, setAiStyle] = useState("Modern Nex");
  const [aiIsWorking, setAiIsWorking] = useState(false);
  const [aiResult, setAiResult] = useState(null);
  const [aiPackage, setAiPackage] = useState(null);
  const [history, setHistory] = useState([]);
  const [future, setFuture] = useState([]);
  const studioStorageIdentity = normalizeEmail(currentUser?.email || "shared");
  const mediaStorageKey = `${MARKETING_MEDIA_LIBRARY_PREFIX}-${studioStorageIdentity}`;
  const headshotStorageKey = `${MARKETING_HEADSHOT_PREFIX}-${studioStorageIdentity}`;
  const [savedMedia, setSavedMedia] = useState(() => dashboardStorageJson(mediaStorageKey, []));
  const [savedHeadshot, setSavedHeadshot] = useState(() => dashboardStorageJson(headshotStorageKey, null));
  const selectedTemplate = templates.find((template) => template.id === selectedTemplateId) || templates[0] || {};
  const selectedFormat = getCreativeFormat(flyerCopy.canvasFormat);
  const categories = ["All", ...Array.from(new Set(templates.map((template) => template.category || "Custom")))];
  const templatesForSelectedFormat = templates.filter((template) => getRecommendedFormatForTemplate(template) === selectedFormat.id);
  const templatePool = templatesForSelectedFormat.length ? templatesForSelectedFormat : templates;
  const filteredTemplates = sortStudioTemplates(templatePool.filter((template) => {
    const search = `${template.name} ${template.category} ${template.headline} ${template.badge}`.toLowerCase();
    const matchesSearch = !templateQuery || search.includes(templateQuery.toLowerCase());
    const matchesCategory = templateCategory === "All" || template.category === templateCategory;
    return matchesSearch && matchesCategory;
  }), templateCategory, templateQuery);

  useEffect(() => {
    setSavedMedia(dashboardStorageJson(mediaStorageKey, []));
    setSavedHeadshot(dashboardStorageJson(headshotStorageKey, null));
  }, [mediaStorageKey, headshotStorageKey]);

  useEffect(() => {
    saveStudioJson(mediaStorageKey, savedMedia);
  }, [mediaStorageKey, savedMedia]);

  useEffect(() => {
    saveStudioJson(headshotStorageKey, savedHeadshot);
  }, [headshotStorageKey, savedHeadshot]);

  function snapshot() {
    return { fields, flyerCopy, selectedTemplateId, propertyPhotos, agentHeadshot };
  }

  function restore(state) {
    if (!state) return;
    setFields(state.fields || defaultFields);
    setFlyerCopy({ ...defaultFlyerCopy, ...(state.flyerCopy || {}) });
    setSelectedTemplateId(state.selectedTemplateId || "just-listed");
    setPropertyPhotos(state.propertyPhotos || []);
    setAgentHeadshot(state.agentHeadshot || null);
  }

  function selectStudioElement(id, event) {
    const additive = Boolean(event?.shiftKey || event?.ctrlKey || event?.metaKey);
    setSelectedElement(id);
    setSelectedElements((current) => {
      if (!additive) return [id];
      if (current.includes(id)) {
        const next = current.filter((item) => item !== id);
        return next.length ? next : [id];
      }
      return [...current, id];
    });
  }

  function setSingleSelectedElement(id) {
    setSelectedElement(id);
    setSelectedElements([id]);
  }

  function remember() {
    setHistory((current) => [...current.slice(-14), snapshot()]);
    setFuture([]);
  }

  function undo() {
    if (!history.length) return;
    const previous = history[history.length - 1];
    setFuture((current) => [snapshot(), ...current].slice(0, 15));
    setHistory((current) => current.slice(0, -1));
    restore(previous);
    setToast("Undid last studio edit.");
  }

  function redo() {
    if (!future.length) return;
    const next = future[0];
    setHistory((current) => [...current, snapshot()].slice(-15));
    setFuture((current) => current.slice(1));
    restore(next);
    setToast("Redid studio edit.");
  }

  function updateField(name, value) {
    remember();
    setFields((current) => ({ ...current, [name]: value }));
  }

  function updateFlyer(name, value) {
    remember();
    setFlyerCopy((current) => ({ ...current, [name]: value }));
  }

  function updateFlyerLive(name, value) {
    setFlyerCopy((current) => ({ ...current, [name]: value }));
  }

  function applyStylePreset(preset) {
    remember();
    setFlyerCopy((current) => ({
      ...current,
      accentColor: preset.accentColor,
      backgroundColor: preset.backgroundColor,
      finish: preset.finish,
      layout: preset.layout,
      photoTreatment: preset.photoTreatment
    }));
    setActiveTool("Styles");
    setToast(`${preset.name} style applied.`);
  }

  function updateCanvasFormat(formatId) {
    remember();
    const matchingTemplate = templates.find((template) => getRecommendedFormatForTemplate(template) === formatId);
    if (matchingTemplate) {
      setSelectedTemplateId(matchingTemplate.id);
      setFields((current) => ({
        ...current,
        marketingType: matchingTemplate.name || current.marketingType
      }));
    }
    setFlyerCopy((current) => ({
      ...current,
      headline: matchingTemplate?.headline || current.headline,
      badge: matchingTemplate?.badge || current.badge,
      layout: matchingTemplate?.style || current.layout,
      finish: matchingTemplate?.style === "luxury" ? "black-luxury" : current.finish,
      canvasFormat: formatId,
      ...getFormatDefaults(formatId)
    }));
    setSingleSelectedElement(["business-card", "email-signature"].includes(formatId) ? "agent" : "headline");
  }

  function selectTemplate(template, requestedFormatId = "") {
    remember();
    const formatId = requestedFormatId || getRecommendedFormatForTemplate(template);
    setSelectedTemplateId(template.id);
    setFields((current) => ({
      ...current,
      marketingType: template.name,
      platform: formatId === "instagram-reel" ? "Instagram Reel / Story" : formatId === "instagram-square" ? "Instagram" : formatId === "facebook-post" ? "Facebook" : current.platform
    }));
    setFlyerCopy((current) => ({
      ...current,
      headline: template.headline || current.headline,
      badge: template.badge || current.badge,
      layout: template.style || current.layout,
      finish: template.style === "luxury" ? "black-luxury" : current.finish,
      canvasFormat: formatId,
      ...getFormatDefaults(formatId)
    }));
    setSingleSelectedElement(["business-card", "email-signature"].includes(formatId) ? "agent" : "headline");
  }

  function startFromPreset(item) {
    const template = templates.find((candidate) => candidate.id === item.templateId) || selectedTemplate;
    selectTemplate(template, item.formatId);
    setActiveTool(item.nextTool || "Templates");
    setToast(`${item.title} template loaded.`);
  }

  function rememberStudioMedia(items = [], source = "Uploaded") {
    const mediaItems = items.map((item) => makeStudioMediaItem(item, source)).filter(Boolean);
    if (mediaItems.length) {
      setSavedMedia((current) => mergeStudioMedia(mediaItems, current));
    }
    return mediaItems;
  }

  function useSavedMedia(item, slot = "hero") {
    const media = makeStudioMediaItem(item, item?.source || "Saved media");
    if (!media) return;
    remember();
    if (slot === "headshot") {
      setAgentHeadshot(media);
      setSavedHeadshot(media);
      setToast("Saved headshot applied.");
      return;
    }
    if (slot === "background") {
      setFlyerCopy((current) => ({
        ...current,
        backgroundImage: media.dataUrl,
        backgroundImageName: media.name || "Saved background"
      }));
      setToast("Saved image applied as background.");
      return;
    }
    if (slot === "secondary-1" || slot === "secondary-2") {
      setPropertyPhotos((current) => {
        const targetIndex = slot === "secondary-1" ? 1 : 2;
        const withoutDuplicate = current.filter((photo) => photo.dataUrl !== media.dataUrl);
        const next = [...withoutDuplicate];
        next.splice(Math.min(targetIndex, next.length), 0, media);
        return next.slice(0, 12);
      });
      setToast(`Saved image added to ${slot.replace("-", " ")}.`);
      return;
    }
    setPropertyPhotos((current) => mergeStudioMedia([media], current, 12));
    setToast("Saved image added to the design.");
  }

  function removeSavedMedia(id) {
    setSavedMedia((current) => current.filter((item) => item.id !== id));
    if (savedHeadshot?.id === id) setSavedHeadshot(null);
    setToast("Saved media removed from this browser.");
  }

  function clearSavedHeadshot() {
    setSavedHeadshot(null);
    setToast("Saved headshot cleared.");
  }

  async function replacePhoto(event, index = 0) {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    remember();
    const [upload] = rememberStudioMedia([await fileToDataUrl(file)], "Uploaded photo");
    setPropertyPhotos((current) => {
      const next = [...current];
      next[index] = upload;
      return next.filter(Boolean).slice(0, 12);
    });
    event.target.value = "";
  }

  function removePhoto(index = 0) {
    remember();
    setPropertyPhotos((current) => current.filter((_, itemIndex) => itemIndex !== index));
    setToast("Photo removed from the design.");
  }

  async function onPhotoUpload(event) {
    const files = Array.from((event.target && event.target.files) || event.files || []);
    if (!files.length) return;
    remember();
    const uploads = await Promise.all(files.map(fileToDataUrl));
    const mediaItems = rememberStudioMedia(uploads, "Uploaded photo");
    setPropertyPhotos((current) => mergeStudioMedia(mediaItems, current, 12));
  }

  async function onHeadshotUpload(event) {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    remember();
    const [upload] = rememberStudioMedia([await fileToDataUrl(file)], "Agent headshot");
    setAgentHeadshot(upload);
    setSavedHeadshot(upload);
    event.target.value = "";
  }

  async function onBackgroundUpload(event) {
    const file = (event.files && event.files[0]) || (event.target.files && event.target.files[0]);
    if (!file) return;
    remember();
    const [upload] = rememberStudioMedia([await fileToDataUrl(file)], "Background image");
    setFlyerCopy((current) => ({
      ...current,
      backgroundImage: upload.dataUrl,
      backgroundImageName: upload.name || "Uploaded background"
    }));
    event.target.value = "";
  }

  function addStockPhotoToProject(photo) {
    remember();
    const stockImage = makeStudioMediaItem({
      ...photo,
      name: `${photo.title || "Stock image"}.${String(photo.dataUrl || "").startsWith("data:image/svg") ? "svg" : "jpg"}`,
      type: String(photo.dataUrl || "").startsWith("data:image/svg") ? "image/svg+xml" : "image/jpeg",
      source: photo.source || "Third-party stock"
    }, photo.source || "Third-party stock");
    if (!stockImage) return;
    setSavedMedia((current) => mergeStudioMedia([stockImage], current));
    setPropertyPhotos((current) => mergeStudioMedia([stockImage], current, 12));
    setToast(`${stockImage.title || stockImage.name} added to your media tray.`);
  }

  function assignPhoto(index, slot) {
    const photo = propertyPhotos[index];
    if (!photo) return;
    if (slot === "background") {
      remember();
      setFlyerCopy((current) => ({
        ...current,
        backgroundImage: photo.dataUrl,
        backgroundImageName: photo.name || `Photo ${index + 1}`
      }));
      setToast("Photo assigned as the design background.");
      return;
    }
    remember();
    setPropertyPhotos((current) => {
      const next = current.filter((_, itemIndex) => itemIndex !== index);
      const targetIndex = slot === "hero" ? 0 : slot === "secondary-1" ? 1 : slot === "secondary-2" ? 2 : 3;
      next.splice(Math.min(targetIndex, next.length), 0, photo);
      return next;
    });
    setToast(`Photo assigned to ${slot.replace("-", " ")}.`);
  }

  function applyCtaBlock(label) {
    updateField("cta", label);
    updateFlyer("cta", label);
  }

  function assistantPrompt(action) {
    const base = output?.primary || flyerCopy.body || `${fields.marketingType} for ${fields.propertyAddress || "a Nex Realty campaign"}`;
    return `${action}\n\nCurrent copy:\n${base}`;
  }

  function marketingAiPayload(extra = {}) {
    return {
      prompt: aiPrompt,
      style: aiStyle,
      selectedFormat: flyerCopy.canvasFormat,
      selectedTemplateId,
      propertyInfo: {
        propertyAddress: fields.propertyAddress,
        address: fields.propertyAddress,
        city: fields.city,
        state: fields.state,
        zip: fields.zip,
        price: fields.price,
        bedrooms: fields.bedrooms,
        bathrooms: fields.bathrooms,
        garageSpaces: fields.garageSpaces,
        squareFootage: fields.squareFootage,
        lotSize: fields.lotSize,
        yearBuilt: fields.yearBuilt,
        availableDate: fields.availableDate,
        listingType: fields.marketingType,
        mlsNumber: fields.mlsNumber,
        openHouseDateTime: fields.openHouseDateTime,
        description: fields.propertyHighlights || fields.mlsRemarks,
        cta: fields.cta || flyerCopy.cta
      },
      agentInfo: {
        agentName: fields.agentName || currentUser?.name || "",
        agentPhone: fields.agentPhone || currentUser?.phone || "",
        agentEmail: fields.agentEmail || currentUser?.email || "",
        agentWebsite: flyerCopy.agentWebsite || currentUser?.agentWebsiteUrl || "",
        agentLicense: flyerCopy.agentLicense || "",
        market: currentUser?.market || ""
      },
      design: flyerCopy,
      brand,
      photoCount: propertyPhotos.length,
      ...extra
    };
  }

  function applyAiCopyToDesign(result = {}) {
    const nextHeadline = result.headline || result.headlines?.[0] || result.suggestedHeadline;
    const nextBody = result.bodyCopy || result.descriptions?.[0] || result.primary || result.caption;
    const nextCta = result.cta || result.ctas?.[0] || result.suggestedCTA;
    const nextPrice = result.priceText || result.price;
    remember();
    if (nextPrice && !fields.price) {
      setFields((current) => ({ ...current, price: nextPrice }));
    }
    setFlyerCopy((current) => ({
      ...current,
      headline: nextHeadline || current.headline,
      body: nextBody || current.body,
      cta: nextCta || current.cta,
      badge: result.designType || current.badge,
      footer: current.footer || brand.defaultDisclaimer
    }));
    if (setOutput) {
      setOutput((current) => ({
        ...(current || {}),
        suggestedHeadline: nextHeadline || current?.suggestedHeadline,
        suggestedCTA: nextCta || current?.suggestedCTA,
        primary: nextBody || current?.primary,
        flyerReadyCopy: nextBody || current?.flyerReadyCopy,
        socialCaption: result.socialCaption || result.captions?.[0] || current?.socialCaption,
        emailSubjects: result.emailSubjects || current?.emailSubjects,
        complianceWarnings: result.complianceWarnings || current?.complianceWarnings
      }));
    }
  }

  function applyAiDesignResult(result = {}) {
    const templateId = result.templateId || result.recommendedTemplateId;
    const formatId = result.recommendedFormat || result.format;
    const template = templates.find((candidate) => candidate.id === templateId);
    remember();
    if (template) selectTemplate(template, formatId || getRecommendedFormatForTemplate(template));
    else if (formatId) updateCanvasFormat(formatId);
    setFields((current) => ({
      ...current,
      marketingType: result.designType || current.marketingType,
      price: result.priceText && !current.price ? result.priceText : current.price,
      propertyHighlights: result.bodyCopy || current.propertyHighlights,
      cta: result.cta || current.cta
    }));
    setFlyerCopy((current) => ({
      ...current,
      headline: result.headline || current.headline,
      badge: result.subheadline || result.designType || current.badge,
      body: result.bodyCopy || current.body,
      cta: result.cta || current.cta,
      canvasFormat: formatId || current.canvasFormat,
      showQr: current.showQr || (Array.isArray(result.requiredBlocks) && result.requiredBlocks.includes("qr")),
      footer: current.footer || brand.defaultDisclaimer
    }));
    applyAiCopyToDesign(result);
    setSingleSelectedElement("headline");
  }

  async function runMarketingAi(endpoint, payload = {}) {
    setAiIsWorking(true);
    try {
      const result = await API.request(endpoint, {
        method: "POST",
        body: JSON.stringify(marketingAiPayload(payload)),
        retries: 0
      });
      setAiResult(result);
      if (Array.isArray(result.complianceWarnings) && result.complianceWarnings.length) {
        setToast(result.complianceWarnings[0]);
      } else {
        setToast(result.provider === "openai" ? "AI studio draft ready." : "AI studio draft ready in local mode.");
      }
      return result;
    } catch (error) {
      setToast(error.message || "Marketing AI could not finish this request.");
      throw error;
    } finally {
      setAiIsWorking(false);
    }
  }

  async function createAiDesign(extra = {}) {
    const result = await runMarketingAi("/api/marketing/ai/create-design", extra);
    applyAiDesignResult(result);
    setActiveTool("AI Create");
    return result;
  }

  async function generateAiCopy(extra = {}) {
    const result = await runMarketingAi("/api/marketing/ai/generate-copy", extra);
    applyAiCopyToDesign(result);
    setActiveTool("AI Create");
    return result;
  }

  async function suggestAiTemplate(extra = {}) {
    const result = await runMarketingAi("/api/marketing/ai/suggest-template", extra);
    const template = templates.find((candidate) => candidate.id === result.recommendedTemplateId);
    if (template) selectTemplate(template, result.recommendedFormat);
    setActiveTool("Templates");
    return result;
  }

  async function improveAiDesign(extra = {}) {
    const result = await runMarketingAi("/api/marketing/ai/improve-design", extra);
    setActiveTool("AI Create");
    return result;
  }

  async function createAiPackage(extra = {}) {
    const result = await runMarketingAi("/api/marketing/ai/create-package", extra);
    setAiPackage(result);
    setActiveTool("AI Create");
    return result;
  }

  const selectedSimpleWorkflow = simpleMarketingWorkflows.find((workflow) => workflow.id === simpleWorkflowId);
  const recommendedSimpleFormats = (selectedSimpleWorkflow?.recommendedFormats || ["letter-flyer", "instagram-square"])
    .map((formatId) => getCreativeFormat(formatId));

  function chooseSimpleWorkflow(workflow) {
    if (workflow.advancedDefault) {
      setStudioMode("advanced");
      setActiveTool("Templates");
      return;
    }
    remember();
    setSimpleWorkflowId(workflow.id);
    setSimpleGenerated(false);
    setAiPrompt(workflow.defaultPrompt);
    setSelectedElement(workflow.id === "business-card" ? "agent" : "headline");
    setSelectedElements([workflow.id === "business-card" ? "agent" : "headline"]);
    const template = templates.find((candidate) => candidate.id === workflow.templateId) || selectedTemplate;
    selectTemplate(template, workflow.recommendedFormats[0]);
    setFields((current) => ({
      ...current,
      marketingType: workflow.type,
      status: workflow.type === "For Rent" ? "For rent" : workflow.type === "Open House" ? "Open house" : workflow.type === "Just Sold" ? "Sold" : current.status,
      cta: current.cta || recommendedCtaForWorkflow(workflow)
    }));
    setFlyerCopy((current) => ({
      ...current,
      cta: current.cta || recommendedCtaForWorkflow(workflow),
      showQr: current.showQr || ["recruiting", "event"].includes(workflow.id)
    }));
  }

  function returnToSimpleHome() {
    setSimpleWorkflowId("");
    setSimpleGenerated(false);
    setSimpleAssets([]);
  }

  function buildSimplePrompt(workflow, mode = "package") {
    const formatNames = workflow.recommendedFormats.map((formatId) => getCreativeFormat(formatId).name).join(", ");
    const propertyLine = fields.propertyAddress ? `Property: ${fields.propertyAddress}` : "Use editable placeholders for any missing property details.";
    const detailLine = [
      fields.price && `Price/rent: ${fields.price}`,
      fields.bedrooms && `${fields.bedrooms} beds`,
      fields.bathrooms && `${fields.bathrooms} baths`,
      fields.garageSpaces && `${fields.garageSpaces} garage`,
      fields.squareFootage && `${fields.squareFootage} sqft`,
      fields.openHouseDateTime && `Open house: ${fields.openHouseDateTime}`,
      fields.rentalAvailableDate && `Available: ${fields.rentalAvailableDate}`
    ].filter(Boolean).join(", ");
    return [
      workflow.defaultPrompt,
      `Style: ${aiStyle}.`,
      `Goal: ${mode === "package" ? `Create the recommended package (${formatNames})` : `Create the best ${mode} asset`}.`,
      propertyLine,
      detailLine,
      fields.propertyHighlights || fields.mlsRemarks ? `Notes: ${fields.propertyHighlights || fields.mlsRemarks}` : "",
      fields.cta || flyerCopy.cta ? `CTA: ${fields.cta || flyerCopy.cta}` : "Use a practical real estate CTA.",
      propertyPhotos.length ? `Use the first uploaded photo as the hero image. Photo count: ${propertyPhotos.length}.` : "No photos uploaded yet. Leave clear photo placeholders."
    ].filter(Boolean).join("\n");
  }

  async function generateSimpleMarketing(mode = "package") {
    if (!selectedSimpleWorkflow) return;
    const formats = selectedSimpleWorkflow.recommendedFormats;
    const formatId = mode === "social"
      ? (formats.find((item) => ["instagram-square", "facebook-post", "instagram-story"].includes(item)) || formats[0])
      : mode === "flyer"
        ? (formats.find((item) => ["letter-flyer", "open-house-flyer", "qr-code-flyer"].includes(item)) || formats[0])
        : formats[0];
    const template = templates.find((candidate) => candidate.id === selectedSimpleWorkflow.templateId) || selectedTemplate;
    selectTemplate(template, formatId);
    const nextPrompt = buildSimplePrompt(selectedSimpleWorkflow, mode);
    setAiPrompt(nextPrompt);
    const result = await createAiDesign({
      prompt: nextPrompt,
      selectedFormat: formatId,
      selectedTemplateId: selectedSimpleWorkflow.templateId,
      packageFormats: formats
    });
    if (selectedSimpleWorkflow.id === "business-card") {
      selectTemplate(template, "business-card");
      setFlyerCopy((current) => ({
        ...current,
        canvasFormat: "business-card",
        headline: "BUSINESS CARD",
        badge: "Agent Card",
        body: current.body || "Your New Era Experience",
        cta: current.cta || recommendedCtaForWorkflow(selectedSimpleWorkflow)
      }));
      setFields((current) => ({
        ...current,
        marketingType: "Business Card",
        status: "Agent Card"
      }));
      setSingleSelectedElement("agent");
    }
    if (mode === "package") {
      createAiPackage({
        prompt: nextPrompt,
        packageType: selectedSimpleWorkflow.type,
        packageFormats: formats
      }).catch(() => {});
    }
    setSimpleAssets(formats.map((assetFormatId, index) => {
      const format = getCreativeFormat(assetFormatId);
      return {
        id: `${selectedSimpleWorkflow.id}-${assetFormatId}`,
        formatId: assetFormatId,
        name: format.name,
        description: index === 0 ? "Primary design" : "Recommended resize",
        status: index === 0 ? "Ready" : "Resize ready"
      };
    }));
    setSimpleGenerated(true);
    setToast(result.provider === "openai" ? "NIA Studio built your first draft." : "NIA Studio built your first draft in local mode.");
  }

  function openSimpleAsset(formatId) {
    updateCanvasFormat(formatId);
    setSimpleGenerated(true);
  }

  function applyAgentInfoToDesign() {
    remember();
    setFields((current) => ({
      ...current,
      agentName: current.agentName || currentUser?.name || "",
      agentPhone: current.agentPhone || currentUser?.phone || "",
      agentEmail: current.agentEmail || currentUser?.email || ""
    }));
    if (savedHeadshot && !agentHeadshot) {
      setAgentHeadshot(savedHeadshot);
    }
    setToast("Agent info applied to the design.");
  }

  if (studioMode !== "advanced") {
    return (
      <section className="simple-studio">
        {!selectedSimpleWorkflow ? (
          <SimpleMarketingHome
            workflows={simpleMarketingWorkflows}
            onChooseWorkflow={chooseSimpleWorkflow}
            projects={projects}
            loadProject={(project) => {
              const projectLabel = `${project.projectType || ""} ${project.fields?.marketingType || ""} ${project.title || ""}`.toLowerCase();
              const savedWorkflow =
                simpleMarketingWorkflows.find((workflow) => projectLabel.includes(workflow.label.toLowerCase())) ||
                (projectLabel.includes("rent") ? simpleMarketingWorkflows.find((workflow) => workflow.id === "rental") : null) ||
                (projectLabel.includes("open house") ? simpleMarketingWorkflows.find((workflow) => workflow.id === "open-house") : null) ||
                (projectLabel.includes("sold") ? simpleMarketingWorkflows.find((workflow) => workflow.id === "sold") : null) ||
                (projectLabel.includes("recruit") ? simpleMarketingWorkflows.find((workflow) => workflow.id === "recruiting") : null) ||
                (projectLabel.includes("event") || projectLabel.includes("class") ? simpleMarketingWorkflows.find((workflow) => workflow.id === "event") : null) ||
                simpleMarketingWorkflows.find((workflow) => workflow.id === "listing");
              const savedFormat = project.flyerCopy?.canvasFormat || flyerCopy.canvasFormat || "letter";
              loadProject(project);
              setSimpleWorkflowId(savedWorkflow?.id || "listing");
              setSimpleGenerated(true);
              setSimpleAssets([{ id: "saved-current", formatId: savedFormat, name: getCreativeFormat(savedFormat).name, description: "Saved project", status: "Ready" }]);
            }}
            brand={brand}
            currentUser={currentUser}
            agentHeadshot={agentHeadshot || savedHeadshot}
            onAdvanced={() => setStudioMode("advanced")}
          />
        ) : !simpleGenerated ? (
          <SimpleMarketingBuilder
            workflow={selectedSimpleWorkflow}
            fields={fields}
            updateField={updateField}
            flyerCopy={flyerCopy}
            updateFlyer={updateFlyer}
            propertyPhotos={propertyPhotos}
            onPhotoUpload={onPhotoUpload}
            onUsePhotoAsHero={(index) => assignPhoto(index, "hero")}
            onRemovePhoto={removePhoto}
            aiStyle={aiStyle}
            setAiStyle={setAiStyle}
            recommendedFormats={recommendedSimpleFormats}
            isWorking={aiIsWorking}
            onGenerateFlyer={() => generateSimpleMarketing("flyer")}
            onGenerateSocial={() => generateSimpleMarketing("social")}
            onGeneratePackage={() => generateSimpleMarketing("package")}
            onBack={returnToSimpleHome}
            onAdvanced={() => setStudioMode("advanced")}
            onApplyAgentInfo={applyAgentInfoToDesign}
            agentHeadshot={agentHeadshot || savedHeadshot}
            onHeadshotUpload={onHeadshotUpload}
            currentUser={currentUser}
          />
        ) : (
          <SimpleMarketingResult
            workflow={selectedSimpleWorkflow}
            fields={fields}
            updateField={updateField}
            flyerCopy={flyerCopy}
            updateFlyer={updateFlyer}
            brand={brand}
            templates={templates}
            selectedTemplateId={selectedTemplateId}
            propertyPhotos={propertyPhotos}
            agentHeadshot={agentHeadshot || savedHeadshot}
            flyerRef={flyerRef}
            selectedElement={selectedElement}
            selectedElements={selectedElements}
            onSelectElement={selectStudioElement}
            onUpdateFlyerLive={updateFlyerLive}
            onReplacePhoto={replacePhoto}
            onRemovePhoto={removePhoto}
            onHeadshotUpload={onHeadshotUpload}
            assets={simpleAssets.length ? simpleAssets : recommendedSimpleFormats.map((format) => ({ id: format.id, formatId: format.id, name: format.name, description: "Recommended", status: "Ready" }))}
            activeFormat={selectedFormat}
            onOpenAsset={openSimpleAsset}
            onDownloadPng={onDownloadPng}
            onDownloadPdf={onDownloadPdf}
            onSaveProject={onSaveProject}
            onRegenerate={() => generateSimpleMarketing("package")}
            onBack={() => setSimpleGenerated(false)}
            onHome={returnToSimpleHome}
            onAdvanced={() => setStudioMode("advanced")}
            isWorking={aiIsWorking}
            aiResult={aiResult}
          />
        )}
      </section>
    );
  }

  return (
    <section className="canva-studio">
      <header className="studio-top-toolbar">
        <div className="project-title-wrap">
          <p className="eyebrow">Nex Marketing Studio</p>
          <input value={projectTitle} onChange={(event) => setProjectTitle(event.target.value)} placeholder="Untitled Nex marketing project" />
          <span>{saveStatus}</span>
        </div>
        <div className="studio-toolbar-actions">
          <button className="btn secondary" onClick={undo} disabled={!history.length}><Icon name="Undo2" /><span>Undo</span></button>
          <button className="btn secondary" onClick={redo} disabled={!future.length}><Icon name="Redo2" /><span>Redo</span></button>
          <button className="btn secondary" onClick={onDuplicateProject}><Icon name="CopyPlus" /><span>Duplicate</span></button>
          <button className="btn secondary" onClick={onSaveAsTemplate}><Icon name="BadgePlus" /><span>Save Template</span></button>
          <button className="btn primary" onClick={onSaveProject}><Icon name="Save" /><span>Save</span></button>
        </div>
      </header>

      <section className="studio-start-strip" aria-label="Start a marketing design">
        <div className="studio-start-copy">
          <p className="eyebrow">Nex Create</p>
          <strong>What will you design today?</strong>
          <button className="btn primary studio-make-button" onClick={() => { setActiveTool("AI Create"); setAiPrompt(aiPrompt || "Create a luxury just listed flyer for this property"); }}>
            <Icon name="Sparkles" />
            <span>Make it for me</span>
          </button>
          <label className="studio-global-search">
            <Icon name="Search" size={18} />
            <input
              value={templateQuery}
              onChange={(event) => {
                setTemplateQuery(event.target.value);
                setActiveTool("Templates");
              }}
              placeholder="Search templates, formats, projects, and uploads"
            />
          </label>
        </div>
        <div className="studio-start-actions studio-use-case-grid">
          {studioQuickStarts.map((item) => (
            <article key={`${item.title}-${item.formatId}`} className={selectedTemplateId === item.templateId && flyerCopy.canvasFormat === item.formatId ? "selected" : ""}>
              <button type="button" className="studio-use-case-main" onClick={() => startFromPreset(item)}>
                <Icon name={item.icon} />
                <span>
                  <strong>{item.title}</strong>
                  <em>{item.description}</em>
                </span>
              </button>
              <button
                type="button"
                className="studio-use-case-ai"
                disabled={aiIsWorking}
                onClick={() => {
                  const nextPrompt = `Create a ${item.title} for Nex Realty. Make it ${aiStyle.toLowerCase()} and use the current property and agent info.`;
                  setAiPrompt(nextPrompt);
                  createAiDesign({ prompt: nextPrompt, selectedFormat: item.formatId, selectedTemplateId: item.templateId });
                }}
              >
                <Icon name={aiIsWorking ? "LoaderCircle" : "Sparkles"} className={aiIsWorking ? "spin" : ""} />
                <span>Build with AI</span>
              </button>
            </article>
          ))}
        </div>
        <div className="studio-format-strip" aria-label="Canvas format shortcuts">
          {creativeFormatOptions.map((format) => (
            <button key={format.id} onClick={() => { updateCanvasFormat(format.id); setActiveTool("Templates"); setToast(`${format.name} canvas selected.`); }} className={flyerCopy.canvasFormat === format.id ? "selected" : ""}>
              <Icon name={format.icon} size={14} />
              <span>
                <strong>{format.name}</strong>
                <em>{format.exportLabel}</em>
              </span>
            </button>
          ))}
        </div>
      </section>

      <StudioExportStrip
        selectedFormat={selectedFormat}
        onDownloadPng={onDownloadPng}
        onDownloadPdf={onDownloadPdf}
        onDownloadJpg={onDownloadJpg}
        onPrint={onPrint}
        onSharePlatform={onSharePlatform}
      />

      <div className="canva-workspace">
        <aside className="studio-left-panel">
          <nav className="studio-tool-rail" aria-label="Marketing Studio tools">
            {marketingStudioToolTabs.map(([label, icon]) => (
              <button key={label} className={activeTool === label ? "active" : ""} onClick={() => setActiveTool(label)} title={label}>
                <Icon name={icon} />
                <span>{label}</span>
              </button>
            ))}
          </nav>
          <div className="studio-tool-panel">
            {activeTool === "AI Create" ? (
              <StudioAIPanel
                aiPrompt={aiPrompt}
                setAiPrompt={setAiPrompt}
                aiStyle={aiStyle}
                setAiStyle={setAiStyle}
                aiIsWorking={aiIsWorking}
                aiResult={aiResult}
                aiPackage={aiPackage}
                fields={fields}
                updateField={updateField}
                flyerCopy={flyerCopy}
                updateFlyer={updateFlyer}
                selectedFormat={selectedFormat}
                selectedTemplate={selectedTemplate}
                onCreateDesign={createAiDesign}
                onGenerateCopy={generateAiCopy}
                onSuggestTemplate={suggestAiTemplate}
                onImproveDesign={improveAiDesign}
                onCreatePackage={createAiPackage}
                onApplyResult={applyAiDesignResult}
                onApplyCopy={applyAiCopyToDesign}
              />
            ) : activeTool === "Edit" ? (
              <StudioSettingsPanel
                selectedElement={selectedElement}
                setSelectedElement={setSingleSelectedElement}
                fields={fields}
                updateField={updateField}
                flyerCopy={flyerCopy}
                updateFlyer={updateFlyer}
                brand={brand}
                selectedTemplate={selectedTemplate}
                leadCtaBlocks={leadCtaBlocks}
                applyCtaBlock={applyCtaBlock}
                output={output}
                prompt={prompt}
                setPrompt={setPrompt}
                isGenerating={isGenerating}
                onGenerate={onGenerate}
                onQuickAction={(action) => onQuickAction(assistantPrompt(action))}
                setActivePage={setActivePage}
              />
            ) : activeTool === "Export" ? (
              <StudioExportPanel
                selectedFormat={selectedFormat}
                onDownloadPng={onDownloadPng}
                onDownloadPdf={onDownloadPdf}
                onDownloadJpg={onDownloadJpg}
                onPrint={onPrint}
                onSharePlatform={onSharePlatform}
              />
            ) : (
              <StudioToolPanel
                activeTool={activeTool}
                templates={filteredTemplates}
                allCategories={categories}
                templateQuery={templateQuery}
                setTemplateQuery={setTemplateQuery}
                templateCategory={templateCategory}
                setTemplateCategory={setTemplateCategory}
                selectedTemplateId={selectedTemplateId}
                onSelectTemplate={selectTemplate}
                selectedFormat={selectedFormat}
                brand={brand}
                propertyPhotos={propertyPhotos}
                setPropertyPhotos={setPropertyPhotos}
                onPhotoUpload={onPhotoUpload}
                onHeadshotUpload={onHeadshotUpload}
                agentHeadshot={agentHeadshot}
                savedMedia={savedMedia}
                savedHeadshot={savedHeadshot}
                onUseSavedMedia={useSavedMedia}
                onRemoveSavedMedia={removeSavedMedia}
                onClearSavedHeadshot={clearSavedHeadshot}
                assignPhoto={assignPhoto}
                onBackgroundUpload={onBackgroundUpload}
                onAddStockPhoto={addStockPhotoToProject}
                setActivePage={setActivePage}
                projects={projects}
                loadProject={loadProject}
                fields={fields}
                updateField={updateField}
                flyerCopy={flyerCopy}
                updateFlyer={updateFlyer}
                selectedElement={selectedElement}
                selectedElements={selectedElements}
                setSelectedElement={setSelectedElement}
                setSelectedElements={setSelectedElements}
                applyStylePreset={applyStylePreset}
              />
            )}
          </div>
        </aside>

        <main className="studio-canvas-panel">
          <div className="canvas-floating-bar">
            <div>
              <strong>{selectedTemplate.name || "Nex Template"}</strong>
              <span>{selectedFormat.name} - {selectedFormat.exportLabel}</span>
            </div>
            <div className="canvas-view-controls" aria-label="Canvas view controls">
              <button type="button" onClick={() => setCanvasZoom((value) => Math.max(60, value - 10))} title="Zoom out"><Icon name="ZoomOut" size={14} /></button>
              <strong>{canvasZoom}%</strong>
              <button type="button" onClick={() => setCanvasZoom((value) => Math.min(140, value + 10))} title="Zoom in"><Icon name="ZoomIn" size={14} /></button>
              <button type="button" onClick={() => setCanvasZoom(100)}>100%</button>
              <button type="button" className={showSafeGuides ? "selected" : ""} onClick={() => setShowSafeGuides((value) => !value)}>
                <Icon name="ScanLine" size={14} />
                <span>Guides</span>
              </button>
            </div>
            <div className="canvas-format-pills">
              {creativeFormatOptions.map((format) => (
                <button key={format.id} className={flyerCopy.canvasFormat === format.id ? "selected" : ""} onClick={() => updateCanvasFormat(format.id)} title={format.name}>
                  <Icon name={format.icon} size={14} />
                  <span>{format.name}</span>
                </button>
              ))}
            </div>
          </div>
          <FlyerPreview
            brand={brand}
            fields={fields}
            templates={templates}
            selectedTemplateId={selectedTemplateId}
            flyerCopy={flyerCopy}
            propertyPhotos={propertyPhotos}
            agentHeadshot={agentHeadshot}
            flyerRef={flyerRef}
            onSelectElement={selectStudioElement}
            selectedElement={selectedElement}
            selectedElements={selectedElements}
            onUpdateField={updateField}
            onUpdateFlyer={updateFlyer}
            onUpdateFlyerLive={updateFlyerLive}
            onReplacePhoto={replacePhoto}
            onRemovePhoto={removePhoto}
            onHeadshotUpload={onHeadshotUpload}
            previewZoom={canvasZoom}
            showSafeGuides={showSafeGuides}
          />
          <CanvasInspectorPanel
            selectedElement={selectedElement}
            selectedElements={selectedElements}
            setSelectedElement={setSelectedElement}
            setSelectedElements={setSelectedElements}
            fields={fields}
            updateField={updateField}
            flyerCopy={flyerCopy}
            updateFlyer={updateFlyer}
            brand={brand}
            selectedFormat={selectedFormat}
            onBackgroundUpload={onBackgroundUpload}
            showAdvancedControls={showAdvancedControls}
            setShowAdvancedControls={setShowAdvancedControls}
          />
        </main>
      </div>
    </section>
  );
}

function StudioExportStrip({ selectedFormat, onDownloadPng, onDownloadPdf, onDownloadJpg, onPrint, onSharePlatform }) {
  return (
    <section className="studio-export-strip" aria-label="Marketing Studio export actions">
      <div>
        <p className="eyebrow">Ready to use</p>
        <strong>{selectedFormat.name}</strong>
        <span>{selectedFormat.exportLabel} output with Nex branding applied.</span>
      </div>
      <div className="studio-export-actions">
        <button className="btn dark" onClick={onDownloadPng}><Icon name="ImageDown" /><span>PNG</span></button>
        <button className="btn secondary" onClick={onDownloadPdf}><Icon name="Download" /><span>PDF</span></button>
        <button className="btn secondary" onClick={onDownloadJpg}><Icon name="Image" /><span>JPG</span></button>
        <button className="btn secondary" onClick={onPrint}><Icon name="Printer" /><span>Print</span></button>
        <button className="btn primary" onClick={() => onSharePlatform("native")}><Icon name="Share2" /><span>Share</span></button>
      </div>
    </section>
  );
}

function recommendedCtaForWorkflow(workflow = {}) {
  const ctas = {
    listing: "Schedule your private tour today.",
    rental: "Message today to schedule a showing.",
    "open-house": "Stop by this open house.",
    sold: "Thinking about selling? Request your home value.",
    recruiting: "Book a confidential Nex discovery call.",
    event: "Reserve your spot today.",
    social: "Contact Nex Realty to learn more.",
    "business-card": "Modern brokerage. Bold marketing. Smarter moves.",
    template: "Contact Nex Realty today."
  };
  return ctas[workflow.id] || "Contact Nex Realty today.";
}

function simpleWorkflowMissingDetails(workflow = {}, fields = {}, propertyPhotos = []) {
  const checks = [
    workflow.fields?.includes("address") && !fields.propertyAddress && "address",
    (workflow.fields?.includes("price") || workflow.fields?.includes("rent")) && !fields.price && "price/rent",
    workflow.fields?.includes("eventTitle") && !fields.propertyAddress && "event title",
    workflow.fields?.includes("dateTime") && !fields.openHouseDateTime && "date/time",
    workflow.fields?.includes("photos") && !propertyPhotos.length && "photos"
  ];
  return checks.filter(Boolean);
}

function simpleRecentLabel(value, fallback = "Saved") {
  if (!value) return fallback;
  const timestamp = new Date(value).getTime();
  if (!Number.isFinite(timestamp)) return fallback;
  const minutes = Math.max(0, Math.round((Date.now() - timestamp) / 60000));
  if (minutes < 1) return "Just now";
  if (minutes < 60) return `${minutes}m ago`;
  const hours = Math.round(minutes / 60);
  if (hours < 24) return `${hours}h ago`;
  const days = Math.round(hours / 24);
  return `${days}d ago`;
}

function SimpleMarketingHome({ workflows, onChooseWorkflow, projects, loadProject, brand, currentUser, agentHeadshot, onAdvanced }) {
  const visibleWorkflows = workflows.filter((workflow) => ["listing", "rental", "open-house", "sold", "recruiting", "event", "social", "business-card", "template"].includes(workflow.id));
  return (
    <section className="simple-studio-home">
      <header className="simple-studio-hero">
        <div>
          <p className="eyebrow">Marketing Studio</p>
          <h2>Create Nex-branded marketing in minutes.</h2>
          <p>Tell NIA Studio what you are making. Add the basics, upload photos, and the first draft is built for you.</p>
        </div>
        <button type="button" className="btn secondary" onClick={onAdvanced}>
          <Icon name="SlidersHorizontal" />
          <span>Advanced Editor</span>
        </button>
      </header>

      <section className="simple-create-panel">
        <div className="simple-section-head">
          <div>
            <p className="eyebrow">Step 1</p>
            <h3>What do you want to create?</h3>
          </div>
          <span>Start with the purpose. We will handle the format.</span>
        </div>
        <div className="simple-workflow-grid">
          {visibleWorkflows.map((workflow) => (
            <button key={workflow.id} type="button" onClick={() => onChooseWorkflow(workflow)}>
              <Icon name={workflow.icon} />
              <strong>{workflow.label}</strong>
              <span>{workflow.description}</span>
              <em>{workflow.advancedDefault ? "Browse templates" : "Start"}</em>
            </button>
          ))}
        </div>
      </section>

      <section className="simple-studio-bottom">
        <article>
          <div className="simple-section-head">
            <div>
              <p className="eyebrow">Recent Projects</p>
              <h3>Pick up where you left off</h3>
            </div>
          </div>
          <div className="simple-recent-grid">
            {projects.slice(0, 4).map((project) => (
              <button key={project.id} type="button" onClick={() => loadProject(project)}>
                <span>{project.projectType || project.fields?.marketingType || "Marketing"}</span>
                <strong>{project.title || "Untitled project"}</strong>
                <em>{simpleRecentLabel(project.updatedAt || project.createdAt)}</em>
              </button>
            ))}
            {!projects.length && <p>No saved marketing projects yet. Create your first one in a few minutes.</p>}
          </div>
        </article>

        <article className="simple-brand-card">
          <div>
            <p className="eyebrow">Brand / Agent Info</p>
            <h3>{currentUser?.name || "Your agent profile"}</h3>
            <p>Nex logo, brand colors, and your profile details can be applied automatically.</p>
          </div>
          <div className="simple-brand-status">
            <span>{agentHeadshot?.dataUrl ? <img src={agentHeadshot.dataUrl} alt="" /> : <Wordmark brand={brand} variant="light" />}</span>
            <strong>{currentUser?.email || "Agent email"}</strong>
            <em>{currentUser?.phone || "Phone can be added in Admin"}</em>
          </div>
        </article>
      </section>
    </section>
  );
}

function SimpleMarketingBuilder({
  workflow,
  fields,
  updateField,
  flyerCopy,
  updateFlyer,
  propertyPhotos,
  onPhotoUpload,
  onUsePhotoAsHero,
  onRemovePhoto,
  aiStyle,
  setAiStyle,
  recommendedFormats,
  isWorking,
  onGenerateFlyer,
  onGenerateSocial,
  onGeneratePackage,
  onBack,
  onAdvanced,
  onApplyAgentInfo,
  agentHeadshot,
  onHeadshotUpload,
  currentUser
}) {
  const missingDetails = simpleWorkflowMissingDetails(workflow, fields, propertyPhotos);
  const styleOptions = ["Modern Nex", "Luxury", "Bold", "Clean"].map((name) => ({ id: name, name }));
  const needs = (field) => workflow.fields.includes(field);
  const isBusinessCard = workflow.id === "business-card";

  return (
    <section className="simple-builder">
      <header className="simple-builder-head">
        <button type="button" className="btn secondary" onClick={onBack}><Icon name="ArrowLeft" /><span>Back</span></button>
        <div>
          <p className="eyebrow">Step 2</p>
          <h2>{workflow.title}</h2>
          <p>Start with the basics. NIA Studio will build the design for you. Missing details become editable placeholders.</p>
        </div>
        <button type="button" className="btn secondary" onClick={onAdvanced}><Icon name="SlidersHorizontal" /><span>Advanced</span></button>
      </header>

      <div className="simple-builder-grid">
        <main className="simple-builder-form">
          <section>
            <div className="simple-section-head">
              <div>
                <p className="eyebrow">Details</p>
                <h3>{workflow.label} basics</h3>
              </div>
              <button type="button" className="btn secondary small-btn" onClick={onApplyAgentInfo}>
                <Icon name="Contact" />
                <span>Apply my info</span>
              </button>
            </div>

            {(needs("address") || needs("eventTitle")) && (
              <Field
                label={needs("eventTitle") ? "Event title" : "Property address"}
                value={fields.propertyAddress || ""}
                onChange={(value) => updateField("propertyAddress", value)}
                placeholder={needs("eventTitle") ? "Nex Buyer Class" : "123 Main Street"}
              />
            )}

            {(needs("price") || needs("rent")) && (
              <Field
                label={needs("rent") ? "Monthly rent" : "Price"}
                value={fields.price || ""}
                onChange={(value) => updateField("price", value)}
                placeholder={needs("rent") ? "$2,400 / month" : "$725,000"}
              />
            )}

            {(needs("beds") || needs("baths") || needs("garage") || needs("sqft")) && (
              <div className="simple-inline-fields">
                {needs("beds") && <Field label="Beds" value={fields.bedrooms || ""} onChange={(value) => updateField("bedrooms", value)} />}
                {needs("baths") && <Field label="Baths" value={fields.bathrooms || ""} onChange={(value) => updateField("bathrooms", value)} />}
                {needs("garage") && <Field label="Garage" value={fields.garageSpaces || ""} onChange={(value) => updateField("garageSpaces", value)} />}
                {needs("sqft") && <Field label="Sq ft" value={fields.squareFootage || ""} onChange={(value) => updateField("squareFootage", value)} />}
              </div>
            )}

            {needs("available") && <Field label="Available date" type="date" value={fields.rentalAvailableDate || ""} onChange={(value) => updateField("rentalAvailableDate", value)} />}
            {(needs("openHouse") || needs("dateTime")) && <Field label="Date and time" type="datetime-local" value={fields.openHouseDateTime || ""} onChange={(value) => updateField("openHouseDateTime", value)} />}
            {needs("location") && <Field label="Location / link" value={fields.city || ""} onChange={(value) => updateField("city", value)} placeholder="SoWork link, office, or property address" />}
            {needs("speaker") && <Field label="Speaker / partner" value={fields.propertyType || ""} onChange={(value) => updateField("propertyType", value)} placeholder="Wolk Mortgage, NexU, broker support..." />}
            {needs("message") && <Field label="Main message" value={flyerCopy.headline || ""} onChange={(value) => updateFlyer("headline", value)} placeholder="Build. Produce. Grow with Nex." />}
            {needs("plan") && <Field label="Plan or highlight" value={flyerCopy.badge || ""} onChange={(value) => updateFlyer("badge", value)} placeholder="Nex Level, Nex Elite, Nex Central, PowerShare..." />}
            {(needs("agentName") || needs("agentPhone") || needs("agentEmail")) && (
              <div className="simple-inline-fields">
                {needs("agentName") && <Field label="Agent name" value={fields.agentName || ""} onChange={(value) => updateField("agentName", value)} placeholder={currentUser?.name || "Nex Realty Agent"} />}
                {needs("agentPhone") && <Field label="Phone" value={fields.agentPhone || ""} onChange={(value) => updateField("agentPhone", value)} placeholder="555-010-2026" />}
                {needs("agentEmail") && <Field label="Email" value={fields.agentEmail || ""} onChange={(value) => updateField("agentEmail", value)} placeholder={currentUser?.email || "agent@nexrealty.com"} />}
              </div>
            )}
            {(needs("agentWebsite") || needs("agentTitle") || needs("license")) && (
              <div className="simple-inline-fields">
                {needs("agentWebsite") && <Field label="Website" value={flyerCopy.agentWebsite || ""} onChange={(value) => updateFlyer("agentWebsite", value)} placeholder="www.mynexrealty.com/agent" />}
                {needs("agentTitle") && <Field label="Title" value={flyerCopy.agentTitle || ""} onChange={(value) => updateFlyer("agentTitle", value)} placeholder="Real Estate Professional" />}
                {needs("license") && <Field label="License / line" value={flyerCopy.agentLicense || ""} onChange={(value) => updateFlyer("agentLicense", value)} placeholder="Advertised by Nex Realty" />}
              </div>
            )}
            {isBusinessCard && (
              <section className="simple-headshot-field">
                <div className="simple-section-head compact">
                  <div>
                    <p className="eyebrow">Headshot</p>
                    <h3>Agent photo</h3>
                  </div>
                  <span>Optional, but recommended for a polished card.</span>
                </div>
                <FileDrop label={agentHeadshot ? "Replace headshot" : "Upload headshot"} onChange={onHeadshotUpload} preview={agentHeadshot?.dataUrl} />
              </section>
            )}
            {needs("description") && <Field label="Short description" value={fields.propertyHighlights || ""} onChange={(value) => updateField("propertyHighlights", value)} as="textarea" placeholder="Paste rough notes. NIA Studio will clean it up." />}
            {needs("cta") && <Field label="Call to action" value={fields.cta || flyerCopy.cta || ""} onChange={(value) => { updateField("cta", value); updateFlyer("cta", value); }} placeholder={recommendedCtaForWorkflow(workflow)} />}
          </section>

          {needs("photos") && (
            <section>
              <div className="simple-section-head">
                <div>
                  <p className="eyebrow">Photos</p>
                  <h3>Upload your best photos</h3>
                </div>
                <span>Upload your best exterior photo first. We will use it as the hero image.</span>
              </div>
              <FileDrop label="Upload property photos" multiple onChange={onPhotoUpload} count={propertyPhotos.length} />
              {propertyPhotos.length > 0 && (
                <div className="simple-photo-row">
                  {propertyPhotos.slice(0, 8).map((photo, index) => (
                    <article key={`${photo.name}-${index}`}>
                      <img src={photo.dataUrl} alt={photo.name} />
                      <div>
                        <button type="button" onClick={() => onUsePhotoAsHero(index)}>{index === 0 ? "Hero" : "Make hero"}</button>
                        <button type="button" onClick={() => onRemovePhoto(index)}>Remove</button>
                      </div>
                    </article>
                  ))}
                </div>
              )}
            </section>
          )}
        </main>

        <aside className="simple-builder-side">
          <section>
            <p className="eyebrow">Step 3</p>
            <h3>Let NIA Studio build it</h3>
            <p>Choose a style and generate the finished draft. You can edit everything after it is created.</p>
            <ChoiceGrid label="Style" value={aiStyle} options={styleOptions} onChange={setAiStyle} />
          </section>

          <section className="simple-recommended-box">
            <p className="eyebrow">Recommended package</p>
            <div>
              {recommendedFormats.map((format) => (
                <span key={format.id}><Icon name={format.icon} size={14} />{format.name}</span>
              ))}
            </div>
            {missingDetails.length > 0 && (
              <small>Missing: {missingDetails.join(", ")}. Placeholders will stay editable.</small>
            )}
          </section>

          <div className="simple-generate-actions">
            <button type="button" className="btn primary" onClick={onGeneratePackage} disabled={isWorking}>
              <Icon name={isWorking ? "LoaderCircle" : "Sparkles"} className={isWorking ? "spin" : ""} />
              <span>{isWorking ? "Building" : "Make it for me"}</span>
            </button>
            <button type="button" className="btn secondary" onClick={onGenerateFlyer} disabled={isWorking}><Icon name={isBusinessCard ? "Contact" : "FileText"} /><span>{isBusinessCard ? "Generate Card" : "Generate Flyer"}</span></button>
            {!isBusinessCard && <button type="button" className="btn secondary" onClick={onGenerateSocial} disabled={isWorking}><Icon name="Share2" /><span>Generate Social Post</span></button>}
          </div>

          <small className="simple-helper-note">Agent profile: {currentUser?.name || "not loaded"} | Missing details can be filled in later.</small>
        </aside>
      </div>
    </section>
  );
}

function SimpleMarketingResult({
  workflow,
  fields,
  updateField,
  flyerCopy,
  updateFlyer,
  brand,
  templates,
  selectedTemplateId,
  propertyPhotos,
  agentHeadshot,
  flyerRef,
  selectedElement,
  selectedElements,
  onSelectElement,
  onUpdateFlyerLive,
  onReplacePhoto,
  onRemovePhoto,
  onHeadshotUpload,
  assets,
  activeFormat,
  onOpenAsset,
  onDownloadPng,
  onDownloadPdf,
  onSaveProject,
  onRegenerate,
  onBack,
  onHome,
  onAdvanced,
  isWorking,
  aiResult
}) {
  const headlineAlternates = (aiResult?.alternateHeadlines || aiResult?.headlines || []).slice(0, 2);
  const ctaAlternates = (aiResult?.ctaOptions || aiResult?.ctas || []).slice(0, 2);
  const isBusinessCard = workflow.id === "business-card";

  return (
    <section className="simple-result">
      <header className="simple-result-head">
        <div>
          <p className="eyebrow">Draft Ready</p>
          <h2>{workflow.label} marketing is ready to review.</h2>
          <p>Make small edits, export what you need, or open Advanced Editor if you want full control.</p>
        </div>
        <div>
          <button type="button" className="btn secondary" onClick={onHome}><Icon name="Home" /><span>New project</span></button>
          <button type="button" className="btn secondary" onClick={onBack}><Icon name="Pencil" /><span>Edit details</span></button>
          <button type="button" className="btn primary" onClick={onAdvanced}><Icon name="SlidersHorizontal" /><span>Advanced Editor</span></button>
        </div>
      </header>

      <div className="simple-result-grid">
        <aside className="simple-asset-list">
          <p className="eyebrow">Generated assets</p>
          {assets.map((asset) => {
            const format = getCreativeFormat(asset.formatId);
            return (
              <button key={asset.id || asset.formatId} type="button" className={activeFormat.id === asset.formatId ? "selected" : ""} onClick={() => onOpenAsset(asset.formatId)}>
                <Icon name={format.icon} />
                <span>
                  <strong>{asset.name || format.name}</strong>
                  <em>{asset.description || format.exportLabel}</em>
                </span>
              </button>
            );
          })}
        </aside>

        <main className="simple-preview-wrap">
          <FlyerPreview
            brand={brand}
            fields={fields}
            templates={templates}
            selectedTemplateId={selectedTemplateId}
            flyerCopy={flyerCopy}
            propertyPhotos={propertyPhotos}
            agentHeadshot={agentHeadshot}
            flyerRef={flyerRef}
            onSelectElement={onSelectElement}
            selectedElement={selectedElement}
            selectedElements={selectedElements}
            onUpdateField={updateField}
            onUpdateFlyer={updateFlyer}
            onUpdateFlyerLive={onUpdateFlyerLive}
            onReplacePhoto={onReplacePhoto}
            onRemovePhoto={onRemovePhoto}
            onHeadshotUpload={onHeadshotUpload}
            previewZoom={100}
            showSafeGuides={false}
          />
        </main>

        <aside className="simple-edit-panel">
          <section>
            <p className="eyebrow">Simple edits</p>
            <h3>Make final tweaks</h3>
            {isBusinessCard ? (
              <>
                <Field label="Agent name" value={fields.agentName || ""} onChange={(value) => updateField("agentName", value)} />
                <Field label="Phone" value={fields.agentPhone || ""} onChange={(value) => updateField("agentPhone", value)} />
                <Field label="Email" value={fields.agentEmail || ""} onChange={(value) => updateField("agentEmail", value)} />
                <Field label="Website" value={flyerCopy.agentWebsite || ""} onChange={(value) => updateFlyer("agentWebsite", value)} />
                <Field label="Title" value={flyerCopy.agentTitle || ""} onChange={(value) => updateFlyer("agentTitle", value)} />
                <Field label="Tagline" value={flyerCopy.cta || ""} onChange={(value) => updateFlyer("cta", value)} />
              </>
            ) : (
              <>
                <Field label="Headline" value={flyerCopy.headline || ""} onChange={(value) => updateFlyer("headline", value)} />
                <Field label="CTA" value={flyerCopy.cta || ""} onChange={(value) => updateFlyer("cta", value)} />
                <Field label="Body copy" value={flyerCopy.body || ""} onChange={(value) => updateFlyer("body", value)} as="textarea" />
                {headlineAlternates.length > 0 && (
                  <div className="simple-option-list">
                    <span>Alternate headlines</span>
                    {headlineAlternates.map((headline) => <button type="button" key={headline} onClick={() => updateFlyer("headline", headline)}>{headline}</button>)}
                  </div>
                )}
                {ctaAlternates.length > 0 && (
                  <div className="simple-option-list">
                    <span>CTA options</span>
                    {ctaAlternates.map((cta) => <button type="button" key={cta} onClick={() => updateFlyer("cta", cta)}>{cta}</button>)}
                  </div>
                )}
              </>
            )}
          </section>

          <section>
            <p className="eyebrow">Style</p>
            <div className="simple-style-buttons">
              {[
                ["Modern", "clean-white"],
                ["Luxury", "black-luxury"],
                ["Bold", "red-signature"]
              ].map(([label, finish]) => (
                <button key={finish} type="button" className={flyerCopy.finish === finish ? "selected" : ""} onClick={() => updateFlyer("finish", finish)}>{label}</button>
              ))}
            </div>
          </section>

          <section className="simple-export-card">
            <p className="eyebrow">Export</p>
            <button type="button" className="btn primary" onClick={onDownloadPng}><Icon name="ImageDown" /><span>Download PNG</span></button>
            <button type="button" className="btn secondary" onClick={onDownloadPdf}><Icon name="Download" /><span>Download PDF</span></button>
            <button type="button" className="btn secondary" onClick={onSaveProject}><Icon name="Save" /><span>Save Project</span></button>
            <button type="button" className="btn secondary" onClick={onRegenerate} disabled={isWorking}>
              <Icon name={isWorking ? "LoaderCircle" : "RefreshCcw"} className={isWorking ? "spin" : ""} />
              <span>Regenerate</span>
            </button>
          </section>
        </aside>
      </div>
    </section>
  );
}

function StudioExportPanel({ selectedFormat, onDownloadPng, onDownloadPdf, onDownloadJpg, onPrint, onSharePlatform }) {
  const socialActions = [
    ["facebook", "Facebook", "Share2"],
    ["instagram", "Instagram", "Camera"],
    ["x", "X", "AtSign"],
    ["linkedin", "LinkedIn", "Linkedin"]
  ];

  return (
    <div className="studio-tool-content">
      <div className="studio-panel-head">
        <p className="eyebrow">Export</p>
        <h3>Download, print, or share</h3>
      </div>

      <div className="settings-card export-primary-card">
        <p className="studio-label">Current design</p>
        <strong>{selectedFormat.name}</strong>
        <span>{selectedFormat.exportLabel}. Download the final asset first when posting to social or sending to print.</span>
      </div>

      <div className="studio-export-grid">
        <button onClick={onDownloadPng}><Icon name="ImageDown" /><span>Download PNG</span></button>
        <button onClick={onDownloadPdf}><Icon name="Download" /><span>Download PDF</span></button>
        <button onClick={onDownloadJpg}><Icon name="Image" /><span>Download JPG</span></button>
        <button onClick={onPrint}><Icon name="Printer" /><span>Print with VistaPrint</span></button>
      </div>

      <div className="settings-card">
        <p className="studio-label">Social handoff</p>
        <div className="studio-social-grid">
          {socialActions.map(([platform, label, icon]) => (
            <button key={platform} onClick={() => onSharePlatform(platform)}>
              <Icon name={icon} />
              <span>{label}</span>
            </button>
          ))}
        </div>
        <small className="studio-note">
          Nex Central copies your caption and opens the network. Some platforms require you to upload the exported image from your account before posting.
        </small>
      </div>
    </div>
  );
}

function StudioAIPanel({
  aiPrompt,
  setAiPrompt,
  aiStyle,
  setAiStyle,
  aiIsWorking,
  aiResult,
  aiPackage,
  fields,
  updateField,
  flyerCopy,
  updateFlyer,
  selectedFormat,
  selectedTemplate,
  onCreateDesign,
  onGenerateCopy,
  onSuggestTemplate,
  onImproveDesign,
  onCreatePackage,
  onApplyResult,
  onApplyCopy
}) {
  const promptChips = [
    "Create a luxury just listed flyer for this property",
    "Make an open house Instagram post",
    "Create a rental flyer with a strong call to action",
    "Create a seller lead ad for a home value campaign",
    "Create a recruiting post for Nex Realty",
    "Rewrite this listing description to sound more high-end",
    "Create a full listing marketing package"
  ];
  const missingFacts = [
    !fields.propertyAddress && "Property address",
    !fields.price && "Price",
    !fields.agentName && "Agent name",
    !fields.agentPhone && !fields.agentEmail && "Agent contact"
  ].filter(Boolean);
  const styleOptions = ["Modern Nex", "Luxury", "Bold", "Clean", "Minimal", "Social-first"].map((name) => ({ id: name, name }));

  return (
    <div className="studio-tool-content studio-ai-panel">
      <div className="studio-panel-head">
        <p className="eyebrow">AI Create</p>
        <h3>Describe it. NIA Studio builds the draft.</h3>
      </div>

      <div className="ai-create-hero">
        <div>
          <strong>Make it for me</strong>
          <span>AI uses your current property details, agent profile, selected template, Nex brand kit, and compliance guardrails.</span>
        </div>
        <Icon name="Sparkles" />
      </div>

      <div className="settings-card">
        <p className="studio-label">Current design context</p>
        <div className="ai-context-pills">
          <span>{selectedFormat.name}</span>
          <span>{selectedTemplate?.name || "Nex template"}</span>
          <span>{fields.marketingType || "Marketing"}</span>
        </div>
        {missingFacts.length ? (
          <div className="ai-warning-box">
            <Icon name="ShieldAlert" size={15} />
            <span>Missing: {missingFacts.join(", ")}. AI will leave placeholders instead of inventing facts.</span>
          </div>
        ) : (
          <div className="ai-ready-box">
            <Icon name="BadgeCheck" size={15} />
            <span>Property and agent basics are ready for AI drafting.</span>
          </div>
        )}
      </div>

      <div className="settings-card">
        <p className="studio-label">What should we create?</p>
        <textarea value={aiPrompt} onChange={(event) => setAiPrompt(event.target.value)} rows={5} placeholder="Example: Create a luxury just listed flyer for this Tampa property and make the CTA strong." />
        <ChoiceGrid label="Style" value={aiStyle} options={styleOptions} onChange={setAiStyle} />
        <div className="ai-prompt-chip-grid">
          {promptChips.map((chip) => (
            <button key={chip} type="button" onClick={() => setAiPrompt(chip)}>{chip}</button>
          ))}
        </div>
      </div>

      <div className="ai-action-stack">
        <button className="btn primary" onClick={() => onCreateDesign()} disabled={aiIsWorking || !aiPrompt.trim()}>
          <Icon name={aiIsWorking ? "LoaderCircle" : "Sparkles"} className={aiIsWorking ? "spin" : ""} />
          <span>{aiIsWorking ? "Building" : "Generate design draft"}</span>
        </button>
        <button className="btn secondary" onClick={() => onGenerateCopy()} disabled={aiIsWorking || !aiPrompt.trim()}><Icon name="Type" /><span>Generate copy only</span></button>
        <button className="btn secondary" onClick={() => onSuggestTemplate()} disabled={aiIsWorking || !aiPrompt.trim()}><Icon name="LayoutTemplate" /><span>Suggest template</span></button>
        <button className="btn secondary" onClick={() => onImproveDesign()} disabled={aiIsWorking}><Icon name="WandSparkles" /><span>Improve current design</span></button>
        <button className="btn dark" onClick={() => onCreatePackage()} disabled={aiIsWorking || !aiPrompt.trim()}><Icon name="PackagePlus" /><span>Create marketing package</span></button>
      </div>

      <div className="settings-card ai-data-card">
        <p className="studio-label">Property quick fill</p>
        <Field label="Address" value={fields.propertyAddress || ""} onChange={(value) => updateField("propertyAddress", value)} />
        <Field label="Price" value={fields.price || ""} onChange={(value) => updateField("price", value)} />
        <div className="mini-field-grid">
          <Field label="Beds" value={fields.bedrooms || ""} onChange={(value) => updateField("bedrooms", value)} />
          <Field label="Baths" value={fields.bathrooms || ""} onChange={(value) => updateField("bathrooms", value)} />
        </div>
        <Field label="CTA" value={flyerCopy.cta || ""} onChange={(value) => updateFlyer("cta", value)} />
      </div>

      {aiResult && (
        <div className="settings-card ai-result-card">
          <p className="studio-label">Latest AI draft</p>
          <strong>{aiResult.headline || aiResult.headlines?.[0] || aiResult.recommendedTemplateId || aiResult.packageName || "Draft ready"}</strong>
          {aiResult.bodyCopy && <span>{aiResult.bodyCopy}</span>}
          {Array.isArray(aiResult.descriptions) && aiResult.descriptions[0] && <span>{aiResult.descriptions[0]}</span>}
          {aiResult.reason && <span>{aiResult.reason}</span>}
          {Array.isArray(aiResult.suggestions) && (
            <ul>
              {aiResult.suggestions.slice(0, 4).map((item) => <li key={item}>{item}</li>)}
            </ul>
          )}
          {Array.isArray(aiResult.complianceWarnings) && aiResult.complianceWarnings.length > 0 && (
            <div className="ai-warning-list">
              {aiResult.complianceWarnings.slice(0, 4).map((item) => <span key={item}>{item}</span>)}
            </div>
          )}
          <div className="ai-result-actions">
            <button type="button" onClick={() => onApplyResult(aiResult)}><Icon name="Check" size={14} /><span>Apply to design</span></button>
            <button type="button" onClick={() => onApplyCopy(aiResult)}><Icon name="Type" size={14} /><span>Apply copy</span></button>
          </div>
          <small>{aiResult.provider === "openai" ? `OpenAI ${aiResult.model || ""}` : "Local structured mode"} {aiResult.openAiReason ? `- ${aiResult.openAiReason}` : ""}</small>
        </div>
      )}

      {aiPackage && Array.isArray(aiPackage.items) && (
        <div className="settings-card ai-package-card">
          <p className="studio-label">{aiPackage.packageName || "Marketing package"}</p>
          <div className="ai-package-grid">
            {aiPackage.items.map((item) => (
              <article key={`${item.format}-${item.label}`}>
                <strong>{item.label || item.format}</strong>
                <span>{item.headline}</span>
                <button type="button" onClick={() => onCreateDesign({ prompt: `Create ${item.label || item.format} for this campaign`, selectedFormat: item.format, selectedTemplateId: item.templateId })}>
                  <Icon name="MousePointerClick" size={14} />
                  <span>Open this size</span>
                </button>
              </article>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

function StudioToolPanel({
  activeTool,
  templates,
  allCategories,
  templateQuery,
  setTemplateQuery,
  templateCategory,
  setTemplateCategory,
  selectedTemplateId,
  onSelectTemplate,
  selectedFormat,
  brand,
  propertyPhotos,
  setPropertyPhotos,
  onPhotoUpload,
  onHeadshotUpload,
  onBackgroundUpload,
  agentHeadshot,
  savedMedia = [],
  savedHeadshot = null,
  onUseSavedMedia = () => {},
  onRemoveSavedMedia = () => {},
  onClearSavedHeadshot = () => {},
  onAddStockPhoto = () => {},
  assignPhoto,
  setActivePage,
  projects,
  loadProject,
  fields,
  updateField,
  flyerCopy,
  updateFlyer,
  selectedElement,
  selectedElements = [],
  setSelectedElement,
  setSelectedElements,
  applyStylePreset
}) {
  if (activeTool === "Templates") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head">
          <p className="eyebrow">Templates</p>
          <h3>Start from a Nex design</h3>
        </div>
        <div className="studio-size-note">
          <Icon name={selectedFormat?.icon || "Ruler"} size={14} />
          <span>Showing templates for {selectedFormat?.name || "selected size"} ({selectedFormat?.exportLabel || "current format"}).</span>
        </div>
        <input className="studio-search" value={templateQuery} onChange={(event) => setTemplateQuery(event.target.value)} placeholder="Search templates" />
        <div className="studio-filter-row">
          {allCategories.map((category) => (
            <button key={category} className={templateCategory === category ? "selected" : ""} onClick={() => setTemplateCategory(category)}>{category}</button>
          ))}
        </div>
        <div className="studio-template-browser">
          {templates.map((template) => (
            <button key={template.id} className={classNames("studio-template-preview", selectedTemplateId === template.id && "selected")} onClick={() => onSelectTemplate(template)} style={{ "--accent": template.accent || brand.primaryColor }}>
              <MiniTemplatePreview template={template} brand={brand} />
              <strong>{template.name}</strong>
              <span>{template.category} - {getCreativeFormat(getRecommendedFormatForTemplate(template)).name}</span>
              <em className="template-use-pill">Use Template</em>
            </button>
          ))}
        </div>
      </div>
    );
  }

  if (activeTool === "Brand Kit") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Brand Kit</p><h3>Nex Realty defaults</h3></div>
        <div className="brand-kit-card dark"><Wordmark brand={brand} variant="dark" /><span>Dark background logo</span></div>
        <div className="brand-kit-card light"><Wordmark brand={brand} variant="light" /><span>Light background logo</span></div>
        <div className="brand-swatch-row">
          {[brand.primaryColor, brand.black, brand.white, brand.charcoal, brand.gold].map((color) => (
            <button key={color} style={{ background: color }} onClick={() => updateFlyer("accentColor", color)} title={color} />
          ))}
        </div>
        <div className="brand-font-list">
          {brandFontPairings.map((font) => <span key={font}>{font}</span>)}
        </div>
        <div className="tagline-list">
          {brandTaglines.map((tagline) => (
            <button key={tagline} onClick={() => updateFlyer("cta", tagline)}>{tagline}</button>
          ))}
        </div>
      </div>
    );
  }

  if (activeTool === "Styles") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Styles</p><h3>One-click design systems</h3></div>
        <div className="style-preset-grid">
          {studioStylePresets.map((preset) => (
            <button key={preset.id} className="style-preset-card" onClick={() => applyStylePreset(preset)} style={{ "--accent": preset.accentColor, "--preset-bg": preset.backgroundColor }}>
              <span />
              <strong>{preset.name}</strong>
              <em>{preset.description}</em>
            </button>
          ))}
        </div>
        <div className="settings-card">
          <p className="studio-label">Manual style controls</p>
          <Field label="Background color" value={flyerCopy.backgroundColor || "#ffffff"} onChange={(value) => updateFlyer("backgroundColor", value)} type="color" />
          <Field label="Accent color" value={flyerCopy.accentColor || brand.primaryColor} onChange={(value) => updateFlyer("accentColor", value)} type="color" />
          <ChoiceGrid label="Layout" value={flyerCopy.layout || "classic"} options={flyerLayoutOptions} onChange={(value) => updateFlyer("layout", value)} />
          <ChoiceGrid label="Finish" value={flyerCopy.finish || "red-signature"} options={flyerFinishOptions} onChange={(value) => updateFlyer("finish", value)} />
          <ChoiceGrid label="Photo treatment" value={flyerCopy.photoTreatment || "dramatic-overlay"} options={photoTreatmentOptions} onChange={(value) => updateFlyer("photoTreatment", value)} />
        </div>
      </div>
    );
  }

  if (activeTool === "Layers") {
    function chooseLayer(id, event) {
      const additive = Boolean(event?.shiftKey || event?.ctrlKey || event?.metaKey);
      setSelectedElement(id);
      setSelectedElements((current) => {
        if (!additive) return [id];
        if (current.includes(id)) {
          const next = current.filter((item) => item !== id);
          return next.length ? next : [id];
        }
        return [...current, id];
      });
    }

    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Layers</p><h3>Select and arrange</h3></div>
        <div className="studio-layer-list">
          {studioLayerDefinitions.map((layer) => {
            const visible = layer.visibilityField ? flyerCopy[layer.visibilityField] !== false : true;
            return (
              <article key={layer.id} className={classNames(selectedElements.includes(layer.id) && "selected", !visible && "muted")}>
                <button type="button" onClick={(event) => chooseLayer(layer.id, event)}>
                  <Icon name={layer.icon} size={15} />
                  <span>{layer.label}</span>
                </button>
                {layer.visibilityField ? (
                  <button type="button" onClick={() => updateFlyer(layer.visibilityField, !visible)} title={visible ? "Hide layer" : "Show layer"}>
                    <Icon name={visible ? "Eye" : "EyeOff"} size={15} />
                  </button>
                ) : (
                  <span className="layer-lock"><Icon name="LockKeyhole" size={13} /></span>
                )}
              </article>
            );
          })}
        </div>
        <small className="studio-note">Hold Shift/Ctrl while clicking layers to select more than one item.</small>
      </div>
    );
  }

  if (activeTool === "Uploads" || activeTool === "Photos") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">{activeTool}</p><h3>Media tray</h3></div>
        <div className="media-quick-upload-grid">
          <FileDrop label="Upload property photos" multiple onChange={onPhotoUpload} count={propertyPhotos.length} />
          <FileDrop label="Upload background image" onChange={onBackgroundUpload} preview={flyerCopy.backgroundImage} />
          <FileDrop label="Upload agent headshot" onChange={onHeadshotUpload} preview={agentHeadshot?.dataUrl || savedHeadshot?.dataUrl} />
        </div>
        <SavedHeadshotCard savedHeadshot={savedHeadshot} agentHeadshot={agentHeadshot} onHeadshotUpload={onHeadshotUpload} onUseSavedMedia={onUseSavedMedia} onClearSavedHeadshot={onClearSavedHeadshot} />
        <SavedMediaTray media={savedMedia} onUseSavedMedia={onUseSavedMedia} onRemoveSavedMedia={onRemoveSavedMedia} />
        <div className="studio-section-label">
          <span>Current project photos</span>
          <em>{propertyPhotos.length}/12</em>
        </div>
        <div className="media-assignment-grid">
          {propertyPhotos.map((photo, index) => (
            <article key={`${photo.name}-${index}`}>
              <img src={photo.dataUrl} alt={photo.name} crossOrigin={String(photo.dataUrl || "").startsWith("http") ? "anonymous" : undefined} />
              <strong>{photo.name || `Photo ${index + 1}`}</strong>
              <div>
                <button onClick={() => assignPhoto(index, "hero")}>Hero</button>
                <button onClick={() => assignPhoto(index, "secondary-1")}>2</button>
                <button onClick={() => assignPhoto(index, "secondary-2")}>3</button>
                <button onClick={() => assignPhoto(index, "background")}>Background</button>
                <button onClick={() => setPropertyPhotos((current) => current.filter((_, itemIndex) => itemIndex !== index))}>Remove</button>
              </div>
            </article>
          ))}
        </div>
        <StockPhotoTray onAddStockPhoto={onAddStockPhoto} />
      </div>
    );
  }

  if (activeTool === "Text") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Text</p><h3>Campaign copy</h3></div>
        <div className="text-preset-grid">
          <button onClick={() => updateFlyer("headline", flyerCopy.headline || "JUST LISTED")}><Icon name="Heading1" size={14} /><span>Add heading</span></button>
          <button onClick={() => updateFlyer("badge", flyerCopy.badge || "New Listing")}><Icon name="Badge" size={14} /><span>Add badge</span></button>
          <button onClick={() => updateFlyer("body", flyerCopy.body || "Add polished listing copy here.")}><Icon name="AlignLeft" size={14} /><span>Add body</span></button>
          <button onClick={() => updateFlyer("cta", flyerCopy.cta || "Schedule Your Tour Today")}><Icon name="MousePointerClick" size={14} /><span>Add CTA</span></button>
        </div>
        <Field label="Headline" value={flyerCopy.headline} onChange={(value) => updateFlyer("headline", value)} />
        <Field label="Badge" value={flyerCopy.badge} onChange={(value) => updateFlyer("badge", value)} />
        <Field label="Body" value={flyerCopy.body} onChange={(value) => updateFlyer("body", value)} as="textarea" />
        <Field label="CTA" value={flyerCopy.cta} onChange={(value) => updateFlyer("cta", value)} />
        <Field label="Disclaimer" value={flyerCopy.footer} onChange={(value) => updateFlyer("footer", value)} as="textarea" />
      </div>
    );
  }

  if (activeTool === "Elements") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Elements</p><h3>Visibility and QR</h3></div>
        {[
          ["showPrice", "Price section"],
          ["showStats", "Beds / baths / sqft"],
          ["showAgent", "Agent footer"],
          ["showDisclaimer", "Compliance footer"],
          ["showQr", "QR code block"]
        ].map(([field, label]) => (
          <label className="toggle-row" key={field}>
            <input type="checkbox" checked={flyerCopy[field] !== false} onChange={(event) => updateFlyer(field, event.target.checked)} />
            <span>{label}</span>
          </label>
        ))}
        <Field label="QR / lead capture URL" value={flyerCopy.qrUrl || ""} onChange={(value) => updateFlyer("qrUrl", value)} placeholder="https://..." />
        <ChoiceGrid label="Photo fit" value={flyerCopy.heroImageFit || "Cover"} options={headshotFitOptions.map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("heroImageFit", value)} />
      </div>
    );
  }

  if (activeTool === "QR Code") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">QR Code</p><h3>Add a scan action</h3></div>
        <label className="toggle-row">
          <input type="checkbox" checked={flyerCopy.showQr === true} onChange={(event) => updateFlyer("showQr", event.target.checked)} />
          <span>Show QR block on the design</span>
        </label>
        <Field label="QR destination URL" value={flyerCopy.qrUrl || ""} onChange={(value) => updateFlyer("qrUrl", value)} placeholder="https://agent-site.com/listing" />
        <div className="qr-purpose-grid">
          {[
            ["Agent website", flyerCopy.agentWebsite || "https://mynexrealty.com"],
            ["Property page", "https://mynexrealty.com/property"],
            ["Open house sign-in", "https://mynexrealty.com/open-house"],
            ["Recruiting page", "https://mynexrealty.com/careers"]
          ].map(([label, url]) => (
            <button key={label} onClick={() => updateFlyer("qrUrl", url)}>
              <Icon name="QrCode" size={15} />
              <span>{label}</span>
            </button>
          ))}
        </div>
        <small className="studio-note">MVP note: the preview shows a QR placeholder and saves the destination URL. A generated scannable QR image can be added in the next pass.</small>
      </div>
    );
  }

  if (activeTool === "Agent Info") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Agent Info</p><h3>Personalize</h3></div>
        <SavedHeadshotCard savedHeadshot={savedHeadshot} agentHeadshot={agentHeadshot} onHeadshotUpload={onHeadshotUpload} onUseSavedMedia={onUseSavedMedia} onClearSavedHeadshot={onClearSavedHeadshot} />
        <FileDrop label="Upload agent headshot" onChange={onHeadshotUpload} preview={agentHeadshot?.dataUrl || savedHeadshot?.dataUrl} />
        <Field label="Agent name" value={fields.agentName} onChange={(value) => updateField("agentName", value)} />
        <Field label="Agent phone" value={fields.agentPhone} onChange={(value) => updateField("agentPhone", value)} />
        <Field label="Agent email" value={fields.agentEmail} onChange={(value) => updateField("agentEmail", value)} />
        <Field label="Agent title" value={flyerCopy.agentTitle || ""} onChange={(value) => updateFlyer("agentTitle", value)} placeholder="Real Estate Professional" />
        <Field label="Agent website" value={flyerCopy.agentWebsite || ""} onChange={(value) => updateFlyer("agentWebsite", value)} placeholder="https://..." />
        <Field label="Social account" value={flyerCopy.agentSocial || ""} onChange={(value) => updateFlyer("agentSocial", value)} placeholder="@nexrealty" />
        <Field label="License number" value={flyerCopy.agentLicense || ""} onChange={(value) => updateFlyer("agentLicense", value)} />
      </div>
    );
  }

  if (activeTool === "Property Info") {
    return (
      <div className="studio-tool-content">
        <div className="studio-panel-head"><p className="eyebrow">Property Info</p><h3>Listing details</h3></div>
        <Field label="Address" value={fields.propertyAddress} onChange={(value) => updateField("propertyAddress", value)} />
        <Field label="City" value={fields.city} onChange={(value) => updateField("city", value)} />
        <Field label="State" value={fields.state} onChange={(value) => updateField("state", value)} />
        <Field label="Price" value={fields.price} onChange={(value) => updateField("price", value)} />
        <div className="mini-field-grid">
          <Field label="Beds" value={fields.bedrooms} onChange={(value) => updateField("bedrooms", value)} />
          <Field label="Baths" value={fields.bathrooms} onChange={(value) => updateField("bathrooms", value)} />
          <Field label="Garage" value={fields.garageSpaces} onChange={(value) => updateField("garageSpaces", value)} />
          <Field label="Sq ft" value={fields.squareFootage} onChange={(value) => updateField("squareFootage", value)} />
        </div>
        <Field label="Highlights" value={fields.propertyHighlights} onChange={(value) => updateField("propertyHighlights", value)} as="textarea" />
      </div>
    );
  }

  return (
    <div className="studio-tool-content">
      <div className="studio-panel-head"><p className="eyebrow">Saved Projects</p><h3>Recent work</h3></div>
      <div className="studio-saved-list">
        {projects.slice(0, 8).map((project) => (
          <button key={project.id} onClick={() => loadProject(project)}>
            <ProjectThumbnail project={project} brand={brand} />
            <span>{project.title}</span>
          </button>
        ))}
      </div>
      <button className="btn secondary" onClick={() => setActivePage("Saved Projects")}><Icon name="FolderOpen" /><span>Open library</span></button>
    </div>
  );
}

function SavedHeadshotCard({ savedHeadshot, agentHeadshot, onHeadshotUpload, onUseSavedMedia, onClearSavedHeadshot }) {
  const activeHeadshot = savedHeadshot || agentHeadshot;
  return (
    <section className="saved-headshot-card">
      <div>
        <p className="studio-label">Saved headshot</p>
        <span>Stored in this browser for future designs.</span>
      </div>
      <label className="saved-headshot-preview">
        {activeHeadshot ? (
          <img src={activeHeadshot.dataUrl} alt={activeHeadshot.name || "Saved headshot"} />
        ) : (
          <span><Icon name="UserRound" size={22} /></span>
        )}
        <input type="file" accept="image/*" onChange={onHeadshotUpload} />
      </label>
      <div className="saved-headshot-actions">
        <button type="button" onClick={() => activeHeadshot && onUseSavedMedia(activeHeadshot, "headshot")} disabled={!activeHeadshot}>
          <Icon name="UserCheck" size={14} />
          <span>Use</span>
        </button>
        <button type="button" onClick={onClearSavedHeadshot} disabled={!savedHeadshot}>
          <Icon name="X" size={14} />
          <span>Clear</span>
        </button>
      </div>
    </section>
  );
}

function SavedMediaTray({ media = [], onUseSavedMedia, onRemoveSavedMedia }) {
  return (
    <section className="saved-media-section">
      <div className="studio-section-label">
        <span>Saved uploads</span>
        <em>{media.length}/24</em>
      </div>
      {media.length ? (
        <div className="saved-media-grid">
          {media.slice(0, 24).map((item) => (
            <article key={item.id}>
              <img src={item.dataUrl} alt={item.name || item.title || "Saved upload"} crossOrigin={String(item.dataUrl || "").startsWith("http") ? "anonymous" : undefined} />
              <strong>{item.title || item.name || "Saved image"}</strong>
              <small>{item.source || "Saved media"}</small>
              <div>
                <button type="button" onClick={() => onUseSavedMedia(item, "hero")}>Hero</button>
                <button type="button" onClick={() => onUseSavedMedia(item, "secondary-1")}>2</button>
                <button type="button" onClick={() => onUseSavedMedia(item, "background")}>Background</button>
                <button type="button" onClick={() => onUseSavedMedia(item, "headshot")}>Headshot</button>
                <button type="button" className="danger-mini" onClick={() => onRemoveSavedMedia(item.id)}>Remove</button>
              </div>
            </article>
          ))}
        </div>
      ) : (
        <div className="media-empty-state">
          <Icon name="Images" size={18} />
          <span>Uploaded images and stock picks will stay here for this agent on this device.</span>
        </div>
      )}
    </section>
  );
}

function StudioSettingsPanel({ selectedElement, setSelectedElement, fields, updateField, flyerCopy, updateFlyer, brand, selectedTemplate, leadCtaBlocks, applyCtaBlock, output, prompt, setPrompt, isGenerating, onGenerate, onQuickAction, setActivePage }) {
  const activeFormat = getCreativeFormat(flyerCopy.canvasFormat);

  return (
    <div className="studio-settings-content">
      <div className="studio-panel-head">
        <p className="eyebrow">Settings</p>
        <h3>{selectedElement === "headline" ? "Headline" : selectedElement === "agent" ? "Agent block" : selectedElement === "media" ? "Images" : "Design controls"}</h3>
      </div>
      <div className="selected-element-row">
        {["headline", "address", "price", "stats", "body", "agent", "disclaimer", "media"].map((item) => (
          <button key={item} className={selectedElement === item ? "selected" : ""} onClick={() => setSelectedElement(item)}>{item}</button>
        ))}
      </div>

      <div className="settings-card">
        <p className="studio-label">Template</p>
        <strong>{selectedTemplate.name || "Nex template"}</strong>
        <span>{selectedTemplate.category || "Marketing"} - {activeFormat.name} - {activeFormat.exportLabel}</span>
      </div>

      {activeFormat.id === "business-card" && (
        <div className="settings-card business-card-helper">
          <p className="studio-label">Business card mode</p>
          <strong>Use Agent Info for card details.</strong>
          <span>Headshot, website, social account, phone, and email all feed this card preview.</span>
          <button className="btn secondary" onClick={() => setActivePage("Business Card Builder")}>
            <Icon name="Contact" />
            <span>Open Full Card Builder</span>
          </button>
        </div>
      )}

      <div className="settings-card">
        <p className="studio-label">Typography</p>
        <RangeField label="Font size" value={flyerCopy.fontScale || 100} min={70} max={140} suffix="%" onChange={(value) => updateFlyer("fontScale", value)} />
        <RangeField label="Weight" value={flyerCopy.fontWeight || 900} min={500} max={950} step={50} onChange={(value) => updateFlyer("fontWeight", value)} />
        <ChoiceGrid label="Align" value={flyerCopy.textAlign || "left"} options={["left", "center", "right"].map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("textAlign", value)} />
      </div>

      <div className="settings-card">
        <p className="studio-label">Colors</p>
        <div className="brand-swatch-row">
          {[brand.primaryColor, brand.black, brand.white, brand.charcoal, brand.gold].map((color) => (
            <button key={color} style={{ background: color }} onClick={() => updateFlyer("accentColor", color)} title={color} />
          ))}
        </div>
        <Field label="Custom accent" value={flyerCopy.accentColor || selectedTemplate.accent || brand.primaryColor} onChange={(value) => updateFlyer("accentColor", value)} type="color" />
      </div>

      <div className="settings-card">
        <p className="studio-label">Lead CTA blocks</p>
        <div className="cta-chip-grid">
          {leadCtaBlocks.map((label) => <button key={label} onClick={() => applyCtaBlock(label)}>{label}</button>)}
        </div>
      </div>

      <div className="settings-card">
        <p className="studio-label">Quick editors</p>
        <Field label="Headline" value={flyerCopy.headline} onChange={(value) => updateFlyer("headline", value)} />
        <Field label="Address" value={fields.propertyAddress} onChange={(value) => updateField("propertyAddress", value)} />
        <Field label="Price" value={fields.price} onChange={(value) => updateField("price", value)} />
        <Field label="CTA" value={flyerCopy.cta} onChange={(value) => updateFlyer("cta", value)} />
      </div>

      <div className="settings-card assistant-card">
        <p className="studio-label">AI Copy Assistant</p>
        <div className="assistant-action-grid">
          {copyQuickActions.map(([label, action]) => (
            <button key={label} onClick={() => onQuickAction(action)}>{label}</button>
          ))}
        </div>
        <textarea value={prompt} onChange={(event) => setPrompt(event.target.value)} placeholder="Ask for a caption, email, SMS, luxury version, or flyer copy..." rows={4} />
        <button className="btn primary" onClick={() => onGenerate(prompt)} disabled={isGenerating}>
          <Icon name={isGenerating ? "LoaderCircle" : "Sparkles"} className={isGenerating ? "spin" : ""} />
          <span>{isGenerating ? "Generating" : "Generate Copy"}</span>
        </button>
        {output && <small>Latest output: {output.suggestedHeadline}</small>}
      </div>

      <div className="settings-card export-card">
        <p className="studio-label">More tools</p>
        {marketingStudioPages.map(([page, icon]) => (
          <button key={page} onClick={() => setActivePage(page)}>
            <Icon name={icon} size={15} />
            <span>{page}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

function CanvasInspectorPanel({
  selectedElement,
  selectedElements = [selectedElement],
  setSelectedElement,
  setSelectedElements,
  fields,
  updateField,
  flyerCopy,
  updateFlyer,
  brand,
  selectedFormat,
  onBackgroundUpload,
  showAdvancedControls = false,
  setShowAdvancedControls = () => {}
}) {
  const layers = studioLayerDefinitions;
  const isTextLayer = ["logo", "headline", "address", "price", "stats", "body", "agent", "disclaimer", "qr"].includes(selectedElement);
  const selectedLayerCount = selectedElements.length;
  const hasVideoFormat = ["instagram-reel", "instagram-story", "horizontal-video", "youtube-thumbnail"].includes(selectedFormat.id);

  function chooseLayer(id, event) {
    const additive = Boolean(event?.shiftKey || event?.ctrlKey || event?.metaKey);
    if (!additive) {
      setSelectedElement(id);
      setSelectedElements([id]);
      return;
    }
    setSelectedElements((current) => {
      const next = current.includes(id) ? current.filter((item) => item !== id) : [...current, id];
      return next.length ? next : [id];
    });
  }

  function selectAllLayers() {
    const ids = layers.map((layer) => layer.id);
    setSelectedElements(ids);
    setSelectedElement(ids[0]);
  }

  function deleteSelected() {
    const targets = selectedElements.length ? selectedElements : [selectedElement];
    if (targets.includes("headline")) updateFlyer("headline", "");
    if (targets.includes("price")) updateFlyer("showPrice", false);
    if (targets.includes("stats")) updateFlyer("showStats", false);
    if (targets.includes("agent")) updateFlyer("showAgent", false);
    if (targets.includes("disclaimer")) updateFlyer("showDisclaimer", false);
    if (targets.includes("body")) updateFlyer("body", "");
    if (targets.includes("media")) updateFlyer("heroImageFit", "Cover");
    if (targets.includes("qr")) updateFlyer("showQr", false);
  }

  function duplicateSelected() {
    const targets = selectedElements.length ? selectedElements : [selectedElement];
    if (targets.includes("headline")) updateFlyer("body", `${flyerCopy.body || ""}\n\n${flyerCopy.headline || "New headline"}`.trim());
    if (targets.includes("body")) updateFlyer("body", `${flyerCopy.body || "Add your copy here."}\n\n${flyerCopy.body || "Add your copy here."}`);
    if (targets.includes("price")) updateFlyer("badge", fields.price || flyerCopy.badge || "Featured");
  }

  function updateSelectedScale(value) {
    selectedElements.forEach((id) => {
      if (id !== "headline" && id !== "media") updateFlyer(`${id}Scale`, value);
    });
  }

  return (
    <aside className="canvas-inspector-panel" aria-label="Selected design controls">
      <div className="inspector-head">
        <p className="eyebrow">Selected</p>
        <strong>{selectedLayerCount > 1 ? `${selectedLayerCount} layers selected` : layers.find((layer) => layer.id === selectedElement)?.label || "Design item"}</strong>
        <span>{selectedFormat.name} - {selectedFormat.exportLabel}</span>
      </div>

      <div className="inspector-selection-actions">
        <button type="button" onClick={selectAllLayers}><Icon name="MousePointer2" size={14} /><span>Select all</span></button>
        <button type="button" onClick={() => { setSelectedElements([selectedElement]); }}><Icon name="SquareMousePointer" size={14} /><span>Single layer</span></button>
        <button type="button" className={showAdvancedControls ? "selected" : ""} onClick={() => setShowAdvancedControls(!showAdvancedControls)}>
          <Icon name="SlidersHorizontal" size={14} />
          <span>{showAdvancedControls ? "Hide advanced" : "Advanced"}</span>
        </button>
        <small>Tip: hold Shift/Ctrl while clicking layers or canvas items to multi-select.</small>
      </div>

      <div className="inspector-layers">
        {layers.map((layer) => (
          <button key={layer.id} className={selectedElements.includes(layer.id) ? "selected" : ""} onClick={(event) => chooseLayer(layer.id, event)} type="button">
            <Icon name={layer.icon} size={14} />
            <span>{layer.label}</span>
          </button>
        ))}
      </div>

      {selectedLayerCount > 1 && (
        <div className="inspector-card">
          <p className="studio-label">Group controls</p>
          <div className="inspector-action-grid">
            <button type="button" onClick={() => updateFlyer("accentColor", brand.primaryColor)}><Icon name="Palette" size={14} /><span>Nex red</span></button>
            <button type="button" onClick={() => updateFlyer("accentColor", brand.gold)}><Icon name="Gem" size={14} /><span>Gold accent</span></button>
            <button type="button" onClick={duplicateSelected}><Icon name="CopyPlus" size={14} /><span>Duplicate group</span></button>
            <button type="button" onClick={deleteSelected}><Icon name="Trash2" size={14} /><span>Hide group</span></button>
          </div>
          {showAdvancedControls && <RangeField label="Group scale" value={flyerCopy[`${selectedElement}Scale`] || 100} min={70} max={160} suffix="%" onChange={updateSelectedScale} />}
        </div>
      )}

      {selectedElement === "headline" && (
        <div className="inspector-card">
          <p className="studio-label">Text</p>
          <Field label="Headline" value={flyerCopy.headline || ""} onChange={(value) => updateFlyer("headline", value)} />
          <RangeField label="Size" value={flyerCopy.fontScale || 100} min={70} max={150} suffix="%" onChange={(value) => updateFlyer("fontScale", value)} />
          <ChoiceGrid label="Align" value={flyerCopy.textAlign || "left"} options={["left", "center", "right"].map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("textAlign", value)} />
          {showAdvancedControls && (
            <div className="advanced-control-grid">
              <RangeField label="Move X" value={Number(flyerCopy.headlineOffsetX) || 0} min={-140} max={140} step={1} suffix="px" onChange={(value) => updateFlyer("headlineOffsetX", value)} />
              <RangeField label="Move Y" value={Number(flyerCopy.headlineOffsetY) || 0} min={-140} max={140} step={1} suffix="px" onChange={(value) => updateFlyer("headlineOffsetY", value)} />
              <RangeField label="Width" value={flyerCopy.headlineWidth || 360} min={160} max={680} step={10} suffix="px" onChange={(value) => updateFlyer("headlineWidth", value)} />
              <RangeField label="Weight" value={flyerCopy.fontWeight || 900} min={500} max={950} step={50} onChange={(value) => updateFlyer("fontWeight", value)} />
            </div>
          )}
        </div>
      )}

      {selectedElement === "media" && (
        <div className="inspector-card">
          <p className="studio-label">Image controls</p>
          <RangeField label="Hero height" value={flyerCopy.heroHeight || 274} min={140} max={560} step={5} suffix="px" onChange={(value) => updateFlyer("heroHeight", value)} />
          <ChoiceGrid label="Fit" value={flyerCopy.heroImageFit || "Cover"} options={["Cover", "Contain", "Fill", "Center"].map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("heroImageFit", value)} />
          <ChoiceGrid label="Crop focus" value={flyerCopy.heroImagePosition || "center"} options={["center", "top", "bottom", "left", "right"].map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("heroImagePosition", value)} />
          <label className="toggle-row">
            <input type="checkbox" checked={flyerCopy.showQr === true} onChange={(event) => updateFlyer("showQr", event.target.checked)} />
            <span>Show QR block</span>
          </label>
          <Field label="QR destination" value={flyerCopy.qrUrl || ""} onChange={(value) => updateFlyer("qrUrl", value)} placeholder="https://..." />
        </div>
      )}

      {isTextLayer && selectedElement !== "headline" && (
        <div className="inspector-card">
          <p className="studio-label">Layer controls</p>
          {selectedElement === "address" && <Field label="Address" value={fields.propertyAddress || ""} onChange={(value) => updateField("propertyAddress", value)} />}
          {selectedElement === "price" && <Field label="Price" value={fields.price || ""} onChange={(value) => updateField("price", value)} />}
          {selectedElement === "body" && <Field label="Body copy" value={flyerCopy.body || ""} onChange={(value) => updateFlyer("body", value)} as="textarea" />}
          {selectedElement === "agent" && <Field label="Agent name" value={fields.agentName || ""} onChange={(value) => updateField("agentName", value)} />}
          {selectedElement === "disclaimer" && <Field label="Compliance footer" value={flyerCopy.footer || ""} onChange={(value) => updateFlyer("footer", value)} as="textarea" />}
          {selectedElement === "qr" && <Field label="QR destination" value={flyerCopy.qrUrl || ""} onChange={(value) => updateFlyer("qrUrl", value)} placeholder="https://..." />}
          {showAdvancedControls && (
            <div className="advanced-control-grid">
              <RangeField label="Move X" value={Number(flyerCopy[`${selectedElement}OffsetX`]) || 0} min={-160} max={160} step={1} suffix="px" onChange={(value) => updateFlyer(`${selectedElement}OffsetX`, value)} />
              <RangeField label="Move Y" value={Number(flyerCopy[`${selectedElement}OffsetY`]) || 0} min={-160} max={160} step={1} suffix="px" onChange={(value) => updateFlyer(`${selectedElement}OffsetY`, value)} />
              <RangeField label="Layer scale" value={flyerCopy[`${selectedElement}Scale`] || 100} min={70} max={160} suffix="%" onChange={(value) => updateFlyer(`${selectedElement}Scale`, value)} />
            </div>
          )}
        </div>
      )}

      <div className="inspector-card">
        <p className="studio-label">Background</p>
        <Field label="Background color" value={flyerCopy.backgroundColor || "#ffffff"} onChange={(value) => updateFlyer("backgroundColor", value)} type="color" />
        <label className="canvas-upload-button">
          <Icon name="ImagePlus" size={14} />
          <span>{flyerCopy.backgroundImage ? "Replace background" : "Upload background"}</span>
          <input type="file" accept="image/*" onChange={onBackgroundUpload} />
        </label>
        {showAdvancedControls && <RangeField label="Background image opacity" value={flyerCopy.backgroundOpacity || 12} min={0} max={70} suffix="%" onChange={(value) => updateFlyer("backgroundOpacity", value)} />}
        {flyerCopy.backgroundImage && (
          <button type="button" className="mini-danger-button" onClick={() => { updateFlyer("backgroundImage", ""); updateFlyer("backgroundImageName", ""); }}>
            <Icon name="X" size={14} />
            <span>Remove background image</span>
          </button>
        )}
      </div>

      {hasVideoFormat && (
        <div className="inspector-card">
          <p className="studio-label">Video / motion prep</p>
          <ChoiceGrid label="Motion style" value={flyerCopy.videoMotion || "Subtle zoom"} options={["Subtle zoom", "Slide up", "Pan left", "Static cover"].map((name) => ({ id: name, name }))} onChange={(value) => updateFlyer("videoMotion", value)} />
          <RangeField label="Duration" value={flyerCopy.videoDuration || 8} min={4} max={20} suffix=" sec" onChange={(value) => updateFlyer("videoDuration", value)} />
          <small className="studio-note">This prepares reel/story cover motion settings for the Quick Video Builder. Full timeline editing remains a later upgrade.</small>
        </div>
      )}

      <div className="inspector-card">
        <p className="studio-label">Layer actions</p>
        <div className="inspector-action-grid">
          <button type="button" onClick={() => updateFlyer("accentColor", brand.primaryColor)}><Icon name="Palette" size={14} /><span>Nex red</span></button>
          <button type="button" onClick={() => updateFlyer("accentColor", brand.black)}><Icon name="Circle" size={14} /><span>Black</span></button>
          <button type="button" onClick={duplicateSelected}><Icon name="CopyPlus" size={14} /><span>Duplicate</span></button>
          <button type="button" onClick={deleteSelected}><Icon name="Trash2" size={14} /><span>Delete</span></button>
        </div>
      </div>
    </aside>
  );
}

function MiniTemplatePreview({ template, brand }) {
  return (
    <div className="mini-template-preview" style={{ "--accent": template.accent || brand.primaryColor }}>
      <Wordmark brand={brand} compact variant={template.style === "luxury" ? "dark" : "light"} />
      <span>{template.badge}</span>
      <strong>{template.headline}</strong>
      <em>{template.category}</em>
    </div>
  );
}

function ProjectThumbnail({ project, brand }) {
  const headline = project.flyerCopy?.headline || project.fields?.marketingType || "Nex Project";
  const badge = project.flyerCopy?.badge || project.fields?.status || "Marketing";
  return (
    <div className="project-thumb" style={{ "--accent": project.flyerCopy?.accentColor || brand.primaryColor }}>
      <Wordmark brand={brand} compact variant="dark" />
      <span>{badge}</span>
      <strong>{headline}</strong>
    </div>
  );
}

function BulletinBoard({ announcements, role, setAnnouncements, setToast }) {
  const [query, setQuery] = useState("");
  const [category, setCategory] = useState("All");
  const [editingId, setEditingId] = useState("");
  const [editDraft, setEditDraft] = useState({});
  const [draft, setDraft] = useState({
    title: "",
    body: "",
    category: "General",
    pinned: false,
    urgent: false,
    expiresAt: ""
  });
  const canManage = isAdminRole(role);
  const filtered = announcements.filter((item) => {
    const matchesCategory = category === "All" || item.category === category;
    const matchesQuery = `${item.title} ${item.body}`.toLowerCase().includes(query.toLowerCase());
    return matchesCategory && matchesQuery;
  });

  async function addAnnouncement() {
    if (!draft.title.trim()) return;
    try {
      const saved = await API.request("/api/announcements", {
        method: "POST",
        body: JSON.stringify(draft)
      });
      setAnnouncements((current) => [saved, ...current]);
      setDraft({ title: "", body: "", category: "General", pinned: false, urgent: false, expiresAt: "" });
      setToast("Announcement posted.");
    } catch (error) {
      setToast(error.message || "Could not post announcement.");
    }
  }

  async function updateAnnouncement(id, patch) {
    try {
      const saved = await API.request(`/api/announcements/${encodeURIComponent(id)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      setAnnouncements((current) => current.map((item) => (item.id === id ? saved : item)));
      setToast("Announcement updated.");
    } catch (error) {
      setToast(error.message || "Could not update announcement.");
    }
  }

  async function deleteAnnouncement(id) {
    try {
      await API.request(`/api/announcements/${encodeURIComponent(id)}`, { method: "DELETE" });
      setAnnouncements((current) => current.filter((item) => item.id !== id));
      setToast("Announcement deleted.");
    } catch (error) {
      setToast(error.message || "Could not delete announcement.");
    }
  }

  function startEditing(item) {
    setEditingId(item.id);
    setEditDraft({
      title: item.title || "",
      body: item.body || "",
      category: item.category || "General",
      expiresAt: item.expiresAt || ""
    });
  }

  async function saveEditing(id) {
    await updateAnnouncement(id, editDraft);
    setEditingId("");
    setEditDraft({});
  }

  return (
    <section className="portal-page">
      <div className="portal-toolbar">
        <Field label="Search announcements" value={query} onChange={setQuery} placeholder="Search updates..." />
        <Field label="Category" value={category} onChange={setCategory} as="select" options={["All", ...announcementCategories]} />
      </div>

      {canManage && (
        <div className="panel admin-compose">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Admin</p>
              <h3>Post announcement</h3>
            </div>
          </div>
          <div className="admin-form-grid">
            <Field label="Title" value={draft.title} onChange={(value) => setDraft((current) => ({ ...current, title: value }))} />
            <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} as="select" options={announcementCategories} />
            <Field label="Expires" value={draft.expiresAt} onChange={(value) => setDraft((current) => ({ ...current, expiresAt: value }))} type="date" />
            <label className="check-field"><input type="checkbox" checked={draft.pinned} onChange={(event) => setDraft((current) => ({ ...current, pinned: event.target.checked }))} />Pinned</label>
            <label className="check-field"><input type="checkbox" checked={draft.urgent} onChange={(event) => setDraft((current) => ({ ...current, urgent: event.target.checked }))} />Urgent</label>
            <Field label="Body" value={draft.body} onChange={(value) => setDraft((current) => ({ ...current, body: value }))} as="textarea" />
          </div>
          <button className="btn primary" onClick={addAnnouncement}>
            <Icon name="Plus" />
            <span>Post Announcement</span>
          </button>
        </div>
      )}

      <div className="announcement-grid">
        {filtered.map((item) => (
          <article className={classNames("announcement-card", item.urgent && "urgent", item.pinned && "pinned")} key={item.id}>
            <div className="announcement-meta">
              <span>{item.category}</span>
              {item.pinned && <em>Pinned</em>}
              {item.urgent && <em>Urgent</em>}
            </div>
            {editingId === item.id ? (
              <div className="announcement-edit-grid">
                <Field label="Title" value={editDraft.title || ""} onChange={(value) => setEditDraft((current) => ({ ...current, title: value }))} />
                <Field label="Category" value={editDraft.category || "General"} onChange={(value) => setEditDraft((current) => ({ ...current, category: value }))} as="select" options={announcementCategories} />
                <Field label="Expires" value={editDraft.expiresAt || ""} onChange={(value) => setEditDraft((current) => ({ ...current, expiresAt: value }))} type="date" />
                <Field label="Body" value={editDraft.body || ""} onChange={(value) => setEditDraft((current) => ({ ...current, body: value }))} as="textarea" />
              </div>
            ) : (
              <>
                <h3>{item.title}</h3>
                <p>{item.body}</p>
                {item.expiresAt && <small>Expires {new Date(item.expiresAt).toLocaleDateString()}</small>}
              </>
            )}
            {canManage && (
              <div className="row-actions">
                {editingId === item.id ? (
                  <>
                    <button className="btn secondary small-btn" onClick={() => saveEditing(item.id)}>Save</button>
                    <button className="btn secondary small-btn" onClick={() => setEditingId("")}>Cancel</button>
                  </>
                ) : (
                  <button className="btn secondary small-btn" onClick={() => startEditing(item)}>Edit</button>
                )}
                <button className="btn secondary small-btn" onClick={() => updateAnnouncement(item.id, { pinned: !item.pinned })}>Pin</button>
                <button className="btn secondary small-btn" onClick={() => updateAnnouncement(item.id, { urgent: !item.urgent })}>Urgent</button>
                <button className="icon-btn small" onClick={() => deleteAnnouncement(item.id)} title="Delete">
                  <Icon name="Trash2" size={15} />
                </button>
              </div>
            )}
          </article>
        ))}
      </div>
    </section>
  );
}

function QuickLinksCenter({ quickLinks, role, setQuickLinks, setToast, openQuickLink }) {
  const [draft, setDraft] = useState({ title: "", url: "", category: "General", description: "", icon: "ExternalLink", order: 99 });
  const canManage = isAdminRole(role);
  const groupedLinks = Object.entries(
    [...quickLinks]
      .sort((a, b) => Number(a.order || 999) - Number(b.order || 999))
      .reduce((groups, link) => {
        const category = link.category || "General";
        groups[category] = groups[category] || [];
        groups[category].push(link);
        return groups;
      }, {})
  );

  async function addLink() {
    if (!draft.title.trim()) return;
    try {
      const saved = await API.request("/api/quick-links", { method: "POST", body: JSON.stringify(draft) });
      setQuickLinks((current) => [...current, saved].sort((a, b) => Number(a.order) - Number(b.order)));
      setDraft({ title: "", url: "", category: "General", description: "", icon: "ExternalLink", order: 99 });
      setToast("Quick link added.");
    } catch (error) {
      setToast(error.message || "Could not add link.");
    }
  }

  async function deleteLink(id) {
    try {
      await API.request(`/api/quick-links/${encodeURIComponent(id)}`, { method: "DELETE" });
      setQuickLinks((current) => current.filter((item) => item.id !== id));
      setToast("Quick link removed.");
    } catch (error) {
      setToast(error.message || "Could not remove link.");
    }
  }

  async function updateLink(id, patch) {
    try {
      const saved = await API.request(`/api/quick-links/${encodeURIComponent(id)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      setQuickLinks((current) =>
        current.map((item) => (item.id === id ? saved : item)).sort((a, b) => Number(a.order || 999) - Number(b.order || 999))
      );
    } catch (error) {
      setToast(error.message || "Could not update link.");
    }
  }

  return (
    <section className="portal-page">
      {canManage && (
        <div className="panel admin-compose">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Admin</p>
              <h3>Add quick link</h3>
            </div>
          </div>
          <div className="admin-form-grid">
            <Field label="Title" value={draft.title} onChange={(value) => setDraft((current) => ({ ...current, title: value }))} />
            <Field label="URL or app:Page Name" value={draft.url} onChange={(value) => setDraft((current) => ({ ...current, url: value }))} />
            <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} />
            <Field label="Icon" value={draft.icon} onChange={(value) => setDraft((current) => ({ ...current, icon: value }))} />
            <Field label="Order" value={draft.order} onChange={(value) => setDraft((current) => ({ ...current, order: value }))} type="number" />
            <Field label="Description" value={draft.description} onChange={(value) => setDraft((current) => ({ ...current, description: value }))} as="textarea" />
          </div>
          <button className="btn primary" onClick={addLink}>
            <Icon name="Plus" />
            <span>Add Link</span>
          </button>
        </div>
      )}

      <div className="quick-link-sections">
        {groupedLinks.map(([category, links]) => (
          <section className="quick-link-section" key={category}>
            <div className="quick-link-section-head">
              <h3>{category}</h3>
              <span>{links.length} link{links.length === 1 ? "" : "s"}</span>
            </div>
            <div className="quick-links-grid">
              {links.map((link) => {
                const url = String(link.url || "");
                const linkType = link.id === "nexu" || link.title === "NexU" ? "Internal" : url.startsWith("app:") ? "Internal" : url === "#" || !url ? "Needs URL" : "External";
                return (
                  <article className={classNames("quick-link-card", `type-${slugify(linkType)}`)} key={link.id}>
                    <button onClick={() => openQuickLink(link)}>
                      <span className="quick-link-icon">
                        {link.logoUrl ? <img src={link.logoUrl} alt="" /> : <Icon name={link.icon || "ExternalLink"} />}
                      </span>
                      <span className="quick-link-copy">
                        <strong>{link.title}</strong>
                        <span>{link.description}</span>
                      </span>
                      <em>{linkType}</em>
                    </button>
                    {canManage && (
                      <details className="link-admin-controls">
                        <summary>Manage link</summary>
                        <div>
                          <input value={link.title} onChange={(event) => updateLink(link.id, { title: event.target.value })} aria-label="Quick link title" />
                          <input value={link.url} onChange={(event) => updateLink(link.id, { url: event.target.value })} aria-label="Quick link URL" />
                          <input type="number" value={link.order || 99} onChange={(event) => updateLink(link.id, { order: event.target.value })} aria-label="Quick link order" />
                          <button className="icon-btn small" onClick={() => deleteLink(link.id)} title="Remove link">
                            <Icon name="Trash2" size={15} />
                          </button>
                        </div>
                      </details>
                    )}
                  </article>
                );
              })}
            </div>
          </section>
        ))}
      </div>
    </section>
  );
}

function AgentDirectory({ agents = [], currentUser, setToast, setActivePage }) {
  const [query, setQuery] = useState("");
  const [market, setMarket] = useState("All");
  const [directoryType, setDirectoryType] = useState("Agent");
  const marketOptions = ["All", "Tampa Bay", "Orlando", "Miami", ...Array.from(new Set(agents.map((agent) => agent.market).filter(Boolean))).filter((item) => !["Tampa Bay", "Orlando", "Miami"].includes(item))];
  const visibleAgents = agents
    .filter((agent) => agent.active !== false)
    .filter((agent) => (agent.directoryType || "Agent") === directoryType)
    .filter((agent) => market === "All" || agent.market === market)
    .filter((agent) => {
      const haystack = [agent.name, agent.email, agent.phone, agent.market, agent.role, agent.directoryType].join(" ").toLowerCase();
      return haystack.includes(query.toLowerCase());
    })
    .sort((a, b) => (a.market || "").localeCompare(b.market || "") || (a.name || a.email).localeCompare(b.name || b.email));
  const activeDirectoryCounts = agents
    .filter((agent) => agent.active !== false)
    .reduce((counts, agent) => {
      const type = agent.directoryType || "Agent";
      counts[type] = Number(counts[type] || 0) + 1;
      return counts;
    }, {});

  return (
    <section className="agent-directory-page">
      <div className="directory-hero">
        <div>
          <p className="eyebrow">Nex collaboration</p>
          <h1>Directory</h1>
          <p>Find Nex agents and staff by region, name, phone, or email so the team can collaborate beyond chat.</p>
        </div>
        <div className="directory-hero-stat">
          <strong>{visibleAgents.length}</strong>
          <span>{market === "All" ? `Active ${directoryType}` : `${market} ${directoryType}`}</span>
        </div>
      </div>

      <div className="directory-type-switch panel">
        {directoryTypeOptions.map((type) => (
          <button key={type} className={classNames(directoryType === type && "active")} onClick={() => setDirectoryType(type)}>
            <Icon name={type === "Staff" ? "ShieldCheck" : "ContactRound"} />
            <span>{type}</span>
            <em>{activeDirectoryCounts[type] || 0}</em>
          </button>
        ))}
      </div>

      <div className="directory-controls panel">
        <label className="field">
          <span>Search {directoryType.toLowerCase()}</span>
          <input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search name, email, phone, or region" />
        </label>
        <label className="field">
          <span>Region</span>
          <select value={market} onChange={(event) => setMarket(event.target.value)}>
            {marketOptions.map((option) => <option key={option} value={option}>{option}</option>)}
          </select>
        </label>
      </div>

      <div className="directory-grid">
        {visibleAgents.map((agent) => (
          <article className="agent-directory-card" key={agent.id || agent.email}>
            <UserAvatar user={agent} size="lg" className="agent-directory-avatar" />
            <div>
              <h3>{agent.name || agent.email}</h3>
              <p>{agent.market || "Region not set"}</p>
            </div>
            <span className="directory-type-pill">{agent.directoryType || "Agent"}</span>
            <div className="agent-directory-actions">
              {agent.phone && <a className="btn secondary" href={`tel:${agent.phone}`}><Icon name="Phone" /><span>Call</span></a>}
              {agent.phone && <a className="btn secondary" href={`sms:${agent.phone}`}><Icon name="MessageSquareText" /><span>Text</span></a>}
              <button className="btn secondary" type="button" onClick={() => { localStorage.setItem("nex-chat-open-dm", agent.email); setActivePage?.("Nex Chat"); }}>
                <Icon name="MessagesSquare" />
                <span>DM</span>
              </button>
              <a className="btn secondary" href={`mailto:${agent.email}`}><Icon name="Mail" /><span>Email</span></a>
              <button className="btn secondary" onClick={() => copyToClipboard([agent.name, agent.phone, agent.email, agent.market].filter(Boolean).join(" | "), setToast)}>
                <Icon name="Copy" />
                <span>Copy</span>
              </button>
            </div>
            <dl>
              <div><dt>Email</dt><dd>{agent.email}</dd></div>
              <div><dt>Phone</dt><dd>{agent.phone || "Not added"}</dd></div>
              <div><dt>Type</dt><dd>{agent.directoryType || "Agent"}</dd></div>
              <div><dt>Role</dt><dd>{agent.role || "Agent"}</dd></div>
            </dl>
            {agent.email === currentUser?.email && <em className="agent-directory-self">You</em>}
          </article>
        ))}
      </div>
      {!visibleAgents.length && <EmptyState icon="ContactRound" title={`No ${directoryType.toLowerCase()} found`} body="Try a different search or ask admin to update directory type, phone, and region details in the Admin Panel." />}
    </section>
  );
}

function chatChannelKey(channelId) {
  return `channel:${String(channelId || "general").replace(/^#/, "")}`;
}

function chatDmKeyForUsers(emailA, emailB) {
  return `dm:${[emailA, emailB].map((email) => String(email || "").toLowerCase()).sort().join("|")}`;
}

function chatInitials(nameOrEmail) {
  const text = String(nameOrEmail || "NX").trim();
  const parts = text.includes("@") ? [text[0], text.split("@")[1]?.[0]] : text.split(/\s+/);
  return parts.filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase() || "NX";
}

function chatUserForMessage(message, users = [], currentUser = null) {
  const email = normalizeEmail(message?.senderEmail);
  return users.find((user) => normalizeEmail(user.email) === email)
    || (normalizeEmail(currentUser?.email) === email ? currentUser : null)
    || { name: message?.senderName || email, email, headshotUrl: message?.senderHeadshotUrl };
}

function chatMessageTime(value) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  return date.toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
}

function chatFileExtension(name) {
  const parts = String(name || "").toLowerCase().split(".");
  return parts.length > 1 ? parts.pop() : "";
}

function chatAttachmentAllowed(file) {
  return CHAT_ALLOWED_EXTENSIONS.includes(chatFileExtension(file.name)) && Number(file.size || 0) <= CHAT_UPLOAD_LIMIT_BYTES;
}

function chatFileSize(size) {
  const number = Number(size || 0);
  if (number > 1024 * 1024) return `${(number / (1024 * 1024)).toFixed(1)} MB`;
  if (number > 1024) return `${Math.round(number / 1024)} KB`;
  return `${number || 0} B`;
}

function chatMessageRoomKey(message) {
  return message?.roomType === "dm" ? message.dmKey : chatChannelKey(message?.channelId);
}

function chatMessagePreviewText(message) {
  const text = String(message?.text || "").trim();
  if (text) return text.length > 92 ? `${text.slice(0, 89)}...` : text;
  const attachmentCount = Array.isArray(message?.attachments) ? message.attachments.length : 0;
  if (attachmentCount) return `${attachmentCount} attachment${attachmentCount === 1 ? "" : "s"} shared`;
  return "New chat activity";
}

function chatDashboardRoomLabel(message, channels = [], users = [], currentUser = null) {
  if (!message) return "Nex Chat";
  if (message.roomType === "dm") {
    const currentEmail = normalizeEmail(currentUser?.email);
    const otherEmail = (message.participantEmails || []).map(normalizeEmail).find((email) => email && email !== currentEmail);
    const otherUser = users.find((user) => normalizeEmail(user.email) === otherEmail);
    return otherUser?.name || otherEmail || "Direct message";
  }
  const channel = channels.find((item) => item.id === message.channelId);
  return channel?.name || message.channelName || `#${String(message.channelId || "channel").replace(/^#/, "")}`;
}

function chatDashboardOpenMessage(message, currentUser, setActivePage) {
  if (message?.roomType === "dm") {
    const currentEmail = normalizeEmail(currentUser?.email);
    const otherEmail = (message.participantEmails || []).map(normalizeEmail).find((email) => email && email !== currentEmail);
    if (otherEmail) localStorage.setItem("nex-chat-open-dm", otherEmail);
  } else if (message?.channelId) {
    localStorage.setItem("nex-chat-open-channel", message.channelId);
  }
  setActivePage("Nex Chat");
}

function NexChatDashboardWidget({ currentUser, setActivePage, latestChat = null, chatUnreadTotal = 0, variant = "success" }) {
  const [chatState, setChatState] = useState({
    loading: true,
    error: "",
    channels: [],
    users: [],
    messages: latestChat ? [latestChat] : [],
    unreadCounts: {}
  });
  const currentEmail = normalizeEmail(currentUser?.email);
  const unreadTotal = Object.values(chatState.unreadCounts || {}).reduce((sum, value) => sum + Number(value || 0), 0)
    || Number(chatUnreadTotal || 0);
  const unreadRoomKeys = new Set(Object.entries(chatState.unreadCounts || {}).filter(([, count]) => Number(count || 0) > 0).map(([key]) => key));
  const sortedMessages = [...(chatState.messages || [])].sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
  const unreadMessages = sortedMessages.filter((message) => unreadRoomKeys.has(chatMessageRoomKey(message)) && normalizeEmail(message.senderEmail) !== currentEmail);
  const previewMessages = [...unreadMessages, ...sortedMessages]
    .filter((message, index, list) => message?.id && list.findIndex((item) => item?.id === message.id) === index)
    .slice(0, 5);
  const widgetHeadClass = variant === "nex" ? "nex-widget-head" : "success-widget-head";
  const widgetClass = variant === "nex" ? "nex-widget dashboard-chat-widget" : "success-widget dashboard-chat-widget";
  const statusLabel = chatState.loading
    ? "Checking messages..."
    : unreadTotal > 0
      ? `${unreadTotal} unread chat${unreadTotal === 1 ? "" : "s"}`
      : "No missed chats";

  async function refreshChatWidget() {
    setChatState((current) => ({ ...current, loading: true, error: "" }));
    try {
      const data = await API.request("/api/chat/bootstrap");
      setChatState({
        loading: false,
        error: "",
        channels: data.channels || [],
        users: data.users || [],
        messages: data.messages || [],
        unreadCounts: data.unreadCounts || {}
      });
    } catch (error) {
      setChatState((current) => ({
        ...current,
        loading: false,
        error: error.message || "Could not load Nex Chat preview."
      }));
    }
  }

  useEffect(() => {
    let stream;
    refreshChatWidget();
    if (window.EventSource) {
      stream = new EventSource("/api/chat/stream");
      stream.addEventListener("chat-message", (event) => {
        try {
          const payload = JSON.parse(event.data || "{}");
          if (!payload.message) return;
          setChatState((current) => {
            const exists = current.messages.some((message) => message.id === payload.message.id);
            const nextMessages = exists ? current.messages : [...current.messages, payload.message];
            const roomKey = chatMessageRoomKey(payload.message);
            const fromCurrentUser = normalizeEmail(payload.message.senderEmail) === currentEmail;
            const nextUnreadCounts = fromCurrentUser ? current.unreadCounts : {
              ...current.unreadCounts,
              [roomKey]: Number(current.unreadCounts?.[roomKey] || 0) + 1
            };
            return {
              ...current,
              messages: nextMessages.sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0)),
              unreadCounts: nextUnreadCounts
            };
          });
        } catch (_) {}
      });
      stream.addEventListener("chat-channel", (event) => {
        try {
          const payload = JSON.parse(event.data || "{}");
          if (!payload.channel) return;
          setChatState((current) => ({
            ...current,
            channels: current.channels.some((channel) => channel.id === payload.channel.id)
              ? current.channels
              : [...current.channels, payload.channel].sort((a, b) => Number(a.order || 999) - Number(b.order || 999))
          }));
        } catch (_) {}
      });
    }
    return () => {
      if (stream) stream.close();
    };
  }, [currentEmail]);

  return (
    <article className={classNames(widgetClass, unreadTotal > 0 && "has-unread")}>
      <div className={widgetHeadClass}>
        <div>
          <p className="eyebrow">Nex Chat</p>
          <h2>{statusLabel}</h2>
        </div>
        <span className={unreadTotal > 0 ? "dashboard-chat-badge unread" : "dashboard-chat-badge"}>
          <Icon name={unreadTotal > 0 ? "MessageCircleWarning" : "CheckCheck"} size={15} />
          {unreadTotal > 0 ? "New" : "Caught up"}
        </span>
      </div>

      <div className="dashboard-chat-list">
        {previewMessages.map((message) => {
          const sender = chatUserForMessage(message, chatState.users, currentUser);
          const roomKey = chatMessageRoomKey(message);
          const isUnread = unreadRoomKeys.has(roomKey) && normalizeEmail(message.senderEmail) !== currentEmail;
          const mentionedYou = (message.mentionedEmails || []).map(normalizeEmail).includes(currentEmail);
          return (
            <button
              key={message.id}
              type="button"
              className={classNames("dashboard-chat-item", isUnread && "unread", mentionedYou && "mention")}
              onClick={() => chatDashboardOpenMessage(message, currentUser, setActivePage)}
            >
              <UserAvatar user={sender} size="sm" className="dashboard-chat-avatar" />
              <span className="dashboard-chat-copy">
                <strong>
                  {normalizeEmail(message.senderEmail) === currentEmail ? "You" : message.senderName || sender.name || sender.email}
                  <em>{chatDashboardRoomLabel(message, chatState.channels, chatState.users, currentUser)}</em>
                </strong>
                <small>{chatMessagePreviewText(message)}</small>
              </span>
              <span className="dashboard-chat-meta">
                {isUnread && <i />}
                <time>{dashboardTime(message.createdAt, "Now")}</time>
                {mentionedYou && <b>@you</b>}
              </span>
            </button>
          );
        })}

        {!previewMessages.length && (
          <div className="dashboard-chat-empty">
            <Icon name="MessagesSquare" />
            <strong>You are all caught up.</strong>
            <span>No new messages right now.</span>
          </div>
        )}

        {chatState.error && <p className="dashboard-chat-error">{chatState.error}</p>}
      </div>

      <div className="dashboard-chat-actions">
        <button className="btn primary compact" type="button" onClick={() => setActivePage("Nex Chat")}>
          <Icon name="MessagesSquare" />
          <span>Open Nex Chat</span>
        </button>
        <button className="btn secondary compact" type="button" onClick={refreshChatWidget} disabled={chatState.loading}>
          <Icon name="RefreshCcw" className={chatState.loading ? "spin" : ""} />
          <span>Refresh</span>
        </button>
      </div>
    </article>
  );
}

function NexChat({ currentUser, role, setToast, onUnreadTotalChange, onLatestMessageChange }) {
  const [channels, setChannels] = useState([]);
  const [users, setUsers] = useState([]);
  const [messages, setMessages] = useState([]);
  const [unreadCounts, setUnreadCounts] = useState({});
  const [activeRoom, setActiveRoom] = useState({ type: "channel", id: "announcements", key: "channel:announcements", label: "Company Wide" });
  const [chatMode, setChatMode] = useState("all");
  const [chatSearch, setChatSearch] = useState("");
  const [draft, setDraft] = useState("");
  const [pendingFiles, setPendingFiles] = useState([]);
  const [loading, setLoading] = useState(true);
  const [sending, setSending] = useState(false);
  const [channelDraft, setChannelDraft] = useState("");
  const [dmDirectoryType, setDmDirectoryType] = useState("Agent");
  const activeRoomRef = useRef(activeRoom);
  const messageEndRef = useRef(null);
  const canManageChannels = isAdminRole(role);

  function updateUnread(nextCounts) {
    const counts = nextCounts || {};
    setUnreadCounts(counts);
    onUnreadTotalChange?.(Object.values(counts).reduce((sum, value) => sum + Number(value || 0), 0));
  }

  async function markRead(roomKey = activeRoomRef.current.key) {
    if (!roomKey) return;
    try {
      const response = await API.request("/api/chat/read", {
        method: "POST",
        body: JSON.stringify({ roomKey })
      });
      updateUnread(response.unreadCounts || {});
    } catch (error) {
      // Read state is helpful, but chat should continue even if this request misses.
    }
  }

  useEffect(() => {
    activeRoomRef.current = activeRoom;
  }, [activeRoom]);

  useEffect(() => {
    let mounted = true;
    let stream;

    async function loadChat() {
      try {
        const data = await API.request("/api/chat/bootstrap");
        if (!mounted) return;
        const nextChannels = data.channels || [];
        setChannels(nextChannels);
        setUsers(data.users || []);
        setMessages(data.messages || []);
        setActiveRoom((current) => {
          if (current.type === "dm") return current;
          if (nextChannels.some((channel) => chatChannelKey(channel.id) === current.key)) return current;
          const firstChannel = nextChannels[0];
          return firstChannel
            ? { type: "channel", id: firstChannel.id, key: chatChannelKey(firstChannel.id), label: firstChannel.name || firstChannel.id }
            : current;
        });
        onLatestMessageChange?.((data.messages || []).slice(-1)[0] || null);
        updateUnread(data.unreadCounts || {});
      } catch (error) {
        setToast(error.message || "Could not load Nex Chat.");
      } finally {
        if (mounted) setLoading(false);
      }
    }

    loadChat();

    if (window.EventSource) {
      stream = new EventSource("/api/chat/stream");
      stream.addEventListener("chat-message", (event) => {
        const payload = JSON.parse(event.data || "{}");
        if (!payload.message) return;
        const roomKey = payload.message.roomType === "dm" ? payload.message.dmKey : chatChannelKey(payload.message.channelId);
        onLatestMessageChange?.(payload.message);
        setMessages((current) => {
          if (current.some((message) => message.id === payload.message.id)) return current;
          return [...current, payload.message].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0));
        });
        if (roomKey === activeRoomRef.current.key) {
          markRead(roomKey);
        } else if (payload.message.senderEmail !== currentUser?.email) {
          setUnreadCounts((current) => {
            const next = { ...current, [roomKey]: Number(current[roomKey] || 0) + 1 };
            onUnreadTotalChange?.(Object.values(next).reduce((sum, value) => sum + Number(value || 0), 0));
            return next;
          });
        }
      });
      stream.addEventListener("chat-channel", (event) => {
        const payload = JSON.parse(event.data || "{}");
        if (!payload.channel) return;
        setChannels((current) => current.some((channel) => channel.id === payload.channel.id) ? current : [...current, payload.channel].sort((a, b) => Number(a.order || 999) - Number(b.order || 999)));
      });
    }

    return () => {
      mounted = false;
      if (stream) stream.close();
    };
  }, []);

  useEffect(() => {
    markRead(activeRoom.key);
  }, [activeRoom.key]);

  useEffect(() => {
    messageEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
  }, [messages.length, activeRoom.key]);

  const roomMessages = messages.filter((message) => {
    const key = message.roomType === "dm" ? message.dmKey : chatChannelKey(message.channelId);
    return key === activeRoom.key;
  });
  const allDmUsers = users.filter((user) => user.email && user.email !== currentUser?.email);
  const searchValue = chatSearch.trim().toLowerCase();
  const channelMatches = (channel) => !searchValue
    || String(channel.name || channel.id || "").toLowerCase().includes(searchValue)
    || String(channel.topic || "").toLowerCase().includes(searchValue);
  const userMatches = (user) => !searchValue
    || String(user.name || "").toLowerCase().includes(searchValue)
    || String(user.email || "").toLowerCase().includes(searchValue)
    || String(user.directoryType || "").toLowerCase().includes(searchValue);
  const filteredChannels = channels.filter(channelMatches);
  const primaryChannelIds = new Set(["announcements", "tampa-bay", "miami", "orlando"]);
  const primaryChannels = filteredChannels.filter((channel) => channel.featured || primaryChannelIds.has(channel.id));
  const otherChannels = filteredChannels.filter((channel) => !primaryChannelIds.has(channel.id) && !channel.featured);
  const filteredDmUsers = allDmUsers.filter(userMatches);
  const dmUsers = filteredDmUsers.filter((user) => (user.directoryType || "Agent") === dmDirectoryType);
  const activeDmUser = allDmUsers.find((user) => chatDmKeyForUsers(currentUser?.email, user.email) === activeRoom.key);
  const activeChannel = activeRoom.type === "channel" ? channels.find((channel) => chatChannelKey(channel.id) === activeRoom.key) : null;
  const activeRoomAdminOnly = activeRoom.type === "channel" && Boolean(activeChannel?.adminOnly);
  const canPostInActiveRoom = activeRoom.type !== "channel" || !activeRoomAdminOnly || canManageChannels;
  const showChannels = chatMode === "all" || chatMode === "channels";
  const showDms = chatMode === "all" || chatMode === "dms";
  const mentionTokens = [currentUser?.name?.split(/\s+/)[0], currentUser?.email?.split("@")[0]]
    .map((value) => String(value || "").toLowerCase())
    .filter(Boolean);
  const currentUserEmail = normalizeEmail(currentUser?.email);
  const mentionMessages = messages.filter((message) => {
    const mentionedEmails = Array.isArray(message.mentionedEmails) ? message.mentionedEmails.map(normalizeEmail) : [];
    if (mentionedEmails.includes(currentUserEmail)) return true;
    return mentionTokens.some((token) => String(message.text || "").toLowerCase().includes(`@${token}`));
  });
  const showMentions = chatMode === "mentions";
  const dmTypeCounts = allDmUsers.reduce((counts, user) => {
    const type = user.directoryType || "Agent";
    counts[type] = Number(counts[type] || 0) + 1;
    return counts;
  }, {});

  useEffect(() => {
    const pendingEmail = normalizeEmail(localStorage.getItem("nex-chat-open-dm"));
    if (!pendingEmail || !users.length) return;
    const user = users.find((item) => normalizeEmail(item.email) === pendingEmail);
    if (!user) return;
    localStorage.removeItem("nex-chat-open-dm");
    setDmDirectoryType(user.directoryType || "Agent");
    openDm(user);
  }, [users.length]);

  useEffect(() => {
    const pendingChannelId = String(localStorage.getItem("nex-chat-open-channel") || "").replace(/^#/, "");
    if (!pendingChannelId || !channels.length) return;
    const channel = channels.find((item) => item.id === pendingChannelId);
    if (!channel) return;
    localStorage.removeItem("nex-chat-open-channel");
    setChatMode("channels");
    openChannel(channel);
  }, [channels.length]);

  function openChannel(channel) {
    setActiveRoom({ type: "channel", id: channel.id, key: chatChannelKey(channel.id), label: channel.name || channel.id });
  }

  function openDm(user) {
    setActiveRoom({ type: "dm", id: user.email, key: chatDmKeyForUsers(currentUser?.email, user.email), label: user.name || user.email, recipientEmail: user.email });
  }

  async function addFiles(event) {
    const files = Array.from(event.target.files || []);
    const valid = [];
    for (const file of files) {
      if (!chatAttachmentAllowed(file)) {
        setToast(`${file.name} is not an allowed chat upload or is over 5MB.`);
        continue;
      }
      valid.push(await fileToDataUrl(file));
    }
    setPendingFiles((current) => [...current, ...valid].slice(0, 6));
    event.target.value = "";
  }

  async function sendMessage(event) {
    event.preventDefault();
    if (!draft.trim() && !pendingFiles.length) return;
    if (!canPostInActiveRoom) {
      setToast("Company Wide is admin-post only. Use a market channel or direct message to reply.");
      return;
    }
    setSending(true);
    try {
      const payload = {
        roomType: activeRoom.type,
        channelId: activeRoom.type === "channel" ? activeRoom.id : "",
        recipientEmail: activeRoom.type === "dm" ? activeRoom.recipientEmail || activeDmUser?.email : "",
        text: draft,
        attachments: pendingFiles
      };
      const response = await API.request("/api/chat/messages", {
        method: "POST",
        body: JSON.stringify(payload)
      });
      if (response.message) {
        onLatestMessageChange?.(response.message);
        setMessages((current) => current.some((message) => message.id === response.message.id) ? current : [...current, response.message].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0)));
      }
      updateUnread(response.unreadCounts || {});
      setDraft("");
      setPendingFiles([]);
    } catch (error) {
      setToast(error.message || "Could not send chat message.");
    } finally {
      setSending(false);
    }
  }

  function handleComposerKeyDown(event) {
    if (event.key !== "Enter" || event.shiftKey) return;
    event.preventDefault();
    sendMessage(event);
  }

  async function createChannel() {
    if (!channelDraft.trim()) return;
    try {
      const channel = await API.request("/api/chat/channels", {
        method: "POST",
        body: JSON.stringify({ name: channelDraft })
      });
      setChannels((current) => [...current, channel].sort((a, b) => Number(a.order || 999) - Number(b.order || 999)));
      setChannelDraft("");
      setToast("Chat channel created.");
    } catch (error) {
      setToast(error.message || "Could not create chat channel.");
    }
  }

  function roomLastMessage(roomKey) {
    return [...messages].reverse().find((message) => {
      const key = message.roomType === "dm" ? message.dmKey : chatChannelKey(message.channelId);
      return key === roomKey;
    });
  }

  function roomTime(roomKey) {
    const message = roomLastMessage(roomKey);
    return message ? chatMessageTime(message.createdAt) : "";
  }

  function roomPreview(roomKey, fallback = "") {
    const message = roomLastMessage(roomKey);
    if (!message) return fallback;
    if (message.text) return `${message.senderName || "Nex"}: ${message.text}`;
    return `${message.senderName || "Nex"} shared an attachment`;
  }

  function renderChannelRow(channel) {
    const key = chatChannelKey(channel.id);
    const unread = Number(unreadCounts[key] || 0);
    const active = activeRoom.key === key;
    return (
      <button key={channel.id} className={classNames("nex-chat-list-row", active && "active", channel.adminOnly && "admin-only")} onClick={() => openChannel(channel)}>
        <span className="nex-chat-row-icon"><Icon name={channel.adminOnly ? "Megaphone" : "Hash"} /></span>
        <span className="nex-chat-row-copy">
          <strong>{channel.name}</strong>
          <small>{roomPreview(key, channel.topic || "Shared Nex channel")}</small>
        </span>
        <span className="nex-chat-row-meta">
          {unread > 0 ? <em>{unread}</em> : <small>{roomTime(key) || (channel.adminOnly ? "Admin" : "")}</small>}
          {channel.adminOnly && <b>Locked</b>}
        </span>
      </button>
    );
  }

  function renderDmRow(user) {
    const key = chatDmKeyForUsers(currentUser?.email, user.email);
    const unread = Number(unreadCounts[key] || 0);
    const active = activeRoom.key === key;
    return (
      <button key={user.email} className={classNames("nex-chat-list-row dm-row", active && "active")} onClick={() => openDm(user)}>
        <UserAvatar user={user} size="sm" className="mini-avatar" />
        <span className="nex-chat-row-copy">
          <strong>{user.name || user.email}</strong>
          <small>{roomPreview(key, user.role ? `${user.directoryType || "Agent"} - ${user.role}` : user.email)}</small>
        </span>
        <span className="nex-chat-row-meta">
          {unread > 0 ? <em>{unread}</em> : <small>{roomTime(key)}</small>}
        </span>
      </button>
    );
  }

  function openMention(message) {
    if (!message) return;
    if (message.roomType === "dm") {
      const otherEmail = (message.participantEmails || []).find((email) => normalizeEmail(email) !== normalizeEmail(currentUser?.email));
      const user = allDmUsers.find((item) => normalizeEmail(item.email) === normalizeEmail(otherEmail));
      if (user) openDm(user);
      return;
    }
    const channel = channels.find((item) => item.id === message.channelId);
    if (channel) openChannel(channel);
  }

  if (loading) return <EmptyState icon="MessagesSquare" title="Loading Nex Chat" body="Opening company channels, direct messages, and live updates." />;

  return (
    <section className="nex-chat-page nex-chat-app">
      <aside className="nex-chat-sidebar">
        <div className="nex-chat-topbar">
          <span className="nex-chat-icon-button is-static" title="Nex Chat">
            <Icon name="Settings" />
          </span>
          <div className="nex-chat-brand">
            <strong>Nex Chat</strong>
            <small>Team channels + private DMs</small>
          </div>
          {canManageChannels ? (
            <button className="nex-chat-icon-button" title="Create channel" onClick={() => setChannelDraft((current) => current || "new-channel")}>
              <Icon name="MessageCirclePlus" />
            </button>
          ) : (
            <span className="nex-chat-icon-button is-static" title="Direct messages">
              <Icon name="MessageCircle" />
            </span>
          )}
        </div>

        <div className="nex-chat-tabs" role="tablist" aria-label="Nex Chat sections">
          {[
            ["all", "MessageCircle", "All"],
            ["dms", "MessagesSquare", "DMs"],
            ["channels", "List", "Channels"],
            ["mentions", "AtSign", "Mentions"]
          ].map(([key, icon, label]) => (
            <button key={key} className={classNames(chatMode === key && "active")} onClick={() => setChatMode(key)} type="button">
              <Icon name={icon} />
              <span>{label}</span>
            </button>
          ))}
        </div>

        <label className="nex-chat-search">
          <Icon name="Search" />
          <input value={chatSearch} onChange={(event) => setChatSearch(event.target.value)} placeholder="Search chats, channels, agents" />
        </label>

        {showChannels && (
          <>
            <div className="nex-chat-section-heading">
              <span>Channels</span>
              <em>{primaryChannels.length + otherChannels.length}</em>
            </div>
            <div className="nex-chat-room-list chat-list-modern">
              {primaryChannels.map(renderChannelRow)}
              {otherChannels.length > 0 && (
                <>
                  <div className="nex-chat-section-heading soft-heading">
                    <span>More channels</span>
                    <em>{otherChannels.length}</em>
                  </div>
                  {otherChannels.map(renderChannelRow)}
                </>
              )}
            </div>
          </>
        )}

        {canManageChannels && showChannels && (
          <div className="nex-channel-create">
            <input value={channelDraft} onChange={(event) => setChannelDraft(event.target.value)} placeholder="Create a channel" />
            <button onClick={createChannel} title="Create channel"><Icon name="Plus" size={15} /></button>
          </div>
        )}

        {showDms && (
          <>
            <div className="nex-chat-section-heading dm-heading">
              <span>Direct Messages</span>
              <em>{dmUsers.length}</em>
            </div>
            <div className="chat-dm-filter">
              {directoryTypeOptions.map((type) => (
                <button key={type} className={classNames(dmDirectoryType === type && "active")} onClick={() => setDmDirectoryType(type)}>
                  <span>{type}</span>
                  <em>{dmTypeCounts[type] || 0}</em>
                </button>
              ))}
            </div>
            <div className="nex-chat-room-list chat-list-modern">
              {dmUsers.map(renderDmRow)}
              {!dmUsers.length && <p className="nex-chat-empty-list">No direct messages match that filter.</p>}
            </div>
          </>
        )}

        {showMentions && (
          <>
            <div className="nex-chat-section-heading">
              <span>Mentions</span>
              <em>{mentionMessages.length}</em>
            </div>
            <div className="nex-chat-room-list chat-list-modern">
              {mentionMessages.slice(-20).reverse().map((message) => (
                <button key={message.id} className="nex-chat-list-row mention-row" type="button" onClick={() => openMention(message)}>
                  <span className="nex-chat-row-icon"><Icon name="AtSign" /></span>
                  <span className="nex-chat-row-copy">
                    <strong>{message.senderName || message.senderEmail}</strong>
                    <small>{message.text}</small>
                  </span>
                  <span className="nex-chat-row-meta"><small>{chatMessageTime(message.createdAt)}</small></span>
                </button>
              ))}
              {!mentionMessages.length && <p className="nex-chat-empty-list">No mentions yet.</p>}
            </div>
          </>
        )}
      </aside>

      <main className="nex-chat-main">
        <header className="nex-chat-header">
          <div>
            <p className="eyebrow">{activeRoom.type === "dm" ? "Direct message" : activeRoomAdminOnly ? "Admin announcement channel" : "Market channel"}</p>
            <h3>{activeRoom.label}</h3>
            <span>
              {activeRoom.type === "dm"
                ? "Private conversation between participants only."
                : activeRoomAdminOnly
                  ? "Company-wide updates are visible to everyone. Posting is limited to admins."
                  : activeChannel?.topic || "Visible to logged-in Nex Central users."}
            </span>
          </div>
          <button className="btn secondary small-btn" onClick={() => markRead(activeRoom.key)}>
            <Icon name="CheckCheck" />
            <span>Mark Read</span>
          </button>
        </header>

        <div className="nex-chat-stream">
          {roomMessages.length ? (
            roomMessages.map((message) => (
              <NexChatMessage key={message.id} message={message} currentUser={currentUser} users={users} />
            ))
          ) : (
            <EmptyState icon="MessageCircle" title="No messages yet" body="Start the conversation with a quick update, question, file, or photo." />
          )}
          <div ref={messageEndRef} />
        </div>

        <form className={classNames("nex-chat-composer", !canPostInActiveRoom && "composer-disabled")} onSubmit={sendMessage}>
          {!canPostInActiveRoom && (
            <div className="nex-chat-readonly-note">
              <Icon name="Lock" />
              <span>Company Wide is admin-post only. Use Tampa Bay, Miami, Orlando, or a direct message to chat.</span>
            </div>
          )}
          <div className="emoji-row">
            {chatEmojiOptions.map((emoji) => (
              <button key={emoji} type="button" disabled={!canPostInActiveRoom} onClick={() => setDraft((current) => `${current}${emoji}`)}>{emoji}</button>
            ))}
          </div>
          {pendingFiles.length > 0 && (
            <div className="pending-attachments">
              {pendingFiles.map((file, index) => (
                <span key={`${file.name}-${index}`}>
                  {file.name}
                  <button type="button" onClick={() => setPendingFiles((current) => current.filter((_, itemIndex) => itemIndex !== index))}>x</button>
                </span>
              ))}
            </div>
          )}
          <div className="composer-row">
            <label className="chat-attach-button" title="Attach file">
              <Icon name="Paperclip" />
              <input type="file" multiple disabled={!canPostInActiveRoom} accept=".jpg,.jpeg,.png,.gif,.webp,.pdf,.doc,.docx,.xls,.xlsx,.csv" onChange={addFiles} />
            </label>
            <textarea value={draft} disabled={!canPostInActiveRoom} onKeyDown={handleComposerKeyDown} onChange={(event) => setDraft(event.target.value)} placeholder={canPostInActiveRoom ? `Message ${activeRoom.label} or @name` : "Admin-only announcement channel"} rows={2} />
            <button className="btn primary" type="submit" disabled={sending || !canPostInActiveRoom}>
              <Icon name={sending ? "LoaderCircle" : "Send"} className={sending ? "spin" : ""} />
              <span>Send</span>
            </button>
          </div>
        </form>
      </main>
    </section>
  );
}

function NexChatMessage({ message, currentUser, users = [] }) {
  const mine = message.senderEmail === currentUser?.email;
  const sender = chatUserForMessage(message, users, currentUser);
  return (
    <article className={classNames("nex-chat-message", mine && "mine")}>
      <UserAvatar user={sender} size="sm" className="chat-avatar" />
      <div className="chat-message-body">
        <div className="chat-message-meta">
          <strong>{message.senderName || message.senderEmail}</strong>
          <span>{chatMessageTime(message.createdAt)}</span>
        </div>
        {message.text && <p>{message.text}</p>}
        {Array.isArray(message.attachments) && message.attachments.length > 0 && (
          <div className="chat-attachments">
            {message.attachments.map((file) => (
              <a key={file.id || file.name} href={file.dataUrl} download={file.name} target="_blank" rel="noreferrer" className={classNames(file.isImage && "image-attachment")}>
                {file.isImage ? <img src={file.dataUrl} alt={file.name} /> : <Icon name="FileDown" />}
                <span>{file.name}<small>{chatFileSize(file.size)}</small></span>
              </a>
            ))}
          </div>
        )}
      </div>
    </article>
  );
}

function NexAgentAssist({ currentUser, role, setToast }) {
  const [prompt, setPrompt] = useState("");
  const welcomeMessage = {
    id: "assist-welcome",
    type: "assistant",
    provider: "nex",
    text: "Hi, I'm NIA. Tell me what is happening with the client, lead, transaction, or marketing task and we can work through it together. You can ask follow-ups without starting over."
  };
  const [messages, setMessages] = useState([
    welcomeMessage
  ]);
  const [isAsking, setIsAsking] = useState(false);
  const [conversationId, setConversationId] = useState("");
  const [conversations, setConversations] = useState([]);
  const [knowledgeArticles, setKnowledgeArticles] = useState([]);
  const [knowledgeDraft, setKnowledgeDraft] = useState({ title: "", category: "General", content: "" });
  const isAdmin = isAdminRole(role);

  useEffect(() => {
    refreshNiaConversations();
  }, []);

  useEffect(() => {
    if (isAdmin) refreshNiaKnowledge();
  }, [isAdmin]);

  function niaMessageFromApi(message) {
    return {
      id: message.id,
      type: message.role === "user" ? "user" : "assistant",
      text: message.content || "",
      provider: message.provider,
      model: message.model,
      confidence: message.confidence,
      openAiReason: message.openAiReason,
      knowledgeBase: Array.isArray(message.sources) && message.sources.length > 0,
      sources: message.sources || [],
      needsEscalation: Boolean(message.needsEscalation),
      sections: message.sections || null,
      createdAt: message.createdAt
    };
  }

  async function refreshNiaConversations() {
    try {
      const rows = await API.request("/api/nia/conversations");
      setConversations(Array.isArray(rows) ? rows : []);
    } catch (error) {
      setConversations([]);
    }
  }

  async function openConversation(id) {
    if (!id) return;
    try {
      const conversation = await API.request(`/api/nia/conversations/${encodeURIComponent(id)}`);
      setConversationId(conversation.id);
      const nextMessages = (conversation.messages || []).map(niaMessageFromApi);
      setMessages(nextMessages.length ? nextMessages : [{ ...welcomeMessage, id: `assist-welcome-${Date.now()}` }]);
    } catch (error) {
      setToast(error.message || "Could not open NIA conversation.");
    }
  }

  async function refreshNiaKnowledge() {
    try {
      const rows = await API.request("/api/admin/nia/knowledge");
      setKnowledgeArticles(Array.isArray(rows) ? rows : []);
    } catch (error) {
      setKnowledgeArticles([]);
    }
  }

  async function revealAssistantMessage(message) {
    const parts = String(message.text || "").split(/(\s+)/);
    let shown = "";
    setMessages((current) => [...current, { ...message, text: "" }]);
    for (let index = 0; index < parts.length; index += 1) {
      shown += parts[index];
      if (index % 4 === 0 || index === parts.length - 1) {
        setMessages((current) => current.map((item) => (item.id === message.id ? { ...item, text: shown } : item)));
        await new Promise((resolve) => setTimeout(resolve, 8));
      }
    }
  }

  function resetConversation() {
    setMessages([
      {
        ...welcomeMessage,
        id: `assist-welcome-${Date.now()}`
      }
    ]);
    setConversationId("");
    setPrompt("");
    setToast("NIA started a fresh chat.");
  }

  async function ask(question) {
    const nextPrompt = question || prompt;
    if (!nextPrompt.trim()) return;
    setIsAsking(true);
    setMessages((current) => [...current, { id: `ask-${Date.now()}`, type: "user", text: nextPrompt }]);
    try {
      const response = await API.request("/api/nia/chat", { method: "POST", body: JSON.stringify({ message: nextPrompt, conversationId }) });
      if (response.conversation?.id) setConversationId(response.conversation.id);
      const assistantMessage = niaMessageFromApi(response.assistantMessage || {
        id: response.id,
        role: "assistant",
        content: response.answer,
        provider: response.provider,
        model: response.model,
        confidence: response.confidence,
        openAiReason: response.openAiReason,
        sources: response.sources,
        needsEscalation: response.needsEscalation,
        sections: response.sections
      });
      await revealAssistantMessage(assistantMessage);
      setPrompt("");
      refreshNiaConversations();
    } catch (error) {
      setToast("NIA could not answer right now.");
    } finally {
      setIsAsking(false);
    }
  }

  function handlePromptKeyDown(event) {
    if (event.key !== "Enter" || event.shiftKey || isAsking) return;
    event.preventDefault();
    ask();
  }

  async function sendFeedback(message, rating) {
    try {
      await API.request("/api/nia/feedback", { method: "POST", body: JSON.stringify({ messageId: message.id, rating }) });
      setToast(rating === "up" ? "Thanks. NIA feedback saved." : "Thanks. Admin can review that answer.");
    } catch (error) {
      setToast(error.message || "Could not save feedback.");
    }
  }

  async function createNiaSupportTicket(message) {
    if (!conversationId) return;
    try {
      const ticket = await API.request("/api/nia/support-ticket", {
        method: "POST",
        body: JSON.stringify({
          conversationId,
          category: message?.needsEscalation ? "Broker support" : "NIA escalation",
          urgency: message?.needsEscalation ? "High" : "Normal"
        })
      });
      setToast(`Support ticket created: ${ticket.subject || "NIA escalation"}`);
    } catch (error) {
      setToast(error.message || "Could not create support ticket.");
    }
  }

  async function saveKnowledgeArticle(event) {
    event.preventDefault();
    if (!knowledgeDraft.title.trim() || !knowledgeDraft.content.trim()) return;
    try {
      await API.request("/api/admin/nia/knowledge", { method: "POST", body: JSON.stringify(knowledgeDraft) });
      setKnowledgeDraft({ title: "", category: "General", content: "" });
      refreshNiaKnowledge();
      setToast("NIA knowledge article added.");
    } catch (error) {
      setToast(error.message || "Could not save NIA knowledge.");
    }
  }

  async function toggleKnowledgeArticle(article) {
    try {
      await API.request(`/api/admin/nia/knowledge/${encodeURIComponent(article.id)}`, {
        method: "PUT",
        body: JSON.stringify({ active: article.active === false })
      });
      refreshNiaKnowledge();
    } catch (error) {
      setToast(error.message || "Could not update article.");
    }
  }

  function displayedNiaSources(message) {
    const sourceTitles = Array.isArray(message.sections?.nexSourceUsed) ? message.sections.nexSourceUsed.filter(Boolean) : [];
    if (sourceTitles.length) {
      return sourceTitles.map((title) => message.sources?.find((source) => source.title === title) || { title });
    }
    return Array.isArray(message.sources) ? message.sources : [];
  }

  function niaProviderLabel(message) {
    if (message.provider === "openai") return "NIA + OpenAI";
    if (message.openAiReason) return "NIA guide mode";
    return "NIA";
  }

  return (
    <section className="chat-layout agent-assist-layout">
      <div className="chat-card">
        <div className="agent-assist-hero">
          <div>
            <p className="eyebrow">Nex Intelligent Assistant</p>
            <h2>Meet NIA.</h2>
            <p>Your Nex support chat for transactions, CRM follow-up, marketing, NexU, commissions, and brokerage workflows.</p>
          </div>
          <div className="agent-assist-status-stack">
            <span><i /> OpenAI + Nex knowledge</span>
            <button type="button" onClick={resetConversation}>New chat</button>
          </div>
        </div>
        <ComplianceNotice text={agentAssistDisclaimer} />
        <div className="prompt-starters">
          {agentAssistStarters.map((starter) => (
            <button key={starter} type="button" onClick={() => ask(starter)}>
              <Icon name="Sparkles" size={15} />
              <span>{starter}</span>
            </button>
          ))}
        </div>
        <div className="chat-stream">
          {messages.map((message) => {
            const sources = displayedNiaSources(message);
            return (
              <div className={classNames("message", message.type)} key={message.id}>
                <div className="message-bubble">
                  {message.type === "assistant" && (
                    <div className="assistant-answer-meta">
                      <span>{niaProviderLabel(message)}</span>
                      {message.knowledgeBase && <em>Nex-sourced</em>}
                      {message.needsEscalation && <em className="urgent">Support review</em>}
                      {message.openAiReason && <em>Fallback active</em>}
                    </div>
                  )}
                  <p>{message.text}</p>
                  {sources.length > 0 && (
                    <div className="nia-source-list">
                      <strong><Icon name="BadgeCheck" size={13} /> Verified sources</strong>
                      {sources.map((source) => (
                        <span key={source.id || source.title}>{source.title}</span>
                      ))}
                    </div>
                  )}
                  {message.type === "assistant" && message.id !== "assist-welcome" && !message.id.startsWith("assist-welcome-") && (
                    <div className="nia-message-actions">
                      <button type="button" onClick={() => copyToClipboard(message.text, setToast)} title="Copy answer">
                        <Icon name="Copy" size={14} />
                        <span>Copy</span>
                      </button>
                      <button type="button" onClick={() => sendFeedback(message, "up")} title="Good answer">
                        <Icon name="ThumbsUp" size={14} />
                        <span>Helpful</span>
                      </button>
                      <button type="button" onClick={() => sendFeedback(message, "down")} title="Needs review">
                        <Icon name="ThumbsDown" size={14} />
                        <span>Review</span>
                      </button>
                      <button type="button" onClick={() => createNiaSupportTicket(message)} title="Create support ticket">
                        <Icon name="LifeBuoy" size={14} />
                        <span>Ticket</span>
                      </button>
                    </div>
                  )}
                </div>
              </div>
            );
          })}
          {isAsking && (
            <div className="message assistant">
              <div className="message-bubble thinking-bubble">
                <Icon name="LoaderCircle" className="spin" size={16} />
                <p>NIA is thinking...</p>
              </div>
            </div>
          )}
        </div>
        <form className="chat-composer" onSubmit={(event) => { event.preventDefault(); ask(); }}>
          <textarea value={prompt} onChange={(event) => setPrompt(event.target.value)} onKeyDown={handlePromptKeyDown} placeholder="Ask NIA naturally. Press Enter to send, Shift+Enter for a new line." rows={2} />
          <button className="btn primary" disabled={isAsking}>
            <Icon name={isAsking ? "LoaderCircle" : "Send"} className={isAsking ? "spin" : ""} />
            <span>{isAsking ? "Thinking" : "Ask"}</span>
          </button>
        </form>
      </div>
      <div className="panel">
        <p className="eyebrow">Agent support</p>
        <h3>NIA history</h3>
        <p className="support-panel-copy">NIA saves agent chats, keeps context, and can escalate a conversation into a support ticket when the answer needs human review.</p>
        <div className="nia-conversation-list">
          {conversations.slice(0, 8).map((conversation) => (
            <button key={conversation.id} type="button" className={conversation.id === conversationId ? "active" : ""} onClick={() => openConversation(conversation.id)}>
              <strong>{conversation.title}</strong>
              <span>{conversation.messageCount} messages</span>
            </button>
          ))}
          {!conversations.length && <span className="muted-copy">No saved NIA conversations yet.</span>}
        </div>
        <div className="support-topic-list">
          {["Florida workflow guidance", "Brokerage procedures", "Transaction next steps", "CRM scripts", "NexU topics", "Marketing copy", "CDA prep", "Follow-up planning"].map((item) => (
            <span key={item}>{item}</span>
          ))}
        </div>
        <div className="agent-assist-tip-card">
          <Icon name="Lightbulb" />
          <div>
            <strong>Build on the conversation</strong>
            <p>Example: ask about an inspection deadline, then follow up with "What text should I send the buyer?" or "What should I upload next?"</p>
          </div>
        </div>
        {isAdmin && (
          <div className="nia-admin-card">
            <p className="eyebrow">Admin NIA Knowledge</p>
            <h3>Approved answers</h3>
            <form onSubmit={saveKnowledgeArticle} className="nia-knowledge-form">
              <input value={knowledgeDraft.title} onChange={(event) => setKnowledgeDraft((current) => ({ ...current, title: event.target.value }))} placeholder="Article title" />
              <input value={knowledgeDraft.category} onChange={(event) => setKnowledgeDraft((current) => ({ ...current, category: event.target.value }))} placeholder="Category" />
              <textarea value={knowledgeDraft.content} onChange={(event) => setKnowledgeDraft((current) => ({ ...current, content: event.target.value }))} placeholder="Approved Nex guidance NIA can use..." rows={4} />
              <button className="btn primary" type="submit"><Icon name="Plus" /><span>Add Knowledge</span></button>
            </form>
            <div className="nia-knowledge-list">
              {knowledgeArticles.slice(0, 6).map((article) => (
                <article key={article.id}>
                  <strong>{article.title}</strong>
                  <span>{article.category}</span>
                  <button type="button" onClick={() => toggleKnowledgeArticle(article)}>{article.active === false ? "Activate" : "Pause"}</button>
                </article>
              ))}
            </div>
          </div>
        )}
      </div>
    </section>
  );
}

function NexCrm({ currentUser, role, setToast }) {
  const [activeCrmPage, setActiveCrmPage] = useState("Dashboard");
  const [crm, setCrm] = useState({
    contacts: [],
    notes: [],
    tasks: [],
    activity: [],
    dripCampaigns: [],
    dripEnrollments: [],
    stages: crmDefaultStages,
    pipelines: [],
    deals: [],
    teams: [],
    permissions: {}
  });
  const [loading, setLoading] = useState(true);
  const [query, setQuery] = useState("");
  const [leadTypeFilter, setLeadTypeFilter] = useState("All");
  const [stageFilter, setStageFilter] = useState("All");
  const [sourceFilter, setSourceFilter] = useState("All");
  const [temperatureFilter, setTemperatureFilter] = useState("All");
  const [assignedFilter, setAssignedFilter] = useState("All");
  const [addLeadOpen, setAddLeadOpen] = useState(false);
  const [smartListKey, setSmartListKey] = useState("hot");
  const [taskView, setTaskView] = useState("Today");
  const [pipelineView, setPipelineView] = useState("Buyer");
  const [selectedContactId, setSelectedContactId] = useState("");
  const [draft, setDraft] = useState(emptyCrmContact);
  const [contactEdit, setContactEdit] = useState(emptyCrmContact);
  const [noteDraft, setNoteDraft] = useState("");
  const [taskDraft, setTaskDraft] = useState({ title: "", taskType: "Call", dueDate: "", dueTime: "", priority: "Normal", notes: "" });
  const [communicationDraft, setCommunicationDraft] = useState({ type: "Call", outcome: "Connected", notes: "", nextStep: "", nextFollowUpDate: "" });
  const [emailDraft, setEmailDraft] = useState({ subject: "Following up from Nex Realty", message: "" });
  const [emailBusy, setEmailBusy] = useState(false);
  const [selectedDripCampaignId, setSelectedDripCampaignId] = useState("default-buyer-365");
  const [dripBusy, setDripBusy] = useState(false);
  const [dripAiDraft, setDripAiDraft] = useState(null);
  const [selectedSmartPlanId, setSelectedSmartPlanId] = useState("new-buyer-lead");
  const [aiOutput, setAiOutput] = useState(null);
  const [aiBusy, setAiBusy] = useState("");
  const [crmNiaPrompt, setCrmNiaPrompt] = useState("");
  const [crmNiaAnswer, setCrmNiaAnswer] = useState(null);
  const [crmNiaBusy, setCrmNiaBusy] = useState(false);
  const [crmNiaConversationId, setCrmNiaConversationId] = useState("");
  const [csvText, setCsvText] = useState("");
  const [stagesText, setStagesText] = useState(crmDefaultStages.join("\n"));

  const stages = crm.stages?.length ? crm.stages : crmDefaultStages;
  const tasks = crm.tasks || [];
  const notes = crm.notes || [];
  const activity = crm.activity || [];
  const dripCampaigns = crm.dripCampaigns || [];
  const dripEnrollments = crm.dripEnrollments || [];
  const permissions = crm.permissions || {};
  const agentCanCreatePrivateLead = permissions.canViewAll !== true;
  const contacts = useMemo(
    () =>
      (crm.contacts || []).map((contact) => {
        const contactActivity = crmContactActivityItems(contact, notes, activity);
        const leadScore = typeof contact.leadScore === "number" ? contact.leadScore : crmLeadScore(contact, contactActivity);
        return {
          ...contact,
          leadScore,
          temperature: contact.temperature || crmTemperature({ ...contact, leadScore }, contactActivity)
        };
      }),
    [crm.contacts, notes, activity]
  );
  const agentOptions = useMemo(
    () =>
      ["All", "Unassigned", ...Array.from(new Set(contacts.map((contact) => contact.assignedAgentEmail).filter(Boolean))).sort((a, b) => a.localeCompare(b))],
    [contacts]
  );
  const sourceOptions = useMemo(
    () => ["All", ...Array.from(new Set([...crmLeadSources, ...contacts.map((contact) => contact.leadSource).filter(Boolean)])).sort((a, b) => a.localeCompare(b))],
    [contacts]
  );
  const smartLists = useMemo(() => crmSmartListDefinitions(contacts, tasks, notes, activity, permissions), [contacts, tasks, notes, activity, permissions.canViewAll]);
  const selectedSmartList = smartLists.find((list) => list.key === smartListKey) || smartLists[0];
  const smartListContacts = selectedSmartList ? contacts.filter(selectedSmartList.predicate) : contacts;
  const lowerQuery = query.toLowerCase();
  const filteredContacts = contacts.filter((contact) => {
    const haystack = [
      crmContactName(contact),
      contact.email,
      contact.phone,
      contact.secondaryPhone,
      contact.secondaryEmail,
      contact.leadType,
      contact.leadSource,
      contact.stage,
      contact.status,
      contact.temperature,
      contact.budgetRange,
      contact.desiredArea,
      contact.timeline,
      contact.propertyAddress,
      contact.campaignName,
      contact.formName,
      contact.assignedAgentEmail,
      crmTagsText(contact.tags)
    ]
      .filter(Boolean)
      .join(" ")
      .toLowerCase();
    const matchesSearch = !lowerQuery || haystack.includes(lowerQuery);
    const matchesLeadType = leadTypeFilter === "All" || contact.leadType === leadTypeFilter;
    const matchesStage = stageFilter === "All" || contact.stage === stageFilter;
    const matchesSource = sourceFilter === "All" || contact.leadSource === sourceFilter;
    const matchesTemperature = temperatureFilter === "All" || crmTemperature(contact, crmContactActivityItems(contact, notes, activity)) === temperatureFilter;
    const matchesAssigned =
      assignedFilter === "All" ||
      (assignedFilter === "Unassigned" ? !contact.assignedAgentEmail : normalizeEmail(contact.assignedAgentEmail) === normalizeEmail(assignedFilter));
    return matchesSearch && matchesLeadType && matchesStage && matchesSource && matchesTemperature && matchesAssigned;
  });
  const selectedContact =
    contacts.find((contact) => contact.id === selectedContactId) ||
    filteredContacts[0] ||
    contacts[0] ||
    null;
  const selectedNotes = selectedContact ? notes.filter((note) => note.contactId === selectedContact.id) : [];
  const selectedTasks = selectedContact ? tasks.filter((task) => task.contactId === selectedContact.id) : [];
  const selectedActivity = selectedContact ? activity.filter((item) => item.contactId === selectedContact.id) : [];
  const openTasks = tasks.filter((task) => task.status !== "Completed");
  const dueTodayTasks = openTasks.filter((task) => crmIsDueToday(task.dueDate));
  const dueTasks = openTasks.filter((task) => crmIsDue(task.dueDate));
  const newLeadCount = contacts.filter((contact) => contact.stage === "New Lead").length;
  const hotLeads = contacts.filter((contact) => crmTemperature(contact, crmContactActivityItems(contact, notes, activity)) === "Hot");
  const activeBuyerCount = contacts.filter((contact) => contact.leadType === "Buyer" && !["Closed", "Nurture", "Lost", "Lost/Inactive"].includes(contact.stage)).length;
  const activeSellerCount = contacts.filter((contact) => contact.leadType === "Seller" && !["Closed", "Nurture", "Lost", "Lost/Inactive"].includes(contact.stage)).length;
  const underContractCount = contacts.filter((contact) => contact.stage === "Under Contract").length;
  const closedCount = contacts.filter((contact) => contact.stage === "Closed").length;
  const nurtureCount = contacts.filter((contact) => contact.stage === "Nurture").length;
  const lostCount = contacts.filter((contact) => /lost/i.test(contact.stage || "")).length;
  const unassignedCount = contacts.filter((contact) => !contact.assignedAgentEmail).length;
  const appointmentCount = contacts.filter((contact) => /appointment|consultation|discovery call/i.test(contact.stage || "")).length;
  const conversionRate = contacts.length ? Math.round((closedCount / contacts.length) * 100) : 0;
  const leadContacts = contacts.filter((contact) => !["Vendor", "Past Client", "Sphere", "Referral Partner"].includes(contact.leadType) || /lead|prospect/i.test(contact.stage || ""));

  useEffect(() => {
    refreshCrm();
  }, []);

  useEffect(() => {
    if (!selectedContact) return;
    setContactEdit({
      ...emptyCrmContact,
      ...selectedContact,
      tags: crmTagsText(selectedContact.tags)
    });
    setSelectedDripCampaignId(recommendedDripCampaignId(selectedContact));
    setDripAiDraft(null);
    const firstName = selectedContact.firstName || crmContactName(selectedContact).split(" ")[0] || "there";
    setEmailDraft({
      subject: `Following up from Nex Realty`,
      message: `Hi ${firstName},\n\nI wanted to follow up and see how I can help with your real estate goals. What is the best next step for you right now?\n\nBest,`
    });
  }, [selectedContact?.id, selectedContact?.updatedAt]);

  useEffect(() => {
    setStagesText(stages.join("\n"));
  }, [stages.join("|")]);

  async function refreshCrm() {
    setLoading(true);
    try {
      const payload = await API.request("/api/crm/bootstrap");
      setCrm(payload);
      if (!selectedContactId && payload.contacts?.[0]) setSelectedContactId(payload.contacts[0].id);
    } catch (error) {
      setToast(error.message || "Could not load Nex CRM.");
    } finally {
      setLoading(false);
    }
  }

  async function createContact(event) {
    event.preventDefault();
    if (![draft.firstName, draft.lastName, draft.email, draft.phone].some((value) => String(value || "").trim())) {
      setToast("Add a name, email, or phone before saving a contact.");
      return;
    }
    try {
      const saved = await API.request("/api/crm/contacts", { method: "POST", body: JSON.stringify(draft) });
      setCrm((current) => ({ ...current, contacts: [saved, ...(current.contacts || [])] }));
      setDraft({ ...emptyCrmContact, assignedAgentEmail: currentUser?.email || "" });
      setSelectedContactId(saved.id);
      setAddLeadOpen(false);
      setActiveCrmPage("Contacts");
      setToast("CRM contact added.");
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not add CRM contact.");
    }
  }

  async function updateContact(contactId, patch, toastMessage = "Contact updated.") {
    try {
      const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(contactId)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      setCrm((current) => ({
        ...current,
        contacts: (current.contacts || []).map((contact) => (contact.id === saved.id ? saved : contact))
      }));
      setToast(toastMessage);
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not update contact.");
    }
  }

  async function deleteContact(contactId) {
    if (!window.confirm("Delete this CRM contact and its notes/tasks?")) return;
    try {
      await API.request(`/api/crm/contacts/${encodeURIComponent(contactId)}`, { method: "DELETE" });
      setCrm((current) => ({
        ...current,
        contacts: (current.contacts || []).filter((contact) => contact.id !== contactId),
        notes: (current.notes || []).filter((note) => note.contactId !== contactId),
        tasks: (current.tasks || []).filter((task) => task.contactId !== contactId),
        activity: (current.activity || []).filter((item) => item.contactId !== contactId)
      }));
      setSelectedContactId("");
      setToast("CRM contact deleted.");
    } catch (error) {
      setToast(error.message || "Could not delete contact.");
    }
  }

  async function saveContactEdit() {
    if (!selectedContact) return;
    await updateContact(selectedContact.id, contactEdit, "Contact detail saved.");
  }

  async function addNote(event) {
    event.preventDefault();
    if (!selectedContact || !noteDraft.trim()) return;
    try {
      const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/notes`, {
        method: "POST",
        body: JSON.stringify({ body: noteDraft })
      });
      setCrm((current) => ({
        ...current,
        notes: [saved.note, ...(current.notes || [])],
        activity: [saved.activity, ...(current.activity || [])],
        contacts: (current.contacts || []).map((contact) => (contact.id === saved.contact.id ? saved.contact : contact))
      }));
      setNoteDraft("");
      setToast("Note added.");
    } catch (error) {
      setToast(error.message || "Could not add note.");
    }
  }

  async function addTask(event) {
    event.preventDefault();
    if (!selectedContact || !taskDraft.title.trim()) return;
    try {
      const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/tasks`, {
        method: "POST",
        body: JSON.stringify(taskDraft)
      });
      setCrm((current) => ({
        ...current,
        tasks: [saved.task, ...(current.tasks || [])],
        activity: [saved.activity, ...(current.activity || [])],
        contacts: (current.contacts || []).map((contact) => (contact.id === saved.contact.id ? saved.contact : contact))
      }));
      setTaskDraft({ title: "", taskType: "Call", dueDate: "", dueTime: "", priority: "Normal", notes: "" });
      setToast("Follow-up task added.");
    } catch (error) {
      setToast(error.message || "Could not add task.");
    }
  }

  async function addCommunication(event) {
    event.preventDefault();
    if (!selectedContact || !communicationDraft.notes.trim()) {
      setToast("Add a quick note before logging communication.");
      return;
    }
    try {
      const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/activity`, {
        method: "POST",
        body: JSON.stringify(communicationDraft)
      });
      setCrm((current) => ({
        ...current,
        activity: [saved.activity, ...(current.activity || [])],
        contacts: (current.contacts || []).map((contact) => (contact.id === saved.contact.id ? saved.contact : contact))
      }));
      setCommunicationDraft({ type: "Call", outcome: "Connected", notes: "", nextStep: "", nextFollowUpDate: "" });
      setToast("Communication logged.");
    } catch (error) {
      setToast(error.message || "Could not log communication.");
    }
  }

  async function sendCrmEmail(event) {
    event.preventDefault();
    if (!selectedContact?.email) {
      setToast("Add an email address before sending.");
      return;
    }
    if (selectedContact.doNotContact) {
      setToast("This contact is marked do-not-contact.");
      return;
    }
    if (!emailDraft.message.trim()) {
      setToast("Add a message before sending.");
      return;
    }
    setEmailBusy(true);
    try {
      const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/email`, {
        method: "POST",
        body: JSON.stringify(emailDraft)
      });
      setCrm((current) => ({
        ...current,
        activity: [saved.activity, ...(current.activity || [])],
        contacts: (current.contacts || []).map((contact) => (contact.id === saved.contact.id ? saved.contact : contact))
      }));
      setToast(saved.delivery?.sent ? "Email sent from Nex Central." : "Email logged. SMTP is not configured for delivery in this environment.");
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not send CRM email.");
    } finally {
      setEmailBusy(false);
    }
  }

  async function startDripCampaign() {
    if (!selectedContact) return;
    setDripBusy(true);
    try {
      const response = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/drip-enrollments`, {
        method: "POST",
        body: JSON.stringify({
          campaignId: selectedDripCampaignId,
          customSteps: dripAiDraft?.steps || []
        })
      });
      setCrm((current) => ({
        ...current,
        dripEnrollments: [response.enrollment, ...(current.dripEnrollments || [])],
        activity: response.activity ? [response.activity, ...(current.activity || [])] : current.activity,
        contacts: (current.contacts || []).map((contact) => (contact.id === response.contact.id ? response.contact : contact))
      }));
      setToast(response.enrollment?.aiGenerated ? "AI-custom drip campaign started." : response.dripDelivery?.sent ? "Drip campaign started and first email sent." : "Drip campaign started. First email is queued or logged.");
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not start drip campaign.");
    } finally {
      setDripBusy(false);
    }
  }

  async function updateDripEnrollment(enrollmentId, status) {
    setDripBusy(true);
    try {
      const saved = await API.request(`/api/crm/drip-enrollments/${encodeURIComponent(enrollmentId)}`, {
        method: "PUT",
        body: JSON.stringify({ status })
      });
      setCrm((current) => ({
        ...current,
        dripEnrollments: (current.dripEnrollments || []).map((enrollment) => (enrollment.id === saved.id ? saved : enrollment))
      }));
      setToast(`Drip campaign ${status.toLowerCase()}.`);
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not update drip campaign.");
    } finally {
      setDripBusy(false);
    }
  }

  async function generateDripAiDraft() {
    if (!selectedContact) return;
    setDripBusy(true);
    try {
      const response = await API.request("/api/crm/drip-campaigns/ai-draft", {
        method: "POST",
        body: JSON.stringify({ contactId: selectedContact.id, campaignId: selectedDripCampaignId })
      });
      setDripAiDraft(response);
      setToast("AI drip guidance generated.");
    } catch (error) {
      setToast(error.message || "Could not generate AI drip guidance.");
    } finally {
      setDripBusy(false);
    }
  }

  async function applySmartPlan() {
    if (!selectedContact) return;
    const plan = crmSmartPlans.find((item) => item.id === selectedSmartPlanId) || crmSmartPlans[0];
    if (!plan) return;
    try {
      const createdTasks = [];
      for (const [offsetDays, title, taskType, priority] of plan.tasks) {
        const saved = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/tasks`, {
          method: "POST",
          body: JSON.stringify({
            title,
            taskType,
            priority,
            dueDate: addDays(new Date().toISOString().slice(0, 10), offsetDays),
            notes: `Created from ${plan.name} smart plan.`
          })
        });
        createdTasks.push(saved.task);
      }
      const note = await API.request(`/api/crm/contacts/${encodeURIComponent(selectedContact.id)}/notes`, {
        method: "POST",
        body: JSON.stringify({ body: `${plan.name} smart plan applied. Suggested first text: ${plan.scripts?.text || "Follow up with value and a clear next step."}` })
      });
      setCrm((current) => ({
        ...current,
        tasks: [...createdTasks, ...(current.tasks || [])],
        notes: [note.note, ...(current.notes || [])],
        activity: [note.activity, ...(current.activity || [])]
      }));
      setToast(`${plan.name} smart plan applied.`);
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not apply smart plan.");
    }
  }

  async function updateTask(taskId, patch) {
    try {
      const saved = await API.request(`/api/crm/tasks/${encodeURIComponent(taskId)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      setCrm((current) => ({
        ...current,
        tasks: (current.tasks || []).map((task) => (task.id === saved.id ? saved : task))
      }));
      setToast("Task updated.");
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not update task.");
    }
  }

  async function deleteTask(taskId) {
    try {
      await API.request(`/api/crm/tasks/${encodeURIComponent(taskId)}`, { method: "DELETE" });
      setCrm((current) => ({
        ...current,
        tasks: (current.tasks || []).filter((task) => task.id !== taskId)
      }));
      setToast("Task deleted.");
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not delete task.");
    }
  }

  async function runAi(action, label) {
    if (!selectedContact) return;
    setAiBusy(action);
    try {
      const response = await API.request("/api/crm/ai", {
        method: "POST",
        body: JSON.stringify({ contactId: selectedContact.id, action })
      });
      setAiOutput({ label, ...response });
      setCrm((current) => ({ ...current, activity: [response.activity, ...(current.activity || [])] }));
      setToast(`${label} generated.`);
    } catch (error) {
      setToast(error.message || "Could not generate CRM AI content.");
    } finally {
      setAiBusy("");
    }
  }

  function crmNiaPageContext(promptText) {
    const queueTasks = [...dueTodayTasks, ...dueTasks].slice(0, 6).map((task) => {
      const contact = contacts.find((item) => item.id === task.contactId);
      return {
        title: task.title,
        taskType: task.taskType,
        dueDate: task.dueDate,
        priority: task.priority,
        status: task.status,
        contactName: crmContactName(contact),
        contactId: task.contactId
      };
    });
    const selectedLead = selectedContact
      ? {
          id: selectedContact.id,
          name: crmContactName(selectedContact),
          leadType: selectedContact.leadType,
          leadSource: selectedContact.leadSource,
          stage: selectedContact.stage,
          status: selectedContact.status,
          temperature: selectedContact.temperature || crmTemperature(selectedContact, crmContactActivityItems(selectedContact, notes, activity)),
          leadScore: selectedContact.leadScore,
          phonePresent: Boolean(selectedContact.phone),
          emailPresent: Boolean(selectedContact.email),
          desiredArea: selectedContact.desiredArea,
          budgetRange: selectedContact.budgetRange,
          timeline: selectedContact.timeline,
          nextFollowUpDate: selectedContact.nextFollowUpDate,
          privateLead: Boolean(selectedContact.privateLead),
          doNotContact: Boolean(selectedContact.doNotContact),
          recentNotes: selectedNotes.slice(0, 4).map((note) => ({ body: note.body, createdAt: note.createdAt })),
          openTasks: selectedTasks.filter((task) => task.status !== "Completed").slice(0, 5).map((task) => ({
            title: task.title,
            taskType: task.taskType,
            dueDate: task.dueDate,
            priority: task.priority,
            notes: task.notes
          })),
          recentActivity: selectedActivity.slice(0, 5).map((item) => ({
            type: item.type,
            title: item.title,
            body: item.body,
            createdAt: item.createdAt
          }))
        }
      : null;
    return {
      module: "Nex CRM",
      currentView: activeCrmPage,
      agentView: permissions.canViewAll ? "Admin brokerage CRM view" : "Agent-owned CRM view",
      requestedHelp: promptText,
      counts: {
        totalContacts: contacts.length,
        newLeads: newLeadCount,
        overdueTasks: dueTasks.length,
        dueTodayTasks: dueTodayTasks.length,
        hotLeads: hotLeads.length,
        appointments: appointmentCount,
        unassigned: unassignedCount,
        conversionRate
      },
      actionQueue: queueTasks,
      hotLeadPreview: hotLeads.slice(0, 6).map((contact) => ({
        id: contact.id,
        name: crmContactName(contact),
        leadType: contact.leadType,
        leadSource: contact.leadSource,
        stage: contact.stage,
        score: contact.leadScore,
        nextFollowUpDate: contact.nextFollowUpDate
      })),
      selectedLead
    };
  }

  async function askCrmNia(question) {
    const fallbackPrompt = selectedContact
      ? `What is the next best action for ${crmContactName(selectedContact)}?`
      : "Who should I follow up with first today?";
    const promptText = String(question || crmNiaPrompt || fallbackPrompt).trim();
    setCrmNiaBusy(true);
    try {
      const response = await API.request("/api/nia/chat", {
        method: "POST",
        body: JSON.stringify({
          message: promptText,
          conversationId: crmNiaConversationId,
          pageContext: crmNiaPageContext(promptText)
        })
      });
      if (response.conversation?.id) setCrmNiaConversationId(response.conversation.id);
      setCrmNiaAnswer(response);
      setCrmNiaPrompt("");
      setToast(response.provider === "openai" ? "NIA reviewed your CRM context." : "NIA answered from Nex guide mode.");
    } catch (error) {
      setToast(error.message || "NIA could not review the CRM right now.");
    } finally {
      setCrmNiaBusy(false);
    }
  }

  function handleCrmNiaKeyDown(event) {
    if (event.key !== "Enter" || event.shiftKey || crmNiaBusy) return;
    event.preventDefault();
    askCrmNia();
  }

  function crmNiaAnswerText() {
    return crmNiaAnswer?.assistantMessage?.content || crmNiaAnswer?.answer || "";
  }

  function crmNiaSources() {
    const message = crmNiaAnswer?.assistantMessage || crmNiaAnswer || {};
    const sourceTitles = Array.isArray(message.sections?.nexSourceUsed) ? message.sections.nexSourceUsed.filter(Boolean) : [];
    if (sourceTitles.length) return sourceTitles.map((title) => message.sources?.find((source) => source.title === title) || { title });
    return Array.isArray(message.sources) ? message.sources : [];
  }

  function renderCrmNiaCoach({ compact = false } = {}) {
    const selectedName = selectedContact ? crmContactName(selectedContact) : "";
    const prompts = selectedContact
      ? [
          `What is the next best action for ${selectedName}?`,
          `Write a short follow-up text for ${selectedName}.`,
          `Build a 7-day nurture plan for ${selectedName}.`
        ]
      : [
          "Who should I follow up with first today?",
          "Which CRM leads are most at risk right now?",
          "Give me a 20-minute CRM action plan for today."
        ];
    const answerText = crmNiaAnswerText();
    const sources = crmNiaSources();
    return (
      <div className={classNames("crm-nia-panel", compact && "compact")}>
        <div className="crm-nia-head">
          <div>
            <p className="eyebrow">NIA CRM Coach</p>
            <h3>{selectedContact ? "Ask about this lead" : "Ask about today's follow-up"}</h3>
          </div>
          <span><Icon name="Sparkles" /> Live CRM context</span>
        </div>
        <p className="crm-helper-text">
          Ask NIA who to work first, what to say, how to follow up, or how to move a lead forward.
        </p>
        <div className="crm-nia-prompts">
          {prompts.map((item) => (
            <button key={item} type="button" onClick={() => askCrmNia(item)} disabled={crmNiaBusy}>
              {item}
            </button>
          ))}
        </div>
        <form className="crm-nia-form" onSubmit={(event) => { event.preventDefault(); askCrmNia(); }}>
          <textarea
            value={crmNiaPrompt}
            onChange={(event) => setCrmNiaPrompt(event.target.value)}
            onKeyDown={handleCrmNiaKeyDown}
            placeholder={selectedContact ? "Ask NIA what to do next with this lead..." : "Ask NIA to prioritize your CRM day..."}
            rows={compact ? 2 : 3}
          />
          <button className="btn primary" disabled={crmNiaBusy}>
            <Icon name={crmNiaBusy ? "LoaderCircle" : "Send"} className={crmNiaBusy ? "spin" : ""} />
            <span>{crmNiaBusy ? "Thinking" : "Ask NIA"}</span>
          </button>
        </form>
        {crmNiaBusy && (
          <article className="crm-nia-answer crm-nia-loading">
            <div className="output-card-head">
              <span>NIA is reviewing CRM context</span>
            </div>
            <p>Checking lead details, follow-up tasks, recent activity, and Nex guidance...</p>
          </article>
        )}
        {answerText && (
          <article className="crm-nia-answer">
            <div className="output-card-head">
              <span>{crmNiaAnswer?.provider === "openai" ? "NIA + OpenAI" : "NIA"}</span>
              <button className="icon-btn small" onClick={() => copyToClipboard(answerText, setToast)} title="Copy NIA answer">
                <Icon name="Copy" size={15} />
              </button>
            </div>
            <p>{answerText}</p>
            {sources.length > 0 && (
              <div className="nia-source-list crm-nia-source-list">
                <strong><Icon name="BadgeCheck" size={13} /> Sources</strong>
                {sources.slice(0, 5).map((source) => <span key={source.id || source.title}>{source.title}</span>)}
              </div>
            )}
          </article>
        )}
      </div>
    );
  }

  function exportCsv() {
    const headers = [
      "firstName",
      "lastName",
      "email",
      "phone",
      "secondaryEmail",
      "secondaryPhone",
      "leadType",
      "leadSource",
      "status",
      "stage",
      "assignedAgentEmail",
      "budgetRange",
      "desiredArea",
      "timeline",
      "buyingTimeline",
      "sellingTimeline",
      "propertyAddress",
      "bedrooms",
      "bathrooms",
      "financingStatus",
      "preApproved",
      "workingWithAnotherAgent",
      "consentStatus",
      "doNotContact",
      "campaignName",
      "formName",
      "utmSource",
      "utmMedium",
      "utmCampaign",
      "referringUrl",
      "tags",
      "lastContactedDate",
      "nextFollowUpDate",
      "notes"
    ];
    const body = contacts.map((contact) => headers.map((header) => csvEscape(header === "tags" ? crmTagsText(contact.tags) : contact[header])).join(","));
    const csv = [headers.join(","), ...body].join("\n");
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "nex-crm-contacts.csv";
    link.click();
    URL.revokeObjectURL(url);
    setToast("CRM contacts exported.");
  }

  async function importCsv(event) {
    event.preventDefault();
    const rows = parseCsvRows(csvText);
    if (rows.length < 2) {
      setToast("Paste a CSV with a header row and at least one contact.");
      return;
    }
    const [headers, ...dataRows] = rows;
    const payloads = dataRows.map((row) => crmContactFromCsvRow(headers, row)).filter((contact) => contact.firstName || contact.lastName || contact.email || contact.phone);
    if (!payloads.length) {
      setToast("No importable contacts found in the CSV.");
      return;
    }
    try {
      const created = [];
      for (const payload of payloads) {
        created.push(await API.request("/api/crm/contacts", { method: "POST", body: JSON.stringify(payload) }));
      }
      setCrm((current) => ({ ...current, contacts: [...created, ...(current.contacts || [])] }));
      setCsvText("");
      setToast(`${created.length} CRM contacts imported.`);
      refreshCrm();
    } catch (error) {
      setToast(error.message || "Could not import CRM contacts.");
    }
  }

  function handleCsvFile(event) {
    const file = event.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => setCsvText(String(reader.result || ""));
    reader.readAsText(file);
  }

  async function saveStages() {
    try {
      const response = await API.request("/api/crm/stages", {
        method: "PUT",
        body: JSON.stringify({ stages: stagesText })
      });
      setCrm((current) => ({ ...current, stages: response.stages, pipelines: response.pipelines }));
      setToast("CRM stages saved.");
    } catch (error) {
      setToast(error.message || "Could not save CRM stages.");
    }
  }

  function renderDashboard() {
    const avgSpeedLeads = contacts.filter((contact) => contact.speedToLead?.minutes !== null && typeof contact.speedToLead?.minutes !== "undefined");
    const avgSpeedMinutes = avgSpeedLeads.length ? Math.round(avgSpeedLeads.reduce((sum, contact) => sum + Number(contact.speedToLead.minutes || 0), 0) / avgSpeedLeads.length) : null;

    const cockpitCards = [
      ["Today's Follow-Ups", dueTodayTasks.length, "CalendarClock", "Work these first", "due-today"],
      ["Overdue Leads", dueTasks.length, "AlarmClock", "Needs action", "overdue"],
      ["Hot Leads", hotLeads.length, "Flame", "Highest intent", "hot"],
      ["New Leads Needing Contact", newLeadCount, "Inbox", "Not contacted", "new-not-contacted"],
      ["Appointments", appointmentCount, "CalendarCheck", "Booked", ""],
      [permissions.canViewAll ? "Unassigned" : "Active Leads", permissions.canViewAll ? unassignedCount : leadContacts.length, permissions.canViewAll ? "UserRoundX" : "UsersRound", permissions.canViewAll ? "Assign now" : `${conversionRate}% close rate`, permissions.canViewAll ? "unassigned" : ""]
    ];

    return (
      <div className="crm-cockpit">
        <section className="crm-cockpit-hero">
          <div>
            <p className="eyebrow">Nex CRM dashboard</p>
            <h2>Today&apos;s lead command center.</h2>
            <p>
              Start with overdue leads, hot opportunities, and new inquiries that still need a first touch.
            </p>
          </div>
          <div className="crm-cockpit-status">
            <span><Icon name="Activity" /> {contacts.length} records</span>
            <span><Icon name="Gauge" /> Avg speed: {avgSpeedMinutes === null ? "sample pending" : `${avgSpeedMinutes} min`}</span>
            <span><Icon name="ShieldCheck" /> {permissions.canViewAll ? "Admin brokerage view" : "My leads view"}</span>
          </div>
        </section>

        <section className="crm-cockpit-metrics">
          {cockpitCards.map(([label, value, icon, status, smartKey]) => (
            <button
              key={label}
                className={classNames("crm-cockpit-card", label === "Hot Leads" && "hot", label === "Overdue Leads" && "danger")}
              onClick={() => {
                if (smartKey) {
                  setSmartListKey(smartKey);
                  setActiveCrmPage("Smart Lists");
                } else {
                  setActiveCrmPage("Contacts");
                }
              }}
            >
              <Icon name={icon} />
              <strong>{value}</strong>
              <span>{label}</span>
              <em>{status}</em>
            </button>
          ))}
        </section>

        <section className="crm-cockpit-grid">
          <div className="panel crm-action-queue">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Today</p>
                <h3>Action queue</h3>
              </div>
              <button className="btn secondary small-btn" onClick={() => setActiveCrmPage("Tasks")}>Open Tasks</button>
            </div>
            <div className="crm-task-stack">
              {[...dueTodayTasks, ...dueTasks].slice(0, 7).map((task) => {
                const contact = contacts.find((item) => item.id === task.contactId);
                return (
                  <article key={task.id} className={classNames(crmIsDue(task.dueDate) && "overdue")}>
                    <strong>{task.title}</strong>
                    <span>{crmContactName(contact)} - {task.taskType || "Follow-up"} - {crmShortDate(task.dueDate)}</span>
                    <div className="row-actions">
                      <button className="btn secondary small-btn" onClick={() => { setSelectedContactId(task.contactId); setActiveCrmPage("Contacts"); }}>Open Lead</button>
                      <button className="btn secondary small-btn" onClick={() => updateTask(task.id, { status: "Completed" })}>Complete</button>
                    </div>
                  </article>
                );
              })}
              {!openTasks.length && <EmptyState icon="ListTodo" title="No open follow-ups" body="Create tasks from a contact profile or apply a smart plan." />}
            </div>
          </div>

          {renderCrmNiaCoach({ compact: true })}

          <div className="panel crm-hot-queue">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Hot leads</p>
                <h3>Highest intent</h3>
              </div>
              <button className="btn secondary small-btn" onClick={() => { setSmartListKey("hot"); setActiveCrmPage("Smart Lists"); }}>View List</button>
            </div>
            <div className="crm-lead-queue">
              {hotLeads.slice(0, 6).map((contact) => (
                <button key={contact.id} onClick={() => { setSelectedContactId(contact.id); setActiveCrmPage("Contacts"); }}>
                  <strong>{crmContactName(contact)}</strong>
                  <span>{contact.leadType} - {contact.leadSource || "No source"} - {contact.stage}</span>
                  <em>{contact.leadScore} score</em>
                </button>
              ))}
              {!hotLeads.length && <p className="muted-text">No hot leads yet. Lead scores rise when phone, timeline, source, budget, area, or contact activity improves.</p>}
            </div>
          </div>

          <div className="panel crm-wide-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Pipeline snapshot</p>
              <h3>Stage conversion view</h3>
            </div>
            <button className="btn secondary" onClick={() => setActiveCrmPage("Pipeline")}>
              <Icon name="Kanban" />
              <span>Open Board</span>
            </button>
          </div>
          <div className="crm-stage-meter">
            {crmPipelineStagesForType(pipelineView, stages).map((stage) => {
              const count = contacts.filter((contact) => contact.stage === stage).length;
              return (
                <button key={stage} onClick={() => { setStageFilter(stage); setActiveCrmPage("Contacts"); }}>
                  <strong>{count}</strong>
                  <span>{stage}</span>
                </button>
              );
            })}
          </div>
          </div>

          <div className="panel crm-smart-list-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Smart lists</p>
              <h3>Conversion filters</h3>
            </div>
          </div>
          <div className="crm-smart-list-mini">
            {smartLists.slice(0, 10).map((list) => (
              <button key={list.key} onClick={() => { setSmartListKey(list.key); setActiveCrmPage("Smart Lists"); }}>
                <Icon name={list.icon} />
                <span>{list.label}</span>
                <strong>{contacts.filter(list.predicate).length}</strong>
              </button>
            ))}
          </div>
          </div>

        </section>
      </div>
    );
  }

  function renderContactDetail() {
    if (!selectedContact) {
      return <EmptyState icon="UsersRound" title="No contact selected" body="Add or import a CRM contact to open the contact detail page." />;
    }
    const aiActions = [
      ["text", "Write follow-up text", "MessageSquare"],
      ["email", "Write follow-up email", "Mail"],
      ["nurture", "Create nurture plan", "CalendarClock"],
      ["summary", "Summarize contact notes", "ClipboardList"],
      ["next-action", "Suggest next action", "Target"]
    ];
    const contactActivityItems = crmContactActivityItems(selectedContact, notes, activity);
    const leadScore = typeof selectedContact.leadScore === "number" ? selectedContact.leadScore : crmLeadScore(selectedContact, contactActivityItems);
    const temperature = selectedContact.temperature || crmTemperature({ ...selectedContact, leadScore }, contactActivityItems);
    const selectedPlan = crmSmartPlans.find((plan) => plan.id === selectedSmartPlanId) || crmSmartPlans[0];
    const selectedDripCampaign = dripCampaigns.find((campaign) => campaign.id === selectedDripCampaignId) || dripCampaigns.find((campaign) => campaign.id === recommendedDripCampaignId(selectedContact)) || dripCampaigns[0];
    const contactDripEnrollments = dripEnrollments.filter((enrollment) => enrollment.contactId === selectedContact.id);
    const activeDripEnrollment = contactDripEnrollments.find((enrollment) => enrollment.status === "Active");
    const contactEmailActivity = selectedActivity
      .filter((item) => ["email", "drip-email"].includes(item.type))
      .sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
    const profileStageOptions = Array.from(new Set([...crmPipelineStagesForType(contactEdit.leadType || selectedContact.leadType, stages), contactEdit.stage || selectedContact.stage, ...stages].filter(Boolean)));
    const canToggleSelectedPrivateLead =
      agentCanCreatePrivateLead &&
      normalizeEmail(selectedContact.createdByEmail) === normalizeEmail(currentUser?.email) &&
      !selectedContact.websiteLeadId;
    return (
      <div className="crm-detail-stack">
        <div className="crm-contact-head">
          <div>
            <p className="eyebrow">Lead profile</p>
            <h3>{crmContactName(selectedContact)}</h3>
            <span>{selectedContact.leadType} - {selectedContact.stage}</span>
            <div className="crm-profile-badges">
              {selectedContact.privateLead && <em className="private-lead-badge"><Icon name="LockKeyhole" size={13} /> Private Agent Lead</em>}
              <em className={classNames("lead-source-pill", sourcePillTone(selectedContact))}>{crmSourceLabel(selectedContact)}</em>
              <em className={classNames("temperature-badge", crmTemperatureClass(temperature))}>{temperature}</em>
              <em>{leadScore} score</em>
              <em>{selectedContact.leadSource || "No source"}</em>
              <em>Speed: {selectedContact.speedToLead?.label || crmSpeedToLead(selectedContact)}</em>
            </div>
          </div>
          <div className="row-actions">
            {selectedContact.phone && <a className="btn secondary small-btn" href={`tel:${selectedContact.phone}`}><Icon name="Phone" /><span>Call</span></a>}
            {selectedContact.phone && <a className="btn secondary small-btn" href={`sms:${selectedContact.phone}`}><Icon name="MessageSquare" /><span>Text</span></a>}
            {selectedContact.email && (
              <button
                className="btn secondary small-btn"
                type="button"
                onClick={() => document.getElementById("crm-email-panel")?.scrollIntoView({ behavior: "smooth", block: "start" })}
              >
                <Icon name="Mail" />
                <span>Send CRM Email</span>
              </button>
            )}
            <button className="icon-btn small" onClick={() => deleteContact(selectedContact.id)} title="Delete contact">
              <Icon name="Trash2" size={15} />
            </button>
          </div>
        </div>

        <div className="crm-next-action-strip">
          <Icon name="Sparkles" />
          <div>
            <strong>Next best action</strong>
            <p>
              {selectedTasks.find((task) => task.status !== "Completed")?.title ||
                (selectedContact.nextFollowUpDate
                  ? `Follow up by ${crmShortDate(selectedContact.nextFollowUpDate)}`
                  : temperature === "Hot"
                    ? "Call or text this lead now and log the result."
                    : "Set a specific next follow-up so this lead does not go cold.")}
            </p>
          </div>
          <button className="btn secondary small-btn" onClick={() => askCrmNia(`What is the next best action for ${crmContactName(selectedContact)}?`)} disabled={crmNiaBusy}>
            {crmNiaBusy ? "NIA thinking" : "Ask NIA"}
          </button>
        </div>

        {renderCrmNiaCoach({ compact: true })}

        <div className="crm-profile-editor">
          <div className="crm-section-heading">
            <div>
              <p className="eyebrow">Lead essentials</p>
              <h3>Contact, stage, and next action</h3>
            </div>
            <button className="btn primary small-btn" onClick={saveContactEdit}>
              <Icon name="Save" />
              <span>Save Lead</span>
            </button>
          </div>
          <div className="crm-form-grid compact">
            <Field label="First name" value={contactEdit.firstName || ""} onChange={(value) => setContactEdit((current) => ({ ...current, firstName: value }))} />
            <Field label="Last name" value={contactEdit.lastName || ""} onChange={(value) => setContactEdit((current) => ({ ...current, lastName: value }))} />
            <Field label="Email" value={contactEdit.email || ""} onChange={(value) => setContactEdit((current) => ({ ...current, email: value }))} type="email" />
            <Field label="Phone" value={contactEdit.phone || ""} onChange={(value) => setContactEdit((current) => ({ ...current, phone: value }))} />
            <Field label="Lead type" value={contactEdit.leadType || "Other"} onChange={(value) => setContactEdit((current) => ({ ...current, leadType: value }))} as="select" options={crmLeadTypes} />
            <Field label="Stage" value={contactEdit.stage || profileStageOptions[0]} onChange={(value) => setContactEdit((current) => ({ ...current, stage: value }))} as="select" options={profileStageOptions} />
            <Field label="Lead source" value={contactEdit.leadSource || ""} onChange={(value) => setContactEdit((current) => ({ ...current, leadSource: value }))} as="select" options={crmLeadSources} />
            <Field label="Next follow-up" value={contactEdit.nextFollowUpDate || ""} onChange={(value) => setContactEdit((current) => ({ ...current, nextFollowUpDate: value }))} type="date" />
            <Field label="Assigned agent email" value={contactEdit.assignedAgentEmail || ""} onChange={(value) => setContactEdit((current) => ({ ...current, assignedAgentEmail: value }))} type="email" />
            <Field label="Preferred contact" value={contactEdit.preferredContactMethod || "Any"} onChange={(value) => setContactEdit((current) => ({ ...current, preferredContactMethod: value }))} as="select" options={crmContactMethods} />
            <Field label="Quick notes" value={contactEdit.notes || ""} onChange={(value) => setContactEdit((current) => ({ ...current, notes: value }))} as="textarea" />
          </div>

          <details className="crm-advanced-fields">
            <summary>
              <span>More lead details</span>
              <em>Budget, area, timelines, tags, opt-in, UTM, and seller fields</em>
            </summary>
            <div className="crm-form-grid">
              <Field label="Lead status" value={contactEdit.status || "New"} onChange={(value) => setContactEdit((current) => ({ ...current, status: value }))} />
              <Field label="Secondary email" value={contactEdit.secondaryEmail || ""} onChange={(value) => setContactEdit((current) => ({ ...current, secondaryEmail: value }))} type="email" />
              <Field label="Secondary phone" value={contactEdit.secondaryPhone || ""} onChange={(value) => setContactEdit((current) => ({ ...current, secondaryPhone: value }))} />
              <Field label="Budget / price range" value={contactEdit.budgetRange || ""} onChange={(value) => setContactEdit((current) => ({ ...current, budgetRange: value }))} />
              <Field label="Desired area" value={contactEdit.desiredArea || ""} onChange={(value) => setContactEdit((current) => ({ ...current, desiredArea: value }))} />
              <Field label="Timeline" value={contactEdit.timeline || ""} onChange={(value) => setContactEdit((current) => ({ ...current, timeline: value }))} />
              <Field label="Buying timeline" value={contactEdit.buyingTimeline || ""} onChange={(value) => setContactEdit((current) => ({ ...current, buyingTimeline: value }))} />
              <Field label="Selling timeline" value={contactEdit.sellingTimeline || ""} onChange={(value) => setContactEdit((current) => ({ ...current, sellingTimeline: value }))} />
              <Field label="Seller property address" value={contactEdit.propertyAddress || ""} onChange={(value) => setContactEdit((current) => ({ ...current, propertyAddress: value }))} />
              <Field label="Beds" value={contactEdit.bedrooms || ""} onChange={(value) => setContactEdit((current) => ({ ...current, bedrooms: value }))} />
              <Field label="Baths" value={contactEdit.bathrooms || ""} onChange={(value) => setContactEdit((current) => ({ ...current, bathrooms: value }))} />
              <Field label="Financing status" value={contactEdit.financingStatus || ""} onChange={(value) => setContactEdit((current) => ({ ...current, financingStatus: value }))} />
              <Field label="Pre-approved" value={contactEdit.preApproved || "Unknown"} onChange={(value) => setContactEdit((current) => ({ ...current, preApproved: value }))} as="select" options={crmPreApprovedOptions} />
              <Field label="Working with another agent" value={contactEdit.workingWithAnotherAgent || "Unknown"} onChange={(value) => setContactEdit((current) => ({ ...current, workingWithAnotherAgent: value }))} as="select" options={crmWorkingAgentOptions} />
              <Field label="Consent status" value={contactEdit.consentStatus || "Unknown"} onChange={(value) => setContactEdit((current) => ({ ...current, consentStatus: value, doNotContact: value === "Do Not Contact" || value === "Unsubscribed" }))} as="select" options={crmConsentOptions} />
              <Field label="Opt-in source" value={contactEdit.optInSource || ""} onChange={(value) => setContactEdit((current) => ({ ...current, optInSource: value }))} />
              <Field label="Birthday" value={contactEdit.birthday || ""} onChange={(value) => setContactEdit((current) => ({ ...current, birthday: value }))} type="date" />
              <Field label="Home anniversary" value={contactEdit.homeAnniversary || ""} onChange={(value) => setContactEdit((current) => ({ ...current, homeAnniversary: value }))} type="date" />
              <Field label="Campaign name" value={contactEdit.campaignName || ""} onChange={(value) => setContactEdit((current) => ({ ...current, campaignName: value }))} />
              <Field label="Form name" value={contactEdit.formName || ""} onChange={(value) => setContactEdit((current) => ({ ...current, formName: value }))} />
              <Field label="UTM source" value={contactEdit.utmSource || ""} onChange={(value) => setContactEdit((current) => ({ ...current, utmSource: value }))} />
              <Field label="UTM campaign" value={contactEdit.utmCampaign || ""} onChange={(value) => setContactEdit((current) => ({ ...current, utmCampaign: value }))} />
              <Field label="Referring URL" value={contactEdit.referringUrl || ""} onChange={(value) => setContactEdit((current) => ({ ...current, referringUrl: value }))} />
              <Field label="Tags" value={contactEdit.tags || ""} onChange={(value) => setContactEdit((current) => ({ ...current, tags: value }))} placeholder="open house, luxury, referral" />
              <Field label="Last contacted" value={contactEdit.lastContactedDate || ""} onChange={(value) => setContactEdit((current) => ({ ...current, lastContactedDate: value }))} type="date" />
              <label className="check-field crm-dnc-toggle">
                <input type="checkbox" checked={Boolean(contactEdit.doNotContact)} onChange={(event) => setContactEdit((current) => ({ ...current, doNotContact: event.target.checked }))} />
                Do not contact
              </label>
              {canToggleSelectedPrivateLead && (
                <label className="check-field private-lead-toggle">
                  <input type="checkbox" checked={Boolean(contactEdit.privateLead)} onChange={(event) => setContactEdit((current) => ({ ...current, privateLead: event.target.checked }))} />
                  Private Agent Lead
                  <span>Only you can see this manually entered lead. It is not a paid/company lead and no brokerage-generated lead fee applies.</span>
                </label>
              )}
            </div>
          </details>
        </div>

        <div className="crm-smart-plan-panel">
          <div>
            <p className="eyebrow">Smart plans</p>
            <h3>Action plan automation</h3>
            <p>Apply a starter plan to create scheduled tasks and a script note for this lead.</p>
          </div>
          <label className="field">
            <span>Plan</span>
            <select value={selectedSmartPlanId} onChange={(event) => setSelectedSmartPlanId(event.target.value)}>
              {crmSmartPlans.map((plan) => <option key={plan.id} value={plan.id}>{plan.name}</option>)}
            </select>
          </label>
          <button className="btn primary" onClick={applySmartPlan}>
            <Icon name="ListPlus" />
            <span>Apply {selectedPlan?.name || "Smart Plan"}</span>
          </button>
          <article>
            <strong>First text script</strong>
            <p>{selectedPlan?.scripts?.text || "Select a smart plan to see suggested scripts."}</p>
          </article>
        </div>

        <div className="crm-ai-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">NIA quick drafts</p>
              <h3>Follow-up support</h3>
            </div>
          </div>
          <div className="crm-ai-actions">
            {aiActions.map(([action, label, icon]) => (
              <button className="btn secondary" key={action} onClick={() => runAi(action, label)} disabled={Boolean(aiBusy)}>
                <Icon name={aiBusy === action ? "LoaderCircle" : icon} className={aiBusy === action ? "spin" : ""} />
                <span>{label}</span>
              </button>
            ))}
          </div>
          {aiOutput && (
            <article className="ai-output-card">
              <div className="output-card-head">
                <span>{aiOutput.label}</span>
                <button className="icon-btn small" onClick={() => copyToClipboard(aiOutput.output, setToast)} title="Copy AI output">
                  <Icon name="Copy" size={15} />
                </button>
              </div>
              <p>{aiOutput.output}</p>
            </article>
          )}
        </div>

        <div className="crm-email-panel" id="crm-email-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">CRM email</p>
              <h3>Send and log lead email</h3>
            </div>
          </div>
          <form className="crm-communication-form" onSubmit={sendCrmEmail}>
            <Field label="To" value={selectedContact.email || ""} onChange={() => {}} disabled type="email" />
            <Field label="Subject" value={emailDraft.subject} onChange={(value) => setEmailDraft((current) => ({ ...current, subject: value }))} />
            <Field label="Message" value={emailDraft.message} onChange={(value) => setEmailDraft((current) => ({ ...current, message: value }))} as="textarea" />
            <div className="crm-email-footer">
              <span>Replies go to {currentUser?.email || "the agent email on file"}.</span>
              <button className="btn primary" disabled={emailBusy || !selectedContact.email || selectedContact.doNotContact}>
                <Icon name={emailBusy ? "LoaderCircle" : "Send"} className={emailBusy ? "spin" : ""} />
                <span>{emailBusy ? "Sending" : "Send Email"}</span>
              </button>
            </div>
          </form>
          {selectedContact.doNotContact && <p className="muted-text">This contact is marked do-not-contact, so direct CRM email is disabled.</p>}
          <div className="crm-email-history">
            <div className="panel-heading compact-heading">
              <div>
                <p className="eyebrow">Email history</p>
                <h3>Sent and logged emails</h3>
              </div>
            </div>
            {contactEmailActivity.length ? (
              contactEmailActivity.slice(0, 8).map((item) => (
                <article key={item.id}>
                  <div>
                    <strong>{item.title || "Email activity"}</strong>
                    <span>{titleCaseDate(item.createdAt)}</span>
                  </div>
                  <p>{item.body || "Email activity was logged for this contact."}</p>
                </article>
              ))
            ) : (
              <p className="muted-text">No CRM emails have been sent or logged for this lead yet.</p>
            )}
          </div>
        </div>

        <div className="crm-drip-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Email drip campaigns</p>
              <h3>Automated follow-up for up to 365 days</h3>
            </div>
          </div>
          <div className="crm-drip-grid">
            <label className="field">
              <span>Campaign</span>
              <select value={selectedDripCampaignId} onChange={(event) => setSelectedDripCampaignId(event.target.value)} disabled={Boolean(activeDripEnrollment)}>
                {dripCampaigns.map((campaign) => (
                  <option key={campaign.id} value={campaign.id}>{campaign.name}</option>
                ))}
              </select>
            </label>
            <div className="crm-drip-summary">
              <strong>{activeDripEnrollment ? activeDripEnrollment.campaignName : selectedDripCampaign?.name || "Stock drip campaign"}</strong>
              <span>
                {activeDripEnrollment
                  ? `Step ${Number(activeDripEnrollment.stepIndex || 0)} of ${activeDripEnrollment.totalSteps || selectedDripCampaign?.steps?.length || 0} - next ${crmShortDate(activeDripEnrollment.nextSendAt)}`
                  : selectedDripCampaign?.description || "Choose a stock campaign based on lead type."}
              </span>
            </div>
          </div>
          <div className="crm-drip-step-preview">
            {(selectedDripCampaign?.steps || []).slice(0, 4).map((step) => (
              <article key={`${selectedDripCampaign.id}-${step.day}-${step.subject}`}>
                <em>Day {step.day}</em>
                <strong>{step.subject}</strong>
              </article>
            ))}
          </div>
          <div className="row-actions">
            {activeDripEnrollment ? (
              <>
                <button className="btn secondary" onClick={() => updateDripEnrollment(activeDripEnrollment.id, "Paused")} disabled={dripBusy}>
                  <Icon name="PauseCircle" />
                  <span>Pause</span>
                </button>
                <button className="btn danger-soft" onClick={() => updateDripEnrollment(activeDripEnrollment.id, "Stopped")} disabled={dripBusy}>
                  <Icon name="CircleStop" />
                  <span>Stop</span>
                </button>
              </>
            ) : (
              <button className="btn primary" onClick={startDripCampaign} disabled={dripBusy || !selectedContact.email || selectedContact.doNotContact || !selectedDripCampaign}>
                <Icon name={dripBusy ? "LoaderCircle" : "Rocket"} className={dripBusy ? "spin" : ""} />
                <span>{dripBusy ? "Starting" : "Start Drip"}</span>
              </button>
            )}
            <button className="btn secondary" onClick={generateDripAiDraft} disabled={dripBusy || !selectedDripCampaign}>
              <Icon name="Sparkles" />
              <span>AI Campaign Guidance</span>
            </button>
          </div>
          <p className="muted-text">Emails merge lead details automatically, include an opt-out link, and replies go to the assigned agent email on file.</p>
          {dripAiDraft && (
            <article className="ai-output-card">
              <div className="output-card-head">
                <span>{dripAiDraft.subject}</span>
                <button className="icon-btn small" onClick={() => copyToClipboard(dripAiDraft.output, setToast)} title="Copy AI guidance">
                  <Icon name="Copy" size={15} />
                </button>
              </div>
              <p>{dripAiDraft.output}</p>
              {dripAiDraft.provider === "openai" && <em className="ai-provider-badge">OpenAI custom copy ready - start the drip to use it</em>}
              {dripAiDraft.provider !== "openai" && dripAiDraft.openAiReason && <em className="ai-provider-badge fallback">Fallback guidance shown - OpenAI is not configured or unavailable</em>}
              {Array.isArray(dripAiDraft.steps) && dripAiDraft.steps.length > 0 && (
                <div className="crm-drip-step-preview">
                  {dripAiDraft.steps.slice(0, 4).map((step) => (
                    <article key={`ai-${step.day}-${step.subject}`}>
                      <em>AI Day {step.day}</em>
                      <strong>{step.subject}</strong>
                    </article>
                  ))}
                </div>
              )}
            </article>
          )}
          {contactDripEnrollments.length > 0 && (
            <div className="crm-drip-history">
              {contactDripEnrollments.slice(0, 3).map((enrollment) => (
                <span key={enrollment.id}>{enrollment.campaignName}: {enrollment.status}</span>
              ))}
            </div>
          )}
        </div>

        <div className="crm-communication-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Communication log</p>
              <h3>Log calls, texts, emails, voicemails, and appointments</h3>
            </div>
          </div>
          <form className="crm-communication-form" onSubmit={addCommunication}>
            <Field label="Type" value={communicationDraft.type} onChange={(value) => setCommunicationDraft((current) => ({ ...current, type: value }))} as="select" options={crmCommunicationTypes} />
            <Field label="Outcome" value={communicationDraft.outcome} onChange={(value) => setCommunicationDraft((current) => ({ ...current, outcome: value }))} as="select" options={crmCommunicationOutcomes} />
            <Field label="Next follow-up" value={communicationDraft.nextFollowUpDate} onChange={(value) => setCommunicationDraft((current) => ({ ...current, nextFollowUpDate: value }))} type="date" />
            <Field label="Next step" value={communicationDraft.nextStep} onChange={(value) => setCommunicationDraft((current) => ({ ...current, nextStep: value }))} />
            <Field label="Notes" value={communicationDraft.notes} onChange={(value) => setCommunicationDraft((current) => ({ ...current, notes: value }))} as="textarea" />
            <button className="btn primary">
              <Icon name="Activity" />
              <span>Log Communication</span>
            </button>
          </form>
        </div>

        <div className="crm-split-panels">
          <div className="crm-inner-panel">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Notes</p>
                <h3>Activity timeline</h3>
              </div>
            </div>
            <form className="crm-inline-form" onSubmit={addNote}>
              <Field label="Add note" value={noteDraft} onChange={setNoteDraft} as="textarea" placeholder="Log a call, meeting, or client preference..." />
              <button className="btn primary">
                <Icon name="Plus" />
                <span>Add Note</span>
              </button>
            </form>
            <div className="crm-timeline-list">
              {[...selectedNotes.map((note) => ({ ...note, type: "note", title: "Note" })), ...selectedActivity].slice(0, 10).map((item) => (
                <article key={`${item.type}-${item.id}`}>
                  <span>{item.title || item.type} - {crmShortDate(item.createdAt)}</span>
                  <p>{item.body}</p>
                </article>
              ))}
              {!selectedNotes.length && !selectedActivity.length && <p className="muted-text">No timeline activity yet.</p>}
            </div>
          </div>

          <div className="crm-inner-panel">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Tasks</p>
                <h3>Follow-up reminders</h3>
              </div>
            </div>
            <form className="crm-inline-form" onSubmit={addTask}>
              <Field label="Task" value={taskDraft.title} onChange={(value) => setTaskDraft((current) => ({ ...current, title: value }))} placeholder="Call client, send homes, request docs..." />
              <Field label="Task type" value={taskDraft.taskType} onChange={(value) => setTaskDraft((current) => ({ ...current, taskType: value }))} as="select" options={crmTaskTypes} />
              <Field label="Due date" value={taskDraft.dueDate} onChange={(value) => setTaskDraft((current) => ({ ...current, dueDate: value }))} type="date" />
              <Field label="Due time" value={taskDraft.dueTime} onChange={(value) => setTaskDraft((current) => ({ ...current, dueTime: value }))} type="time" />
              <Field label="Priority" value={taskDraft.priority} onChange={(value) => setTaskDraft((current) => ({ ...current, priority: value }))} as="select" options={crmTaskPriorities} />
              <Field label="Task notes" value={taskDraft.notes} onChange={(value) => setTaskDraft((current) => ({ ...current, notes: value }))} as="textarea" />
              <button className="btn primary">
                <Icon name="Plus" />
                <span>Add Task</span>
              </button>
            </form>
            <div className="crm-task-stack">
              {selectedTasks.map((task) => (
                <article key={task.id} className={classNames(task.status === "Completed" && "done", crmIsDue(task.dueDate) && "overdue")}>
                  <strong>{task.title}</strong>
                  <span>{task.taskType || "Follow-up"} - {task.priority} - {crmShortDate(task.dueDate)}{task.dueTime ? ` at ${task.dueTime}` : ""} - {task.status}</span>
                  {task.notes && <p>{task.notes}</p>}
                  <div className="row-actions">
                    <button className="btn secondary small-btn" onClick={() => updateTask(task.id, { status: task.status === "Completed" ? "Open" : "Completed" })}>
                      {task.status === "Completed" ? "Reopen" : "Complete"}
                    </button>
                    <button className="icon-btn small" onClick={() => deleteTask(task.id)} title="Delete task">
                      <Icon name="Trash2" size={15} />
                    </button>
                  </div>
                </article>
              ))}
              {!selectedTasks.length && <p className="muted-text">No follow-up tasks yet.</p>}
            </div>
          </div>
        </div>
      </div>
    );
  }

  function renderContacts({ leadOnly = false } = {}) {
    const listContacts = leadOnly
      ? filteredContacts.filter((contact) => leadContacts.some((lead) => lead.id === contact.id))
      : filteredContacts;
    return (
      <div className="crm-layout">
        <div className="panel crm-list-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">{leadOnly ? "Lead inbox" : "Contact database"}</p>
              <h3>{leadOnly ? "Active leads" : "Contacts and leads"}</h3>
            </div>
          </div>
          <div className="crm-filter-grid">
            <Field label="Search" value={query} onChange={setQuery} placeholder="Name, email, area, tag..." />
            <Field label="Lead type" value={leadTypeFilter} onChange={setLeadTypeFilter} as="select" options={["All", ...crmLeadTypes]} />
            <Field label="Stage" value={stageFilter} onChange={setStageFilter} as="select" options={["All", ...stages]} />
            <Field label="Source" value={sourceFilter} onChange={setSourceFilter} as="select" options={sourceOptions} />
            <Field label="Temperature" value={temperatureFilter} onChange={setTemperatureFilter} as="select" options={crmTemperatureOptions} />
            <Field label="Assigned agent" value={assignedFilter} onChange={setAssignedFilter} as="select" options={agentOptions} />
          </div>
          <div className="crm-contact-list">
            {listContacts.map((contact) => {
              const temperature = crmTemperature(contact, crmContactActivityItems(contact, notes, activity));
              return (
              <button
                key={contact.id}
                className={classNames("crm-contact-card", selectedContact?.id === contact.id && "active")}
                onClick={() => setSelectedContactId(contact.id)}
              >
                <div className="crm-contact-card-head">
                  <strong>{crmContactName(contact)}</strong>
                  <em className={classNames("temperature-badge", crmTemperatureClass(temperature))}>{temperature}</em>
                </div>
                {contact.privateLead && <span className="private-lead-inline"><Icon name="LockKeyhole" size={13} /> Private Agent Lead</span>}
                <span className={classNames("lead-source-pill crm-source-badge", sourcePillTone(contact))}>{crmSourceLabel(contact)}</span>
                <span>{contact.leadType} - {contact.stage}</span>
                <span>{contact.leadSource || "No source"} - {contact.assignedAgentEmail || "Unassigned"}</span>
                <em>{contact.nextFollowUpDate ? `Next: ${crmShortDate(contact.nextFollowUpDate)}` : contact.desiredArea || "No follow-up set"}</em>
                <small>{contact.leadScore || crmLeadScore(contact)} score</small>
              </button>
            );})}
            {!listContacts.length && <EmptyState icon="Search" title="No CRM contacts found" body="Try a different filter or add a new contact below." />}
          </div>

          <details className="crm-add-details" open={addLeadOpen} onToggle={(event) => setAddLeadOpen(event.currentTarget.open)}>
            <summary>
              <span>Add new lead</span>
              <em>Open only when you need to create a contact manually.</em>
            </summary>
            <form className="crm-add-form" onSubmit={createContact}>
              <div className="crm-form-grid compact">
                <Field label="First name" value={draft.firstName} onChange={(value) => setDraft((current) => ({ ...current, firstName: value }))} />
                <Field label="Last name" value={draft.lastName} onChange={(value) => setDraft((current) => ({ ...current, lastName: value }))} />
                <Field label="Email" value={draft.email} onChange={(value) => setDraft((current) => ({ ...current, email: value }))} type="email" />
                <Field label="Phone" value={draft.phone} onChange={(value) => setDraft((current) => ({ ...current, phone: value }))} />
                <Field label="Lead type" value={draft.leadType} onChange={(value) => setDraft((current) => ({ ...current, leadType: value }))} as="select" options={crmLeadTypes} />
                <Field label="Stage" value={draft.stage} onChange={(value) => setDraft((current) => ({ ...current, stage: value }))} as="select" options={crmPipelineStagesForType(draft.leadType, stages)} />
                <Field label="Lead source" value={draft.leadSource} onChange={(value) => setDraft((current) => ({ ...current, leadSource: value }))} as="select" options={crmLeadSources} />
                <Field label="Assigned agent email" value={draft.assignedAgentEmail} onChange={(value) => setDraft((current) => ({ ...current, assignedAgentEmail: value }))} type="email" />
                {agentCanCreatePrivateLead && (
                  <label className="check-field private-lead-toggle">
                    <input type="checkbox" checked={Boolean(draft.privateLead)} onChange={(event) => setDraft((current) => ({ ...current, privateLead: event.target.checked }))} />
                    Private Agent Lead
                    <span>Only you can see this manually entered lead. Admin dashboards will not display it and it will not be counted as a paid/company lead.</span>
                  </label>
                )}
                <Field label="Budget / price range" value={draft.budgetRange} onChange={(value) => setDraft((current) => ({ ...current, budgetRange: value }))} />
                <Field label="Desired area" value={draft.desiredArea} onChange={(value) => setDraft((current) => ({ ...current, desiredArea: value }))} />
                <Field label="Timeline" value={draft.timeline} onChange={(value) => setDraft((current) => ({ ...current, timeline: value }))} />
                <Field label="Next follow-up" value={draft.nextFollowUpDate} onChange={(value) => setDraft((current) => ({ ...current, nextFollowUpDate: value }))} type="date" />
                <Field label="Campaign name" value={draft.campaignName} onChange={(value) => setDraft((current) => ({ ...current, campaignName: value }))} />
                <Field label="Tags" value={draft.tags} onChange={(value) => setDraft((current) => ({ ...current, tags: value }))} />
              </div>
              <Field label="Notes" value={draft.notes} onChange={(value) => setDraft((current) => ({ ...current, notes: value }))} as="textarea" />
              <button className="btn primary">
                <Icon name="Plus" />
                <span>Add Contact</span>
              </button>
            </form>
          </details>
        </div>

        <div className="panel crm-detail-panel">
          {renderContactDetail()}
        </div>
      </div>
    );
  }

  function renderPipeline() {
    const boardStages = pipelineView === "All" ? stages : crmPipelineStagesForType(pipelineView, stages);
    const boardContacts = pipelineView === "All" ? filteredContacts : filteredContacts.filter((contact) => (contact.leadType === pipelineView || (pipelineView === "Agent Recruit" && contact.leadType === "Recruit")));
    return (
      <div className="panel crm-board-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Pipeline board</p>
            <h3>Smart real estate pipeline</h3>
          </div>
          <div className="row-actions">
            {["Buyer", "Seller", "Renter", "Agent Recruit", "Investor", "All"].map((view) => (
              <button key={view} className={classNames("btn secondary small-btn", pipelineView === view && "active-soft")} onClick={() => setPipelineView(view)}>
                {view}
              </button>
            ))}
          </div>
        </div>
        <div className="pipeline-board">
          {boardStages.map((stage) => {
            const stageContacts = boardContacts.filter((contact) => contact.stage === stage);
            return (
              <section className="pipeline-column" key={stage}>
                <div className="pipeline-column-head">
                  <strong>{stage}</strong>
                  <span>{stageContacts.length}</span>
                </div>
                {stageContacts.map((contact) => (
                  <article className="pipeline-card" key={contact.id}>
                    <button onClick={() => { setSelectedContactId(contact.id); setActiveCrmPage("Contacts"); }}>
                      <div className="pipeline-card-head">
                        <strong>{crmContactName(contact)}</strong>
                        <em className={classNames("temperature-badge", crmTemperatureClass(crmTemperature(contact, crmContactActivityItems(contact, notes, activity))))}>{contact.leadScore || crmLeadScore(contact)}</em>
                      </div>
                      <span>{contact.leadType} - {contact.desiredArea || contact.leadSource || "No area set"}</span>
                      <small>{contact.nextFollowUpDate ? `Next ${crmShortDate(contact.nextFollowUpDate)}` : "No next follow-up"}</small>
                    </button>
                    <select value={contact.stage} onChange={(event) => updateContact(contact.id, { stage: event.target.value }, "Pipeline stage updated.")}>
                      {Array.from(new Set([...crmPipelineStagesForType(contact.leadType, stages), contact.stage].filter(Boolean))).map((option) => <option key={option} value={option}>{option}</option>)}
                    </select>
                  </article>
                ))}
                {!stageContacts.length && <p className="pipeline-empty">No leads in this stage.</p>}
              </section>
            );
          })}
        </div>
      </div>
    );
  }

  function renderTasks() {
    const visibleTasks = openTasks.filter((task) => {
      if (taskView === "Today") return crmIsDueToday(task.dueDate);
      if (taskView === "Overdue") return crmIsDue(task.dueDate);
      if (taskView === "Upcoming") return !crmIsDue(task.dueDate) && !crmIsDueToday(task.dueDate);
      return true;
    });
    return (
      <div className="panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Tasks and follow-ups</p>
            <h3>Daily accountability queue</h3>
          </div>
          <div className="row-actions">
            {["Today", "Overdue", "Upcoming", "All"].map((view) => (
              <button key={view} className={classNames("btn secondary small-btn", taskView === view && "active-soft")} onClick={() => setTaskView(view)}>
                {view}
              </button>
            ))}
          </div>
        </div>
        <div className="crm-task-table">
          {visibleTasks.map((task) => {
            const contact = contacts.find((item) => item.id === task.contactId);
            return (
              <article key={task.id} className={classNames(crmIsDue(task.dueDate) && "overdue")}>
                <div>
                  <strong>{task.title}</strong>
                  <span>{crmContactName(contact)} - {task.taskType || "Follow-up"} - {task.priority} - {crmShortDate(task.dueDate)}{task.dueTime ? ` at ${task.dueTime}` : ""}</span>
                  {task.notes && <p>{task.notes}</p>}
                </div>
                <div className="row-actions">
                  <button className="btn secondary small-btn" onClick={() => { setSelectedContactId(task.contactId); setActiveCrmPage("Contacts"); }}>Open Contact</button>
                  <button className="btn secondary small-btn" onClick={() => updateTask(task.id, { status: "Completed" })}>Complete</button>
                </div>
              </article>
            );
          })}
          {!visibleTasks.length && <EmptyState icon="ListTodo" title="No tasks in this view" body="Add follow-up reminders from any contact profile or apply a smart plan." />}
        </div>
      </div>
    );
  }

  function renderSmartLists() {
    return (
      <div className="crm-smart-layout">
        <aside className="panel crm-smart-list-sidebar">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Smart lists</p>
              <h3>Lead intelligence</h3>
            </div>
          </div>
          <div className="crm-smart-list-buttons">
            {smartLists.map((list) => (
              <button key={list.key} className={classNames(smartListKey === list.key && "active")} onClick={() => setSmartListKey(list.key)}>
                <Icon name={list.icon} />
                <span>{list.label}</span>
                <strong>{contacts.filter(list.predicate).length}</strong>
              </button>
            ))}
          </div>
        </aside>

        <section className="panel crm-smart-results">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Selected list</p>
              <h3>{selectedSmartList?.label || "Smart list"}</h3>
            </div>
            <button className="btn secondary small-btn" onClick={() => { setStageFilter("All"); setLeadTypeFilter("All"); setSourceFilter("All"); setTemperatureFilter("All"); }}>
              Clear Filters
            </button>
          </div>
          <div className="crm-lead-table">
            {smartListContacts.map((contact) => {
              const temperature = crmTemperature(contact, crmContactActivityItems(contact, notes, activity));
              return (
                <button key={contact.id} onClick={() => { setSelectedContactId(contact.id); setActiveCrmPage("Contacts"); }}>
                  <div>
                    <strong>{crmContactName(contact)}</strong>
                    <span>{contact.leadType} - {contact.stage} - {contact.leadSource || "No source"}</span>
                  </div>
                  <em className={classNames("temperature-badge", crmTemperatureClass(temperature))}>{temperature}</em>
                  <span>{contact.leadScore || crmLeadScore(contact)} score</span>
                  <span>{contact.nextFollowUpDate ? crmShortDate(contact.nextFollowUpDate) : "No follow-up"}</span>
                  <span>{contact.assignedAgentEmail || "Unassigned"}</span>
                </button>
              );
            })}
            {!smartListContacts.length && <EmptyState icon="Search" title="No leads in this smart list" body="As CRM activity grows, matching leads will appear here automatically." />}
          </div>
        </section>
      </div>
    );
  }

  function renderImportExport() {
    const sample = "firstName,lastName,email,phone,leadType,leadSource,stage,budgetRange,desiredArea,timeline,tags,nextFollowUpDate,campaignName,propertyAddress,preApproved,consentStatus\nTaylor,Smith,taylor@example.com,555-0199,Buyer,Website,New Lead,$500K-$650K,North Dallas,90 days,website lead,2026-06-01,Home Search Form,,Yes,Website Form";
    return (
      <div className="crm-import-grid">
        <div className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Import</p>
              <h3>CSV contact upload</h3>
            </div>
          </div>
          <form onSubmit={importCsv} className="crm-inline-form">
            <input className="file-input" type="file" accept=".csv,text/csv" onChange={handleCsvFile} />
            <Field label="Paste CSV" value={csvText} onChange={setCsvText} as="textarea" placeholder={sample} />
            <button className="btn primary">
              <Icon name="Upload" />
              <span>Import Contacts</span>
            </button>
          </form>
        </div>
        <div className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Export</p>
              <h3>Download CRM contacts</h3>
            </div>
          </div>
          <p className="crm-helper-text">Exports the contacts visible to your role. Agents export their own contacts; admins export the full brokerage CRM view.</p>
          <button className="btn dark" onClick={exportCsv}>
            <Icon name="Download" />
            <span>Export CSV</span>
          </button>
          <div className="csv-sample">
            <strong>Supported headers</strong>
            <p>firstName, lastName, email, phone, leadType, leadSource, stage, assignedAgentEmail, budgetRange, desiredArea, timeline, tags, nextFollowUpDate, campaignName, propertyAddress, preApproved, consentStatus, notes</p>
          </div>
        </div>
      </div>
    );
  }

  function renderDripCampaigns() {
    return (
      <div className="crm-drip-library">
        <section className="crm-cockpit-hero">
          <div>
            <p className="eyebrow">Automated nurture</p>
            <h2>Stock drip campaigns for buyer, seller, renter, closed client, and recruit follow-up.</h2>
            <p>
              Campaigns merge CRM fields into each email, send from Nex Central, and route replies back to the assigned
              agent email on file. Every sequence includes opt-out protection.
            </p>
          </div>
          <div className="crm-cockpit-status">
            <span><Icon name="MailCheck" /> {dripCampaigns.length} stock campaigns</span>
            <span><Icon name="RefreshCcw" /> {dripEnrollments.filter((item) => item.status === "Active").length} active enrollments</span>
            <span><Icon name="ShieldCheck" /> Opt-out links included</span>
          </div>
        </section>
        <section className="crm-drip-library-grid">
          {dripCampaigns.map((campaign) => (
            <article className="panel crm-drip-library-card" key={campaign.id}>
              <div>
                <p className="eyebrow">{campaign.category}</p>
                <h3>{campaign.name}</h3>
                <p>{campaign.description}</p>
              </div>
              <div className="crm-drip-step-preview">
                {(campaign.steps || []).slice(0, 5).map((step) => (
                  <article key={`${campaign.id}-${step.day}-${step.subject}`}>
                    <em>Day {step.day}</em>
                    <strong>{step.subject}</strong>
                  </article>
                ))}
              </div>
              <span className="muted-text">{campaign.steps?.length || 0} emails over up to {Math.max(...(campaign.steps || [{ day: 0 }]).map((step) => Number(step.day || 0)))} days</span>
            </article>
          ))}
        </section>
      </div>
    );
  }

  function renderSettings() {
    return (
      <div className="crm-settings-grid">
        <div className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">CRM settings</p>
              <h3>Pipeline stages</h3>
            </div>
          </div>
          {permissions.canManageStages ? (
            <>
              <Field label="Stages, one per line" value={stagesText} onChange={setStagesText} as="textarea" />
              <button className="btn primary" onClick={saveStages}>
                <Icon name="Save" />
                <span>Save Stages</span>
              </button>
            </>
          ) : (
            <div className="crm-stage-tags">
              {stages.map((stage) => <span key={stage}>{stage}</span>)}
            </div>
          )}
        </div>
        <div className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Future-ready</p>
              <h3>Integration path</h3>
            </div>
          </div>
          <div className="native-readiness-list">
            <article><strong>CRM sync path</strong><span>Keep Nex CRM focused now, then connect approved lead/contact systems later.</span></article>
            <article><strong>Calendar and Gmail</strong><span>Tasks and contact activity are structured for future calendar and email integrations.</span></article>
            <article><strong>Standalone CRM option</strong><span>The API-first CRM can become its own app and stay connected to Nex Central.</span></article>
          </div>
        </div>
      </div>
    );
  }

  function renderActiveCrmPage() {
    if (loading) return <EmptyState icon="LoaderCircle" title="Loading Nex CRM" body="Preparing contacts, tasks, pipeline, and activity." />;
    if (activeCrmPage === "Contacts") return renderContacts();
    if (activeCrmPage === "Leads") return renderContacts({ leadOnly: true });
    if (activeCrmPage === "Pipeline" || activeCrmPage === "Pipeline Board") return renderPipeline();
    if (activeCrmPage === "Smart Lists") return renderSmartLists();
    if (activeCrmPage === "Tasks" || activeCrmPage === "Follow-Up Tasks" || activeCrmPage === "Tasks/Follow-Ups") return renderTasks();
    if (activeCrmPage === "Drips" || activeCrmPage === "Drip Campaigns") return renderDripCampaigns();
    if (activeCrmPage === "NIA Coach") return <div className="crm-nia-page-shell">{renderCrmNiaCoach({ compact: false })}</div>;
    if (activeCrmPage === "Import/Export") return renderImportExport();
    if (activeCrmPage === "Settings" || activeCrmPage === "CRM Settings") return renderSettings();
    return renderDashboard();
  }

  return (
    <section className="portal-page crm-module">
      <div className="module-hero crm-hero">
        <div>
          <div className="crm-command-title">
            <p className="eyebrow">Lead command center</p>
            <h3>Nex CRM</h3>
            <p>Work the right leads, follow up faster, and keep your pipeline moving from one clean daily workspace.</p>
          </div>
          <div className="crm-command-status">
            <span><Icon name="Inbox" /> {newLeadCount} new</span>
            <span><Icon name="AlarmClock" /> {dueTasks.length} overdue</span>
            <span><Icon name="Flame" /> {hotLeads.length} hot</span>
          </div>
          <div className="hero-actions crm-command-actions">
            <button className="btn light" onClick={() => setActiveCrmPage("Leads")}>
              <Icon name="UserPlus" />
              <span>Lead Inbox</span>
            </button>
            <button className="btn light" onClick={() => { setAddLeadOpen(true); setActiveCrmPage("Contacts"); }}>
              <Icon name="Plus" />
              <span>Add Lead</span>
            </button>
            <button className="btn light" onClick={refreshCrm}>
              <Icon name="RefreshCcw" />
              <span>Refresh CRM</span>
            </button>
            <button className="btn light" onClick={() => setActiveCrmPage("NIA Coach")}>
              <Icon name="Bot" />
              <span>Ask NIA</span>
            </button>
          </div>
        </div>
      </div>

      <div className="crm-tabs">
        {crmPages.map((page) => (
          <button key={page} className={classNames(activeCrmPage === page && "active")} onClick={() => setActiveCrmPage(page)}>
            {page}
          </button>
        ))}
      </div>

      {renderActiveCrmPage()}
    </section>
  );
}

function DeadlineSummaryCard({ transaction, tasks }) {
  const next = nextBuyerDeadline(tasks);
  const percent = buyerCompletionPercent(tasks);
  const overdue = buyerOverdueCount(tasks);
  const days = next ? daysUntil(next.dueDate) : null;
  return (
    <div className="deadline-summary-card">
      <div>
        <p className="eyebrow">Next deadline</p>
        <h3>{next ? next.taskName : "No open dated tasks"}</h3>
        <span>
          {next ? `${formatDate(next.dueDate)}${days === 0 ? " - due today" : days > 0 ? ` - ${days} day${days === 1 ? "" : "s"} left` : ` - ${Math.abs(days)} day${Math.abs(days) === 1 ? "" : "s"} overdue`}` : "Add due dates to track upcoming items."}
        </span>
      </div>
      <div className="deadline-summary-metrics">
        <strong>{percent}%</strong>
        <span>Complete</span>
        <strong className={overdue ? "danger" : ""}>{overdue}</strong>
        <span>Overdue</span>
      </div>
      <div className="progress-track">
        <div style={{ width: `${percent}%` }} />
      </div>
      {transaction && <em>{buyerDisplayStatus(transaction)}</em>}
    </div>
  );
}

function BuyerTransactionCard({ transaction, tasks, onOpen }) {
  const percent = buyerCompletionPercent(tasks);
  const next = nextBuyerDeadline(tasks);
  const overdue = buyerOverdueCount(tasks);
  return (
    <article className="buyer-transaction-card">
      <button onClick={onOpen}>
        <div className="buyer-card-head">
          <span className={classNames("status-badge", buyerDisplayStatus(transaction).toLowerCase().replace(/\s+/g, "-"))}>
            {buyerDisplayStatus(transaction)}
          </span>
          <strong>{transaction.transactionName}</strong>
        </div>
        <p>{transaction.propertyAddress || "No property address entered"}</p>
        <div className="buyer-card-meta">
          <span>Buyer: {transaction.buyerName || "Not set"}</span>
          <span>Closing: {formatDate(transaction.closingDate)}</span>
          <span>Next: {next ? `${next.taskName} (${formatDate(next.dueDate)})` : "No upcoming deadline"}</span>
          <span>{overdue} overdue</span>
        </div>
        <div className="progress-track">
          <div style={{ width: `${percent}%` }} />
        </div>
        <em>{percent}% complete</em>
      </button>
    </article>
  );
}

function ChecklistTaskItem({ task, onUpdate, onDelete }) {
  const tone = buyerTaskTone(task);
  const days = task.dueDate ? daysUntil(task.dueDate) : null;
  return (
    <article className={classNames("checklist-task-item", `tone-${tone}`, task.completed && "completed")}>
      <label className="task-check">
        <input type="checkbox" checked={Boolean(task.completed)} onChange={(event) => onUpdate(task.id, { completed: event.target.checked })} />
        <span />
      </label>
      <div className="task-main">
        <div className="task-title-row">
          <strong>{task.taskName}</strong>
          <span className={classNames("deadline-badge", `tone-${tone}`)}>
            {task.completed
              ? "Completed"
              : task.dueDate
                ? days < 0
                  ? `Overdue ${Math.abs(days)}d`
                  : days === 0
                    ? "Due today"
                    : days === 1
                      ? "Due tomorrow"
                      : days <= 3
                        ? `Due in ${days}d`
                        : formatDate(task.dueDate)
                : "No due date"}
          </span>
        </div>
        <div className="task-edit-grid">
          <Field label="Due date" value={task.dueDate || ""} onChange={(value) => onUpdate(task.id, { dueDate: value })} type="date" />
          <Field label="Due time" value={task.dueTime || ""} onChange={(value) => onUpdate(task.id, { dueTime: value })} type="time" />
          <Field label="Priority" value={task.priority || "Normal"} onChange={(value) => onUpdate(task.id, { priority: value })} as="select" options={buyerTaskPriorities} />
          <Field label="Assigned person" value={task.assignedTo || ""} onChange={(value) => onUpdate(task.id, { assignedTo: value })} />
          <Field label="Linked document" value={task.linkedDocument || ""} onChange={(value) => onUpdate(task.id, { linkedDocument: value })} />
          <Field label="Notes" value={task.notes || ""} onChange={(value) => onUpdate(task.id, { notes: value })} as="textarea" />
        </div>
      </div>
      {task.isCustom && (
        <button className="icon-btn small" onClick={() => onDelete(task.id)} title="Delete custom task">
          <Icon name="Trash2" size={15} />
        </button>
      )}
    </article>
  );
}

function ChecklistSection({ section, tasks, expanded, onToggle, onUpdateTask, onDeleteTask }) {
  const completedCount = tasks.filter((task) => task.completed).length;
  const openTasks = tasks.filter((task) => !task.completed);
  const previewTasks = openTasks.slice(0, 3);
  const deadlineAlerts = tasks.filter((task) => !task.completed && ["overdue", "today", "tomorrow", "soon"].includes(buyerTaskTone(task))).length;
  const percent = buyerCompletionPercent(tasks);

  return (
    <section className={classNames("checklist-section", !expanded && "collapsed")}>
      <button className="checklist-section-head" type="button" onClick={onToggle} aria-expanded={expanded}>
        <div className="checklist-section-title">
          <Icon name={expanded ? "ChevronDown" : "ChevronRight"} />
          <div>
            <h3>{section}</h3>
            <p>
              {completedCount}/{tasks.length} complete - {openTasks.length} open
              {deadlineAlerts ? ` - ${deadlineAlerts} deadline alert${deadlineAlerts === 1 ? "" : "s"}` : ""}
            </p>
          </div>
        </div>
        <span>{percent}%</span>
      </button>
      {!expanded && (
        <div className="checklist-section-preview">
          {previewTasks.map((task) => (
            <div key={task.id} className={classNames("preview-task", `tone-${buyerTaskTone(task)}`)}>
              <strong>{task.taskName}</strong>
              <small>{task.dueDate ? formatDate(task.dueDate) : "No due date"}</small>
            </div>
          ))}
          {!previewTasks.length && <span>All tasks complete in this section.</span>}
          {openTasks.length > previewTasks.length && <em>+{openTasks.length - previewTasks.length} more open task{openTasks.length - previewTasks.length === 1 ? "" : "s"}</em>}
        </div>
      )}
      {expanded && (
        <div className="checklist-task-list">
          {tasks.map((task) => (
            <ChecklistTaskItem key={task.id} task={task} onUpdate={onUpdateTask} onDelete={onDeleteTask} />
          ))}
        </div>
      )}
    </section>
  );
}

function ReminderSettingsPanel({ settings, onSave }) {
  const [draft, setDraft] = useState(settings || {});

  useEffect(() => {
    setDraft(settings || {});
  }, [settings?.id, settings?.updatedAt]);

  if (!settings) return null;

  const options = [
    ["remind3DaysBefore", "Notify me 3 days before"],
    ["remind1DayBefore", "Notify me 1 day before"],
    ["remindSameDay", "Notify me same day"],
    ["remindOverdue", "Notify me when overdue"],
    ["inAppEnabled", "In-app reminders enabled"],
    ["emailEnabled", "Email reminders enabled"]
  ];

  return (
    <div className="reminder-settings-panel">
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Reminders</p>
          <h3>Notification settings</h3>
        </div>
      </div>
      <div className="check-grid">
        {options.map(([key, label]) => (
          <label className="check-field" key={key}>
            <input type="checkbox" checked={Boolean(draft[key])} onChange={(event) => setDraft((current) => ({ ...current, [key]: event.target.checked }))} />
            {label}
          </label>
        ))}
      </div>
      <p className="muted-text">Email reminder delivery is prepared in the data model, but no email provider is configured yet.</p>
      <button className="btn secondary" onClick={() => onSave(settings.id, draft)}>
        <Icon name="Save" />
        <span>Save Reminders</span>
      </button>
    </div>
  );
}

function NotificationCenter({ notifications, transactions, tasks, onMarkRead, onOpenTransaction }) {
  return (
    <div className="panel notification-center">
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Notifications</p>
          <h3>Buyer contract reminders</h3>
        </div>
      </div>
      <div className="notification-list">
        {notifications.map((notification) => {
          const transaction = transactions.find((item) => item.id === notification.transactionId);
          const task = tasks.find((item) => item.id === notification.taskId);
          return (
            <article className={classNames(!notification.read && "unread")} key={notification.id}>
              <div>
                <span>{notification.notificationType}</span>
                <strong>{notification.title}</strong>
                <p>{notification.message}</p>
                <em>{transaction?.transactionName || "Buyer transaction"}{task ? ` - ${task.taskName}` : ""}</em>
              </div>
              <div className="row-actions">
                {transaction && <button className="btn secondary small-btn" onClick={() => onOpenTransaction(transaction.id)}>Open</button>}
                {!notification.read && <button className="btn secondary small-btn" onClick={() => onMarkRead(notification.id)}>Mark Read</button>}
              </div>
            </article>
          );
        })}
        {!notifications.length && <EmptyState icon="Bell" title="No buyer tracker notifications" body="Upcoming and overdue deadline reminders will appear here." />}
      </div>
    </div>
  );
}

function CreateBuyerTransactionForm({ currentUser, onCreate }) {
  const [draft, setDraft] = useState({
    ...emptyBuyerTransaction,
    agentName: currentUser?.name || "",
    agentEmail: currentUser?.email || ""
  });

  function update(field, value) {
    setDraft((current) => ({ ...current, [field]: value }));
  }

  function submit(event) {
    event.preventDefault();
    onCreate(draft);
  }

  return (
    <form className="panel buyer-create-form" onSubmit={submit}>
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Create New Transaction</p>
          <h3>Buyer under-contract checklist</h3>
        </div>
      </div>
      <div className="buyer-form-grid">
        <Field label="Transaction name" value={draft.transactionName} onChange={(value) => update("transactionName", value)} placeholder="Smith purchase - 123 Main St" />
        <Field label="Buyer name" value={draft.buyerName} onChange={(value) => update("buyerName", value)} />
        <Field label="Property address" value={draft.propertyAddress} onChange={(value) => update("propertyAddress", value)} />
        <Field label="MLS number optional" value={draft.mlsNumber} onChange={(value) => update("mlsNumber", value)} />
        <Field label="Contract effective date" value={draft.effectiveDate} onChange={(value) => update("effectiveDate", value)} type="date" />
        <Field label="Closing date" value={draft.closingDate} onChange={(value) => update("closingDate", value)} type="date" />
        <Field label="Inspection period end date" value={draft.inspectionPeriodEndDate} onChange={(value) => update("inspectionPeriodEndDate", value)} type="date" />
        <Field label="Financing period end date" value={draft.financingPeriodEndDate} onChange={(value) => update("financingPeriodEndDate", value)} type="date" />
        <Field label="Appraisal deadline optional" value={draft.appraisalDeadline} onChange={(value) => update("appraisalDeadline", value)} type="date" />
        <Field label="HOA application deadline optional" value={draft.hoaDeadline} onChange={(value) => update("hoaDeadline", value)} type="date" />
        <Field label="EMD due date" value={draft.emdDueDate} onChange={(value) => update("emdDueDate", value)} type="date" />
        <Field label="Final walkthrough date" value={draft.finalWalkthroughDate} onChange={(value) => update("finalWalkthroughDate", value)} type="date" />
        <Field label="Agent name" value={draft.agentName} onChange={(value) => update("agentName", value)} />
        <Field label="Agent email" value={draft.agentEmail} onChange={(value) => update("agentEmail", value)} type="email" />
        <Field label="Agent phone" value={draft.agentPhone} onChange={(value) => update("agentPhone", value)} />
        <Field label="Notes" value={draft.notes} onChange={(value) => update("notes", value)} as="textarea" />
      </div>
      <button className="btn primary">
        <Icon name="ClipboardCheck" />
        <span>Generate Checklist</span>
      </button>
    </form>
  );
}

function BuyerTransactionList({ transactions, tasks, filters, setFilters, permissions, onOpen }) {
  const agentOptions = ["All", ...Array.from(new Set(transactions.map((transaction) => transaction.userEmail).filter(Boolean)))];
  const filtered = transactions.filter((transaction) => {
    const transactionTasks = tasks.filter((task) => task.transactionId === transaction.id);
    const matchesStatus = filters.status === "All" || buyerDisplayStatus(transaction) === filters.status || transaction.status === filters.status;
    const matchesAgent = filters.agent === "All" || transaction.userEmail === filters.agent;
    const matchesOverdue = !filters.overdueOnly || buyerOverdueCount(transactionTasks) > 0;
    const matchesClosing = !filters.closingBefore || (transaction.closingDate && transaction.closingDate <= filters.closingBefore);
    return matchesStatus && matchesAgent && matchesOverdue && matchesClosing;
  });

  return (
    <div className="buyer-list-page">
      <div className="panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Transaction list</p>
            <h3>Buyer contract checklists</h3>
          </div>
        </div>
        <div className="buyer-filter-grid">
          <Field label="Status" value={filters.status} onChange={(value) => setFilters((current) => ({ ...current, status: value }))} as="select" options={["All", ...buyerStatuses]} />
          {permissions.canViewAll && <Field label="Agent" value={filters.agent} onChange={(value) => setFilters((current) => ({ ...current, agent: value }))} as="select" options={agentOptions} />}
          <Field label="Closing before" value={filters.closingBefore} onChange={(value) => setFilters((current) => ({ ...current, closingBefore: value }))} type="date" />
          <label className="check-field buyer-overdue-filter">
            <input type="checkbox" checked={filters.overdueOnly} onChange={(event) => setFilters((current) => ({ ...current, overdueOnly: event.target.checked }))} />
            Overdue only
          </label>
        </div>
      </div>
      <div className="buyer-transaction-grid">
        {filtered.map((transaction) => (
          <BuyerTransactionCard
            key={transaction.id}
            transaction={transaction}
            tasks={tasks.filter((task) => task.transactionId === transaction.id)}
            onOpen={() => onOpen(transaction.id)}
          />
        ))}
        {!filtered.length && <EmptyState icon="ClipboardCheck" title="No buyer contract checklists yet" body="Create a transaction to generate the default checklist." />}
      </div>
    </div>
  );
}

function BuyerTransactionDetail({ transaction, tasks, reminderSettings, onBack, onUpdateTransaction, onUpdateTask, onDeleteTask, onAddTask, onSaveReminders }) {
  const [customTask, setCustomTask] = useState({ section: "Custom Tasks", taskName: "", dueDate: "", dueTime: "", priority: "Normal", assignedTo: "", linkedDocument: "", notes: "" });
  const [expandedSections, setExpandedSections] = useState({});
  const sectionGroups = useMemo(() => {
    const sectionNames = Array.from(new Set(tasks.map((task) => task.section || "General")));
    return sectionNames.map((section) => ({
      section,
      tasks: tasks
        .filter((task) => (task.section || "General") === section)
        .sort((a, b) => Number(a.order || 0) - Number(b.order || 0))
    }));
  }, [tasks]);
  const sectionNamesKey = sectionGroups.map((group) => group.section).join("|");

  useEffect(() => {
    setExpandedSections((current) => {
      const next = {};
      sectionGroups.forEach((group, index) => {
        const hasUrgentOpenTask = group.tasks.some((task) => !task.completed && ["overdue", "today", "tomorrow"].includes(buyerTaskTone(task)));
        next[group.section] = Object.prototype.hasOwnProperty.call(current, group.section)
          ? current[group.section]
          : index === 0 || hasUrgentOpenTask;
      });
      return next;
    });
  }, [transaction.id, sectionNamesKey]);

  function addCustom(event) {
    event.preventDefault();
    if (!customTask.taskName.trim()) return;
    onAddTask(transaction.id, customTask);
    setCustomTask({ section: "Custom Tasks", taskName: "", dueDate: "", dueTime: "", priority: "Normal", assignedTo: "", linkedDocument: "", notes: "" });
  }

  function toggleSection(section) {
    setExpandedSections((current) => ({ ...current, [section]: !current[section] }));
  }

  function expandAllSections() {
    setExpandedSections(sectionGroups.reduce((next, group) => ({ ...next, [group.section]: true }), {}));
  }

  function showPrioritySections() {
    setExpandedSections(
      sectionGroups.reduce((next, group, index) => {
        const hasDeadlineAlert = group.tasks.some((task) => !task.completed && ["overdue", "today", "tomorrow", "soon"].includes(buyerTaskTone(task)));
        const hasOpenTask = group.tasks.some((task) => !task.completed);
        next[group.section] = hasDeadlineAlert || (index === 0 && hasOpenTask);
        return next;
      }, {})
    );
  }

  return (
    <section className="buyer-detail-page">
      <button className="btn secondary" onClick={onBack}>
        <Icon name="ArrowLeft" />
        <span>Back to Transactions</span>
      </button>
      <div className="buyer-detail-hero">
        <div>
          <p className="eyebrow">Buyer Contract Tracker</p>
          <h3>{transaction.transactionName}</h3>
          <p>{transaction.propertyAddress || "No property address entered"} - Buyer: {transaction.buyerName || "Not set"}</p>
        </div>
        <div className="row-actions">
          <button className="btn secondary" onClick={() => onUpdateTransaction(transaction.id, { status: "Closed" })}>Mark Closed</button>
          <button className="btn secondary" onClick={() => onUpdateTransaction(transaction.id, { status: "Cancelled" })}>Cancel</button>
        </div>
      </div>
      <DeadlineSummaryCard transaction={transaction} tasks={tasks} />
      <div className="buyer-detail-grid">
        <div className="buyer-checklist-stack">
          <div className="panel buyer-checklist-toolbar">
            <div>
              <p className="eyebrow">Checklist view</p>
              <h3>Work by section</h3>
              <span>Open the section you need, or focus only on deadline-sensitive work.</span>
            </div>
            <div className="row-actions">
              <button className="btn secondary small-btn" type="button" onClick={showPrioritySections}>
                <Icon name="AlertTriangle" />
                <span>Priority View</span>
              </button>
              <button className="btn secondary small-btn" type="button" onClick={expandAllSections}>
                <Icon name="ListChecks" />
                <span>Expand All</span>
              </button>
            </div>
          </div>
          {sectionGroups.map((group) => (
            <ChecklistSection
              key={group.section}
              section={group.section}
              tasks={group.tasks}
              expanded={Boolean(expandedSections[group.section])}
              onToggle={() => toggleSection(group.section)}
              onUpdateTask={onUpdateTask}
              onDeleteTask={onDeleteTask}
            />
          ))}
          <form className="panel custom-task-form" onSubmit={addCustom}>
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Custom task</p>
                <h3>Add an extra checklist item</h3>
              </div>
            </div>
            <div className="buyer-form-grid compact">
              <Field label="Section/category" value={customTask.section} onChange={(value) => setCustomTask((current) => ({ ...current, section: value }))} />
              <Field label="Task name" value={customTask.taskName} onChange={(value) => setCustomTask((current) => ({ ...current, taskName: value }))} />
              <Field label="Due date" value={customTask.dueDate} onChange={(value) => setCustomTask((current) => ({ ...current, dueDate: value }))} type="date" />
              <Field label="Due time" value={customTask.dueTime} onChange={(value) => setCustomTask((current) => ({ ...current, dueTime: value }))} type="time" />
              <Field label="Priority" value={customTask.priority} onChange={(value) => setCustomTask((current) => ({ ...current, priority: value }))} as="select" options={buyerTaskPriorities} />
              <Field label="Assigned person optional" value={customTask.assignedTo} onChange={(value) => setCustomTask((current) => ({ ...current, assignedTo: value }))} />
              <Field label="Linked document optional" value={customTask.linkedDocument} onChange={(value) => setCustomTask((current) => ({ ...current, linkedDocument: value }))} />
              <Field label="Notes" value={customTask.notes} onChange={(value) => setCustomTask((current) => ({ ...current, notes: value }))} as="textarea" />
            </div>
            <button className="btn primary">
              <Icon name="Plus" />
              <span>Add Custom Task</span>
            </button>
          </form>
        </div>
        <aside className="buyer-side-panel">
          <div className="panel">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Key dates</p>
                <h3>Contract timeline</h3>
              </div>
            </div>
            <div className="buyer-key-date-list">
              {[
                ["Effective", transaction.effectiveDate],
                ["EMD due", transaction.emdDueDate],
                ["Inspection ends", transaction.inspectionPeriodEndDate],
                ["Financing ends", transaction.financingPeriodEndDate],
                ["Appraisal", transaction.appraisalDeadline],
                ["HOA", transaction.hoaDeadline],
                ["Walkthrough", transaction.finalWalkthroughDate],
                ["Closing", transaction.closingDate]
              ].map(([label, value]) => (
                <span key={label}><strong>{label}</strong>{formatDate(value)}</span>
              ))}
            </div>
            <Field label="Status" value={transaction.status || "Active"} onChange={(value) => onUpdateTransaction(transaction.id, { status: value })} as="select" options={buyerStatuses} />
          </div>
          <ReminderSettingsPanel settings={reminderSettings} onSave={onSaveReminders} />
          <ComplianceNotice text={buyerTrackerDisclaimer} />
        </aside>
      </div>
    </section>
  );
}

function transactionTone(value) {
  const text = String(value || "").toLowerCase();
  if (/closed|approved/.test(text)) return "closed";
  if (/cancel|terminate|correction|missing|reject/.test(text)) return "cancelled";
  if (/soon|review|under contract|submitted|pending/.test(text)) return "closing-soon";
  return "";
}

function deadlineTone(deadline) {
  if (deadline.completed || deadline.warningStatus === "completed") return "complete";
  return deadline.warningStatus || "none";
}

function transactionMetricSet(transactions) {
  const closingSoon = transactions.filter((transaction) => {
    const days = daysUntil(transaction.closingDate);
    return days !== null && days >= 0 && days <= 14 && transaction.status !== "Closed";
  });
  return [
    ["Active Transactions", transactions.filter((transaction) => !["Closed", "Cancelled", "Terminated"].includes(transaction.status)).length, "FolderKanban"],
    ["Under Contract", transactions.filter((transaction) => transaction.status === "Under Contract").length, "Handshake"],
    ["Listings", transactions.filter((transaction) => /seller|listing/i.test(transaction.type)).length, "Home"],
    ["Buyers", transactions.filter((transaction) => /buyer/i.test(transaction.type)).length, "UsersRound"],
    ["Rentals", transactions.filter((transaction) => /rental|tenant/i.test(transaction.type)).length, "KeyRound"],
    ["Pending Broker Review", transactions.filter((transaction) => transaction.complianceStatus === "Submitted for Review" || transaction.status === "Pending Broker Review").length, "ShieldCheck"],
    ["Missing Documents", transactions.reduce((sum, transaction) => sum + Number(transaction.missingItemsCount || 0), 0), "FileWarning"],
    ["Closing Soon", closingSoon.length, "CalendarClock"],
    ["Closed", transactions.filter((transaction) => transaction.status === "Closed").length, "BadgeCheck"],
    ["Cancelled / Terminated", transactions.filter((transaction) => ["Cancelled", "Terminated"].includes(transaction.status)).length, "CircleOff"]
  ];
}

function groupTransactionChecklistItems(items = []) {
  const groups = new Map();
  items.forEach((item) => {
    const category = item.category || "General";
    if (!groups.has(category)) groups.set(category, []);
    groups.get(category).push(item);
  });
  return Array.from(groups.entries()).map(([category, groupItems]) => ({
    category,
    items: groupItems.sort((a, b) => Number(Boolean(a.completed)) - Number(Boolean(b.completed)) || String(a.dueDate || "9999-12-31").localeCompare(String(b.dueDate || "9999-12-31")) || String(a.label || "").localeCompare(String(b.label || ""))),
    completed: groupItems.filter((item) => item.completed).length,
    total: groupItems.length
  }));
}

function TransactionMetricCard({ label, value, icon }) {
  return (
    <article className="transaction-metric-card">
      <Icon name={icon} />
      <span>{label}</span>
      <strong>{value}</strong>
    </article>
  );
}

function TransactionCard({ transaction, onOpen }) {
  return (
    <article className="transaction-card">
      <button type="button" onClick={onOpen}>
        <div className="transaction-card-head">
          <span className={classNames("status-badge", transactionTone(transaction.status))}>{transaction.status || "Draft"}</span>
          <strong>{transaction.title}</strong>
          <p>{transaction.propertyAddress || "No property address"}</p>
        </div>
        <div className="transaction-card-grid">
          <span><strong>Type</strong>{transaction.type}</span>
          <span><strong>Client</strong>{transaction.clientName || "Not set"}</span>
          <span><strong>Agent</strong>{transaction.assignedAgentName || transaction.assignedAgentEmail || "Unassigned"}</span>
          <span><strong>Closing</strong>{formatDate(transaction.closingDate)}</span>
          <span><strong>Compliance</strong>{transaction.complianceStatus || "Draft"}</span>
          <span><strong>Missing</strong>{Number(transaction.missingItemsCount || 0)} items</span>
        </div>
        <div className="progress-track">
          <div style={{ width: `${transaction.completionPercent || 0}%` }} />
        </div>
        <small>
          {transaction.nextDeadline
            ? `Next: ${transaction.nextDeadline.label} on ${formatDate(transaction.nextDeadline.date)}`
            : `Last updated ${formatDate((transaction.updatedAt || "").slice(0, 10))}`}
        </small>
      </button>
    </article>
  );
}

function workflowTone(item) {
  if (item.completed || item.warningStatus === "complete") return "complete";
  if (item.type === "document") {
    if (item.status === "Rejected") return "overdue";
    if (item.status === "Submitted") return "upcoming";
    if (item.status === "Missing") return ["overdue", "today", "tomorrow", "soon", "upcoming"].includes(item.warningStatus) ? item.warningStatus : "none";
  }
  return item.warningStatus || "none";
}

function workflowStatusText(item) {
  if (item.completed) return "Complete";
  if (item.type === "document") return item.status || "Missing";
  if (item.warningStatus === "today") return "Due today";
  if (item.warningStatus === "overdue") return "Overdue";
  if (item.warningStatus === "soon") return "Due soon";
  if (item.warningStatus === "upcoming") return "Upcoming";
  return item.status || "Open";
}

function TransactionWorkflowTimeline({ items = [], onToggleItem, compact = false, onOpenDocuments }) {
  const visibleItems = compact ? items.slice(0, 6) : items;
  return (
    <div className={classNames("transaction-workflow-list", compact && "compact")}>
      {visibleItems.map((item) => (
        <article className={classNames("transaction-workflow-item", item.completed && "completed")} key={`${item.type}-${item.id}`}>
          <div className="workflow-marker">
            {item.checkable ? (
              <input type="checkbox" checked={Boolean(item.completed)} onChange={(event) => onToggleItem(item, event.target.checked)} />
            ) : item.type === "document" ? (
              <Icon name={item.completed ? "FileCheck2" : "FileWarning"} size={16} />
            ) : (
              <Icon name="Milestone" size={16} />
            )}
          </div>
          <div>
            <strong>{item.title}</strong>
            <span>{item.category} {item.dueDate ? `- ${formatDate(item.dueDate)}` : "- date not set"}</span>
            {item.fileName && <small>{item.fileName}</small>}
          </div>
          <span className={classNames("deadline-badge", `tone-${workflowTone(item)}`)}>{workflowStatusText(item)}</span>
          {item.type === "document" && !item.completed && onOpenDocuments && (
            <button className="btn secondary small-btn" type="button" onClick={onOpenDocuments}>Upload</button>
          )}
        </article>
      ))}
      {!visibleItems.length && <EmptyState icon="ListChecks" title="No workflow items yet" body="Create a transaction to generate a chronological file-to-close workflow." />}
    </div>
  );
}

function normalizeCommissionPlanName(plan) {
  const value = String(plan || "").toLowerCase();
  if (value.includes("premium.1") || value.includes("premium 1") || value.includes("premium-1") || value.includes("grandfather")) return "Nex Premium.1";
  if (value.includes("level")) return "Nex Level";
  if (value.includes("elite")) return "Nex Elite";
  return "Nex Premium";
}

function commissionPlanRule(plan) {
  return COMMISSION_PLAN_RULES[normalizeCommissionPlanName(plan)] || COMMISSION_PLAN_RULES["Nex Premium"];
}

function capCycleFromAnniversary(anniversaryDate) {
  const now = new Date();
  const fallbackStart = new Date(now.getFullYear(), 0, 1);
  const date = anniversaryDate ? new Date(`${anniversaryDate}T00:00:00`) : null;
  if (!date || Number.isNaN(date.getTime())) {
    return {
      start: fallbackStart,
      end: new Date(now.getFullYear() + 1, 0, 1),
      label: `${now.getFullYear()} calendar year`
    };
  }
  const start = new Date(now.getFullYear(), date.getMonth(), date.getDate());
  if (now < start) start.setFullYear(start.getFullYear() - 1);
  const end = new Date(start);
  end.setFullYear(end.getFullYear() + 1);
  return {
    start,
    end,
    label: `${start.toLocaleDateString([], { month: "short", day: "numeric", year: "numeric" })} - ${end.toLocaleDateString([], { month: "short", day: "numeric", year: "numeric" })}`
  };
}

function transactionCloseDate(transaction) {
  return dateOnly(transaction.closingDate || String(transaction.updatedAt || transaction.createdAt || "").slice(0, 10));
}

function commissionGrossForTransaction(transaction, commission) {
  const savedGross = Number(commission?.grossCommission || 0);
  if (savedGross > 0) return savedGross;
  const base = Number(transaction.purchasePrice || transaction.leaseAmount || 0) || 0;
  const raw = String(transaction.commission || "");
  const match = raw.match(/[\d.]+/);
  if (!match) return base ? Math.round(base * 0.03) : 0;
  const number = Number(match[0]) || 0;
  if (raw.includes("%")) return Math.round(base * (number / 100));
  return Math.round(number);
}

function transactionSalesPrice(transaction) {
  return Number(transaction.purchasePrice || transaction.leaseAmount || 0) || 0;
}

function nexPremiumTransactionFee(transaction, grossCommission) {
  const rule = COMMISSION_PLAN_RULES["Nex Premium"];
  const salesPrice = transactionSalesPrice(transaction);
  if (salesPrice > rule.luxuryThreshold) {
    return Math.max(rule.fee, Math.round((Number(grossCommission) || 0) * rule.luxuryCommissionRate));
  }
  return rule.fee;
}

function isClosedCommissionDeal(transaction, commission) {
  return transaction.status === "Closed" || transaction.complianceStatus === "Closed" || commission?.paymentStatus === "Paid";
}

function calculateAgentCommissionSummary(agent, transactions, commissions) {
  const email = String(agent.email || "").toLowerCase();
  const plan = normalizeCommissionPlanName(agent.commissionPlan);
  const rule = commissionPlanRule(plan);
  const cycle = capCycleFromAnniversary(agent.anniversaryDate);
  const commissionByTransaction = new Map(commissions.map((commission) => [commission.transactionId, commission]));
  const closedDeals = transactions
    .filter((transaction) => String(transaction.assignedAgentEmail || transaction.createdByEmail || "").toLowerCase() === email)
    .filter((transaction) => {
      const commission = commissionByTransaction.get(transaction.id);
      const closeDate = transactionCloseDate(transaction);
      if (!isClosedCommissionDeal(transaction, commission) || !closeDate) return false;
      const closedAt = new Date(`${closeDate}T00:00:00`);
      return closedAt >= cycle.start && closedAt < cycle.end;
    })
    .sort((a, b) => String(transactionCloseDate(a)).localeCompare(String(transactionCloseDate(b))));

  let grossCommission = 0;
  let agentCommission = 0;
  let brokerageContribution = 0;
  let capPaid = 0;
  let capDealCredits = 0;

  const dealRows = closedDeals.map((transaction) => {
    const commission = commissionByTransaction.get(transaction.id);
    const gross = commissionGrossForTransaction(transaction, commission);
    grossCommission += gross;
    let agentNet = gross;
    let brokerShare = 0;
    let capCredit = 0;
    let capNote = "Closed commission";

    if (plan === "Nex Premium") {
      brokerShare = nexPremiumTransactionFee(transaction, gross);
      capCredit = brokerShare;
      agentNet = Math.max(0, gross - brokerShare);
      const overLuxuryThreshold = transactionSalesPrice(transaction) > rule.luxuryThreshold;
      capNote = overLuxuryThreshold ? "Greater of 5% of gross commission or $595" : "$595 transaction fee";
    } else if (plan === "Nex Premium.1") {
      const remainingCap = Math.max(0, rule.capAmount - capPaid);
      const hasDealCreditsRemaining = capDealCredits < rule.capDeals;
      brokerShare = hasDealCreditsRemaining ? Math.min(rule.fee, remainingCap) : 0;
      if (brokerShare > 0) {
        capPaid += brokerShare;
        capDealCredits += 1;
        capCredit = 1;
      }
      agentNet = Math.max(0, gross - brokerShare);
      capNote = brokerShare > 0 ? "$450 grandfathered transaction fee" : "Grandfathered cap met";
    } else if (rule.type === "split-cap") {
      const remainingCap = Math.max(0, rule.capAmount - capPaid);
      brokerShare = Math.min(Math.round(gross * rule.splitRate), remainingCap);
      capPaid += brokerShare;
      capCredit = brokerShare;
      agentNet = Math.max(0, gross - brokerShare);
      capNote = remainingCap <= 0 ? "After cap" : `${Math.round((1 - rule.splitRate) * 100)}/${Math.round(rule.splitRate * 100)} until ${formatCurrency(rule.capAmount)} cap`;
    }

    agentCommission += agentNet;
    brokerageContribution += brokerShare;
    return {
      id: transaction.id,
      title: transaction.title,
      propertyAddress: transaction.propertyAddress,
      closingDate: transactionCloseDate(transaction),
      gross,
      agentNet,
      brokerageContribution: brokerShare,
      capCredit,
      capNote
    };
  });

  const capProgress = plan === "Nex Premium"
    ? 100
    : plan === "Nex Premium.1"
      ? Math.min(100, Math.round(Math.max(capPaid / rule.capAmount, capDealCredits / rule.capDeals) * 100))
      : rule.capAmount
        ? Math.min(100, Math.round((capPaid / rule.capAmount) * 100))
        : 0;

  return {
    agent,
    plan,
    rule,
    cycle,
    closedDeals,
    dealRows,
    grossCommission,
    agentCommission,
    brokerageContribution,
    premiumFeeTotal: plan === "Nex Premium" ? brokerageContribution : 0,
    premiumCapDeals: plan === "Nex Premium.1" ? capDealCredits : 0,
    premiumCapRemaining: plan === "Nex Premium.1" ? Math.max(0, rule.capDeals - capDealCredits) : 0,
    grandfatheredCapDeals: plan === "Nex Premium.1" ? capDealCredits : 0,
    grandfatheredCapRemainingDeals: plan === "Nex Premium.1" ? Math.max(0, rule.capDeals - capDealCredits) : 0,
    grandfatheredCapPaid: plan === "Nex Premium.1" ? capPaid : 0,
    grandfatheredCapRemaining: plan === "Nex Premium.1" ? Math.max(0, rule.capAmount - capPaid) : 0,
    splitCapPaid: rule.type === "split-cap" ? capPaid : 0,
    splitCapRemaining: rule.type === "split-cap" ? Math.max(0, rule.capAmount - capPaid) : 0,
    levelCapPaid: rule.type === "split-cap" ? capPaid : 0,
    levelCapRemaining: rule.type === "split-cap" ? Math.max(0, rule.capAmount - capPaid) : 0,
    capProgress
  };
}

function commissionCapLabel(summary) {
  if (summary.plan === "Nex Premium") return "No cap - transaction fee per closing";
  if (summary.plan === "Nex Premium.1") {
    return `${summary.grandfatheredCapDeals} of 12 transactions / ${formatCurrency(summary.grandfatheredCapPaid)} of $5,400`;
  }
  if (summary.rule?.type === "split-cap") {
    return `${formatCurrency(summary.splitCapPaid)} of ${formatCurrency(summary.rule.capAmount)} cap paid`;
  }
  return "Plan details";
}

function commissionTeamCaption(summary) {
  if (summary.plan === "Nex Premium") return `${formatCurrency(summary.premiumFeeTotal)} transaction fees tracked`;
  if (summary.plan === "Nex Premium.1") return `${summary.grandfatheredCapDeals}/12 deals - ${formatCurrency(summary.grandfatheredCapRemaining)} cap remaining`;
  if (summary.rule?.type === "split-cap") return `${formatCurrency(summary.splitCapRemaining)} cap remaining`;
  return "Plan details";
}

function CommissionCapTracker({ currentUser, role, users = [], setToast }) {
  const [transactions, setTransactions] = useState([]);
  const [commissions, setCommissions] = useState([]);
  const [selectedEmail, setSelectedEmail] = useState(currentUser?.email || "");
  const [loading, setLoading] = useState(true);
  const isAdmin = isAdminRole(role);

  useEffect(() => {
    let cancelled = false;
    async function load() {
      setLoading(true);
      try {
        const payload = await API.request("/api/transactions/bootstrap");
        if (cancelled) return;
        setTransactions(payload.transactions || []);
        setCommissions(payload.commissions || []);
      } catch (error) {
        setToast(error.message || "Could not load commission tracker.");
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    load();
    return () => {
      cancelled = true;
    };
  }, [setToast]);

  const agentOptions = useMemo(() => {
    const byEmail = new Map();
    [currentUser, ...users].filter(Boolean).forEach((user) => {
      if (user.email) byEmail.set(String(user.email).toLowerCase(), { ...user, commissionPlan: user.commissionPlan || "Nex Premium" });
    });
    if (isAdmin) {
      transactions.forEach((transaction) => {
        const email = String(transaction.assignedAgentEmail || transaction.createdByEmail || "").toLowerCase();
        if (email && !byEmail.has(email)) {
          byEmail.set(email, {
            email,
            name: transaction.assignedAgentName || email,
            commissionPlan: "Nex Premium",
            anniversaryDate: ""
          });
        }
      });
    }
    return Array.from(byEmail.values()).sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email));
  }, [currentUser, users, transactions, isAdmin]);

  useEffect(() => {
    if (!selectedEmail && agentOptions[0]?.email) setSelectedEmail(agentOptions[0].email);
  }, [agentOptions, selectedEmail]);

  const selectedAgent = agentOptions.find((agent) => String(agent.email).toLowerCase() === String(selectedEmail || currentUser?.email || "").toLowerCase()) || currentUser || {};
  const summary = useMemo(
    () => calculateAgentCommissionSummary(selectedAgent, transactions, commissions),
    [selectedAgent, transactions, commissions]
  );
  const teamSummaries = useMemo(
    () => agentOptions.map((agent) => calculateAgentCommissionSummary(agent, transactions, commissions)),
    [agentOptions, transactions, commissions]
  );

  const capLabel = commissionCapLabel(summary);
  const capProgressLabel = summary.plan === "Nex Premium" ? "No cap" : `${summary.capProgress}%`;

  return (
    <section className="portal-page commission-page">
      <div className="module-hero commission-hero">
        <div>
          <p className="eyebrow">Agent money pipeline</p>
          <h3>Commission & Cap Tracker</h3>
          <p>Track closed commissions against each agent's assigned Nex plan and current anniversary-year cap cycle.</p>
        </div>
        <div className="commission-plan-card">
          <span>{summary.plan}</span>
          <strong>{capLabel}</strong>
          <small>Cycle: {summary.cycle.label}</small>
        </div>
      </div>

      {isAdmin && (
        <div className="panel commission-admin-filter">
          <div>
            <p className="eyebrow">Admin view</p>
            <h3>Review an agent's cap tracker</h3>
          </div>
          <Field label="Agent" value={selectedAgent.email || ""} onChange={setSelectedEmail} as="select" options={agentOptions.map((agent) => agent.email)} />
        </div>
      )}

      {loading ? (
        <EmptyState icon="LoaderCircle" title="Loading commissions" body="Pulling transaction commission details and cap-cycle data." />
      ) : (
        <>
          <div className="commission-summary-grid">
            <CommissionSummaryCard icon="BadgeDollarSign" label="Agent commission" value={formatCurrency(summary.agentCommission)} />
            <CommissionSummaryCard icon="Handshake" label="Closed deals this cycle" value={summary.closedDeals.length} />
            <CommissionSummaryCard icon="Gauge" label="Cap / fee status" value={capProgressLabel} />
            <CommissionSummaryCard icon="Landmark" label="Brokerage contribution" value={formatCurrency(summary.brokerageContribution)} />
          </div>

          <div className="commission-detail-grid">
            <article className="panel commission-plan-detail">
              <div className="panel-heading">
                <div>
                  <p className="eyebrow">Plan rules</p>
                  <h3>{summary.plan}</h3>
                </div>
                <span className="status-badge closed">{capProgressLabel}</span>
              </div>
              <div className="progress-track large">
                <div style={{ width: `${summary.capProgress}%` }} />
              </div>
              {summary.plan === "Nex Premium" && (
                <p>Nex Premium is the independent 100% commission plan with no annual cap. It has a $99 monthly fee, no upfront fee, and a $595 transaction fee on sales prices up to $1,000,000. Over $1,000,000, the transaction fee is the greater of 5% of gross commission or $595. NPS is not included.</p>
              )}
              {summary.plan === "Nex Premium.1" && (
                <p>Nex Premium.1 is the grandfathered 100% plan for existing assigned agents. It has a $450 transaction fee capped at $5,400 or 12 transactions per anniversary year, is no longer offered to new agents, and does not include NPS.</p>
              )}
              {summary.plan === "Nex Level" && (
                <p>Nex Level is the Growth Plan: 80/20 split, $20,000 annual cap, $0 monthly fee, $99 one-time join fee, $295 transaction fee, Nex Central included, and Nex PowerShare eligible.</p>
              )}
              {summary.plan === "Nex Elite" && (
                <p>Nex Elite is the Leadership & Teams plan: 90/10 split, $18,000 annual cap, $59 monthly fee, no upfront fee, $295 transaction fee, Nex Central included, individual-agent NPS eligible, and team-start eligibility subject to approval.</p>
              )}
              <div className="commission-plan-stats">
                {summary.plan === "Nex Premium" && (
                  <>
                    <span><strong>Annual cap</strong>No cap</span>
                    <span><strong>Fees tracked</strong>{formatCurrency(summary.premiumFeeTotal)}</span>
                  </>
                )}
                {summary.plan === "Nex Premium.1" && (
                  <>
                    <span><strong>Cap credits</strong>{summary.grandfatheredCapDeals} / 12</span>
                    <span><strong>Remaining</strong>{summary.grandfatheredCapRemainingDeals} deals</span>
                  </>
                )}
                {summary.rule?.type === "split-cap" && (
                  <>
                    <span><strong>Cap paid</strong>{formatCurrency(summary.splitCapPaid)}</span>
                    <span><strong>Remaining</strong>{formatCurrency(summary.splitCapRemaining)}</span>
                  </>
                )}
                <span><strong>Gross commission</strong>{formatCurrency(summary.grossCommission)}</span>
                {summary.rule?.fee != null && <span><strong>Transaction fee</strong>{formatCurrency(summary.rule.fee)}</span>}
              </div>
            </article>

            <article className="panel commission-deals-panel">
              <div className="panel-heading">
                <div>
                  <p className="eyebrow">Closed transaction history</p>
                  <h3>Deals in this cap cycle</h3>
                </div>
              </div>
              {summary.dealRows.length ? (
                <div className="commission-deal-list">
                  {summary.dealRows.map((deal) => (
                    <article key={deal.id}>
                      <div>
                        <strong>{deal.title || deal.propertyAddress || "Closed deal"}</strong>
                        <span>{deal.propertyAddress || "No property address"} • Closed {formatDate(deal.closingDate)}</span>
                      </div>
                      <div>
                        <strong>{formatCurrency(deal.agentNet)}</strong>
                        <span>{deal.capNote}</span>
                      </div>
                    </article>
                  ))}
                </div>
              ) : (
                <EmptyState icon="BadgeDollarSign" title="No closed commission deals yet" body="Closed transactions assigned to this agent will appear here for the current cap year." />
              )}
            </article>
          </div>

          {isAdmin && (
            <div className="panel commission-team-panel">
              <div className="panel-heading">
                <div>
                  <p className="eyebrow">Team snapshot</p>
                  <h3>Agent plan and cap progress</h3>
                </div>
              </div>
              <div className="commission-team-grid">
                {teamSummaries.map((item) => (
                  <button key={item.agent.email} type="button" onClick={() => setSelectedEmail(item.agent.email)}>
                    <strong>{item.agent.name || item.agent.email}</strong>
                    <span>{item.plan} - {commissionTeamCaption(item)}</span>
                    <div className="progress-track">
                      <div style={{ width: `${item.capProgress}%` }} />
                    </div>
                  </button>
                ))}
              </div>
            </div>
          )}
        </>
      )}
    </section>
  );
}

function CommissionSummaryCard({ icon, label, value }) {
  return (
    <article className="commission-summary-card">
      <Icon name={icon} />
      <span>{label}</span>
      <strong>{value}</strong>
    </article>
  );
}

function NexPowerShareRewards({ currentUser, role, users = [], setUsers, setToast }) {
  const isAdmin = isAdminRole(role);
  const allUsers = useMemo(() => npsUserList(currentUser, users), [currentUser, users]);
  const [transactions, setTransactions] = useState([]);
  const [commissions, setCommissions] = useState([]);
  const [rewards, setRewards] = useState([]);
  const [rewardActivity, setRewardActivity] = useState([]);
  const [editingRewardId, setEditingRewardId] = useState("");
  const [selectedAgentEmail, setSelectedAgentEmail] = useState(normalizeEmail(currentUser?.email));
  const [calculator, setCalculator] = useState({
    closingAgentEmail: normalizeEmail(currentUser?.email),
    eligibleCompanyRevenue: 2000,
    closeDate: new Date().toISOString().slice(0, 10)
  });
  const [rewardDraft, setRewardDraft] = useState(() => defaultNpsRewardDraft(normalizeEmail(currentUser?.email)));
  const [profileDraft, setProfileDraft] = useState(null);
  const selectedAgent = npsFindUser(allUsers, selectedAgentEmail) || currentUser || {};

  useEffect(() => {
    let cancelled = false;
    API.request("/api/transactions/bootstrap")
      .then((payload) => {
        if (cancelled) return;
        setTransactions(payload.transactions || []);
        setCommissions(payload.commissions || []);
      })
      .catch((error) => setToast?.(error.message || "Could not load PowerShare transaction data."));
    API.request("/api/nps/bootstrap")
      .then((payload) => {
        if (cancelled) return;
        setRewards(payload.rewards || []);
        setRewardActivity(payload.rewardActivity || []);
      })
      .catch((error) => setToast?.(error.message || "Could not load PowerShare rewards."));
    return () => {
      cancelled = true;
    };
  }, [setToast]);

  useEffect(() => {
    if (!selectedAgentEmail && allUsers[0]?.email) setSelectedAgentEmail(allUsers[0].email);
  }, [allUsers, selectedAgentEmail]);

  useEffect(() => {
    setProfileDraft({
      sponsorEmail: normalizeEmail(selectedAgent.sponsorEmail),
      npsJoinDate: selectedAgent.npsJoinDate || selectedAgent.anniversaryDate || "",
      npsEligible: selectedAgent.npsEligible !== false,
      licenseActive: selectedAgent.licenseActive !== false
    });
    if (!editingRewardId) {
      setRewardDraft((current) => ({ ...current, recipientEmail: normalizeEmail(selectedAgent.email) || current.recipientEmail }));
    }
  }, [selectedAgent.email]);

  const visibleClosingAgentEmail = isAdmin ? calculator.closingAgentEmail : normalizeEmail(currentUser?.email);
  const eligibleRevenue = Math.max(0, numericInput(calculator.eligibleCompanyRevenue, 0));
  const networkRows = calculateNpsRows({
    closingAgentEmail: visibleClosingAgentEmail,
    eligibleCompanyRevenue: eligibleRevenue,
    closeDate: calculator.closeDate,
    users: allUsers
  });
  const totalGross = networkRows.reduce((sum, row) => sum + row.grossReward, 0);
  const totalVested = networkRows.reduce((sum, row) => sum + row.vestedAmount, 0);
  const totalUnvested = totalGross - totalVested;
  const selectedSummary = calculateNpsRewardSummaryForAgent(selectedAgent, allUsers, transactions, commissions);
  const postedSummary = calculatePostedNpsRewardSummary(selectedAgent, rewards);
  const selectedRewards = rewards.filter((reward) => normalizeEmail(reward.recipientEmail) === normalizeEmail(selectedAgent.email));
  const selectedRewardActivity = rewardActivity.filter((item) => normalizeEmail(item.recipientEmail) === normalizeEmail(selectedAgent.email) || selectedRewards.some((reward) => reward.id === item.rewardId));
  const selectedSponsorChain = getNpsSponsorChain(selectedAgent.email, allUsers);
  const selectedDirectSponsor = npsFindUser(allUsers, selectedAgent.sponsorEmail);
  const selectedDirectRecruits = getNpsDirectRecruits(selectedAgent.email, allUsers);
  const nextMilestone =
    monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date()) < 12
      ? `${12 - monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date())} month${12 - monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date()) === 1 ? "" : "s"} to the 1-year cliff`
      : monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date()) < 36
        ? `${36 - monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date())} month${36 - monthsBetweenDates(selectedAgent.npsJoinDate || selectedAgent.anniversaryDate, new Date()) === 1 ? "" : "s"} to full vesting`
        : "Fully vested";

  function updateCalculator(field, value) {
    if (!isAdmin) return;
    setCalculator((current) => ({ ...current, [field]: value }));
  }

  async function saveNpsProfile(event) {
    event.preventDefault();
    if (!isAdmin || !selectedAgent?.email || !profileDraft) return;
    try {
      const saved = await API.request(`/api/users/${encodeURIComponent(selectedAgent.id || selectedAgent.email)}`, {
        method: "PUT",
        body: JSON.stringify(profileDraft)
      });
      setUsers?.((current) => current.map((user) => (normalizeEmail(user.email) === normalizeEmail(saved.email) ? saved : user)));
      setToast?.("PowerShare profile saved.");
    } catch (error) {
      setToast?.(error.message || "Could not save PowerShare profile.");
    }
  }

  async function saveNpsReward(event) {
    event.preventDefault();
    if (!isAdmin) return;
    try {
      const endpoint = editingRewardId ? `/api/nps/rewards/${encodeURIComponent(editingRewardId)}` : "/api/nps/rewards";
      const response = await API.request(endpoint, {
        method: editingRewardId ? "PUT" : "POST",
        body: JSON.stringify(rewardDraft)
      });
      const savedReward = response.reward;
      setRewards((current) => {
        const without = current.filter((reward) => reward.id !== savedReward.id);
        return [savedReward, ...without];
      });
      if (response.activity) setRewardActivity((current) => [response.activity, ...current]);
      setEditingRewardId("");
      setRewardDraft(defaultNpsRewardDraft(selectedAgent.email || currentUser?.email));
      setToast?.(editingRewardId ? "PowerShare reward updated." : "PowerShare reward added.");
    } catch (error) {
      setToast?.(error.message || "Could not save PowerShare reward.");
    }
  }

  function editNpsReward(reward) {
    if (!isAdmin) return;
    setEditingRewardId(reward.id);
    setRewardDraft({
      recipientEmail: reward.recipientEmail || "",
      sourceAgentEmail: reward.sourceAgentEmail || "",
      rewardType: reward.rewardType || "Growth Credit",
      tierLevel: reward.tierLevel || 1,
      title: reward.title || "PowerShare Reward",
      amount: reward.amount || "",
      status: reward.status || "Pending",
      transactionName: reward.transactionName || "",
      earnedDate: reward.earnedDate || new Date().toISOString().slice(0, 10),
      notes: reward.notes || ""
    });
  }

  async function removeNpsReward(reward) {
    if (!isAdmin || !reward?.id) return;
    try {
      const response = await API.request(`/api/nps/rewards/${encodeURIComponent(reward.id)}`, { method: "DELETE" });
      const removedReward = response.reward;
      setRewards((current) => current.map((item) => (item.id === removedReward.id ? removedReward : item)));
      if (response.activity) setRewardActivity((current) => [response.activity, ...current]);
      if (editingRewardId === reward.id) {
        setEditingRewardId("");
        setRewardDraft(defaultNpsRewardDraft(selectedAgent.email || currentUser?.email));
      }
      setToast?.("PowerShare reward removed from active totals.");
    } catch (error) {
      setToast?.(error.message || "Could not remove PowerShare reward.");
    }
  }

  return (
    <section className="portal-page nps-page">
      <div className="module-hero nps-hero">
        <div>
          <p className="eyebrow">Nex PowerShare</p>
          <h3>Nex PowerShare (NPS)</h3>
          <p>NPS is the Nex Realty rewards program workspace for Growth Credits, Performance Credits, sponsor trees, vesting, payout review, and program reporting.</p>
        </div>
        <div className="commission-plan-card nps-hero-card">
          <span>Program status</span>
          <strong>Live Growth Preview</strong>
          <small>7-level sponsor path, vesting, eligibility, and admin setup are connected to user profiles.</small>
        </div>
      </div>

      <div className="panel nps-disclaimer">
        <Icon name="ShieldCheck" size={22} />
        <p>Nex PowerShare is a company rewards program and does not represent equity, ownership, securities, stock, or membership interest in Nex Realty.</p>
      </div>

      <div className="commission-summary-grid nps-summary-grid">
        <CommissionSummaryCard icon="Network" label="Posted Rewards" value={formatCurrency(postedSummary.total)} />
        <CommissionSummaryCard icon="BadgeCheck" label="Paid Rewards" value={formatCurrency(postedSummary.paid)} />
        <CommissionSummaryCard icon="Clock3" label="Pending / Approved" value={formatCurrency(postedSummary.pending + postedSummary.approved)} />
        <CommissionSummaryCard icon="Milestone" label="Estimated Growth Preview" value={formatCurrency(selectedSummary.gross)} />
      </div>

      <div className="panel nps-agent-summary">
        <div>
          <p className="eyebrow">{isAdmin ? "Admin setup" : "My PowerShare profile"}</p>
          <h3>{selectedAgent.name || selectedAgent.email || "Nex agent"}</h3>
          <p>{isAdmin ? "Choose an agent, assign their sponsor/upline, and preview the reward chain." : "Agents can view who sponsored them, their sponsor path, and estimated rewards. Admin manages payout setup."}</p>
          <div className="nps-network-path">
            <span><strong>Direct Sponsor</strong>{selectedDirectSponsor ? selectedDirectSponsor.name || selectedDirectSponsor.email : selectedAgent.sponsorEmail || "Not assigned yet"}</span>
            <span><strong>Direct Recruits</strong>{selectedDirectRecruits.length}</span>
            <span><strong>Upline Depth</strong>{selectedSponsorChain.length} of 7 levels</span>
            <span><strong>Status</strong>{npsEligibilityStatusText(selectedAgent)}</span>
          </div>
        </div>
        {isAdmin && (
          <Field label="Agent" value={selectedAgent.email || ""} onChange={setSelectedAgentEmail} as="select" options={allUsers.map((user) => user.email)} />
        )}
      </div>

      <div className="panel nps-sponsor-map">
        <div>
          <p className="eyebrow">Sponsor path</p>
          <h3>{selectedAgent.name || selectedAgent.email || "This agent"}'s PowerShare map</h3>
          <p>Agents can clearly see their sponsor and the people they directly invited. The reward calculator follows this path upward from each eligible closing.</p>
        </div>
        <div className="nps-sponsor-lanes">
          <div>
            <strong>Sponsored by</strong>
            <span>{selectedDirectSponsor ? selectedDirectSponsor.name || selectedDirectSponsor.email : selectedAgent.sponsorEmail || "Sponsor not assigned"}</span>
          </div>
          <div>
            <strong>Direct recruits</strong>
            {selectedDirectRecruits.length ? selectedDirectRecruits.slice(0, 5).map((recruit) => <span key={recruit.email}>{recruit.name || recruit.email}</span>) : <span>No direct recruits yet</span>}
          </div>
          <div>
            <strong>7-level upline</strong>
            {selectedSponsorChain.length ? selectedSponsorChain.map((row) => <span key={`${row.level}-${row.recipient.email}`}>L{row.level}: {row.recipient.name || row.recipient.email}</span>) : <span>No upline chain yet</span>}
          </div>
        </div>
      </div>

      <div className="nps-layout">
        <article className="panel nps-calculator-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">{isAdmin ? "Admin calculator" : "Read-only calculator"}</p>
              <h3>PowerShare Network Rewards calculator</h3>
              <p>{isAdmin ? "Select a closing agent and eligible company revenue to preview 7-level sponsor payouts." : "This view shows how the 7-tier structure works. Ask admin to update sponsor assignments or reward inputs."}</p>
            </div>
          </div>
          <div className="nps-calculator-fields">
            <Field label="Closing agent" value={visibleClosingAgentEmail || ""} onChange={(value) => updateCalculator("closingAgentEmail", value)} as="select" options={allUsers.map((user) => user.email)} disabled={!isAdmin} />
            <Field label="Eligible company revenue" value={calculator.eligibleCompanyRevenue} onChange={(value) => updateCalculator("eligibleCompanyRevenue", value)} type="number" disabled={!isAdmin} />
            <Field label="As-of / close date" value={calculator.closeDate} onChange={(value) => updateCalculator("closeDate", value)} type="date" disabled={!isAdmin} />
          </div>
          <div className="nps-vesting-strip">
            <span>Network rows: <strong>{networkRows.length || "No sponsor chain"}</strong></span>
            <span>Total gross preview: <strong>{formatCurrency(totalGross)}</strong></span>
            <span>Total vested preview: <strong>{formatCurrency(totalVested)}</strong></span>
          </div>
          <div className="nps-tier-table">
            {npsTierRates.map((tier) => {
              const row = networkRows.find((item) => item.level === tier.level);
              return (
                <div key={tier.level} className="nps-tier-row">
                  <strong>Level {tier.level}</strong>
                  <span>{tier.label} - {formatPrecisePercent(tier.rate)}</span>
                  <span>{row?.recipient ? `${row.recipient.name || row.recipient.email}${row.isEligible ? "" : ` (${npsEligibilityStatusText(row.recipient)})`}` : "No sponsor assigned"}</span>
                  <span>{row?.directDownline ? `From ${row.directDownline.name || row.directDownline.email}` : "Chain stops here"}</span>
                  <span>{row ? `${formatCurrency(row.grossReward)} gross / ${formatCurrency(row.vestedAmount)} vested` : "$0"}</span>
                </div>
              );
            })}
          </div>
        </article>

        <article className="panel nps-settings-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Program settings</p>
              <h3>NPS configuration model</h3>
            </div>
          </div>
          <div className="nps-setting-list">
            <span><strong>Eligible plans</strong>Nex Level and Nex Elite</span>
            <span><strong>Cliff period</strong>12 months</span>
            <span><strong>Full vesting</strong>36 months</span>
            <span><strong>Direct onboarding bonus</strong>$25</span>
            <span><strong>Direct first closing bonus</strong>$150</span>
            <span><strong>Website reference</strong>www.mynexrealty.com</span>
          </div>
        </article>
      </div>

      {isAdmin && profileDraft && (
        <form className="panel nps-profile-editor" onSubmit={saveNpsProfile}>
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Sponsor management</p>
              <h3>Sync PowerShare to user profiles</h3>
              <p>Sponsor assignments drive the 7-level chain. Level 1 is the closing agent's direct sponsor; each higher level is the sponsor above that person.</p>
            </div>
          </div>
          <div className="nps-calculator-fields">
            <Field label="Sponsor / upline" value={profileDraft.sponsorEmail || ""} onChange={(value) => setProfileDraft((current) => ({ ...current, sponsorEmail: value }))} as="select" options={["", ...allUsers.filter((user) => normalizeEmail(user.email) !== normalizeEmail(selectedAgent.email)).map((user) => user.email)]} />
            <Field label="NPS join date" value={profileDraft.npsJoinDate || ""} onChange={(value) => setProfileDraft((current) => ({ ...current, npsJoinDate: value }))} type="date" />
            <label className="check-field"><input type="checkbox" checked={profileDraft.npsEligible} onChange={(event) => setProfileDraft((current) => ({ ...current, npsEligible: event.target.checked }))} /> NPS eligible</label>
            <label className="check-field"><input type="checkbox" checked={profileDraft.licenseActive} onChange={(event) => setProfileDraft((current) => ({ ...current, licenseActive: event.target.checked }))} /> License active</label>
          </div>
          <button className="btn primary"><Icon name="Save" /><span>Save PowerShare Profile</span></button>
        </form>
      )}

      <div className="nps-layout secondary">
        <article className="panel nps-reward-ledger">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">{isAdmin ? "Reward ledger" : "My posted rewards"}</p>
              <h3>{isAdmin ? "Add, edit, and remove PowerShare rewards" : "PowerShare rewards posted by admin"}</h3>
              <p>{isAdmin ? "Post actual reward rows to an individual agent. Removed rewards stay in the activity trail but no longer count toward active totals." : "This is read-only for agents. Contact admin if a reward needs review."}</p>
            </div>
          </div>
          {isAdmin && (
            <form className="nps-reward-form" onSubmit={saveNpsReward}>
              <Field label="Recipient agent" value={rewardDraft.recipientEmail} onChange={(value) => setRewardDraft((current) => ({ ...current, recipientEmail: value }))} as="select" options={allUsers.map((user) => user.email)} />
              <Field label="Source / closing agent" value={rewardDraft.sourceAgentEmail} onChange={(value) => setRewardDraft((current) => ({ ...current, sourceAgentEmail: value }))} as="select" options={["", ...allUsers.map((user) => user.email)]} />
              <Field label="Reward type" value={rewardDraft.rewardType} onChange={(value) => setRewardDraft((current) => ({ ...current, rewardType: value }))} as="select" options={npsRewardTypes} />
              <Field label="Tier level" value={rewardDraft.tierLevel} onChange={(value) => setRewardDraft((current) => ({ ...current, tierLevel: value }))} as="select" options={[0, 1, 2, 3, 4, 5, 6, 7]} />
              <Field label="Reward title" value={rewardDraft.title} onChange={(value) => setRewardDraft((current) => ({ ...current, title: value }))} />
              <Field label="Amount" value={rewardDraft.amount} onChange={(value) => setRewardDraft((current) => ({ ...current, amount: value }))} type="number" />
              <Field label="Status" value={rewardDraft.status} onChange={(value) => setRewardDraft((current) => ({ ...current, status: value }))} as="select" options={npsRewardStatuses} />
              <Field label="Earned date" value={rewardDraft.earnedDate} onChange={(value) => setRewardDraft((current) => ({ ...current, earnedDate: value }))} type="date" />
              <Field label="Deal / reason" value={rewardDraft.transactionName} onChange={(value) => setRewardDraft((current) => ({ ...current, transactionName: value }))} placeholder="Closing, cap milestone, training reward..." />
              <Field label="Notes" value={rewardDraft.notes} onChange={(value) => setRewardDraft((current) => ({ ...current, notes: value }))} as="textarea" />
              <div className="nps-reward-form-actions">
                <button className="btn primary"><Icon name="Save" /><span>{editingRewardId ? "Update Reward" : "Add Reward"}</span></button>
                {editingRewardId && (
                  <button className="btn secondary" type="button" onClick={() => { setEditingRewardId(""); setRewardDraft(defaultNpsRewardDraft(selectedAgent.email || currentUser?.email)); }}>
                    <Icon name="X" />
                    <span>Cancel Edit</span>
                  </button>
                )}
              </div>
            </form>
          )}
          <div className="nps-ledger-table">
            {selectedRewards.map((reward) => (
              <article className={classNames("nps-ledger-row", reward.status === "Removed" && "removed")} key={reward.id}>
                <div>
                  <strong>{reward.title || reward.rewardType}</strong>
                  <span>{reward.rewardType}{reward.tierLevel ? ` - Level ${reward.tierLevel}` : ""}</span>
                </div>
                <div><strong>{formatCurrency(reward.amount)}</strong><span>{reward.status}</span></div>
                <div><strong>{reward.earnedDate || "No date"}</strong><span>{reward.transactionName || reward.sourceAgentName || reward.sourceAgentEmail || "Manual reward"}</span></div>
                {isAdmin && (
                  <div className="row-actions">
                    <button className="btn secondary small-btn" type="button" onClick={() => editNpsReward(reward)}><Icon name="Pencil" /><span>Edit</span></button>
                    {reward.status !== "Removed" && <button className="btn danger-soft small-btn" type="button" onClick={() => removeNpsReward(reward)}><Icon name="Trash2" /><span>Remove</span></button>}
                  </div>
                )}
              </article>
            ))}
            {!selectedRewards.length && <p className="muted">No PowerShare rewards have been posted for this agent yet.</p>}
          </div>
        </article>

        <article className="panel nps-activity-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Reward activity</p>
              <h3>Posted reward history</h3>
              <p>Shows when rewards are added, edited, paid, held, or removed.</p>
            </div>
          </div>
          <div className="nps-activity-chart">
            {npsRewardStatuses.map((status) => {
              const count = selectedRewards.filter((reward) => reward.status === status).length;
              return <span key={status} style={{ "--value": Math.max(8, count * 18) }}><strong>{count}</strong>{status}</span>;
            })}
          </div>
          <div className="nps-reward-activity-list">
            {selectedRewardActivity.slice(0, 8).map((item) => (
              <article key={item.id}>
                <strong>{item.action}</strong>
                <span>{formatCurrency(item.amount)} - {item.status} - {titleCaseDate(item.createdAt)}</span>
                <small>{item.userEmail || "System"}</small>
              </article>
            ))}
            {!selectedRewardActivity.length && <p className="muted">Reward activity will appear here after admin posts the first reward.</p>}
          </div>
        </article>
      </div>

      <div className="nps-layout secondary">
        <article className="panel nps-performance-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Performance Credits</p>
              <h3>Trackable reward types</h3>
              <p>Admins can manually track these first, then connect them to production, training, compliance, and cap events later.</p>
            </div>
          </div>
          <div className="nps-performance-grid">
            {npsPerformanceRewards.map(([label, amount]) => (
              <span key={label}><strong>{formatCurrency(amount)}</strong>{label}</span>
            ))}
          </div>
        </article>

        <article className="panel nps-workflow-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">{isAdmin ? "Admin controls" : "My NPS view"}</p>
              <h3>{isAdmin ? "Sponsor and payout workflow" : "Rewards dashboard shell"}</h3>
            </div>
          </div>
          <div className="nps-workflow-list">
            {[
              `Direct recruits: ${selectedSummary.directRecruitCount}`,
              `Sponsor chain above this agent: ${selectedSponsorChain.length || "none"}`,
              `Eligible: ${selectedAgent.npsEligible !== false ? "Yes" : "No"}`,
              `License active: ${selectedAgent.licenseActive !== false ? "Yes" : "No"}`,
              ...(isAdmin
                ? ["Admin can edit sponsor assignments and NPS eligibility here.", "Admin can post, approve, hold, pay, edit, or remove reward rows in the ledger above."]
                : ["Agents can view only. Admin controls reward setup and payout status."])
            ].map((item) => (
              <span key={item}><Icon name="CheckCircle2" size={16} />{item}</span>
            ))}
          </div>
        </article>
      </div>

      <div className="panel nps-data-model-card">
        <div>
          <p className="eyebrow">Scalable data model</p>
          <h3>Prepared entities for the full NPS build</h3>
          <p>Future backend tables can map cleanly to AgentSponsorProfile, NpsDealRewardEvent, NpsNetworkReward, NpsPerformanceReward, NpsRewardPayout, and NpsAuditLog.</p>
        </div>
        <div className="nps-model-chips">
          {["Sponsor profiles", "Deal reward events", "Network rewards", "Performance rewards", "Payout reports", "Audit logs"].map((item) => <span key={item}>{item}</span>)}
        </div>
      </div>
    </section>
  );
}

function CreateTransactionForm({ draft, setDraft, currentUser, permissions, onCreate, onCancel }) {
  function update(field, value) {
    setDraft((current) => ({ ...current, [field]: value }));
  }

  function submit(event) {
    event.preventDefault();
    onCreate(draft);
  }

  return (
    <form className="panel transaction-create-form" onSubmit={submit}>
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Create transaction</p>
          <h3>Start a Nex transaction file</h3>
          <p>Choose Buyer purchase or Seller listing to generate the matching contract tracker, deadline timeline, and checklist workflow.</p>
        </div>
        <button className="btn secondary" type="button" onClick={onCancel}>Cancel</button>
      </div>
      <div className="transaction-form-grid">
        <Field label="Transaction name" value={draft.title} onChange={(value) => update("title", value)} placeholder="Smith purchase - 123 Main St" />
        <Field label="Transaction type" value={draft.type} onChange={(value) => update("type", value)} as="select" options={transactionTypes} />
        <Field label="Status" value={draft.status || "Draft"} onChange={(value) => update("status", value)} as="select" options={transactionStatuses} />
        <Field label="Property address" value={draft.propertyAddress} onChange={(value) => update("propertyAddress", value)} />
        <Field label="City" value={draft.city} onChange={(value) => update("city", value)} />
        <Field label="County" value={draft.county} onChange={(value) => update("county", value)} />
        <Field label="ZIP" value={draft.zip} onChange={(value) => update("zip", value)} />
        <Field label="MLS number" value={draft.mlsNumber} onChange={(value) => update("mlsNumber", value)} />
        <Field label="Client name" value={draft.clientName} onChange={(value) => update("clientName", value)} />
        <Field label="Client email" value={draft.clientEmail} onChange={(value) => update("clientEmail", value)} type="email" />
        <Field label="Client phone" value={draft.clientPhone} onChange={(value) => update("clientPhone", value)} />
        <Field label="Other party name" value={draft.otherPartyName} onChange={(value) => update("otherPartyName", value)} />
        <Field label="Other brokerage" value={draft.otherBrokerage} onChange={(value) => update("otherBrokerage", value)} />
        <Field label="Title company" value={draft.titleCompany} onChange={(value) => update("titleCompany", value)} />
        <Field label="Lender" value={draft.lender} onChange={(value) => update("lender", value)} />
        <Field label="Contract price / sales price" value={draft.purchasePrice} onChange={(value) => update("purchasePrice", value)} type="number" />
        <Field label="Lease amount" value={draft.leaseAmount} onChange={(value) => update("leaseAmount", value)} type="number" />
        <Field label="Commission" value={draft.commission} onChange={(value) => update("commission", value)} placeholder="3% or $3,000" />
        {permissions.canViewAll && <Field label="Assigned agent email" value={draft.assignedAgentEmail || currentUser.email} onChange={(value) => update("assignedAgentEmail", value)} type="email" />}
        <Field label="Effective date" value={draft.effectiveDate} onChange={(value) => update("effectiveDate", value)} type="date" />
        <Field label="EMD deadline" value={draft.emdDeadline} onChange={(value) => update("emdDeadline", value)} type="date" />
        <Field label="Inspection deadline" value={draft.inspectionDeadline} onChange={(value) => update("inspectionDeadline", value)} type="date" />
        <Field label="Financing deadline" value={draft.financingDeadline} onChange={(value) => update("financingDeadline", value)} type="date" />
        <Field label="Appraisal deadline" value={draft.appraisalDeadline} onChange={(value) => update("appraisalDeadline", value)} type="date" />
        <Field label="HOA / condo deadline" value={draft.hoaDeadline} onChange={(value) => update("hoaDeadline", value)} type="date" />
        <Field label="Final walkthrough date" value={draft.finalWalkthroughDate} onChange={(value) => update("finalWalkthroughDate", value)} type="date" />
        <Field label="Closing date" value={draft.closingDate} onChange={(value) => update("closingDate", value)} type="date" />
        <Field label="Notes" value={draft.notes} onChange={(value) => update("notes", value)} as="textarea" />
      </div>
      <button className="btn primary" type="submit">
        <Icon name="FolderPlus" />
        <span>Create Transaction</span>
      </button>
    </form>
  );
}

function NexTransactions({ currentUser, role, setToast }) {
  const [loading, setLoading] = useState(true);
  const [transactions, setTransactions] = useState([]);
  const [activity, setActivity] = useState([]);
  const [permissions, setPermissions] = useState({ canViewAll: isAdminRole(role), canReview: isAdminRole(role), canDeleteDocuments: isAdminRole(role), role });
  const [formTemplates, setFormTemplates] = useState([]);
  const [documentCategories, setDocumentCategories] = useState(transactionDocumentCategories);
  const [selectedId, setSelectedId] = useState("");
  const [detail, setDetail] = useState(null);
  const [activeTab, setActiveTab] = useState("Overview");
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState("All");
  const [showCreate, setShowCreate] = useState(false);
  const [draft, setDraft] = useState(() => ({ ...transactionCreateDefaults, assignedAgentEmail: currentUser?.email || "", assignedAgentName: currentUser?.name || "" }));
  const [contactDraft, setContactDraft] = useState({ role: "Title Company", name: "", email: "", phone: "", company: "", notes: "" });
  const [deadlineDraft, setDeadlineDraft] = useState({ label: "", date: "", notes: "" });
  const [checklistDraft, setChecklistDraft] = useState({ label: "", category: "Custom", dueDate: "", required: true });
  const [documentDraft, setDocumentDraft] = useState({ category: "Other", required: true, file: null });
  const [noteDraft, setNoteDraft] = useState("");
  const [reviewNotes, setReviewNotes] = useState("");
  const [signatureDraft, setSignatureDraft] = useState({ signers: "", documentIds: [] });
  const [commissionDraft, setCommissionDraft] = useState({});

  useEffect(() => {
    refreshTransactions();
  }, []);

  useEffect(() => {
    setCommissionDraft(detail?.commission || {});
    setReviewNotes(detail?.complianceReview?.reviewNotes || "");
  }, [detail?.transaction?.id]);

  async function refreshTransactions() {
    setLoading(true);
    try {
      const payload = await API.request("/api/transactions/bootstrap");
      setTransactions(payload.transactions || []);
      setActivity(payload.activity || []);
      setFormTemplates(payload.formTemplates || []);
      setDocumentCategories(payload.documentCategories || transactionDocumentCategories);
      setPermissions(payload.permissions || { canViewAll: isAdminRole(role), canReview: isAdminRole(role), canDeleteDocuments: isAdminRole(role), role });
    } catch (error) {
      setToast(error.message || "Could not load Transactions.");
    } finally {
      setLoading(false);
    }
  }

  function applyDetailPayload(payload) {
    setDetail(payload);
    setSelectedId(payload.transaction?.id || "");
    setTransactions((current) => {
      const next = current.filter((transaction) => transaction.id !== payload.transaction.id);
      return [payload.transaction, ...next].sort((a, b) => new Date(b.updatedAt || b.createdAt || 0) - new Date(a.updatedAt || a.createdAt || 0));
    });
  }

  async function openTransaction(transactionId) {
    try {
      const payload = await API.request(`/api/transactions/${encodeURIComponent(transactionId)}`);
      applyDetailPayload(payload);
      setActiveTab("Overview");
    } catch (error) {
      setToast(error.message || "Could not open transaction.");
    }
  }

  async function createTransaction(payload) {
    try {
      const saved = await API.request("/api/transactions", { method: "POST", body: JSON.stringify(payload) });
      applyDetailPayload(saved);
      setShowCreate(false);
      setDraft({ ...transactionCreateDefaults, assignedAgentEmail: currentUser?.email || "", assignedAgentName: currentUser?.name || "" });
      setToast("Transaction created.");
      refreshTransactions();
    } catch (error) {
      setToast(error.message || "Could not create transaction.");
    }
  }

  async function updateTransaction(patch) {
    if (!detail?.transaction?.id) return;
    try {
      const saved = await API.request(`/api/transactions/${encodeURIComponent(detail.transaction.id)}`, { method: "PUT", body: JSON.stringify(patch) });
      applyDetailPayload(saved);
      setToast("Transaction updated.");
    } catch (error) {
      setToast(error.message || "Could not update transaction.");
    }
  }

  async function postDetail(path, body, method = "POST") {
    if (!detail?.transaction?.id) return null;
    try {
      const saved = await API.request(path, { method, body: JSON.stringify(body) });
      applyDetailPayload(saved);
      return saved;
    } catch (error) {
      setToast(error.message || "Could not save transaction update.");
      return null;
    }
  }

  async function addContact(event) {
    event.preventDefault();
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/contacts`, contactDraft);
    if (saved) {
      setContactDraft({ role: "Title Company", name: "", email: "", phone: "", company: "", notes: "" });
      setToast("Contact added.");
    }
  }

  async function addDeadline(event) {
    event.preventDefault();
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/deadlines`, deadlineDraft);
    if (saved) {
      setDeadlineDraft({ label: "", date: "", notes: "" });
      setToast("Deadline added.");
    }
  }

  async function updateDeadline(deadlineId, patch) {
    const saved = await postDetail(`/api/transaction-deadlines/${encodeURIComponent(deadlineId)}`, patch, "PUT");
    if (saved) setToast("Deadline updated.");
  }

  function toggleWorkflowItem(item, completed) {
    if (item.type === "checklist") {
      updateChecklistItem(item.sourceId || item.id, { completed });
      return;
    }
    if (item.type === "deadline") {
      updateDeadline(item.sourceId || item.id, { completed });
    }
  }

  async function addChecklistItem(event) {
    event.preventDefault();
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/checklist`, checklistDraft);
    if (saved) {
      setChecklistDraft({ label: "", category: "Custom", dueDate: "", required: true });
      setToast("Checklist item added.");
    }
  }

  async function updateChecklistItem(itemId, patch) {
    const saved = await postDetail(`/api/transaction-checklist/${encodeURIComponent(itemId)}`, patch, "PUT");
    if (saved) setToast(patch.completed ? "Checklist item completed." : "Checklist item updated.");
  }

  async function deleteChecklistItem(itemId) {
    const saved = await postDetail(`/api/transaction-checklist/${encodeURIComponent(itemId)}`, {}, "DELETE");
    if (saved) setToast("Checklist item deleted.");
  }

  async function onDocumentFileChange(event) {
    const file = event.target.files?.[0];
    if (!file) return;
    const converted = await fileToDataUrl(file);
    setDocumentDraft((current) => ({ ...current, file: converted }));
  }

  async function uploadDocument(event) {
    event.preventDefault();
    if (!documentDraft.file) {
      setToast("Choose a document first.");
      return;
    }
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/documents`, {
      ...documentDraft.file,
      fileName: documentDraft.file.name,
      category: documentDraft.category,
      required: documentDraft.required
    });
    if (saved) {
      setDocumentDraft({ category: "Other", required: true, file: null });
      setToast("Document uploaded.");
    }
  }

  async function updateDocument(documentId, patch) {
    const saved = await postDetail(`/api/transaction-documents/${encodeURIComponent(documentId)}`, patch, "PUT");
    if (saved) setToast("Document updated.");
  }

  async function deleteDocument(documentId) {
    const saved = await postDetail(`/api/transaction-documents/${encodeURIComponent(documentId)}`, {}, "DELETE");
    if (saved) setToast("Document deleted.");
  }

  function transactionDocumentLink(document, { download = false } = {}) {
    const source = document?.fileUrl || document?.dataUrl || "";
    if (!source || !download) return source;
    if (source.startsWith("/api/") || source.startsWith(window.location.origin)) {
      return `${source}${source.includes("?") ? "&" : "?"}download=1`;
    }
    return source;
  }

  function openTransactionDocument(document) {
    const url = transactionDocumentLink(document);
    if (!url) {
      setToast("This document does not have a file link yet.");
      return;
    }
    const opened = window.open(url, "_blank", "noopener,noreferrer");
    if (!opened) window.location.href = url;
  }

  function saveTransactionDocument(document) {
    const url = transactionDocumentLink(document, { download: true });
    if (!url) {
      setToast("This document does not have a downloadable file yet.");
      return;
    }
    const anchor = window.document.createElement("a");
    anchor.href = url;
    anchor.target = "_blank";
    anchor.rel = "noopener noreferrer";
    anchor.download = document.fileName || "nex-transaction-document";
    window.document.body.appendChild(anchor);
    anchor.click();
    anchor.remove();
    setToast("Document opened. On mobile, use Share or Save to Files if prompted.");
  }

  async function generateForm(templateId) {
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/forms`, { templateId });
    if (saved) setToast("Mock form draft generated.");
  }

  function downloadMockForm(form) {
    const lines = Object.entries(form.content || {}).map(([key, value]) => `${key}: ${value || ""}`).join("\n");
    downloadBlob(new Blob([lines], { type: "text/plain" }), `${form.formName || "nex-mock-form"}.txt`.toLowerCase().replace(/[^a-z0-9.]+/g, "-"));
  }

  async function createEnvelope(event) {
    event.preventDefault();
    const signers = signatureDraft.signers
      .split("\n")
      .map((line) => {
        const [name, email] = line.split(",").map((part) => part.trim());
        return { name, email };
      })
      .filter((signer) => signer.name || signer.email);
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/signature`, { signers, documentIds: signatureDraft.documentIds });
    if (saved) {
      setSignatureDraft({ signers: "", documentIds: [] });
      setToast("E-signature placeholder created.");
    }
  }

  async function updateReview(status) {
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/review`, { status, reviewNotes });
    if (saved) setToast(`Compliance marked ${status}.`);
  }

  async function saveCommission(event) {
    event.preventDefault();
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/commission`, commissionDraft, "PUT");
    if (saved) setToast("Commission saved.");
  }

  async function addNote(event) {
    event.preventDefault();
    if (!noteDraft.trim()) return;
    const saved = await postDetail(`/api/transactions/${encodeURIComponent(detail.transaction.id)}/notes`, { note: noteDraft });
    if (saved) {
      setNoteDraft("");
      setToast("Note added.");
    }
  }

  const filteredTransactions = transactions.filter((transaction) => {
    const haystack = [transaction.title, transaction.propertyAddress, transaction.clientName, transaction.assignedAgentName, transaction.assignedAgentEmail, transaction.type, transaction.status].join(" ").toLowerCase();
    const matchesSearch = !search || haystack.includes(search.toLowerCase());
    const matchesStatus = statusFilter === "All" || transaction.status === statusFilter || transaction.complianceStatus === statusFilter;
    return matchesSearch && matchesStatus;
  });
  const metrics = transactionMetricSet(transactions);
  const selectedTransaction = detail?.transaction;
  const checklistGroups = groupTransactionChecklistItems(detail?.checklistItems || []);
  const workflowItems = detail?.workflowTimeline || [];
  const documentRequirements = detail?.documentRequirements || [];
  const nextWorkflowItem = workflowItems.find((item) => item.checkable && !item.completed) || workflowItems.find((item) => item.type === "document" && !item.completed);
  const workflowCompletedCount = workflowItems.filter((item) => item.completed).length;
  const workflowTotalCount = workflowItems.length;

  return (
    <section className="portal-page transactions-module">
      <div className="module-hero transaction-hero">
        <div>
          <p className="eyebrow">Nex Transactions</p>
          <h3>Transactions & Contract Tracker</h3>
          <p>Create buyer and seller deal files, generate the right contract checklist, track deadlines, organize documents, and prepare compliance review from one place.</p>
          <div className="hero-actions">
            <button className="btn light" onClick={() => { setShowCreate(true); setDetail(null); }}>
              <Icon name="FolderPlus" />
              <span>Create Buyer/Seller Transaction</span>
            </button>
            <button className="btn light" onClick={refreshTransactions}>
              <Icon name="RefreshCcw" />
              <span>Refresh</span>
            </button>
          </div>
        </div>
      </div>

      <ComplianceNotice text={transactionFoundationDisclaimer} />

      {loading ? (
        <EmptyState icon="LoaderCircle" title="Loading Transactions" body="Preparing transaction files, deadlines, documents, and compliance status." />
      ) : showCreate ? (
        <CreateTransactionForm draft={draft} setDraft={setDraft} currentUser={currentUser} permissions={permissions} onCreate={createTransaction} onCancel={() => setShowCreate(false)} />
      ) : selectedTransaction ? (
        <div className="transaction-detail-page">
          <div className="transaction-detail-header">
            <button className="btn secondary" onClick={() => { setDetail(null); setSelectedId(""); }}>
              <Icon name="ArrowLeft" />
              <span>Back to Transactions</span>
            </button>
            <div>
              <p className="eyebrow">{selectedTransaction.type}</p>
              <h3>{selectedTransaction.title}</h3>
              <span>{selectedTransaction.propertyAddress || "No property address"} - {selectedTransaction.clientName || "No client entered"}</span>
            </div>
            <div className="transaction-detail-actions">
              <span className={classNames("status-badge", transactionTone(selectedTransaction.status))}>{selectedTransaction.status}</span>
              <button className="btn secondary" onClick={() => updateTransaction({ status: "Closed" })}>Mark Closed</button>
              <button className="btn secondary" onClick={() => updateTransaction({ status: "Cancelled" })}>Cancel</button>
            </div>
          </div>

          <div className="crm-tabs transaction-tabs">
            {transactionTabs.map((tab) => (
              <button key={tab} className={classNames(activeTab === tab && "active")} onClick={() => setActiveTab(tab)}>{tab}</button>
            ))}
          </div>

          {activeTab === "Overview" && (
            <div className="transaction-detail-grid">
              <div className="panel transaction-overview-panel">
                <div className="panel-heading">
                  <div>
                    <p className="eyebrow">Overview</p>
                    <h3>File summary</h3>
                  </div>
                </div>
                <div className="transaction-summary-grid">
                  {[
                    ["Client", selectedTransaction.clientName],
                    ["Client email", selectedTransaction.clientEmail],
                    ["Client phone", selectedTransaction.clientPhone],
                    ["MLS", selectedTransaction.mlsNumber],
                    ["Price / lease", selectedTransaction.purchasePrice ? formatCurrency(selectedTransaction.purchasePrice) : formatCurrency(selectedTransaction.leaseAmount)],
                    ["Closing", formatDate(selectedTransaction.closingDate)],
                    ["EMD", formatDate(selectedTransaction.emdDeadline)],
                    ["Inspection", formatDate(selectedTransaction.inspectionDeadline)],
                    ["Financing", formatDate(selectedTransaction.financingDeadline)],
                    ["Final walkthrough", formatDate(selectedTransaction.finalWalkthroughDate)],
                    ["Title", selectedTransaction.titleCompany],
                    ["Lender", selectedTransaction.lender],
                    ["Compliance", selectedTransaction.complianceStatus]
                  ].map(([label, value]) => (
                    <span key={label}><strong>{label}</strong>{value || "Not set"}</span>
                  ))}
                </div>
                <div className="transaction-progress-strip">
                  <span>Checklist progress</span>
                  <div className="progress-track"><div style={{ width: `${selectedTransaction.completionPercent || 0}%` }} /></div>
                  <strong>{selectedTransaction.checklistCompleted || 0}/{selectedTransaction.checklistTotal || 0}</strong>
                </div>
              </div>
              <div className="panel">
                <div className="panel-heading">
                  <div>
                    <p className="eyebrow">Next deadline</p>
                    <h3>{nextWorkflowItem?.title || selectedTransaction.nextDeadline?.label || "No upcoming deadline"}</h3>
                  </div>
                  {nextWorkflowItem ? <span className={classNames("deadline-badge", `tone-${workflowTone(nextWorkflowItem)}`)}>{workflowStatusText(nextWorkflowItem)}</span> : selectedTransaction.nextDeadline && <span className={classNames("deadline-badge", `tone-${deadlineTone(selectedTransaction.nextDeadline)}`)}>{deadlineTone(selectedTransaction.nextDeadline)}</span>}
                </div>
                <p>{nextWorkflowItem ? `${formatDate(nextWorkflowItem.dueDate)} - ${nextWorkflowItem.category}. Work this next to keep the file moving cleanly toward closing.` : selectedTransaction.nextDeadline ? `${formatDate(selectedTransaction.nextDeadline.date)} - ${selectedTransaction.nextDeadline.notes || "Review and complete this item on time."}` : "Add key dates in Dates & Deadlines to turn on deadline tracking."}</p>
                <button className="btn secondary" onClick={() => setActiveTab("Workflow")}>Open Workflow</button>
              </div>
              <div className="panel transaction-workflow-preview">
                <div className="panel-heading">
                  <div>
                    <p className="eyebrow">Chronological file flow</p>
                    <h3>Open file to close file</h3>
                  </div>
                  <strong>{workflowCompletedCount}/{workflowTotalCount || 0}</strong>
                </div>
                <TransactionWorkflowTimeline items={workflowItems} onToggleItem={toggleWorkflowItem} compact onOpenDocuments={() => setActiveTab("Documents")} />
              </div>
            </div>
          )}

          {activeTab === "Workflow" && (
            <div className="transaction-workflow-page">
              <div className="panel">
                <div className="panel-heading">
                  <div>
                    <p className="eyebrow">File workflow</p>
                    <h3>Chronological transaction checklist</h3>
                    <p>Dates, checklist items, and required document status are synced from the transaction file so agents can work the deal from file open to close.</p>
                  </div>
                  <div className="transaction-progress-chip">
                    <strong>{workflowCompletedCount}/{workflowTotalCount || 0}</strong>
                    <span>Complete</span>
                  </div>
                </div>
                <TransactionWorkflowTimeline items={workflowItems} onToggleItem={toggleWorkflowItem} onOpenDocuments={() => setActiveTab("Documents")} />
              </div>
            </div>
          )}

          {activeTab === "Contacts" && (
            <div className="transaction-two-column">
              <form className="panel" onSubmit={addContact}>
                <div className="panel-heading"><div><p className="eyebrow">Contacts</p><h3>Add file contact</h3></div></div>
                <Field label="Role" value={contactDraft.role} onChange={(value) => setContactDraft((current) => ({ ...current, role: value }))} />
                <Field label="Name" value={contactDraft.name} onChange={(value) => setContactDraft((current) => ({ ...current, name: value }))} />
                <Field label="Email" value={contactDraft.email} onChange={(value) => setContactDraft((current) => ({ ...current, email: value }))} type="email" />
                <Field label="Phone" value={contactDraft.phone} onChange={(value) => setContactDraft((current) => ({ ...current, phone: value }))} />
                <Field label="Company" value={contactDraft.company} onChange={(value) => setContactDraft((current) => ({ ...current, company: value }))} />
                <Field label="Notes" value={contactDraft.notes} onChange={(value) => setContactDraft((current) => ({ ...current, notes: value }))} as="textarea" />
                <button className="btn primary"><Icon name="UserPlus" /><span>Add Contact</span></button>
              </form>
              <div className="transaction-list-stack">
                {(detail.contacts || []).map((contact) => (
                  <article className="transaction-row-card" key={contact.id}>
                    <strong>{contact.role}: {contact.name || contact.company || "Contact"}</strong>
                    <span>{[contact.email, contact.phone, contact.company].filter(Boolean).join(" - ") || "No contact details"}</span>
                    {contact.notes && <p>{contact.notes}</p>}
                  </article>
                ))}
                {!detail.contacts?.length && <EmptyState icon="Contact" title="No contacts yet" body="Add title, lender, client, and cooperating agent contacts here." />}
              </div>
            </div>
          )}

          {activeTab === "Dates & Deadlines" && (
            <div className="transaction-two-column">
              <form className="panel" onSubmit={addDeadline}>
                <div className="panel-heading"><div><p className="eyebrow">Deadlines</p><h3>Add custom deadline</h3></div></div>
                <Field label="Deadline label" value={deadlineDraft.label} onChange={(value) => setDeadlineDraft((current) => ({ ...current, label: value }))} />
                <Field label="Date" value={deadlineDraft.date} onChange={(value) => setDeadlineDraft((current) => ({ ...current, date: value }))} type="date" />
                <Field label="Notes" value={deadlineDraft.notes} onChange={(value) => setDeadlineDraft((current) => ({ ...current, notes: value }))} as="textarea" />
                <button className="btn primary"><Icon name="CalendarPlus" /><span>Add Deadline</span></button>
              </form>
              <div className="transaction-list-stack">
                {(detail.deadlines || []).map((deadline) => (
                  <article className="transaction-row-card deadline-row" key={deadline.id}>
                    <label className="check-field">
                      <input type="checkbox" checked={Boolean(deadline.completed)} onChange={(event) => updateDeadline(deadline.id, { completed: event.target.checked })} />
                      <span>
                        <strong>{deadline.label}</strong>
                        <small>{deadline.phase || (deadline.isSystem ? "Synced transaction date" : "Custom deadline")}</small>
                      </span>
                    </label>
                    <span>{formatDate(deadline.date)}</span>
                    <span className={classNames("deadline-badge", `tone-${deadlineTone(deadline)}`)}>{deadlineTone(deadline)}</span>
                    <Field label="Edit date" value={deadline.date || ""} onChange={(value) => updateDeadline(deadline.id, { date: value })} type="date" />
                    {deadline.notes && <p>{deadline.notes}</p>}
                  </article>
                ))}
              </div>
            </div>
          )}

          {activeTab === "Checklist" && (
            <div className="transaction-two-column wide-left">
              <div className="transaction-checklist-stack">
                {checklistGroups.map((group, groupIndex) => (
                  <details className="transaction-checklist-section" key={group.category} open={groupIndex < 2}>
                    <summary>
                      <div>
                        <strong>{group.category}</strong>
                        <span>{group.completed}/{group.total} complete</span>
                      </div>
                      <div className="progress-track"><div style={{ width: `${Math.round((group.completed / Math.max(1, group.total)) * 100)}%` }} /></div>
                    </summary>
                    <div className="transaction-checklist-section-items">
                      {group.items.map((item) => (
                        <article className={classNames("transaction-checklist-row", item.completed && "completed")} key={item.id}>
                          <label className="check-field">
                            <input type="checkbox" checked={Boolean(item.completed)} onChange={(event) => updateChecklistItem(item.id, { completed: event.target.checked })} />
                            <span>
                              <strong>{item.label}</strong>
                              <small>{item.dueDate ? `Due ${formatDate(item.dueDate)}` : "No due date assigned"}{item.dateSourceLabel ? ` - synced from ${item.dateSourceLabel}` : ""}</small>
                            </span>
                          </label>
                          <div className="row-actions">
                            <Field label="Due date" value={item.dueDate || ""} onChange={(value) => updateChecklistItem(item.id, { dueDate: value })} type="date" />
                            {(item.isCustom || permissions.canReview) && <button className="icon-btn small" onClick={() => deleteChecklistItem(item.id)} title="Delete checklist item"><Icon name="Trash2" size={15} /></button>}
                          </div>
                        </article>
                      ))}
                    </div>
                  </details>
                ))}
                {!checklistGroups.length && <EmptyState icon="ClipboardCheck" title="No checklist items yet" body="Create a buyer or seller transaction to generate a contract tracker checklist." />}
              </div>
              <form className="panel" onSubmit={addChecklistItem}>
                <div className="panel-heading"><div><p className="eyebrow">Checklist</p><h3>Add custom item</h3></div></div>
                <Field label="Item" value={checklistDraft.label} onChange={(value) => setChecklistDraft((current) => ({ ...current, label: value }))} />
                <Field label="Category" value={checklistDraft.category} onChange={(value) => setChecklistDraft((current) => ({ ...current, category: value }))} />
                <Field label="Due date" value={checklistDraft.dueDate} onChange={(value) => setChecklistDraft((current) => ({ ...current, dueDate: value }))} type="date" />
                <label className="check-field"><input type="checkbox" checked={checklistDraft.required} onChange={(event) => setChecklistDraft((current) => ({ ...current, required: event.target.checked }))} /> Required item</label>
                <button className="btn primary"><Icon name="Plus" /><span>Add Item</span></button>
              </form>
            </div>
          )}

          {activeTab === "Documents" && (
            <div className="transaction-two-column">
              <form className="panel" onSubmit={uploadDocument}>
                <div className="panel-heading"><div><p className="eyebrow">Documents</p><h3>Upload file</h3></div></div>
                <Field label="Category" value={documentDraft.category} onChange={(value) => setDocumentDraft((current) => ({ ...current, category: value }))} as="select" options={documentCategories} />
                <label className="document-file-picker">
                  <Icon name="UploadCloud" />
                  <strong>{documentDraft.file?.name || "Choose PDF, image, Word, Excel, or CSV"}</strong>
                  <input type="file" accept=".jpg,.jpeg,.png,.gif,.webp,.pdf,.doc,.docx,.xls,.xlsx,.csv" onChange={onDocumentFileChange} />
                </label>
                <label className="check-field"><input type="checkbox" checked={documentDraft.required} onChange={(event) => setDocumentDraft((current) => ({ ...current, required: event.target.checked }))} /> Required document</label>
                <button className="btn primary"><Icon name="UploadCloud" /><span>Upload Document</span></button>
              </form>
              <div className="transaction-list-stack">
                <div className="panel transaction-document-requirements">
                  <div className="panel-heading">
                    <div>
                      <p className="eyebrow">Required documents</p>
                      <h3>Synced to file dates</h3>
                    </div>
                  </div>
                  <div className="document-requirement-list">
                    {documentRequirements.map((requirement) => (
                      <article key={requirement.id} className={classNames(requirement.status === "Approved" && "complete")}>
                        <div>
                          <strong>{requirement.label}</strong>
                          <span>{requirement.category} {requirement.dueDate ? `- due ${formatDate(requirement.dueDate)}` : "- no date set"}</span>
                          {requirement.fileName && <small>{requirement.fileName}</small>}
                        </div>
                        <span className={classNames("deadline-badge", requirement.status === "Approved" ? "tone-complete" : requirement.status === "Missing" ? "tone-overdue" : "tone-upcoming")}>{requirement.status}</span>
                      </article>
                    ))}
                  </div>
                </div>
                {(detail.documents || []).map((document) => (
                  <article className="transaction-row-card document-row" key={document.id}>
                    <div>
                      <strong>{document.fileName}</strong>
                      <span>{document.category} - {document.status} {document.required ? "- Required" : "- Optional"}</span>
                      {document.reviewNotes && <p>{document.reviewNotes}</p>}
                    </div>
                    <div className="row-actions">
                      {(document.fileUrl || document.dataUrl) && (
                        <>
                          <button className="btn secondary small-btn" type="button" onClick={() => openTransactionDocument(document)}>Open</button>
                          <button className="btn secondary small-btn" type="button" onClick={() => saveTransactionDocument(document)}>Save</button>
                        </>
                      )}
                      {permissions.canReview && (
                        <>
                          <button className="btn secondary small-btn" onClick={() => updateDocument(document.id, { status: "Approved" })}>Approve</button>
                          <button className="btn secondary small-btn" onClick={() => updateDocument(document.id, { status: "Rejected", reviewNotes: "Please correct and re-upload." })}>Reject</button>
                        </>
                      )}
                      <button className="icon-btn small" onClick={() => deleteDocument(document.id)} title="Delete document"><Icon name="Trash2" size={15} /></button>
                    </div>
                  </article>
                ))}
                {!detail.documents?.length && <EmptyState icon="FileText" title="No documents uploaded" body="Upload contracts, disclosures, commission documents, EMD receipts, title/lender files, and closing documents here." />}
              </div>
            </div>
          )}

          {activeTab === "Forms" && (
            <div className="transaction-two-column">
              <div className="panel">
                <div className="panel-heading"><div><p className="eyebrow">Mock forms</p><h3>Internal templates only</h3></div></div>
                <ComplianceNotice text="These are internal Nex Central mock templates for development and workflow purposes only. Official real estate forms must be accessed through approved/licensed forms providers." />
                <div className="transaction-template-grid">
                  {formTemplates.map((template) => (
                    <article className="transaction-template-card" key={template.id}>
                      <strong>{template.name}</strong>
                      <span>{template.category} - {template.provider}</span>
                      <small>{Object.keys(template.fieldMapping || {}).length} mapped fields</small>
                      <button className="btn secondary small-btn" onClick={() => generateForm(template.id)}>Generate Draft</button>
                    </article>
                  ))}
                </div>
              </div>
              <div className="transaction-list-stack">
                {(detail.generatedForms || []).map((form) => (
                  <article className="transaction-row-card" key={form.id}>
                    <strong>{form.formName}</strong>
                    <span>{form.status} - {formatDate((form.createdAt || "").slice(0, 10))}</span>
                    <pre>{Object.entries(form.content || {}).slice(0, 8).map(([key, value]) => `${key}: ${value || ""}`).join("\n")}</pre>
                    <button className="btn secondary small-btn" onClick={() => downloadMockForm(form)}>Download Draft Text</button>
                  </article>
                ))}
              </div>
            </div>
          )}

          {activeTab === "E-Signature" && (
            <div className="transaction-two-column">
              <form className="panel" onSubmit={createEnvelope}>
                <div className="panel-heading"><div><p className="eyebrow">DocuSign foundation</p><h3>Create placeholder envelope</h3></div></div>
                <p className="muted">Real e-signature requires DocuSign credentials and OAuth. This creates a tracked placeholder now.</p>
                <Field label="Signers, one per line: Name, email" value={signatureDraft.signers} onChange={(value) => setSignatureDraft((current) => ({ ...current, signers: value }))} as="textarea" />
                <div className="transaction-document-picker">
                  {(detail.documents || []).map((document) => (
                    <label className="check-field" key={document.id}>
                      <input
                        type="checkbox"
                        checked={signatureDraft.documentIds.includes(document.id)}
                        onChange={(event) => setSignatureDraft((current) => ({
                          ...current,
                          documentIds: event.target.checked ? [...current.documentIds, document.id] : current.documentIds.filter((id) => id !== document.id)
                        }))}
                      />
                      {document.fileName}
                    </label>
                  ))}
                </div>
                <button className="btn primary"><Icon name="PenLine" /><span>Create Envelope Draft</span></button>
              </form>
              <div className="transaction-list-stack">
                {(detail.signatureEnvelopes || []).map((envelope) => (
                  <article className="transaction-row-card" key={envelope.id}>
                    <strong>{envelope.provider}</strong>
                    <span>{envelope.status} - {envelope.signerData?.length || 0} signer(s)</span>
                    <p>{envelope.integrationNote}</p>
                  </article>
                ))}
              </div>
            </div>
          )}

          {activeTab === "Compliance Review" && (
            <div className="transaction-two-column">
              <div className="panel">
                <div className="panel-heading"><div><p className="eyebrow">Compliance</p><h3>{detail.complianceReview?.status || "Draft"}</h3></div></div>
                <Field label="Review / correction notes" value={reviewNotes} onChange={setReviewNotes} as="textarea" />
                <div className="row-actions">
                  <button className="btn primary" onClick={() => updateReview("Submitted for Review")}><Icon name="Send" /><span>Submit for Review</span></button>
                  {permissions.canReview && (
                    <>
                      <button className="btn secondary" onClick={() => updateReview("Needs Corrections")}>Needs Corrections</button>
                      <button className="btn secondary" onClick={() => updateReview("Approved")}>Approve</button>
                      <button className="btn secondary" onClick={() => updateReview("Closed")}>Mark Closed</button>
                    </>
                  )}
                </div>
              </div>
              <div className="panel">
                <p className="eyebrow">Missing item count</p>
                <h3>{selectedTransaction.missingItemsCount || 0}</h3>
                <p>Missing count combines required checklist items and required documents that are not approved.</p>
              </div>
            </div>
          )}

          {activeTab === "Commission" && (
            <form className="panel transaction-commission-form" onSubmit={saveCommission}>
              <div className="panel-heading"><div><p className="eyebrow">Commission</p><h3>DA and net estimate</h3></div></div>
              <div className="transaction-form-grid compact">
                {[
                  ["grossCommission", "Gross commission"],
                  ["brokerageFee", "Brokerage fee"],
                  ["transactionFee", "Transaction fee"],
                  ["referralFee", "Referral fee"],
                  ["brokerReviewFee", "Broker review fee"],
                  ["rentalFee", "Rental fee"],
                  ["agentNet", "Estimated agent net"]
                ].map(([field, label]) => (
                  <Field key={field} label={label} value={commissionDraft[field] || 0} onChange={(value) => setCommissionDraft((current) => ({ ...current, [field]: value }))} type="number" />
                ))}
                <Field label="Agent split" value={commissionDraft.agentSplit || ""} onChange={(value) => setCommissionDraft((current) => ({ ...current, agentSplit: value }))} />
                <Field label="DA status" value={commissionDraft.daStatus || "Not Requested"} onChange={(value) => setCommissionDraft((current) => ({ ...current, daStatus: value }))} as="select" options={["Not Requested", "Requested", "Uploaded", "Sent", "Complete"]} />
                <Field label="Payment status" value={commissionDraft.paymentStatus || "Unpaid"} onChange={(value) => setCommissionDraft((current) => ({ ...current, paymentStatus: value }))} as="select" options={["Unpaid", "Pending", "Paid"]} />
                <Field label="Closing company" value={commissionDraft.closingCompany || ""} onChange={(value) => setCommissionDraft((current) => ({ ...current, closingCompany: value }))} />
                <Field label="Notes" value={commissionDraft.notes || ""} onChange={(value) => setCommissionDraft((current) => ({ ...current, notes: value }))} as="textarea" />
              </div>
              <button className="btn primary"><Icon name="Save" /><span>Save Commission</span></button>
            </form>
          )}

          {activeTab === "Activity / History" && (
            <div className="transaction-list-stack">
              {(detail.activity || []).map((item) => (
                <article className="transaction-row-card activity-row" key={item.id}>
                  <strong>{item.action}</strong>
                  <span>{item.userName || item.userEmail || "System"} - {new Date(item.createdAt).toLocaleString()}</span>
                  <p>{item.details}</p>
                </article>
              ))}
            </div>
          )}

          {activeTab === "Notes" && (
            <div className="transaction-two-column">
              <form className="panel" onSubmit={addNote}>
                <div className="panel-heading"><div><p className="eyebrow">Notes</p><h3>Add transaction note</h3></div></div>
                <Field label="Note" value={noteDraft} onChange={setNoteDraft} as="textarea" />
                <button className="btn primary"><Icon name="MessageSquarePlus" /><span>Add Note</span></button>
              </form>
              <div className="panel">
                <p className="eyebrow">Current notes</p>
                <p className="transaction-notes-block">{selectedTransaction.notes || "No notes added yet."}</p>
              </div>
            </div>
          )}
        </div>
      ) : (
        <>
          <div className="transaction-metrics-grid">
            {metrics.map(([label, value, icon]) => <TransactionMetricCard key={label} label={label} value={value} icon={icon} />)}
          </div>
          <div className="panel transaction-toolbar">
            <Field label="Search transactions" value={search} onChange={setSearch} placeholder="Search client, address, agent, or status" />
            <Field label="Status" value={statusFilter} onChange={setStatusFilter} as="select" options={["All", ...transactionStatuses, "Submitted for Review"]} />
          </div>
          <div className="transaction-grid">
            {filteredTransactions.map((transaction) => (
              <TransactionCard key={transaction.id} transaction={transaction} onOpen={() => openTransaction(transaction.id)} />
            ))}
            {!filteredTransactions.length && <EmptyState icon="FolderKanban" title="No transactions yet" body="Create a transaction to start tracking documents, deadlines, checklists, compliance, and commission." />}
          </div>
          <div className="panel">
            <div className="panel-heading"><div><p className="eyebrow">Recent activity</p><h3>Transaction audit trail</h3></div></div>
            <div className="transaction-activity-feed">
              {activity.slice(0, 8).map((item) => (
                <article key={item.id}>
                  <span>{item.action}</span>
                  <strong>{item.details}</strong>
                  <small>{item.userName || item.userEmail || "System"} - {new Date(item.createdAt).toLocaleString()}</small>
                </article>
              ))}
              {!activity.length && <p className="muted">Activity will appear here as agents create files, upload documents, and submit reviews.</p>}
            </div>
          </div>
        </>
      )}
    </section>
  );
}

function BuyerContractTrackerPage({ currentUser, role, setToast, notifications, setNotifications, initialView, onInitialViewConsumed }) {
  const [transactions, setTransactions] = useState([]);
  const [tasks, setTasks] = useState([]);
  const [settings, setSettings] = useState([]);
  const [permissions, setPermissions] = useState({ canViewAll: isAdminRole(role), role });
  const [activeTab, setActiveTab] = useState(initialView || "Transactions");
  const [selectedTransactionId, setSelectedTransactionId] = useState("");
  const [filters, setFilters] = useState({ status: "All", agent: "All", overdueOnly: false, closingBefore: "" });
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    refreshTracker();
  }, []);

  useEffect(() => {
    if (initialView) {
      setActiveTab(initialView);
      onInitialViewConsumed?.();
    }
  }, [initialView]);

  async function refreshTracker() {
    setLoading(true);
    try {
      const payload = await API.request("/api/buyer-tracker/bootstrap");
      setTransactions(payload.transactions || []);
      setTasks(payload.tasks || []);
      setSettings(payload.reminderSettings || []);
      setNotifications(payload.notifications || []);
      setPermissions(payload.permissions || { canViewAll: isAdminRole(role), role });
    } catch (error) {
      setToast(error.message || "Could not load buyer contract tracker.");
    } finally {
      setLoading(false);
    }
  }

  async function createTransaction(draft) {
    try {
      const saved = await API.request("/api/buyer-transactions", { method: "POST", body: JSON.stringify(draft) });
      setTransactions((current) => [saved.transaction, ...current]);
      setTasks((current) => [...saved.tasks, ...current]);
      setSettings((current) => [saved.reminderSettings, ...current]);
      setSelectedTransactionId(saved.transaction.id);
      setActiveTab("Detail");
      setToast("Buyer contract checklist created.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not create buyer checklist.");
    }
  }

  async function updateTransaction(transactionId, patch) {
    try {
      const saved = await API.request(`/api/buyer-transactions/${encodeURIComponent(transactionId)}`, { method: "PUT", body: JSON.stringify(patch) });
      setTransactions((current) => current.map((transaction) => (transaction.id === saved.id ? saved : transaction)));
      setToast("Buyer transaction updated.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not update buyer transaction.");
    }
  }

  async function updateTask(taskId, patch) {
    try {
      const saved = await API.request(`/api/buyer-transaction-tasks/${encodeURIComponent(taskId)}`, { method: "PUT", body: JSON.stringify(patch) });
      setTasks((current) => current.map((task) => (task.id === saved.id ? saved : task)));
      setToast(saved.completed ? "Task completed." : "Task updated.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not update task.");
    }
  }

  async function addTask(transactionId, task) {
    try {
      const saved = await API.request(`/api/buyer-transactions/${encodeURIComponent(transactionId)}/tasks`, { method: "POST", body: JSON.stringify(task) });
      setTasks((current) => [saved, ...current]);
      setToast("Custom task added.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not add custom task.");
    }
  }

  async function deleteTask(taskId) {
    try {
      await API.request(`/api/buyer-transaction-tasks/${encodeURIComponent(taskId)}`, { method: "DELETE" });
      setTasks((current) => current.filter((task) => task.id !== taskId));
      setToast("Custom task deleted.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not delete task.");
    }
  }

  async function saveReminders(settingsId, patch) {
    try {
      const saved = await API.request(`/api/reminder-settings/${encodeURIComponent(settingsId)}`, { method: "PUT", body: JSON.stringify(patch) });
      setSettings((current) => current.map((item) => (item.id === saved.id ? saved : item)));
      setToast("Reminder settings saved.");
      refreshTracker();
    } catch (error) {
      setToast(error.message || "Could not save reminder settings.");
    }
  }

  async function markNotificationRead(notificationId) {
    try {
      const saved = await API.request(`/api/notifications/${encodeURIComponent(notificationId)}`, { method: "PUT", body: JSON.stringify({ read: true }) });
      setNotifications((current) => current.map((notification) => (notification.id === saved.id ? saved : notification)));
    } catch (error) {
      setToast(error.message || "Could not update notification.");
    }
  }

  function openTransaction(transactionId) {
    setSelectedTransactionId(transactionId);
    setActiveTab("Detail");
  }

  const selectedTransaction = transactions.find((transaction) => transaction.id === selectedTransactionId);
  const selectedTasks = selectedTransaction ? tasks.filter((task) => task.transactionId === selectedTransaction.id) : [];
  const selectedSettings = selectedTransaction ? settings.find((item) => item.transactionId === selectedTransaction.id) : null;

  return (
    <section className="portal-page buyer-tracker-page">
      <div className="module-hero buyer-hero">
        <div>
          <p className="eyebrow">Buyer Contract Tracker</p>
          <h3>A simple under-contract deadline checklist for Nex buyer files.</h3>
          <p>Use this as an internal guide alongside Brokermint, contract deadlines, lender/title communication, and brokerage compliance review.</p>
          <div className="hero-actions">
            <button className="btn light" onClick={() => setActiveTab("Create New Transaction")}>
              <Icon name="ClipboardCheck" />
              <span>Create New Transaction</span>
            </button>
            <button className="btn light" onClick={() => setActiveTab("Notifications")}>
              <Icon name="Bell" />
              <span>View Notifications</span>
            </button>
            <button className="btn light" onClick={refreshTracker}>
              <Icon name="RefreshCcw" />
              <span>Refresh</span>
            </button>
          </div>
        </div>
      </div>

      <div className="crm-tabs buyer-tabs">
        {buyerTrackerTabs.map((tab) => (
          <button key={tab} className={classNames(activeTab === tab && "active")} onClick={() => setActiveTab(tab)}>
            {tab}
          </button>
        ))}
      </div>

      {loading ? (
        <EmptyState icon="LoaderCircle" title="Loading buyer tracker" body="Preparing transactions, checklist tasks, and reminders." />
      ) : activeTab === "Create New Transaction" ? (
        <CreateBuyerTransactionForm currentUser={currentUser} onCreate={createTransaction} />
      ) : activeTab === "Notifications" ? (
        <NotificationCenter notifications={notifications} transactions={transactions} tasks={tasks} onMarkRead={markNotificationRead} onOpenTransaction={openTransaction} />
      ) : activeTab === "Detail" && selectedTransaction ? (
        <BuyerTransactionDetail
          transaction={selectedTransaction}
          tasks={selectedTasks}
          reminderSettings={selectedSettings}
          onBack={() => setActiveTab("Transactions")}
          onUpdateTransaction={updateTransaction}
          onUpdateTask={updateTask}
          onDeleteTask={deleteTask}
          onAddTask={addTask}
          onSaveReminders={saveReminders}
        />
      ) : (
        <BuyerTransactionList transactions={transactions} tasks={tasks} filters={filters} setFilters={setFilters} permissions={permissions} onOpen={openTransaction} />
      )}
    </section>
  );
}

function ProductionNumberField({ label, value, onChange, min = 0, max, step = 1, prefix = "", suffix = "", helper = "" }) {
  return (
    <label className="production-field">
      <span>{label}</span>
      <div className="production-input-wrap">
        {prefix && <em>{prefix}</em>}
        <input
          type="number"
          aria-label={label}
          min={min}
          max={max}
          step={step}
          value={value}
          onChange={(event) => onChange(event.target.value)}
        />
        {suffix && <em>{suffix}</em>}
      </div>
      {helper && <small>{helper}</small>}
    </label>
  );
}

function ProductionMetricCard({ label, value, icon = "Target", featured = false }) {
  return (
    <article className={classNames("production-metric-card", featured && "featured")}>
      <Icon name={icon} />
      <span>{label}</span>
      <strong>{value}</strong>
    </article>
  );
}

function ProductionActivityRow({ label, actual, goal, icon }) {
  const ratio = progressRatio(actual, goal);
  const percent = Math.round(ratio * 100);
  const pace = getProductionPace(actual, goal);
  const goalLabel = Number(goal) < 10 ? Number(goal).toFixed(1) : roundUp(goal);
  return (
    <article className="production-activity-row">
      <div>
        <Icon name={icon} />
        <strong>{label}</strong>
        <span>{actual || 0} actual / {goalLabel} goal</span>
      </div>
      <div className="production-progress">
        <div style={{ width: `${percent}%` }} />
      </div>
      <em className={classNames("production-pace-badge", pace.toLowerCase().replace(/\s+/g, "-"))}>
        {pace} - {percent}%
      </em>
    </article>
  );
}

function AgentProductionCalculator({ currentUser, setToast }) {
  const [loading, setLoading] = useState(true);
  const [bootstrap, setBootstrap] = useState(null);
  const [activePlan, setActivePlan] = useState(null);
  const [preview, setPreview] = useState(null);
  const [coaching, setCoaching] = useState(null);
  const [showAdvanced, setShowAdvanced] = useState(false);
  const [showAdmin, setShowAdmin] = useState(false);
  const [isBuilding, setIsBuilding] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isLogging, setIsLogging] = useState(false);
  const [isCoaching, setIsCoaching] = useState(false);
  const [assumptions, setAssumptions] = useState(DEFAULT_GAME_PLAN_ASSUMPTIONS);
  const [conversionRates, setConversionRates] = useState(DEFAULT_GAME_PLAN_CONVERSIONS);
  const [channelMix, setChannelMix] = useState(DEFAULT_GAME_PLAN_CHANNEL_MIX);
  const [activityDraft, setActivityDraft] = useState({ ...DEFAULT_ACTIVITY, date: new Date().toISOString().slice(0, 10), notes: "" });

  useEffect(() => {
    let mounted = true;
    setLoading(true);
    API.request("/api/production/bootstrap")
      .then((payload) => {
        if (!mounted) return;
        setBootstrap(payload);
        const plan = payload.activePlan;
        setActivePlan(plan || null);
        const source = plan || {};
        setAssumptions({ ...DEFAULT_GAME_PLAN_ASSUMPTIONS, ...(payload.defaultAssumptions || {}), ...(source.assumptions || {}) });
        setConversionRates({ ...DEFAULT_GAME_PLAN_CONVERSIONS, ...(payload.defaultConversionRates || {}), ...(source.conversionRates || {}) });
        setChannelMix({ ...DEFAULT_GAME_PLAN_CHANNEL_MIX, ...(payload.defaultChannelMix || {}), ...(source.channelMix || {}) });
        setCoaching(source.latestCoaching?.coaching || null);
      })
      .catch((error) => setToast?.(error.message || "Could not load Production Game Plan."))
      .finally(() => mounted && setLoading(false));
    return () => {
      mounted = false;
    };
  }, [currentUser?.email]);

  const currentPlan = activePlan?.calculatedPlan || preview?.calculatedPlan || null;
  const momentum = activePlan?.momentum || null;
  const planRule = currentPlan?.rule || commissionPlanRule(currentUser?.commissionPlan);
  const canViewAdmin = Boolean(bootstrap?.permissions?.canViewAll);

  function updateAssumption(field, value, options = {}) {
    setAssumptions((current) => {
      if (value === "") return { ...current, [field]: "" };
      const number = Number(value);
      if (!Number.isFinite(number)) return current;
      let next = number;
      if (options.percent) next = number / 100;
      next = Math.max(options.min ?? 0, next);
      if (typeof options.max !== "undefined") next = Math.min(options.max, next);
      return { ...current, [field]: next };
    });
  }

  function updateConversion(field, value, options = {}) {
    setConversionRates((current) => {
      if (value === "") return { ...current, [field]: "" };
      const number = Number(value);
      if (!Number.isFinite(number)) return current;
      return { ...current, [field]: options.percent ? number / 100 : Math.max(options.min ?? 0, number) };
    });
  }

  function updateMix(field, value) {
    setChannelMix((current) => ({ ...current, [field]: Math.max(0, Number(value) || 0) }));
  }

  function updateActivity(field, value) {
    setActivityDraft((current) => ({ ...current, [field]: value === "" ? "" : Math.max(0, Number(value) || 0) }));
  }

  function quickAdd(field, amount) {
    setActivityDraft((current) => ({ ...current, [field]: Math.max(0, Number(current[field] || 0) + amount) }));
  }

  async function buildPlan() {
    setIsBuilding(true);
    try {
      const result = await API.request("/api/production/ai/build-plan", {
        method: "POST",
        body: JSON.stringify({ assumptions, conversionRates, channelMix, agentPlan: currentUser?.commissionPlan })
      });
      setPreview(result);
      setCoaching(result.coaching || null);
      setToast?.("Production Game Plan built.");
    } catch (error) {
      setToast?.(error.message || "Could not build the plan.");
    } finally {
      setIsBuilding(false);
    }
  }

  async function saveCurrentPlan(options = {}) {
    const { silent = false } = options;
    setIsSaving(true);
    try {
      const saved = await API.request("/api/production/plans", {
        method: "POST",
        body: JSON.stringify({ assumptions, conversionRates, channelMix, agentPlan: currentUser?.commissionPlan })
      });
      setActivePlan(saved);
      setPreview(null);
      setCoaching(saved.latestCoaching?.coaching || coaching);
      if (!silent) setToast?.("Production Game Plan saved.");
      return saved;
    } catch (error) {
      setToast?.(error.message || "Could not save the production plan.");
      throw error;
    } finally {
      setIsSaving(false);
    }
  }

  async function savePlan() {
    try {
      await saveCurrentPlan();
    } catch {
      // saveCurrentPlan already shows the agent-facing error toast.
    }
  }

  async function logActivity() {
    setIsLogging(true);
    try {
      let savedFirst = false;
      if (!activePlan) {
        await saveCurrentPlan({ silent: true });
        savedFirst = true;
      }
      const result = await API.request("/api/production/activity", {
        method: "POST",
        body: JSON.stringify(activityDraft)
      });
      if (result.activePlan) setActivePlan(result.activePlan);
      setActivityDraft({ ...DEFAULT_ACTIVITY, date: new Date().toISOString().slice(0, 10), notes: "" });
      setToast?.(savedFirst ? "Plan saved and activity logged." : "Activity logged. Momentum updated.");
    } catch (error) {
      setToast?.(error.message || "Could not log activity.");
    } finally {
      setIsLogging(false);
    }
  }

  async function generateCoaching() {
    setIsCoaching(true);
    try {
      const result = await API.request("/api/production/ai/coach", {
        method: "POST",
        body: JSON.stringify({ request: "Give me this week's production coaching." })
      });
      setCoaching(result.coaching);
      if (result.momentum && activePlan) setActivePlan((current) => current ? { ...current, momentum: result.momentum, latestCoaching: result.summary } : current);
      setToast?.(result.coaching?.provider === "openai" ? "NIA coaching generated." : "Coaching generated with Nex fallback.");
    } catch (error) {
      setToast?.(error.message || "Could not generate coaching.");
    } finally {
      setIsCoaching(false);
    }
  }

  function applyGoal(goal) {
    setAssumptions((current) => ({ ...current, incomeGoal: goal }));
  }

  if (loading) {
    return <section className="portal-page production-calculator-page"><div className="panel"><p>Loading Production Game Plan...</p></div></section>;
  }

  const yearly = currentPlan?.annualTargets || {};
  const monthly = currentPlan?.monthlyTargets || {};
  const weekly = currentPlan?.weeklyTargets || {};
  const daily = currentPlan?.dailyTargets || {};
  const coach = coaching || fallbackProductionCoachClient(currentPlan, momentum);

  return (
    <section className="portal-page production-calculator-page production-game-plan-page">
      <div className="module-hero production-hero game-plan-hero">
        <div>
          <p className="eyebrow">Production Game Plan</p>
          <h3>Your income goal, turned into a daily action plan.</h3>
          <p>Tell Nex Central what you want to net this year. The plan applies your Nex commission plan, conversion assumptions, channel mix, and activity pace.</p>
          <div className="hero-actions">
            <button className="btn light" onClick={buildPlan} disabled={isBuilding}>
              <Icon name="Sparkles" />
              <span>{isBuilding ? "Building..." : "Build My Plan"}</span>
            </button>
            <button className="btn light" onClick={savePlan} disabled={isSaving}>
              <Icon name="Save" />
              <span>{isSaving ? "Saving..." : "Save Plan"}</span>
            </button>
            {canViewAdmin && (
              <button className="btn light" onClick={() => setShowAdmin((value) => !value)}>
                <Icon name="ShieldCheck" />
                <span>Admin View</span>
              </button>
            )}
          </div>
        </div>
        <div className="production-score-card">
          <span>Momentum Score</span>
          <strong>{momentum?.momentumScore ?? "--"}</strong>
          <em className={classNames("production-status-badge", `status-${slugify(momentum?.status || "Plan Ready")}`)}>{momentum?.status || "Plan Ready"}</em>
        </div>
      </div>

      <section className="production-daily-card game-plan-daily">
        <div>
          <p>Daily Success Number</p>
          <h3>{daily.calls || 0} calls · {daily.texts || 0} texts · {daily.conversations || 0} conversations</h3>
          <span>{daily.prospectingHours || 0} focused prospecting hours/day. {currentPlan?.riskLevel === "high" ? "This is aggressive, so consider a stronger warm-source mix." : "This is your daily pace marker."}</span>
        </div>
        <Icon name="Target" size={54} />
      </section>

      <div className="production-grid two-column">
        <section className="panel production-card game-plan-builder">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Step 1</p>
              <h3>Choose your income goal</h3>
            </div>
          </div>
          <div className="goal-preset-row">
            {[75000, 100000, 150000, 250000].map((goal) => (
              <button key={goal} className={classNames(Number(assumptions.incomeGoal) === goal && "active")} onClick={() => applyGoal(goal)}>
                {formatCurrency(goal)}
              </button>
            ))}
          </div>
          <ProductionNumberField label="Desired annual agent net income" value={assumptions.incomeGoal} min={1000} step={5000} prefix="$" onChange={(value) => updateAssumption("incomeGoal", value, { min: 1000 })} />

          <div className="game-plan-profile-strip">
            <div>
              <span>Nex plan</span>
              <strong>{currentPlan?.planName || normalizeCommissionPlanName(currentUser?.commissionPlan)}</strong>
              <small>{planRule?.splitLabel || "Plan details from Admin profile"}</small>
            </div>
            <div>
              <span>Average net / closing</span>
              <strong>{formatCurrency(currentPlan?.averageNetPerClosing || 0)}</strong>
              <small>Estimated after plan fees/splits.</small>
            </div>
          </div>

          <div className="production-form-grid">
            <ProductionNumberField label="Average sales price" value={assumptions.averageSalesPrice} min={0} step={10000} prefix="$" onChange={(value) => updateAssumption("averageSalesPrice", value, { min: 0 })} />
            <ProductionNumberField label="Average commission rate" value={productionPercentInputValue(assumptions.averageCommissionRate, 2)} min={0.1} max={100} step={0.1} suffix="%" onChange={(value) => updateAssumption("averageCommissionRate", value, { percent: true })} />
            <ProductionNumberField label="Working weeks / year" value={assumptions.workingWeeksPerYear} min={1} max={52} onChange={(value) => updateAssumption("workingWeeksPerYear", value, { min: 1, max: 52 })} />
            <ProductionNumberField label="Prospecting days / week" value={assumptions.prospectingDaysPerWeek} min={1} max={7} onChange={(value) => updateAssumption("prospectingDaysPerWeek", value, { min: 1, max: 7 })} />
          </div>
          <button className="btn primary full-width" onClick={buildPlan} disabled={isBuilding}>
            <Icon name="WandSparkles" />
            <span>{isBuilding ? "Building your plan..." : "Make the plan for me"}</span>
          </button>
        </section>

        <section className="panel production-card nia-coach-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">NIA Coach</p>
              <h3>What to focus on now</h3>
            </div>
            <button className="btn secondary compact" onClick={generateCoaching} disabled={!activePlan || isCoaching}>
              <Icon name="Bot" />
              <span>{isCoaching ? "Thinking..." : "Ask NIA"}</span>
            </button>
          </div>
          <h4>{coach.headline}</h4>
          <p>{coach.summary}</p>
          <div className="coach-list-grid">
            <div>
              <span>Focus this week</span>
              {(coach.focusThisWeek || []).slice(0, 3).map((item) => <small key={item}>{item}</small>)}
            </div>
            <div>
              <span>Next actions</span>
              {(coach.nextActions || []).slice(0, 3).map((item) => <small key={item}>{item}</small>)}
            </div>
          </div>
        </section>
      </div>

      <section className="panel production-card">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Plan output</p>
            <h3>What your goal requires</h3>
          </div>
          <span className="production-updated">{activePlan ? `Saved ${new Date(activePlan.updatedAt || activePlan.createdAt).toLocaleString()}` : "Preview until saved"}</span>
        </div>
        <div className="production-metrics-grid game-plan-metrics">
          <ProductionMetricCard label="Annual closings" value={yearly.requiredClosings || "--"} icon="BadgeDollarSign" featured />
          <ProductionMetricCard label="Annual volume" value={formatCurrency(yearly.requiredVolume || 0)} icon="TrendingUp" />
          <ProductionMetricCard label="Annual GCI" value={formatCurrency(yearly.requiredGci || 0)} icon="CircleDollarSign" />
          <ProductionMetricCard label="Monthly closings" value={monthly.requiredClosings || "--"} icon="CalendarDays" />
          <ProductionMetricCard label="Weekly appointments" value={weekly.appointments || "--"} icon="CalendarCheck" />
          <ProductionMetricCard label="Weekly leads" value={weekly.leads || "--"} icon="UserPlus" />
          <ProductionMetricCard label="Weekly conversations" value={weekly.conversations || "--"} icon="MessagesSquare" />
          <ProductionMetricCard label="Monthly open houses" value={monthly.openHouses || "--"} icon="DoorOpen" />
          <ProductionMetricCard label="Paid lead budget" value={formatCurrency(monthly.paidBudget || 0)} icon="Megaphone" />
          <ProductionMetricCard label="Projected net" value={formatCurrency(yearly.projectedAgentNet || 0)} icon="WalletCards" />
        </div>
      </section>

      <div className="production-grid two-column">
        <section className="panel production-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Log Activity</p>
              <h3>Today's activity</h3>
            </div>
          </div>
          <div className="quick-log-row">
            <button onClick={() => quickAdd("callsMade", 5)}>+5 calls</button>
            <button onClick={() => quickAdd("textsSent", 10)}>+10 texts</button>
            <button onClick={() => quickAdd("conversations", 1)}>+1 conversation</button>
            <button onClick={() => quickAdd("appointmentsSet", 1)}>+1 appointment</button>
          </div>
          <div className="production-form-grid">
            <ProductionNumberField label="Calls" value={activityDraft.callsMade} min={0} onChange={(value) => updateActivity("callsMade", value)} />
            <ProductionNumberField label="Texts" value={activityDraft.textsSent} min={0} onChange={(value) => updateActivity("textsSent", value)} />
            <ProductionNumberField label="Emails" value={activityDraft.emailsSent} min={0} onChange={(value) => updateActivity("emailsSent", value)} />
            <ProductionNumberField label="Conversations" value={activityDraft.conversations} min={0} onChange={(value) => updateActivity("conversations", value)} />
            <ProductionNumberField label="Leads" value={activityDraft.leadsCreated} min={0} onChange={(value) => updateActivity("leadsCreated", value)} />
            <ProductionNumberField label="Appointments" value={activityDraft.appointmentsSet} min={0} onChange={(value) => updateActivity("appointmentsSet", value)} />
            <ProductionNumberField label="Open houses" value={activityDraft.openHousesHeld} min={0} onChange={(value) => updateActivity("openHousesHeld", value)} />
            <ProductionNumberField label="Closings" value={activityDraft.closings} min={0} onChange={(value) => updateActivity("closings", value)} />
          </div>
          <label className="production-field">
            <span>Notes</span>
            <textarea value={activityDraft.notes} onChange={(event) => setActivityDraft((current) => ({ ...current, notes: event.target.value }))} placeholder="What moved the business today?" rows={3} />
          </label>
          <button className="btn primary full-width" onClick={logActivity} disabled={isLogging || isSaving}>
            <Icon name="PlusCircle" />
            <span>{isLogging ? "Logging..." : activePlan ? "Log Today's Activity" : "Save Plan & Log Activity"}</span>
          </button>
          {!activePlan && <p className="production-muted">No saved plan yet. This will save your current Game Plan first, then record the activity.</p>}
        </section>

        <section className="panel production-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Momentum</p>
              <h3>Pipeline health</h3>
            </div>
          </div>
          <div className="production-score-ring large">
            <strong>{momentum?.momentumScore ?? "--"}</strong>
            <span>{momentum?.status || "No logs yet"}</span>
          </div>
          <p>{momentum?.insight || "Once you log activity, Nex Central will show whether your week is on pace."}</p>
          <div className="production-activity-rows compact">
            {[
              ["Calls", momentum?.currentWeek?.callsMade, weekly.calls, "Phone"],
              ["Texts", momentum?.currentWeek?.textsSent, weekly.texts, "MessageSquare"],
              ["Conversations", momentum?.currentWeek?.conversations, weekly.conversations, "MessagesSquare"],
              ["Leads", momentum?.currentWeek?.leadsCreated, weekly.leads, "UserPlus"],
              ["Appointments", momentum?.currentWeek?.appointmentsSet, weekly.appointments, "CalendarCheck"]
            ].map(([label, actual, goal, icon]) => (
              <ProductionActivityRow key={label} label={label} actual={actual || 0} goal={goal || 0} icon={icon} />
            ))}
          </div>
        </section>
      </div>

      <section className="panel production-card">
        <button className="btn secondary full-width" onClick={() => setShowAdvanced((value) => !value)}>
          <Icon name="SlidersHorizontal" />
          <span>{showAdvanced ? "Hide advanced assumptions" : "Edit advanced assumptions"}</span>
        </button>
        {showAdvanced && (
          <div className="advanced-production-grid">
            <div>
              <h4>Channel mix</h4>
              {Object.keys(DEFAULT_GAME_PLAN_CHANNEL_MIX).map((field) => (
                <ProductionNumberField key={field} label={`${field.replace(/([A-Z])/g, " $1")} %`} value={channelMix[field]} min={0} max={100} suffix="%" onChange={(value) => updateMix(field, value)} />
              ))}
            </div>
            <div>
              <h4>Conversion rates</h4>
              {[
                ["callToConversationRate", "Call to conversation"],
                ["textToConversationRate", "Text to conversation"],
                ["emailToConversationRate", "Email to conversation"],
                ["conversationToLeadRate", "Conversation to lead"],
                ["leadToAppointmentRate", "Lead to appointment"],
                ["appointmentToSignedClientRate", "Appointment to signed client"],
                ["signedClientToContractRate", "Signed client to contract"],
                ["contractToCloseRate", "Contract to close"],
                ["openHouseVisitorToLeadRate", "Open house visitor to lead"]
              ].map(([field, label]) => (
                <ProductionNumberField key={field} label={label} value={productionPercentInputValue(conversionRates[field])} min={0.1} max={100} suffix="%" onChange={(value) => updateConversion(field, value, { percent: true })} />
              ))}
              <ProductionNumberField label="Visitors / open house" value={conversionRates.openHouseVisitors} min={1} onChange={(value) => updateConversion("openHouseVisitors", value, { min: 1 })} />
              <ProductionNumberField label="Paid cost / lead" value={conversionRates.paidCostPerLead} min={1} prefix="$" onChange={(value) => updateConversion("paidCostPerLead", value, { min: 1 })} />
              <ProductionNumberField label="Company lead deal share" value={productionPercentInputValue(assumptions.brokerageGeneratedDealShare)} min={0} max={100} suffix="%" onChange={(value) => updateAssumption("brokerageGeneratedDealShare", value, { percent: true })} />
            </div>
          </div>
        )}
      </section>

      {showAdmin && canViewAdmin && (
        <section className="panel production-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Admin</p>
              <h3>Agent production plans</h3>
            </div>
          </div>
          <div className="admin-production-table">
            {(bootstrap?.adminSummaries || []).length ? bootstrap.adminSummaries.map((plan) => (
              <article key={plan.id}>
                <strong>{plan.agentName || plan.agentEmail}</strong>
                <span>{formatCurrency(plan.assumptions?.incomeGoal || 0)} goal</span>
                <span>{plan.calculatedPlan?.annualTargets?.requiredClosings || 0} closings</span>
                <em>{plan.momentum?.momentumScore || 0} momentum</em>
              </article>
            )) : <p>No saved production plans yet.</p>}
          </div>
        </section>
      )}
    </section>
  );
}

function fallbackProductionCoachClient(plan, momentum) {
  if (!plan) {
    return {
      headline: "Start with your income goal.",
      summary: "Enter what you want to net this year, confirm your Nex plan, and click Make the plan for me.",
      focusThisWeek: ["Choose a realistic income goal.", "Use your real average price point.", "Save the first plan."],
      nextActions: ["Build the plan.", "Save it.", "Log today's activity."]
    };
  }
  return {
    headline: momentum?.momentumScore >= 70 ? "Your plan has momentum." : "Your next move is activity consistency.",
    summary: plan.summary || "The plan is built. Log activity daily so the coaching gets sharper.",
    focusThisWeek: [momentum?.insight || "Focus on conversations first.", "Keep your follow-up blocks protected.", "Update the plan when your assumptions change."],
    nextActions: plan.nextActions || ["Log today's activity.", "Create one new appointment.", "Follow up with warm contacts."]
  };
}

function launchPadMinutes(value = 0) {
  const minutes = Math.max(0, Number(value || 0));
  const hours = Math.floor(minutes / 60);
  const remainder = minutes % 60;
  if (!hours) return `${remainder} min`;
  return remainder ? `${hours}h ${remainder}m` : `${hours}h`;
}

function launchPadFirstName(user = {}) {
  const source = user?.name || user?.displayName || user?.email?.split("@")[0] || "";
  return String(source).trim().split(/\s+/).filter(Boolean)[0] || "there";
}

function launchPadPersonalizeText(value, user = {}) {
  if (typeof value !== "string") return value;
  const firstName = launchPadFirstName(user);
  const preferredName = firstName === "there" ? "you" : firstName;
  return value
    .replace(/\bThe agent should\b/g, "You should")
    .replace(/\bthe agent should\b/g, "you should")
    .replace(/\bThe agent must\b/g, "You must")
    .replace(/\bthe agent must\b/g, "you must")
    .replace(/\bThe agent needs\b/g, "You need")
    .replace(/\bthe agent needs\b/g, "you need")
    .replace(/\bThe agent will\b/g, "You will")
    .replace(/\bthe agent will\b/g, "you will")
    .replace(/\bThe agent can\b/g, "You can")
    .replace(/\bthe agent can\b/g, "you can")
    .replace(/\bThe agent is\b/g, "You are")
    .replace(/\bthe agent is\b/g, "you are")
    .replace(/\bThe agent has\b/g, "You have")
    .replace(/\bthe agent has\b/g, "you have")
    .replace(/\bThe agent\b/g, "You")
    .replace(/\bthe agent\b/g, "you")
    .replace(/\bthis agent\b/gi, preferredName);
}

function NexLaunchPad({ currentUser, role, setToast }) {
  const [payload, setPayload] = useState(null);
  const [loading, setLoading] = useState(true);
  const [viewMode, setViewMode] = useState("home");
  const [selectedDayId, setSelectedDayId] = useState("");
  const [selectedChapterId, setSelectedChapterId] = useState("");
  const [quizAnswers, setQuizAnswers] = useState({});
  const [homeworkText, setHomeworkText] = useState("");
  const [simulatorAnswers, setSimulatorAnswers] = useState({});
  const [simulatorStep, setSimulatorStep] = useState(0);
  const [coachPrompt, setCoachPrompt] = useState("");
  const [lessonTab, setLessonTab] = useState("learn");
  const [checkedActions, setCheckedActions] = useState({});
  const [scriptDraft, setScriptDraft] = useState("");
  const [confidenceLevel, setConfidenceLevel] = useState(3);
  const [busyAction, setBusyAction] = useState("");
  const [adminOpen, setAdminOpen] = useState(false);
  const [curriculumPreviewMode, setCurriculumPreviewMode] = useState(false);
  const [roadmapOpen, setRoadmapOpen] = useState(false);
  const [resourcesOpen, setResourcesOpen] = useState(false);
  const canAdmin = isAdminRole(role);
  const learnerFirstName = launchPadFirstName(currentUser);
  const learnerDisplayName = currentUser?.name || currentUser?.email?.split("@")[0] || "Nex Agent";
  const lpText = (value) => launchPadPersonalizeText(value, currentUser);

  const days = payload?.curriculum?.days || [];
  const flatLessonEntries = days.flatMap((day) => (day.chapters || []).map((chapter, index) => ({ day, chapter, index })));
  const allChapters = flatLessonEntries.map((entry) => entry.chapter);
  const selectedDay = days.find((day) => day.id === selectedDayId) || days[0];
  const chapters = selectedDay?.chapters || [];
  const selectedChapter = chapters.find((chapter) => chapter.id === selectedChapterId) || chapters[0] || days.flatMap((day) => day.chapters || [])[0];
  const selectedLessonIndex = flatLessonEntries.findIndex((entry) => entry.chapter.id === selectedChapter?.id);
  const selectedDayLessonIndex = Math.max(0, chapters.findIndex((chapter) => chapter.id === selectedChapter?.id));
  const previousLessonEntry = selectedLessonIndex > 0 ? flatLessonEntries[selectedLessonIndex - 1] : null;
  const nextLessonEntry = selectedLessonIndex >= 0 ? flatLessonEntries[selectedLessonIndex + 1] : null;
  const chapterProgress = selectedChapter ? payload?.progress?.chapters?.[selectedChapter.id] || {} : {};
  const latestNiaScore = chapterProgress.niaInteractions?.[0]?.feedback?.score;
  const localRequirements = selectedChapter
    ? [
        { key: "time", label: `${selectedChapter.minutesRequired} required minutes`, met: Number(chapterProgress.timeSpentMinutes || 0) >= Number(selectedChapter.minutesRequired || 0) },
        { key: "quiz", label: "Quiz passed", met: Boolean(chapterProgress.quizPassed) },
        { key: "homework", label: "Homework submitted", met: Boolean(chapterProgress.homeworkSubmittedAt) && String(chapterProgress.homeworkText || "").trim().length >= 25 },
        ...(selectedChapter.requiresNiaCheckpoint !== false ? [{ key: "nia", label: "NIA checkpoint passed", met: Number(latestNiaScore || 0) >= 70 }] : []),
        ...(selectedChapter.simulator ? [{ key: "simulator", label: "Simulator score 70%+", met: Number(chapterProgress.simulatorScore || 0) >= 70 }] : [])
      ]
    : [];
  const selectedState = selectedChapter ? payload?.chapterStates?.[selectedChapter.id] || {} : {};
  const chapterRequirements = selectedState.requirements || localRequirements;
  const canCompleteChapter = chapterRequirements.length > 0 && chapterRequirements.every((item) => item.met);
  const lessonTabs = [
    { id: "learn", label: "Learn", icon: "BookOpen" },
    { id: "practice", label: "Practice", icon: "MessagesSquare" },
    { id: "quiz", label: "Quiz", icon: "ClipboardCheck" },
    { id: "homework", label: "Homework", icon: "FileText" },
    { id: "coach", label: "NIA Coach", icon: "Bot" }
  ];
  const lessonSections = selectedChapter?.lessonSections || [];
  const coachModes = selectedChapter?.niaPrompts || [];
  const summary = payload?.summary || {};
  const roadmap = payload?.roadmap || [];
  const resumeTarget = payload?.resumeTarget || {};
  const coachInteractions = chapterProgress.niaInteractions || [];
  const isCurriculumPreview = Boolean(curriculumPreviewMode && payload?.preview?.enabled);
  const certificateReady = summary.status === "Completed";
  const remainingMinutes = Math.max(0, Number(summary.totalRequiredMinutes || 0) - Number(summary.totalTimeMinutes || 0));
  const completedRequirementCount = allChapters.reduce((sum, chapter) => {
    const state = payload?.chapterStates?.[chapter.id];
    const requirements = state?.requirements || [];
    return sum + requirements.filter((item) => item.met).length;
  }, 0);
  const totalRequirementCount = allChapters.reduce((sum, chapter) => {
    const state = payload?.chapterStates?.[chapter.id];
    return sum + (state?.requirements?.length || 0);
  }, 0);
  const nextRequirement = chapterRequirements.find((item) => !item.met);
  const selectedDayLock = summary.dayLocks?.[selectedDay?.id] || {};
  const selectedDayLockedForAgents = Boolean(selectedDayLock.locked);
  const selectedDayBlocked = selectedDayLockedForAgents && !isCurriculumPreview;
  const selectedSimulatorFields = selectedChapter?.simulator?.fields || [];
  const simulatorSteps = selectedChapter?.simulator
    ? [
        { key: "scenario", label: "Scenario" },
        { key: "form", label: "Select form" },
        { key: "fields", label: "Key fields" },
        { key: "reasoning", label: "Reasoning" },
        { key: "review", label: "Review" }
      ]
    : [];
  const dayShortTitles = {
    "day-1": "Setup & Agent Brand Launch",
    "day-2": "Lead Generation",
    "day-3": "Buyer Mastery",
    "day-4": "Seller Mastery",
    "day-5": "Transaction Management",
    "day-6": "Contracts & Compliance",
    "day-7": "Final Readiness"
  };
  const currentTabIndex = Math.max(0, lessonTabs.findIndex((tab) => tab.id === lessonTab));
  const currentLessonTab = lessonTabs[currentTabIndex] || lessonTabs[0];
  const currentStepLabel = currentLessonTab?.label || "Learn";
  const currentStepNumber = currentTabIndex + 1;
  const timeRequirement = chapterRequirements.find((item) => item.key === "time");
  const remainingLessonMinutes = Math.max(0, Number(selectedChapter?.minutesRequired || 0) - Number(chapterProgress.timeSpentMinutes || 0));

  function localResumeTarget(nextPayload = payload) {
    const nextDays = nextPayload?.curriculum?.days || [];
    const nextSummary = nextPayload?.summary || {};
    if (nextSummary.status === "Completed") return { mode: "certificate", cta: "View Certificate" };
    const locks = nextSummary.dayLocks || {};
    for (const day of nextDays) {
      if (locks[day.id]?.locked) continue;
      for (const chapter of day.chapters || []) {
        if (nextPayload?.progress?.chapters?.[chapter.id]?.status !== "Completed") {
          return {
            mode: "lesson",
            dayId: day.id,
            dayNumber: day.day,
            dayTitle: day.title,
            chapterId: chapter.id,
            lessonTitle: chapter.title,
            cta: nextSummary.percent > 0 ? "Continue Where I Left Off" : "Start Day 1"
          };
        }
      }
    }
    return { mode: "home", cta: "Open LaunchPad" };
  }

  function openLesson(dayId, chapterId) {
    const day = days.find((item) => item.id === dayId);
    if (summary.dayLocks?.[dayId]?.locked && !isCurriculumPreview) {
      setToast(summary.dayLocks?.[dayId]?.reason || "Complete the previous LaunchPad day before starting this day.");
      return;
    }
    setSelectedDayId(dayId || day?.id || "");
    setSelectedChapterId(chapterId || day?.chapters?.[0]?.id || "");
    setViewMode("lesson");
  }

  function goToResume() {
    const target = resumeTarget?.mode ? resumeTarget : localResumeTarget();
    if (target.mode === "certificate") {
      setViewMode("certificate");
      return;
    }
    if (target.mode === "lesson") {
      openLesson(target.dayId, target.chapterId);
      return;
    }
    const firstDay = days[0];
    openLesson(firstDay?.id, firstDay?.chapters?.[0]?.id);
  }

  function openLessonEntry(entry) {
    if (!entry?.day || !entry?.chapter) return;
    openLesson(entry.day.id, entry.chapter.id);
  }

  function isLessonEntryLocked(entry) {
    return Boolean(entry && summary.dayLocks?.[entry.day.id]?.locked && !isCurriculumPreview);
  }

  function lessonTabForRequirement(requirement = nextRequirement) {
    const key = String(requirement?.key || "").toLowerCase();
    if (key.includes("quiz")) return "quiz";
    if (key.includes("homework")) return "homework";
    if (key.includes("nia") || key.includes("coach")) return "coach";
    if (key.includes("simulator")) return "practice";
    return "learn";
  }

  function lessonRequirementForTab(tabId) {
    if (tabId === "quiz") return chapterRequirements.find((item) => item.key === "quiz");
    if (tabId === "homework") return chapterRequirements.find((item) => item.key === "homework");
    if (tabId === "coach") return chapterRequirements.find((item) => item.key === "nia" || item.key === "coach");
    if (tabId === "practice") return chapterRequirements.find((item) => item.key === "simulator");
    return chapterRequirements.find((item) => item.key === "time");
  }

  function lessonTabStatus(tabId) {
    const requirement = lessonRequirementForTab(tabId);
    const done = tabId === "learn"
      ? Boolean(timeRequirement?.met || chapterProgress.currentStep)
      : tabId === "practice"
        ? (!selectedChapter?.simulator || Boolean(requirement?.met))
        : requirement ? Boolean(requirement.met) : false;
    const required = nextRequirement && lessonTabForRequirement(nextRequirement) === tabId;
    return { done, required };
  }

  function guidedMinutesForTab(tabId = lessonTab) {
    if (!remainingLessonMinutes) return 0;
    const requiredMinutes = Math.max(1, Number(selectedChapter?.minutesRequired || 0));
    const weights = { learn: 0.34, practice: 0.26, quiz: 0.16, homework: 0.14, coach: 1 };
    const weightedMinutes = Math.max(1, Math.ceil(requiredMinutes * (weights[tabId] || 0.12)));
    return Math.min(remainingLessonMinutes, tabId === "coach" ? remainingLessonMinutes : weightedMinutes);
  }

  async function recordGuidedLessonStep(tabId = lessonTab, successMessage = "Progress saved.") {
    if (isCurriculumPreview || !selectedChapter || chapterProgress.status === "Completed") return null;
    const tab = lessonTabs.find((item) => item.id === tabId) || currentLessonTab;
    return updateChapter("time", {
      minutes: guidedMinutesForTab(tabId),
      step: tabId,
      stepLabel: tab?.label || tabId,
      source: "continue_lesson"
    }, successMessage);
  }

  function nextSequentialTabId() {
    return lessonTabs[Math.min(lessonTabs.length - 1, currentTabIndex + 1)]?.id || "learn";
  }

  function defaultCoachCheckpointPrompt() {
    const prompt = selectedChapter?.rolePlayPrompt || selectedChapter?.scenarioPrompt || selectedChapter?.practiceScenario?.prompt || selectedChapter?.niaPrompt || "";
    return [
      `NIA checkpoint for ${selectedChapter?.title}:`,
      prompt || "Role-play this lesson with me and score my practical response.",
      "",
      "I will answer as myself. Score my accuracy, client communication, documentation, next step, and escalation judgment."
    ].join("\n");
  }

  function simulatorHasMinimumAnswers() {
    if (!selectedChapter?.simulator) return true;
    return selectedSimulatorFields.every((field) => !field.required || String(simulatorAnswers[field.id] || "").trim().length >= 3);
  }

  async function continueLessonStep() {
    if (isCurriculumPreview) {
      if (currentTabIndex < lessonTabs.length - 1) {
        setLessonTab(nextSequentialTabId());
      } else if (nextLessonEntry) {
        openLessonEntry(nextLessonEntry);
      }
      return;
    }

    if (selectedState.state === "complete") {
      if (nextLessonEntry && !isLessonEntryLocked(nextLessonEntry)) openLessonEntry(nextLessonEntry);
      else setToast("This lesson is complete.");
      return;
    }

    if (lessonTab === "learn") {
      await recordGuidedLessonStep("learn", "Learn step saved.");
      setLessonTab("practice");
      return;
    }

    if (lessonTab === "practice") {
      const simulatorRequirement = chapterRequirements.find((item) => item.key === "simulator");
      if (selectedChapter?.simulator && !simulatorRequirement?.met) {
        if (simulatorStep < simulatorSteps.length - 1) {
          await recordGuidedLessonStep("practice", "Practice progress saved.");
          setSimulatorStep((current) => Math.min(simulatorSteps.length - 1, current + 1));
          return;
        }
        if (!simulatorHasMinimumAnswers()) {
          setToast("Complete the simulator answers before moving to the quiz.");
          return;
        }
        const simulatorResponse = await submitSimulator();
        if (!simulatorResponse?.simulator?.complete) return;
      } else {
        await recordGuidedLessonStep("practice", "Practice step saved.");
      }
      setLessonTab("quiz");
      return;
    }

    if (lessonTab === "quiz") {
      if (!chapterProgress.quizPassed) {
        const quizResponse = await updateChapter("quiz", { answers: quizAnswers }, "Quiz submitted.");
        if (!quizResponse?.quiz?.passed && !quizResponse?.chapter?.quizPassed) return;
      } else {
        await recordGuidedLessonStep("quiz", "Quiz step saved.");
      }
      setLessonTab("homework");
      return;
    }

    if (lessonTab === "homework") {
      if (!chapterProgress.homeworkSubmittedAt || String(homeworkText || "").trim().length < 25) {
        const homeworkResponse = await updateChapter("homework", { homeworkText }, "Homework submitted.");
        if (!homeworkResponse?.chapter?.homeworkSubmittedAt) return;
      } else {
        await recordGuidedLessonStep("homework", "Homework step saved.");
      }
      setLessonTab("coach");
      return;
    }

    if (lessonTab === "coach") {
      const niaRequirement = chapterRequirements.find((item) => item.key === "nia" || item.key === "coach");
      if (niaRequirement && !niaRequirement.met) {
        if (String(coachPrompt || "").trim().length < 6) {
          setCoachPrompt(defaultCoachCheckpointPrompt());
          setToast("NIA checkpoint loaded. Add your answer, then ask NIA to review it.");
          return;
        }
        const coachResponse = await submitCoachPrompt("", "checkpoint");
        if (coachResponse?.feedback?.score < 70) return;
      }
      await recordGuidedLessonStep("coach", "Final lesson step saved.");
      await updateChapter("complete", {}, "Lesson completion saved.");
      return;
    }

    setLessonTab(nextSequentialTabId());
  }

  function closeNiaCoach() {
    const nextTab = lessonTabForRequirement(nextRequirement);
    setLessonTab(nextTab === "coach" ? "learn" : nextTab);
  }

  async function loadLaunchPad({ quiet = false, selectResume = false, preserveSelection = true, previewMode = curriculumPreviewMode } = {}) {
    try {
      if (!quiet) setLoading(true);
      const next = await API.request(previewMode ? "/api/launchpad/bootstrap?preview=1" : "/api/launchpad/bootstrap");
      setPayload(next);
      const target = next.resumeTarget || localResumeTarget(next);
      const firstDay = next.curriculum?.days?.[0];
      const fallbackDay = next.curriculum?.days?.find((day) => !next.summary?.dayLocks?.[day.id]?.locked) || firstDay;
      const targetDayId = target.mode === "lesson" ? target.dayId : fallbackDay?.id;
      const targetChapterId = target.mode === "lesson" ? target.chapterId : fallbackDay?.chapters?.[0]?.id;
      setSelectedDayId((current) => (selectResume || !preserveSelection || !current ? targetDayId || "" : current));
      setSelectedChapterId((current) => (selectResume || !preserveSelection || !current ? targetChapterId || "" : current));
      if (target.mode === "certificate") setViewMode("certificate");
      return next;
    } catch (error) {
      setToast(error.message || "Could not load Nex LaunchPad.");
      return null;
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadLaunchPad();
  }, []);

  useEffect(() => {
    if (!selectedChapter) return;
    const progress = payload?.progress?.chapters?.[selectedChapter.id] || {};
    setQuizAnswers(progress.quizAnswers || {});
    setHomeworkText(progress.homeworkText || "");
    setSimulatorAnswers(progress.simulatorAnswers || {});
    setSimulatorStep(0);
    setCoachPrompt("");
    setLessonTab("learn");
    setResourcesOpen(false);
    setRoadmapOpen(false);
    setCheckedActions({});
    setScriptDraft(selectedChapter?.scriptPractice?.starter || selectedChapter?.microCoaching?.script || "");
    setConfidenceLevel(3);
  }, [selectedChapter?.id]);

  async function updateChapter(action, body = {}, successMessage = "LaunchPad updated.") {
    if (!selectedChapter) return;
    if (isCurriculumPreview) {
      setToast("Admin curriculum preview is read-only and does not update agent progress.");
      return null;
    }
    try {
      setBusyAction(action);
      const response = await API.request(`/api/launchpad/chapters/${encodeURIComponent(selectedChapter.id)}/${action}`, {
        method: "POST",
        body: JSON.stringify(body)
      });
      setPayload((current) => ({
        ...(current || {}),
        progress: {
          ...(current?.progress || {}),
          chapters: {
            ...(current?.progress?.chapters || {}),
            [selectedChapter.id]: response.chapter || current?.progress?.chapters?.[selectedChapter.id]
          },
          status: response.summary?.status || current?.progress?.status,
          updatedAt: new Date().toISOString()
        },
        summary: response.summary || current?.summary,
        roadmap: response.roadmap || current?.roadmap,
        chapterStates: response.chapterStates || current?.chapterStates,
        resumeTarget: response.resumeTarget || current?.resumeTarget,
        admin: current?.admin
      }));
      setToast(successMessage);
      if (action === "complete") {
        if (response.summary?.status === "Completed") {
          await loadLaunchPad({ quiet: true, preserveSelection: false });
          setViewMode("certificate");
        } else {
          await loadLaunchPad({ quiet: true, selectResume: true });
          setViewMode("lesson");
        }
      }
      return response;
    } catch (error) {
      const missing = error?.requirements?.filter?.((item) => !item.met).map((item) => item.label).join(", ");
      setToast(missing || error.message || "Could not update LaunchPad.");
      return null;
    } finally {
      setBusyAction("");
    }
  }

  async function submitCoachPrompt(promptOverride = "", mode = "custom") {
    const message = String(promptOverride || coachPrompt || "").trim();
    if (!message) return null;
    setLessonTab("coach");
    const response = await updateChapter("coach", { message, mode }, "NIA reviewed your response.");
    if (response?.chapter) {
      setCoachPrompt("");
    }
    return response;
  }

  async function submitSimulator() {
    if (!selectedChapter?.simulator) return null;
    return updateChapter("simulator", { answers: simulatorAnswers }, "Simulator answers submitted.");
  }

  function updateSimulatorAnswer(key, value) {
    setSimulatorAnswers((current) => ({ ...current, [key]: value }));
  }

  function promptNia(mode) {
    if (!selectedChapter) return;
    const structuredPrompt = (selectedChapter.niaPrompts || []).find((prompt) => prompt.id === mode);
    if (structuredPrompt?.prompt) {
      setCoachPrompt(structuredPrompt.prompt);
      setLessonTab("coach");
      submitCoachPrompt(structuredPrompt.prompt, structuredPrompt.id || mode);
      return;
    }
    const prompts = {
      simple: `Explain ${selectedChapter.title} simply for a brand-new Florida agent. Keep it practical and tell me when to escalate to Nex broker/admin review.`,
      example: `Give me a real Florida residential real estate example for ${selectedChapter.title}, ideally in Tampa Bay, Orlando, or Miami.`,
      roleplay: `Role-play this with me: ${selectedChapter.rolePlayPrompt || selectedChapter.scenarioPrompt}`,
      quiz: `Quiz me on ${selectedChapter.title}. Ask one question at a time and grade my answer.`
    };
    const message = prompts[mode] || "";
    setCoachPrompt(message);
    setLessonTab("coach");
    if (message) submitCoachPrompt(message, mode);
  }

  function startVoiceResponse() {
    const Recognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!Recognition) {
      setToast("Voice capture is not available in this browser yet. Type your answer in the NIA coach box.");
      return;
    }
    const recognition = new Recognition();
    recognition.lang = "en-US";
    recognition.interimResults = false;
    recognition.onresult = (event) => {
      const transcript = Array.from(event.results || [])
        .map((result) => result[0]?.transcript || "")
        .join(" ")
        .trim();
      if (transcript) setCoachPrompt((current) => `${current ? `${current}\n\n` : ""}${transcript}`);
    };
    recognition.onerror = () => setToast("Voice capture stopped. You can still type your response.");
    recognition.start();
  }

  function readNiaBreakdown() {
    const text = selectedChapter?.microCoaching?.explanation || "";
    if (!text) return;
    if (!window.speechSynthesis) {
      setToast("Voice playback is not available in this browser yet.");
      return;
    }
    window.speechSynthesis.cancel();
    window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
  }

  function exportLaunchPadReport() {
    const rows = payload?.admin?.agents || [];
    if (!rows.length) return;
    const header = ["Agent", "Email", "Current Day", "Current Lesson", "Progress", "Time", "Quiz", "NIA", "Flagged", "Status", "Last Active", "Completed"];
    const csvRows = rows.map((agent) => [
      agent.userName,
      agent.userEmail,
      agent.currentDay,
      agent.currentLesson,
      `${agent.percent}%`,
      launchPadMinutes(agent.totalTimeMinutes),
      agent.averageQuizScore === null ? "" : `${agent.averageQuizScore}%`,
      agent.niaScore === null ? "" : `${agent.niaScore}%`,
      agent.flaggedAnswers || 0,
      agent.status,
      agent.lastActiveAt || "",
      agent.completedAt || ""
    ]);
    const csv = [header, ...csvRows]
      .map((row) => row.map((cell) => `"${String(cell || "").replace(/"/g, '""')}"`).join(","))
      .join("\n");
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "nex-launchpad-report.csv";
    link.click();
    URL.revokeObjectURL(url);
  }

  async function overrideAgentDay(agentEmail, dayId) {
    try {
      setBusyAction(`override-${agentEmail}-${dayId}`);
      await API.request("/api/launchpad/admin/override", {
        method: "POST",
        body: JSON.stringify({ agentEmail, dayId, enabled: true, reason: "Admin unlocked day from LaunchPad dashboard." })
      });
      await loadLaunchPad({ quiet: true });
      setToast("LaunchPad day unlocked for agent.");
    } catch (error) {
      setToast(error.message || "Could not unlock LaunchPad day.");
    } finally {
      setBusyAction("");
    }
  }

  async function openAdminCurriculumPreview() {
    if (!canAdmin) return;
    setCurriculumPreviewMode(true);
    const next = await loadLaunchPad({ previewMode: true, preserveSelection: false });
    if (!next) return;
    const firstDay = next.curriculum?.days?.[0];
    setSelectedDayId(firstDay?.id || "");
    setSelectedChapterId(firstDay?.chapters?.[0]?.id || "");
    setViewMode("lesson");
    setAdminOpen(true);
    setToast("Admin preview opened. This does not unlock agent progress.");
  }

  async function exitAdminCurriculumPreview() {
    setCurriculumPreviewMode(false);
    await loadLaunchPad({ previewMode: false, preserveSelection: false });
    setViewMode("home");
    setToast("Exited LaunchPad curriculum preview.");
  }

  async function markAdminReviewed(agentEmail, chapterId) {
    try {
      setBusyAction(`review-${agentEmail}-${chapterId}`);
      await API.request("/api/launchpad/admin/review", {
        method: "POST",
        body: JSON.stringify({ agentEmail, chapterId, needsReview: false, note: "Reviewed by admin in Nex LaunchPad." })
      });
      await loadLaunchPad({ quiet: true });
      setToast("LaunchPad item marked reviewed.");
    } catch (error) {
      setToast(error.message || "Could not update review status.");
    } finally {
      setBusyAction("");
    }
  }

  if (loading) {
    return (
      <section className="portal-page launchpad-page">
        <div className="launchpad-loading">
          <Icon name="Rocket" />
          <span>Loading Nex LaunchPad...</span>
        </div>
      </section>
    );
  }

  if (!payload || !selectedChapter) {
    return <EmptyState icon="Rocket" title="Nex LaunchPad is being prepared" body="The required onboarding curriculum is not available yet." />;
  }

  function renderAdminPanel() {
    if (!canAdmin) return null;
    return (
      <section className="launchpad-admin-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Admin reporting</p>
            <h3>Agent LaunchPad completion tracking</h3>
          </div>
          <div className="row-actions">
            <span>{payload.admin?.agents?.length || 0} agents</span>
            <button className="btn secondary small-btn" onClick={openAdminCurriculumPreview}>
              <Icon name="Eye" />
              <span>Preview LaunchPad Curriculum</span>
            </button>
            <button className="btn secondary small-btn" onClick={exportLaunchPadReport}>
              <Icon name="Download" />
              <span>Export Report</span>
            </button>
          </div>
        </div>
        {payload.preview?.qa && (
          <div className="launchpad-admin-qa-panel">
            <div>
              <p className="eyebrow">Admin curriculum QA</p>
              <h4>{payload.preview.qa.status || "Live"}</h4>
            </div>
            <div className="launchpad-admin-qa-grid">
              <span><strong>{payload.preview.qa.totalLessons}</strong><em>Total lessons</em></span>
              <span><strong>{payload.preview.qa.missingRequiredFields?.length || 0}</strong><em>Missing fields</em></span>
              <span><strong>{payload.preview.qa.missingQuizzes?.length || 0}</strong><em>Missing quizzes</em></span>
              <span><strong>{payload.preview.qa.missingNiaPrompts?.length || 0}</strong><em>Missing NIA prompts</em></span>
              <span><strong>{payload.preview.qa.missingHomework?.length || 0}</strong><em>Missing homework</em></span>
              <span><strong>{payload.preview.qa.formattingWarnings?.length || 0}</strong><em>Formatting warnings</em></span>
            </div>
          </div>
        )}
        <div className="launchpad-admin-table">
          <div className="launchpad-admin-row header">
            <span>Agent</span>
            <span>Current</span>
            <span>Progress</span>
            <span>Time</span>
            <span>Quiz</span>
            <span>NIA</span>
            <span>Flags</span>
            <span>Last active</span>
            <span>Status</span>
            <span>Admin</span>
          </div>
          {(payload.admin?.agents || []).map((agent) => (
            <div className="launchpad-admin-row" key={agent.userEmail}>
              <span><strong>{agent.userName || agent.userEmail}</strong><em>{agent.userEmail}</em></span>
              <span><strong>{agent.currentDay}</strong><em>{agent.currentLesson || "Ready"}</em></span>
              <span><strong>{agent.percent}% | {agent.completedChapters}/{agent.totalChapters}</strong><em>Readiness {agent.readinessScore ?? agent.percent}%</em></span>
              <span>{launchPadMinutes(agent.totalTimeMinutes)}</span>
              <span>{agent.averageQuizScore === null ? "Pending" : `${agent.averageQuizScore}%`}</span>
              <span>{agent.niaScore === null ? "Pending" : `${agent.niaScore}%`}</span>
              <span><strong>{agent.flaggedAnswers || 0}</strong><em>{agent.weakAreas?.[0]?.reason || "No weak area flagged"}</em></span>
              <span>{agent.lastActiveAt ? new Date(agent.lastActiveAt).toLocaleDateString() : "None"}</span>
              <span className={classNames("status-pill", agent.status === "Completed" ? "success" : agent.needsReview ? "warning" : "neutral")}>{agent.needsReview ? "Needs review" : agent.status}</span>
              <span>
                {agent.needsReview ? (
                  <button className="btn secondary small-btn" onClick={() => {
                    markAdminReviewed(agent.userEmail, agent.needsReviewChapterIds?.[0] || days[0]?.chapters?.[0]?.id);
                  }}>
                    Review
                  </button>
                ) : agent.status !== "Completed" ? (
                  <button className="btn secondary small-btn" onClick={() => {
                    const lockedDay = days.find((day) => agent.dayLocks?.[day.id]?.locked);
                    overrideAgentDay(agent.userEmail, lockedDay?.id || days[1]?.id || days[0]?.id);
                  }}>
                    Unlock
                  </button>
                ) : "Clear"}
              </span>
            </div>
          ))}
        </div>
      </section>
    );
  }

  function renderCertificate() {
    return (
      <section className="portal-page launchpad-page">
        <div className="launchpad-certificate-page">
          <div className="launchpad-certificate-seal">
            <Icon name="Award" />
          </div>
          <p className="eyebrow">NEX LaunchPad complete</p>
          <h3>{learnerDisplayName}, you are LaunchPad certified</h3>
          <p>You completed the required Nex Realty onboarding path. Your certificate is saved in Nex Central and admin has visibility into your completion record.</p>
          <div className="launchpad-certificate-metrics">
            <span><strong>{summary.percent || 100}%</strong><em>Complete</em></span>
            <span><strong>{launchPadMinutes(summary.totalTimeMinutes || 0)}</strong><em>Total time</em></span>
            <span><strong>{summary.certificateId || "Pending"}</strong><em>Certificate ID</em></span>
            <span><strong>{summary.certificateEmailSentAt ? "Emailed" : summary.certificateEmailDeliveryStatus ? "Attempted" : "Pending"}</strong><em>Certificate email</em></span>
          </div>
          <div className="launchpad-hero-actions">
            <button className="btn primary" onClick={() => setViewMode("home")}>
              <Icon name="Rocket" />
              <span>View LaunchPad Home</span>
            </button>
            {canAdmin && (
              <button className="btn secondary" onClick={() => setAdminOpen((current) => !current)}>
                <Icon name="BarChart3" />
                <span>{adminOpen ? "Hide Admin Report" : "Open Admin Report"}</span>
              </button>
            )}
          </div>
        </div>
        {adminOpen && renderAdminPanel()}
      </section>
    );
  }

  function renderHome() {
    return (
      <section className="portal-page launchpad-page">
        <div className="launchpad-home-hero">
          <div className="launchpad-home-copy">
            <p className="eyebrow">Required onboarding</p>
            <h3>Welcome to NEX LaunchPad{learnerFirstName !== "there" ? `, ${learnerFirstName}` : ""}</h3>
            <p>Your Florida-focused Nex Realty onboarding path is ready. Follow the roadmap, complete each gate, and use NIA to practice before you move forward.</p>
            <div className="launchpad-home-actions">
              <button className="btn primary" onClick={goToResume}>
                <Icon name="Rocket" />
                <span>{resumeTarget.cta || (summary.percent > 0 ? "Continue Where I Left Off" : "Start Day 1")}</span>
              </button>
              <button className="btn secondary" onClick={() => loadLaunchPad({ quiet: true })}>
                <Icon name="RefreshCw" />
                <span>Refresh Progress</span>
              </button>
              {canAdmin && (
                <button className="btn secondary" onClick={() => setAdminOpen((current) => !current)}>
                  <Icon name="BarChart3" />
                  <span>{adminOpen ? "Hide Admin Report" : "Admin Report"}</span>
                </button>
              )}
              {canAdmin && (
                <button className="btn secondary" onClick={openAdminCurriculumPreview}>
                  <Icon name="Eye" />
                  <span>Preview Curriculum</span>
                </button>
              )}
            </div>
          </div>
          <aside className="launchpad-resume-card">
            <span className={classNames("status-pill", certificateReady ? "success" : summary.percent > 0 ? "warning" : "neutral")}>{summary.status || "Not started"}</span>
            <div className="launchpad-resume-ring" style={{ "--launchpad-progress": `${summary.percent || 0}%` }}>
              <strong>{summary.percent || 0}%</strong>
              <span>complete</span>
            </div>
            <div>
              <p className="eyebrow">Next up</p>
              <h4>{resumeTarget.lessonTitle || "Day 1 Lesson 1"}</h4>
              <p>{resumeTarget.requirementLabel || "Start the first required lesson."}</p>
            </div>
          </aside>
        </div>

        <div className="launchpad-home-strip">
          <article>
            <Icon name="Clock3" />
            <span><strong>{launchPadMinutes(remainingMinutes)}</strong><em>Estimated required time remaining</em></span>
          </article>
          <article>
            <Icon name="ClipboardCheck" />
            <span><strong>{completedRequirementCount}/{totalRequirementCount || "-"}</strong><em>Requirement checkpoints complete</em></span>
          </article>
          <article>
            <Icon name="Bot" />
            <span><strong>{summary.niaScore === null ? "Pending" : `${summary.niaScore}%`}</strong><em>NIA training score</em></span>
          </article>
          <article>
            <Icon name="BookOpenCheck" />
            <span><strong>{summary.completedChapters || 0}/{summary.totalChapters || 0}</strong><em>Lessons completed</em></span>
          </article>
        </div>

        <section className="launchpad-coach-callout">
          <div className="launchpad-nia-orb">
            <Icon name="Bot" />
          </div>
          <div>
            <p className="eyebrow">NIA Training Coach</p>
            <h3>Practice before you perform with clients</h3>
            <p>NIA is built into each lesson to explain concepts, role-play conversations, quiz your comprehension, and flag risky answers for admin review.</p>
          </div>
          <button className="btn secondary" onClick={goToResume}>
            <Icon name="MessagesSquare" />
            <span>Open Current Lesson</span>
          </button>
        </section>

        <section className="launchpad-roadmap-section">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">7-day roadmap</p>
              <h3>Your required LaunchPad path</h3>
            </div>
            <span>{launchPadMinutes(summary.totalRequiredMinutes || 0)} required work</span>
          </div>
          <div className="launchpad-roadmap">
            {(roadmap.length ? roadmap : days.map((day) => ({ id: day.id, day: day.day, title: day.title, percent: 0, totalLessons: day.chapters?.length || 0, completedLessons: 0, tasksRemaining: 0, estimatedMinutes: (day.chapters || []).reduce((sum, chapter) => sum + Number(chapter.minutesRequired || 0), 0), firstActionChapterId: day.chapters?.[0]?.id }))).map((day) => {
              const locked = day.locked || summary.dayLocks?.[day.id]?.locked;
              return (
                <article key={day.id} className={classNames("launchpad-roadmap-card", locked && "locked", day.percent === 100 && "complete")}>
                  <div>
                    <span>Day {day.day}</span>
                    <strong>{dayShortTitles[day.id] || day.title}</strong>
                    <em>{locked ? "Locked" : day.status || "Not started"}</em>
                  </div>
                  <div className="launchpad-mini-progress"><span style={{ width: `${day.percent || 0}%` }} /></div>
                  <p>{day.completedLessons || 0}/{day.totalLessons || 0} lessons complete | {day.tasksRemaining || 0} tasks left</p>
                  <div className="launchpad-roadmap-footer">
                    <small>{launchPadMinutes(day.estimatedMinutes || 0)}</small>
                    <button className="btn secondary small-btn" onClick={() => openLesson(day.id, day.firstActionChapterId)} disabled={locked}>
                      <span>{day.percent ? "Continue" : "Start"}</span>
                    </button>
                  </div>
                </article>
              );
            })}
          </div>
        </section>

        {adminOpen && renderAdminPanel()}
      </section>
    );
  }

  function renderCourseSection(section) {
    if (!section) return null;
    const items = section.items || section.bullets || [];
    return (
      <details className="launchpad-course-section" key={section.id || section.title} open={section.type === "objective" || section.type === "impact"}>
        <summary>
          <span>{lpText(section.title)}</span>
          {section.type === "media" && <em>Coming soon</em>}
        </summary>
        {section.body && <p>{lpText(section.body)}</p>}
        {items.length > 0 && (
          <ul>
            {items.map((item, index) => (
              <li key={`${section.id || section.title}-${index}`}>{lpText(item.label || item)}</li>
            ))}
          </ul>
        )}
      </details>
    );
  }

  function renderLearnTab() {
    const actions = selectedChapter.actionItems || selectedChapter.checklist || [];
    return (
      <div className="launchpad-tab-panel">
        <div className="launchpad-objective-grid">
          <article>
            <p className="eyebrow">Objective</p>
            <h4>{lpText(selectedChapter.objective || selectedChapter.goal)}</h4>
          </article>
          <article>
            <p className="eyebrow">Why it matters</p>
            <p>{lpText(selectedChapter.whyItMatters || "This lesson protects client experience, documentation, compliance habits, and daily productivity.")}</p>
          </article>
        </div>
        <div className="launchpad-course-section-list">
          {lessonSections.map(renderCourseSection)}
        </div>
        <section className="launchpad-action-checklist">
          <div>
            <p className="eyebrow">Do this now</p>
            <h4>Complete these actions before moving on</h4>
          </div>
          <div className="launchpad-checklist-grid">
            {actions.map((item, index) => {
              const label = item.label || item;
              const key = `${selectedChapter.id}-${index}`;
              return (
                <label key={key} className={checkedActions[key] ? "checked" : ""}>
                  <input
                    type="checkbox"
                    checked={Boolean(checkedActions[key])}
                    onChange={(event) => setCheckedActions((current) => ({ ...current, [key]: event.target.checked }))}
                  />
                  <span>{lpText(label)}</span>
                </label>
              );
            })}
          </div>
        </section>
      </div>
    );
  }

  function renderSalesLab() {
    const lab = selectedChapter.salesLab;
    if (!lab) return null;
    const performanceStandard = lab.performanceStandard || [];
    const drills = lab.dailyDrills || [];
    const ladder = lab.conversationLadder || [];
    const objections = lab.objectionClinic || [];
    const scorecard = lab.scorecard || [];
    const proof = lab.fieldMission?.proof || [];
    return (
      <section className="launchpad-sales-lab">
        <div className="launchpad-sales-lab-head">
          <div>
            <p className="eyebrow">{lab.title || "Sales Mastery Lab"}</p>
            <h4>{lpText(lab.missionBrief?.title || "Mission")}</h4>
            <p>{lpText(lab.missionBrief?.body || "Practice this lesson like a working agent, then prove the next step.")}</p>
          </div>
          <button className="btn secondary small-btn" type="button" onClick={() => {
            const prompt = lab.niaDrill || `Run a practical sales drill for ${selectedChapter.title}.`;
            setCoachPrompt(prompt);
            setLessonTab("coach");
            submitCoachPrompt(prompt, "roleplay");
          }}>
            <Icon name="Dumbbell" />
            <span>Run Drill</span>
          </button>
        </div>

        <div className="launchpad-sales-grid">
          <article>
            <p className="eyebrow">Performance standard</p>
            <ul>{performanceStandard.map((item) => <li key={item}>{lpText(item)}</li>)}</ul>
          </article>
          <article>
            <p className="eyebrow">48-hour field mission</p>
            <p>{lpText(lab.fieldMission?.body)}</p>
            <ul>{proof.map((item) => <li key={item}>{lpText(item)}</li>)}</ul>
          </article>
        </div>

        <details className="launchpad-sales-details" open>
          <summary>Daily sales drills</summary>
          <div className="launchpad-sales-drills">
            {drills.map((drill, index) => (
              <article key={`${selectedChapter.id}-drill-${index}`}>
                <strong>{lpText(drill.title)}</strong>
                <em>{lpText(drill.reps)}</em>
                <p>{lpText(drill.instructions)}</p>
              </article>
            ))}
          </div>
        </details>

        <details className="launchpad-sales-details">
          <summary>Conversation ladder</summary>
          <div className="launchpad-conversation-ladder">
            {ladder.map((step, index) => (
              <article key={`${selectedChapter.id}-ladder-${index}`}>
                <span>{index + 1}</span>
                <div>
                  <strong>{lpText(step.stage)}</strong>
                  <p>{lpText(step.goal)}</p>
                  <blockquote>{lpText(step.line)}</blockquote>
                </div>
              </article>
            ))}
          </div>
        </details>

        <details className="launchpad-sales-details">
          <summary>Objection clinic</summary>
          <div className="launchpad-objection-clinic">
            {objections.map((item, index) => (
              <article key={`${selectedChapter.id}-objection-${index}`}>
                <strong>{lpText(item.objection)}</strong>
                <p><b>Weak:</b> {lpText(item.weakResponse)}</p>
                <p><b>Stronger:</b> {lpText(item.strongerResponse)}</p>
                <small>{lpText(item.coachNotes)}</small>
              </article>
            ))}
          </div>
        </details>

        <details className="launchpad-sales-details">
          <summary>Readiness scorecard</summary>
          <div className="launchpad-scorecard-list">
            {scorecard.map((item) => (
              <span key={item}><Icon name="CheckCircle2" size={14} />{lpText(item)}</span>
            ))}
          </div>
        </details>
      </section>
    );
  }

  function renderPracticeTab() {
    const practice = selectedChapter.practiceScenario || {};
    return (
      <div className="launchpad-tab-panel">
        <section className="launchpad-practice-grid">
          <article className="launchpad-practice-card accent">
            <p className="eyebrow">Real-world example</p>
            <h4>{lpText(selectedChapter.examples?.[0] || selectedChapter.microCoaching?.example || "Use a real Florida consumer situation and document the next step.")}</h4>
          </article>
          <article className="launchpad-practice-card">
            <p className="eyebrow">What would you do?</p>
            <h4>{lpText(practice.prompt || selectedChapter.scenarioPrompt)}</h4>
            <p>{lpText(practice.rolePlayPrompt || selectedChapter.rolePlayPrompt || "Use NIA to role-play your answer before submitting your checkpoint.")}</p>
            <button className="btn secondary small-btn" onClick={() => promptNia("roleplay")}>
              <Icon name="MessagesSquare" />
              <span>Role-play this</span>
            </button>
          </article>
        </section>
        {renderSalesLab()}
        <section className="launchpad-decision-tree">
          <div>
            <p className="eyebrow">Decision path</p>
            <h4>Work through the judgment checks</h4>
          </div>
          {(selectedChapter.decisionTree || []).map((node, index) => (
            <article key={`${selectedChapter.id}-decision-${index}`}>
              <span>{index + 1}</span>
              <div>
                <strong>{lpText(node.question)}</strong>
                <p><b>If yes:</b> {lpText(node.yes)}</p>
                <p><b>If no:</b> {lpText(node.no)}</p>
              </div>
            </article>
          ))}
        </section>
        <section className="launchpad-script-practice">
          <div>
            <p className="eyebrow">Script practice</p>
            <h4>{lpText(selectedChapter.scriptPractice?.prompt || "Improve this client-facing script.")}</h4>
          </div>
          <textarea rows={5} value={scriptDraft} onChange={(event) => setScriptDraft(event.target.value)} placeholder="Write or improve your client script here..." />
          <div className="launchpad-confidence-check">
            <label>
              <span>Confidence check: {confidenceLevel}/5</span>
              <input type="range" min="1" max="5" value={confidenceLevel} onChange={(event) => setConfidenceLevel(Number(event.target.value))} />
            </label>
            <button className="btn secondary small-btn" onClick={() => {
              const prompt = `Review and improve this client script for ${selectedChapter.title}:\n\n${scriptDraft}`;
              setCoachPrompt(prompt);
              setLessonTab("coach");
              submitCoachPrompt(prompt, "improve");
            }}>
              <Icon name="Wand2" />
              <span>Ask NIA to improve it</span>
            </button>
          </div>
        </section>
        {renderSimulator()}
      </div>
    );
  }

  function renderQuizTab() {
    return (
      <section className="launchpad-quiz-card launchpad-tab-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Knowledge check</p>
            <h3>Pass with {payload.curriculum?.passingScore || 80}% or higher</h3>
          </div>
          {typeof chapterProgress.quizScore === "number" && <span className={classNames("status-pill", chapterProgress.quizPassed ? "success" : "warning")}>{chapterProgress.quizScore}%</span>}
        </div>
        {chapterProgress.quizSubmittedAt && !chapterProgress.quizPassed && (
          <div className="launchpad-inline-alert warning">Quiz failed. Review the explanations, update your answers, and submit again.</div>
        )}
        {(selectedChapter.quiz || []).map((question) => (
          <div className="launchpad-question" key={question.id}>
            <strong>{lpText(question.question)}</strong>
            <div className="launchpad-options">
              {(question.options || []).map((option, index) => (
                <label key={option}>
                  <input
                    type="radio"
                    name={`${selectedChapter.id}-${question.id}`}
                    checked={Number(quizAnswers[question.id]) === index}
                    onChange={() => setQuizAnswers((current) => ({ ...current, [question.id]: index }))}
                  />
                  <span>{lpText(option)}</span>
                </label>
              ))}
            </div>
            {chapterProgress.quizSubmittedAt && <p>{lpText(question.explanation)}</p>}
          </div>
        ))}
        <button className="btn secondary" disabled={busyAction === "quiz"} onClick={() => updateChapter("quiz", { answers: quizAnswers }, chapterProgress.quizPassed ? "Quiz updated." : "Quiz submitted.")}>
          <Icon name="ClipboardCheck" />
          <span>{busyAction === "quiz" ? "Submitting..." : "Submit Quiz"}</span>
        </button>
      </section>
    );
  }

  function renderHomeworkTab() {
    return (
      <section className="launchpad-homework-card launchpad-tab-panel">
        <div>
          <p className="eyebrow">Homework proof</p>
          <h3>{lpText(selectedChapter.homeworkPrompt)}</h3>
          <p>Submit a real answer or proof summary. Short, vague, or risky responses may be marked for admin review.</p>
        </div>
        {chapterProgress.needsReview && <div className="launchpad-inline-alert warning">Homework or NIA response needs admin review.</div>}
        <textarea value={homeworkText} onChange={(event) => setHomeworkText(event.target.value)} placeholder="Type your homework response here..." rows={7} />
        <button className="btn secondary" disabled={busyAction === "homework"} onClick={() => updateChapter("homework", { homeworkText }, "Homework submitted.")}>
          <Icon name="Send" />
          <span>{busyAction === "homework" ? "Saving..." : "Submit Homework"}</span>
        </button>
      </section>
    );
  }

  function renderCoachTab() {
    return (
      <section className="launchpad-coach-card launchpad-tab-panel">
        <div className="launchpad-coach-topbar">
          <div>
            <p className="eyebrow">NIA Training Coach</p>
            <h3>Ask, role-play, or review your answer</h3>
          </div>
          <button className="btn secondary small-btn" onClick={closeNiaCoach} type="button">
            <Icon name="X" />
            <span>Close NIA</span>
          </button>
        </div>
        <div className="launchpad-nia-breakdown compact">
          <div className="launchpad-nia-orb">
            <Icon name="Bot" />
          </div>
          <div>
            <p className="eyebrow">{selectedChapter.microCoaching?.durationSeconds || 45}-second NIA Breakdown</p>
            <h3>{selectedChapter.microCoaching?.title || `NIA Breakdown: ${selectedChapter.title}`}</h3>
            <p>{lpText(selectedChapter.microCoaching?.explanation || "NIA will explain this lesson in plain English and help you practice the real workflow.")}</p>
            {selectedChapter.microCoaching?.script && (
              <blockquote>
                <strong>Client-facing script</strong>
                <span>{lpText(selectedChapter.microCoaching.script)}</span>
              </blockquote>
            )}
          </div>
        </div>
        <div className="launchpad-coach-mode-grid">
          {(coachModes.length ? coachModes : [
            { id: "simple", label: "Explain this simply", icon: "Sparkles" },
            { id: "example", label: "Give me a real example", icon: "MapPin" },
            { id: "roleplay", label: "Role-play with me", icon: "MessagesSquare" },
            { id: "quiz", label: "Quiz me", icon: "BadgeHelp" }
          ]).map((mode) => (
            <button key={mode.id} className="btn secondary small-btn" onClick={() => promptNia(mode.id)}>
              <Icon name={mode.icon || "Bot"} />
              <span>{lpText(mode.label)}</span>
            </button>
          ))}
          <button className="btn secondary small-btn" onClick={readNiaBreakdown}>
            <Icon name="Volume2" />
            <span>Read aloud</span>
          </button>
        </div>
        <div className="launchpad-readiness-rubric">
          {(selectedChapter.readinessRubric || []).map((item) => (
            <span key={item.key} title={lpText(item.description)}>{lpText(item.label)}</span>
          ))}
        </div>
        <textarea value={coachPrompt} onChange={(event) => setCoachPrompt(event.target.value)} placeholder="Ask NIA to role-play, quiz you, review an answer, or improve your client script..." rows={5} />
        <div className="launchpad-coach-actions">
          <button className="btn secondary" onClick={startVoiceResponse}>
            <Icon name="Mic" />
            <span>Speak Answer</span>
          </button>
          <button className="btn primary" disabled={busyAction === "coach"} onClick={() => submitCoachPrompt()}>
            <Icon name="Bot" />
            <span>{busyAction === "coach" ? "NIA reviewing..." : "Ask NIA Coach"}</span>
          </button>
        </div>
        <div className="launchpad-coach-feed">
          {busyAction === "coach" && (
            <article className="launchpad-coach-loading">
              <span><Icon name="LoaderCircle" className="spin" /> NIA is reviewing your training response...</span>
              <p>Keep this panel open. Your answer will appear here when the checkpoint is ready.</p>
            </article>
          )}
          {coachInteractions.length === 0 && busyAction !== "coach" ? (
            <p>No NIA coaching yet for this lesson. Use a coaching mode or type your scenario answer.</p>
          ) : (
            coachInteractions.slice(0, 3).map((item) => (
              <article key={item.id}>
                <span>{item.feedback?.headline || "NIA feedback"} {Number.isFinite(item.feedback?.score) ? `| ${item.feedback.score}%` : ""}</span>
                <p>{lpText(item.feedback?.summary)}</p>
                {item.feedback?.coachingPoints?.length > 0 && (
                  <ul>
                    {item.feedback.coachingPoints.map((point) => <li key={point}>{lpText(point)}</li>)}
                  </ul>
                )}
                {item.feedback?.strongerSampleAnswer && (
                  <blockquote>
                    <strong>Stronger sample answer</strong>
                    <span>{lpText(item.feedback.strongerSampleAnswer)}</span>
                  </blockquote>
                )}
                {item.feedback?.rubric && (
                  <div className="launchpad-rubric">
                    {Object.entries(item.feedback.rubric).map(([key, value]) => (
                      <em key={key}>{key.replace(/([A-Z])/g, " $1")}: {value}%</em>
                    ))}
                  </div>
                )}
                {item.feedback?.retryGuidance && <p>{lpText(item.feedback.retryGuidance)}</p>}
                {item.feedback?.needsReview && <em>Flagged for admin review</em>}
              </article>
            ))
          )}
        </div>
        {coachInteractions.length > 0 && (
          <div className="launchpad-coach-continue">
            <button className="btn primary" onClick={continueLessonStep} type="button">
              <Icon name="ArrowRight" />
              <span>Continue learning</span>
            </button>
            <button className="btn secondary" onClick={closeNiaCoach} type="button">Close NIA</button>
          </div>
        )}
      </section>
    );
  }

  function renderLessonSidePanel() {
    return (
      <aside className="launchpad-side-panel">
        <div className="launchpad-side-panel-head">
          <div>
            <p className="eyebrow">Lesson resources</p>
            <strong>Optional support material</strong>
          </div>
          <button className="icon-btn" onClick={() => setResourcesOpen(false)} aria-label="Close resources" type="button"><Icon name="X" /></button>
        </div>
        <details open>
          <summary>Resources</summary>
          <section>{(selectedChapter.resources || []).map((item) => <span key={item}>{lpText(item)}</span>)}</section>
        </details>
        <details>
          <summary>Scripts & templates</summary>
          <section>{(selectedChapter.templates || []).map((item) => <span key={item}>{lpText(item)}</span>)}</section>
        </details>
        {selectedChapter.salesLab && (
          <details>
            <summary>Sales Mastery Lab</summary>
            <section>
              {(selectedChapter.salesLab.performanceStandard || []).map((item) => <span key={item}>{lpText(item)}</span>)}
              {(selectedChapter.salesLab.scorecard || []).map((item) => <span key={item}>Scorecard: {lpText(item)}</span>)}
            </section>
          </details>
        )}
        <details className="warning">
          <summary>Escalation rules</summary>
          <section>{(selectedChapter.escalationRules || []).map((item) => <span key={item}>{lpText(item)}</span>)}</section>
        </details>
        <details>
          <summary>Completion gates</summary>
          <section>
            {(selectedChapter.completionGates || []).map((item) => (
              <span key={item.key}>{lpText(item.label)}</span>
            ))}
          </section>
        </details>
        <details>
          <summary>Admin review flags</summary>
          <section>{(selectedChapter.adminReviewFlags || []).map((item) => <span key={item}>{lpText(item)}</span>)}</section>
        </details>
        {selectedChapter.adminNotes && (
          <details>
            <summary>Admin notes</summary>
            <section><span>{lpText(selectedChapter.adminNotes)}</span></section>
          </details>
        )}
      </aside>
    );
  }

  function renderLessonWorkspace() {
    const tabRenderers = {
      learn: renderLearnTab,
      practice: renderPracticeTab,
      quiz: renderQuizTab,
      homework: renderHomeworkTab,
      coach: renderCoachTab
    };
    const renderActiveTab = tabRenderers[lessonTab] || renderLearnTab;
    const nextActionText = selectedState.state === "complete"
      ? "Lesson complete. Continue to the next lesson when ready."
      : nextRequirement
        ? `Next required gate: ${lpText(nextRequirement.label)}`
        : "All gates are ready. Complete this lesson.";
    return (
      <section className="launchpad-course-workspace">
        <div className="launchpad-focus-toolbar">
          <span><Icon name="Focus" /> Focus Mode</span>
          <button className="btn secondary small-btn" type="button" onClick={() => setResourcesOpen((current) => !current)}>
            <Icon name="FolderOpen" />
            <span>{resourcesOpen ? "Hide Resources" : "Open Resources"}</span>
          </button>
        </div>
        <div className="launchpad-guided-path">
          <div>
            <p className="eyebrow">Guided mastery path</p>
            <strong>Step {currentStepNumber} of {lessonTabs.length}: {currentStepLabel}</strong>
            <span>{nextActionText}</span>
          </div>
          <div className="launchpad-guided-progress">
            <span>{launchPadMinutes(chapterProgress.timeSpentMinutes || 0)} logged</span>
            <em>{remainingLessonMinutes ? `${launchPadMinutes(remainingLessonMinutes)} guided work remaining` : "Time gate met"}</em>
          </div>
        </div>
        <div className="launchpad-workspace-tabs">
          {lessonTabs.map((tab) => {
            const status = lessonTabStatus(tab.id);
            return (
              <button key={tab.id} className={classNames(lessonTab === tab.id && "active", status.done && "done", status.required && "required")} onClick={() => setLessonTab(tab.id)}>
                <Icon name={tab.icon} />
                <span>{tab.label}</span>
                {status.done ? <Icon name="CheckCircle2" className="launchpad-step-status" /> : status.required ? <em className="launchpad-step-status">Next</em> : null}
              </button>
            );
          })}
        </div>
        <div className={classNames("launchpad-workspace-grid", !resourcesOpen && "focus-mode")}>
          <div className="launchpad-course-main">
            {renderActiveTab()}
          </div>
          {resourcesOpen && renderLessonSidePanel()}
        </div>
      </section>
    );
  }

  function renderLessonFlowControls() {
    const nextEntryLocked = isLessonEntryLocked(nextLessonEntry);
    const nextLessonAllowed = isCurriculumPreview || selectedState.state === "complete";
    const continueLabel = selectedState.state === "complete"
      ? "Go to Next Lesson"
      : lessonTab === "quiz" && !chapterProgress.quizPassed
        ? "Submit Quiz"
        : lessonTab === "homework" && (!chapterProgress.homeworkSubmittedAt || String(homeworkText || "").trim().length < 25)
          ? "Submit Homework"
          : lessonTab === "coach"
            ? "Finish Lesson"
            : "Save & Continue";
    return (
      <nav className="launchpad-flow-controls" aria-label="Lesson navigation">
        <button className="btn secondary" type="button" disabled={!previousLessonEntry} onClick={() => openLessonEntry(previousLessonEntry)}>
          <Icon name="ChevronLeft" />
          <span>Previous Lesson</span>
        </button>
        <button className="btn secondary" type="button" onClick={() => promptNia("roleplay")}>
          <Icon name="Bot" />
          <span>Role-play with NIA</span>
        </button>
        <button className="btn primary" type="button" disabled={Boolean(busyAction)} onClick={continueLessonStep}>
          <Icon name="ArrowRight" />
          <span>{busyAction ? "Saving..." : continueLabel}</span>
        </button>
        <button className="btn secondary" type="button" disabled={!nextLessonEntry || nextEntryLocked || !nextLessonAllowed} onClick={() => openLessonEntry(nextLessonEntry)}>
          <span>Next Lesson</span>
          <Icon name="ChevronRight" />
        </button>
      </nav>
    );
  }

  function renderSimulator() {
    if (!selectedChapter?.simulator) return null;
    const currentStep = simulatorSteps[simulatorStep] || simulatorSteps[0];
    return (
      <section className="launchpad-simulator-card">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Contract / form simulator</p>
            <h3>{selectedChapter.simulator.title}</h3>
          </div>
          {Number.isFinite(chapterProgress.simulatorScore) && (
            <span className={classNames("status-pill", Number(chapterProgress.simulatorScore) >= 70 ? "success" : "warning")}>{chapterProgress.simulatorScore}%</span>
          )}
        </div>
        <div className="launchpad-simulator-steps">
          {simulatorSteps.map((step, index) => (
            <button key={step.key} className={classNames(index === simulatorStep && "active", index < simulatorStep && "done")} onClick={() => setSimulatorStep(index)}>
              <span>{index + 1}</span>
              {step.label}
            </button>
          ))}
        </div>
        {currentStep.key === "scenario" && (
          <div className="launchpad-simulator-stage">
            <p className="eyebrow">Scenario</p>
            <h4>{lpText(selectedChapter.simulator.scenario)}</h4>
            <p>Read the situation like a real Florida training file. You are practicing judgment, documentation, and when to escalate to Nex broker/admin review.</p>
          </div>
        )}
        {currentStep.key === "form" && (
          <div className="launchpad-simulator-stage">
            <p className="eyebrow">Select correct form or agreement</p>
            <h4>Which document or agreement would you start with?</h4>
            <select value={simulatorAnswers.formSelection || ""} onChange={(event) => updateSimulatorAnswer("formSelection", event.target.value)}>
              <option value="">Choose training answer...</option>
              <option>Buyer broker agreement / buyer representation intake</option>
              <option>Florida AS IS purchase contract training worksheet</option>
              <option>Listing agreement readiness worksheet</option>
              <option>Addendum, rider, or broker review required</option>
            </select>
          </div>
        )}
        {currentStep.key === "fields" && (
          <div className="launchpad-simulator-fields">
            {selectedSimulatorFields.map((field) => (
              <label key={field.id}>
                <span>{lpText(field.label)}</span>
                <textarea
                  rows={3}
                  value={simulatorAnswers[field.id] || ""}
                  onChange={(event) => updateSimulatorAnswer(field.id, event.target.value)}
                  placeholder="Enter mock training answer..."
                />
              </label>
            ))}
          </div>
        )}
        {currentStep.key === "reasoning" && (
          <div className="launchpad-simulator-stage">
            <p className="eyebrow">Explain your reasoning</p>
            <h4>Why is this the right path, and what would you escalate?</h4>
            <textarea rows={5} value={simulatorAnswers.reasoning || ""} onChange={(event) => updateSimulatorAnswer("reasoning", event.target.value)} placeholder="Explain your practical next step, risks, and escalation plan..." />
          </div>
        )}
        {currentStep.key === "review" && (
          <div className="launchpad-simulator-stage">
            <p className="eyebrow">Review and submit</p>
            <h4>Check for missing or risky fields before submitting.</h4>
            <ul>
              {selectedSimulatorFields.map((field) => (
                <li key={field.id}>{lpText(field.label)}: {String(simulatorAnswers[field.id] || "").trim() ? "Answered" : "Missing"}</li>
              ))}
            </ul>
            <div className="launchpad-simulator-note">
              <Icon name="ShieldAlert" />
              <span>Training simulator only. Use broker-approved forms and escalate unclear contract or compliance questions to Nex broker/admin review.</span>
            </div>
          </div>
        )}
        <div className="launchpad-action-row">
          <button className="btn secondary" disabled={simulatorStep === 0} onClick={() => setSimulatorStep((current) => Math.max(0, current - 1))}>
            <Icon name="ArrowLeft" />
            <span>Back</span>
          </button>
          {simulatorStep < simulatorSteps.length - 1 ? (
            <button className="btn secondary" onClick={() => setSimulatorStep((current) => Math.min(simulatorSteps.length - 1, current + 1))}>
              <Icon name="ArrowRight" />
              <span>Next Step</span>
            </button>
          ) : (
            <button className="btn primary" disabled={busyAction === "simulator"} onClick={submitSimulator}>
              <Icon name="FileCheck2" />
              <span>{busyAction === "simulator" ? "Scoring..." : "Submit Simulator"}</span>
            </button>
          )}
        </div>
      </section>
    );
  }

  function renderLessonPlayer() {
    return (
      <section className="portal-page launchpad-page launchpad-player-page">
        <div className="launchpad-player-topbar">
          <button className="btn secondary small-btn" onClick={() => setViewMode("home")}>
            <Icon name="ArrowLeft" />
            <span>LaunchPad Home</span>
          </button>
          <button className="btn secondary small-btn launchpad-roadmap-toggle" onClick={() => setRoadmapOpen((current) => !current)}>
            <Icon name="PanelLeftOpen" />
            <span>Course Roadmap</span>
          </button>
          <div className="launchpad-day-stepper">
            {days.map((day) => {
              const locked = summary.dayLocks?.[day.id]?.locked;
              return (
                <button
                  key={day.id}
                  className={classNames(selectedDay?.id === day.id && "active", locked && "locked", summary.dayStatus?.[day.id] === "Completed" && "complete")}
                  onClick={() => openLesson(day.id, (payload.roadmap || []).find((item) => item.id === day.id)?.firstActionChapterId || day.chapters?.[0]?.id)}
                >
                  <span>{day.day}</span>
                  <em>{dayShortTitles[day.id]?.split(" ")[0] || `Day ${day.day}`}</em>
                </button>
              );
            })}
          </div>
          {isCurriculumPreview && (
            <button className="btn secondary small-btn" onClick={exitAdminCurriculumPreview}>
              <Icon name="X" />
              <span>Exit Preview</span>
            </button>
          )}
        </div>

        {isCurriculumPreview && (
          <div className="launchpad-preview-banner">
            <Icon name="Eye" />
            <div>
              <strong>Admin Preview</strong>
              <span>Preview only. Locked lessons remain locked for agents, and progress buttons do not save while previewing.</span>
            </div>
            <div className="launchpad-preview-selectors">
              <label>
                <span>Day</span>
                <select value={selectedDay?.id || ""} onChange={(event) => openLesson(event.target.value, days.find((day) => day.id === event.target.value)?.chapters?.[0]?.id)}>
                  {days.map((day) => (
                    <option key={day.id} value={day.id}>Day {day.day}: {dayShortTitles[day.id] || day.title}</option>
                  ))}
                </select>
              </label>
              <label>
                <span>Lesson</span>
                <select value={selectedChapter?.id || ""} onChange={(event) => openLesson(selectedDay?.id, event.target.value)}>
                  {chapters.map((chapter, index) => (
                    <option key={chapter.id} value={chapter.id}>{index + 1}. {chapter.title}</option>
                  ))}
                </select>
              </label>
            </div>
          </div>
        )}

        <div className="launchpad-player-shell">
          <aside className={classNames("launchpad-player-sidebar", roadmapOpen && "open")}>
            <p className="eyebrow">Day {selectedDay?.day}</p>
            <h3>{dayShortTitles[selectedDay?.id] || selectedDay?.title}</h3>
            <p>{selectedDay?.focus}</p>
            {isCurriculumPreview && selectedDayLockedForAgents && (
              <div className="launchpad-inline-alert warning">Locked for agents | Admin preview only</div>
            )}
            <div className="launchpad-lesson-rail">
              {chapters.map((chapter, index) => {
                const item = payload.progress?.chapters?.[chapter.id] || {};
                const state = payload.chapterStates?.[chapter.id] || {};
                const requirements = state.requirements || [];
                const metRequirements = requirements.filter((requirement) => requirement.met).length;
                const isActive = selectedChapter.id === chapter.id;
                const isComplete = state.state === "complete";
                const completionPercent = requirements.length ? Math.round((metRequirements / requirements.length) * 100) : isComplete ? 100 : 0;
                const showDetails = isActive || !["complete", "locked"].includes(state.state);
                return (
                  <button
                    key={chapter.id}
                    type="button"
                    className={classNames("launchpad-rail-item", isActive && "active", completionPercent > 0 && "started", isComplete && "complete", state.state === "locked" && "locked", state.state === "needs_review" && "review")}
                    style={{ "--lesson-progress": `${completionPercent}%` }}
                    onClick={() => {
                      setSelectedChapterId(chapter.id);
                      setRoadmapOpen(false);
                    }}
                  >
                    <span className="launchpad-rail-number">{isComplete ? <Icon name="Check" size={14} /> : index + 1}</span>
                    <div>
                      {isActive && <small className="launchpad-current-label">Currently viewing</small>}
                      {isComplete && <small className="launchpad-complete-label"><Icon name="CheckCircle2" size={13} /> Complete</small>}
                      <strong>{chapter.title}</strong>
                      <em>{state.label || item.status || "Not started"} | {launchPadMinutes(chapter.minutesRequired)} lesson</em>
                      {completionPercent > 0 && !isComplete && <small className="launchpad-progress-label">{completionPercent}% complete</small>}
                      {showDetails && (
                        <>
                          <small>{metRequirements}/{requirements.length || 0} gates complete</small>
                          <small>Next: {lpText(state.nextRequirementLabel || "Start lesson")}</small>
                        </>
                      )}
                    </div>
                  </button>
                );
              })}
            </div>
          </aside>

          <article className="launchpad-main-stage">
            {selectedDayBlocked ? (
              <div className="launchpad-locked-state">
                <Icon name="Lock" />
                <h3>This day is locked</h3>
                <p>{selectedDayLock.reason || "Complete the previous LaunchPad day before starting this day."}</p>
                <button className="btn secondary" onClick={() => setViewMode("home")}>Back to roadmap</button>
              </div>
            ) : (
              <>
                <header className="launchpad-lesson-header">
                  <div>
                    <p className="eyebrow">Day {selectedDay?.day} | Lesson {selectedDayLessonIndex + 1} of {chapters.length || 1}</p>
                    <h3>{selectedChapter.title}</h3>
                    <p>{lpText(selectedChapter.goal || selectedChapter.lesson)}</p>
                  </div>
                  <span className={classNames("status-pill", selectedState.state === "complete" ? "success" : selectedState.state === "needs_review" ? "warning" : "neutral")}>
                    {isCurriculumPreview ? "Admin Preview" : selectedState.label || chapterProgress.status || "Not started"}
                  </span>
                </header>

                {isCurriculumPreview && (
                  <div className="launchpad-inline-alert">
                    Admin preview only. This lesson is {selectedDayLockedForAgents ? "locked for agents" : "live for available agent progress"} and any progress actions are disabled in preview mode.
                  </div>
                )}

                <div className="launchpad-requirement-panel">
                  <div>
                    <p className="eyebrow">Completion gates</p>
                    <h4>{nextRequirement ? lpText(nextRequirement.label) : "Ready to complete"}</h4>
                  </div>
                  <div className="launchpad-requirements">
                    {chapterRequirements.map((item) => (
                      <span key={item.key} className={item.met ? "met" : ""}>
                        <Icon name={item.met ? "CheckCircle2" : "Circle"} />
                        {lpText(item.label)}
                      </span>
                    ))}
                  </div>
                </div>

                {renderLessonWorkspace()}
                {renderLessonFlowControls()}

                {false && (
                  <>
                <details className="launchpad-details" open>
                  <summary>Lesson briefing</summary>
                  <div className="launchpad-section-grid">
                    <section className="launchpad-lesson-card">
                      <p className="eyebrow">Learn</p>
                      <h4>{selectedChapter.lesson}</h4>
                      <ul>
                        {(selectedChapter.checklist || []).map((item) => <li key={item}>{item}</li>)}
                      </ul>
                    </section>
                    <section className="launchpad-lesson-card">
                      <p className="eyebrow">Real-life examples</p>
                      <ul>
                        {(selectedChapter.examples || []).map((example) => <li key={example}>{example}</li>)}
                      </ul>
                    </section>
                    <section className="launchpad-lesson-card accent">
                      <p className="eyebrow">Scenario question</p>
                      <h4>{selectedChapter.scenarioPrompt}</h4>
                      <p>{selectedChapter.rolePlayPrompt || "Use the NIA Training Coach below to practice a response and get feedback."}</p>
                    </section>
                  </div>
                </details>

                <section className="launchpad-nia-breakdown">
                  <div className="launchpad-nia-orb">
                    <Icon name="Bot" />
                  </div>
                  <div>
                    <p className="eyebrow">{selectedChapter.microCoaching?.durationSeconds || 45}-second NIA Breakdown</p>
                    <h3>{selectedChapter.microCoaching?.title || `NIA Breakdown: ${selectedChapter.title}`}</h3>
                    <p>{selectedChapter.microCoaching?.explanation || "NIA will explain this lesson in plain English and help you practice the real workflow."}</p>
                    <ul>
                      {(selectedChapter.microCoaching?.takeaways || []).map((takeaway) => <li key={takeaway}>{takeaway}</li>)}
                    </ul>
                    {selectedChapter.microCoaching?.script && (
                      <blockquote>
                        <strong>Client-facing script</strong>
                        <span>{selectedChapter.microCoaching.script}</span>
                      </blockquote>
                    )}
                    <div className="launchpad-micro-actions">
                      <button className="btn secondary small-btn" onClick={() => promptNia("simple")}><Icon name="Sparkles" /><span>Explain simply</span></button>
                      <button className="btn secondary small-btn" onClick={() => promptNia("example")}><Icon name="MapPin" /><span>Real example</span></button>
                      <button className="btn secondary small-btn" onClick={() => promptNia("roleplay")}><Icon name="MessagesSquare" /><span>Role-play</span></button>
                      <button className="btn secondary small-btn" onClick={() => promptNia("quiz")}><Icon name="BadgeHelp" /><span>Quiz me</span></button>
                      <button className="btn secondary small-btn" onClick={readNiaBreakdown}><Icon name="Volume2" /><span>Read aloud</span></button>
                    </div>
                  </div>
                </section>

                <div className="launchpad-task-grid">
                  <section className="launchpad-quiz-card">
                    <div className="panel-heading">
                      <div>
                        <p className="eyebrow">Quiz</p>
                        <h3>Pass with {payload.curriculum?.passingScore || 80}% or higher</h3>
                      </div>
                      {typeof chapterProgress.quizScore === "number" && <span className={classNames("status-pill", chapterProgress.quizPassed ? "success" : "warning")}>{chapterProgress.quizScore}%</span>}
                    </div>
                    {chapterProgress.quizSubmittedAt && !chapterProgress.quizPassed && (
                      <div className="launchpad-inline-alert warning">Quiz failed. Review the explanations, update your answers, and submit again.</div>
                    )}
                    {(selectedChapter.quiz || []).map((question) => (
                      <div className="launchpad-question" key={question.id}>
                        <strong>{question.question}</strong>
                        <div className="launchpad-options">
                          {(question.options || []).map((option, index) => (
                            <label key={option}>
                              <input
                                type="radio"
                                name={`${selectedChapter.id}-${question.id}`}
                                checked={Number(quizAnswers[question.id]) === index}
                                onChange={() => setQuizAnswers((current) => ({ ...current, [question.id]: index }))}
                              />
                              <span>{option}</span>
                            </label>
                          ))}
                        </div>
                        {chapterProgress.quizSubmittedAt && <p>{question.explanation}</p>}
                      </div>
                    ))}
                    <button className="btn secondary" disabled={busyAction === "quiz"} onClick={() => updateChapter("quiz", { answers: quizAnswers }, chapterProgress.quizPassed ? "Quiz updated." : "Quiz submitted.")}>
                      <Icon name="ClipboardCheck" />
                      <span>{busyAction === "quiz" ? "Submitting..." : "Submit Quiz"}</span>
                    </button>
                  </section>

                  <section className="launchpad-homework-card">
                    <div>
                      <p className="eyebrow">Homework</p>
                      <h3>{selectedChapter.homeworkPrompt}</h3>
                      <p>Submit a real answer. Short or low-quality responses may be marked for admin review.</p>
                    </div>
                    {chapterProgress.needsReview && <div className="launchpad-inline-alert warning">Homework or NIA response needs admin review.</div>}
                    <textarea value={homeworkText} onChange={(event) => setHomeworkText(event.target.value)} placeholder="Type your homework response here..." rows={5} />
                    <button className="btn secondary" disabled={busyAction === "homework"} onClick={() => updateChapter("homework", { homeworkText }, "Homework submitted.")}>
                      <Icon name="Send" />
                      <span>{busyAction === "homework" ? "Saving..." : "Submit Homework"}</span>
                    </button>
                  </section>
                </div>

                {renderSimulator()}

                <section className="launchpad-coach-card">
                  <div>
                    <p className="eyebrow">NIA Training Coach</p>
                    <h3>Ask, role-play, or submit your scenario answer</h3>
                    <p>NIA can ask comprehension questions, role-play conversations, review typed or spoken answers, score your response, and flag weak or risky answers for admin review.</p>
                  </div>
                  <textarea value={coachPrompt} onChange={(event) => setCoachPrompt(event.target.value)} placeholder="Ask NIA to role-play, or type your scenario response for feedback..." rows={4} />
                  <div className="launchpad-coach-actions">
                    <button className="btn secondary" onClick={startVoiceResponse}>
                      <Icon name="Mic" />
                      <span>Speak Answer</span>
                    </button>
                    <button className="btn primary" disabled={busyAction === "coach"} onClick={submitCoachPrompt}>
                      <Icon name="Bot" />
                      <span>{busyAction === "coach" ? "NIA reviewing..." : "Ask NIA Coach"}</span>
                    </button>
                  </div>
                  <div className="launchpad-coach-feed">
                    {coachInteractions.length === 0 ? (
                      <p>No NIA coaching yet for this lesson. Use one of the prompts above or type your scenario answer.</p>
                    ) : (
                      coachInteractions.slice(0, 3).map((item) => (
                        <article key={item.id}>
                          <span>{item.feedback?.headline || "NIA feedback"} {Number.isFinite(item.feedback?.score) ? `| ${item.feedback.score}%` : ""}</span>
                          <p>{item.feedback?.summary}</p>
                          {item.feedback?.rubric && (
                            <div className="launchpad-rubric">
                              {Object.entries(item.feedback.rubric).map(([key, value]) => (
                                <em key={key}>{key.replace(/([A-Z])/g, " $1")}: {value}%</em>
                              ))}
                            </div>
                          )}
                          {item.feedback?.needsReview && <em>Flagged for admin review</em>}
                        </article>
                      ))
                    )}
                  </div>
                </section>

                  </>
                )}

                <div className="launchpad-sticky-complete launchpad-legacy-complete" hidden>
                  <div>
                    <strong>{nextRequirement ? `Next gate: ${nextRequirement.label}` : "All requirements met"}</strong>
                    <span>{launchPadMinutes(chapterProgress.timeSpentMinutes || 0)} logged of {launchPadMinutes(selectedChapter.minutesRequired || 0)} required</span>
                  </div>
                  <div className="launchpad-action-row">
                    <button className="btn secondary" disabled={busyAction === "time"} onClick={() => updateChapter("time", { minutes: 15 }, "15 training minutes logged.")}>
                      <Icon name="Timer" />
                      <span>{busyAction === "time" ? "Logging..." : "Log 15 Minutes"}</span>
                    </button>
                    <button className="btn primary" disabled={!canCompleteChapter || busyAction === "complete"} onClick={() => updateChapter("complete", {}, "Lesson completion saved.")}>
                      <Icon name="CheckCheck" />
                      <span>{busyAction === "complete" ? "Checking..." : "Complete Lesson"}</span>
                    </button>
                  </div>
                </div>
              </>
            )}
          </article>
        </div>
      </section>
    );
  }

  if (viewMode === "certificate") return renderCertificate();
  if (viewMode === "lesson") return renderLessonPlayer();
  return renderHome();
}

function TrainingCenter({ resources, role, setTrainingResources, setToast }) {
  const [category, setCategory] = useState("All");
  const [draft, setDraft] = useState({ title: "", category: "Nex Level Learning", type: "Video", url: "", description: "", featured: false, isNew: true });
  const [bulkVideoUrls, setBulkVideoUrls] = useState("");
  const [activeResourceId, setActiveResourceId] = useState("");
  const canManage = isAdminRole(role);
  const filtered = category === "All" ? resources : resources.filter((item) => normalizeTrainingCategory(item.category) === category);
  const embeddableResources = filtered.filter(isEmbeddableTrainingResource);
  const activeResource =
    resources.find((item) => item.id === activeResourceId) ||
    embeddableResources[0] ||
    resources.find(isEmbeddableTrainingResource);
  const activeEmbedUrl = activeResource ? getTrainingEmbedUrl(trainingResourceUrl(activeResource)) : "";

  useEffect(() => {
    if (!activeResourceId && embeddableResources[0]?.id) {
      setActiveResourceId(embeddableResources[0].id);
    }
  }, [activeResourceId, embeddableResources]);

  async function addResource() {
    if (!draft.title.trim()) return;
    try {
      const saved = await API.request("/api/training-resources", { method: "POST", body: JSON.stringify(draft) });
      setTrainingResources((current) => [saved, ...current]);
      if (getTrainingEmbedUrl(trainingResourceUrl(saved))) setActiveResourceId(saved.id);
      setDraft({ title: "", category: "Nex Level Learning", type: "Video", url: "", description: "", featured: false, isNew: true });
      setToast("Training added.");
    } catch (error) {
      setToast(error.message || "Could not add training.");
    }
  }

  async function importBulkVideos() {
    const parsed = bulkVideoUrls
      .split("\n")
      .map((line, index) => parseBulkTrainingVideoLine(line, index + 1))
      .filter((item) => item?.url);
    if (!parsed.length) return;

    const created = [];
    for (const item of parsed) {
      try {
        const saved = await API.request("/api/training-resources", {
          method: "POST",
          body: JSON.stringify({
            title: item.title,
            category: draft.category || "Nex Level Learning",
            type: "Video",
            url: item.url,
            description: "NexU video training resource.",
            featured: false,
            isNew: true
          })
        });
        created.push(saved);
      } catch (error) {
        setToast(error.message || "Could not import one of the NexU videos.");
      }
    }

    if (created.length) {
      setTrainingResources((current) => [...created, ...current]);
      setActiveResourceId(created.find(isEmbeddableTrainingResource)?.id || created[0].id);
      setBulkVideoUrls("");
      setToast(`${created.length} NexU video${created.length === 1 ? "" : "s"} imported.`);
    }
  }

  async function deleteResource(id) {
    try {
      await API.request(`/api/training-resources/${encodeURIComponent(id)}`, { method: "DELETE" });
      setTrainingResources((current) => current.filter((item) => item.id !== id));
      setToast("Training removed.");
    } catch (error) {
      setToast(error.message || "Could not remove training.");
    }
  }

  return (
    <section className="portal-page">
      <div className="nexu-internal-card">
        <div>
          <p className="eyebrow">NexU</p>
          <h3>NexU Training Center</h3>
          <p>Watch Nex Realty training directly inside Nex Central. Choose a category, open a lesson, and keep learning without leaving the portal.</p>
        </div>
        <span>Internal Library</span>
      </div>

      <div className="nexu-player-layout">
        <section className="nexu-player-panel">
          {activeEmbedUrl ? (
            <iframe
              title={activeResource?.title || "NexU training video"}
              src={activeEmbedUrl}
              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
              allowFullScreen
            />
          ) : (
            <EmptyState icon="PlayCircle" title="No embedded NexU videos yet" body="Add a YouTube, Vimeo, Loom, or Google Drive video URL to play it inside Nex Central." />
          )}
        </section>
        <aside className="nexu-now-playing">
          <p className="eyebrow">Now playing</p>
          <h3>{activeResource?.title || "Add your first NexU video"}</h3>
          <p>{activeResource?.description || "Paste video links below as admin, or send me the URLs and I can load them into the training library."}</p>
          <div className="nexu-player-meta">
            <span>{activeResource?.category || "NexU"}</span>
            <span>{activeResource?.type || "Video"}</span>
          </div>
        </aside>
      </div>

      <div className="category-pills">
        {["All", ...trainingCategories].map((item) => (
          <button key={item} className={category === item ? "selected" : ""} onClick={() => setCategory(item)}>{item}</button>
        ))}
      </div>
      {canManage && (
        <div className="panel admin-compose">
          <div className="panel-heading"><div><p className="eyebrow">Admin</p><h3>Add NexU resource</h3></div></div>
          <div className="admin-form-grid">
            <Field label="Title" value={draft.title} onChange={(value) => setDraft((current) => ({ ...current, title: value }))} />
            <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} as="select" options={trainingCategories} />
            <Field label="Type" value={draft.type} onChange={(value) => setDraft((current) => ({ ...current, type: value }))} as="select" options={["Video", "Google Site", "PDF", "Link"]} />
            <Field label="URL" value={draft.url} onChange={(value) => setDraft((current) => ({ ...current, url: value }))} />
            <label className="check-field"><input type="checkbox" checked={draft.featured} onChange={(event) => setDraft((current) => ({ ...current, featured: event.target.checked }))} />Featured</label>
            <label className="check-field"><input type="checkbox" checked={draft.isNew} onChange={(event) => setDraft((current) => ({ ...current, isNew: event.target.checked }))} />New</label>
            <Field label="Description" value={draft.description} onChange={(value) => setDraft((current) => ({ ...current, description: value }))} as="textarea" />
          </div>
          <button className="btn primary" onClick={addResource}><Icon name="Plus" /><span>Add Training</span></button>
          <div className="bulk-video-import">
            <Field
              label="Bulk NexU video URLs"
              value={bulkVideoUrls}
              onChange={setBulkVideoUrls}
              as="textarea"
              placeholder="One per line, or Title | URL"
            />
            <button className="btn secondary" onClick={importBulkVideos}>
              <Icon name="ListPlus" />
              <span>Import Video URLs</span>
            </button>
          </div>
        </div>
      )}
      <div className="resource-grid">
        {filtered.map((item) => {
          const embedUrl = getTrainingEmbedUrl(trainingResourceUrl(item));
          return (
            <article className={classNames("resource-card", activeResource?.id === item.id && "selected")} key={item.id}>
              <Icon name={embedUrl ? "PlayCircle" : item.type === "PDF" ? "FileText" : "Link"} />
              <span>{normalizeTrainingCategory(item.category)}</span>
              <h3>{item.title}</h3>
              <p>{item.description}</p>
              <div>{embedUrl && <em>Embedded</em>}{item.featured && <em>Featured</em>}{item.isNew && <em>New</em>}</div>
              <div className="row-actions">
                {embedUrl ? (
                  <button className="btn secondary small-btn" onClick={() => setActiveResourceId(item.id)}>
                    <Icon name="Play" />
                    <span>Watch Inside</span>
                  </button>
                ) : (
                  <a className="btn secondary small-btn" href={trainingResourceUrl(item)} target="_blank" rel="noreferrer">Open Resource</a>
                )}
                {canManage && (
                  <button className="icon-btn small" onClick={() => deleteResource(item.id)} title="Remove training">
                    <Icon name="Trash2" size={15} />
                  </button>
                )}
              </div>
            </article>
          );
        })}
      </div>
    </section>
  );
}

function DocumentsLibrary({ documents, setDocuments, role, setToast }) {
  const canManage = isAdminRole(role);
  const [section, setSection] = useState("All");
  const [query, setQuery] = useState("");
  const [draft, setDraft] = useState({ title: "", section: "Agent Learning", description: "", fileUrl: "" });
  const [selectedFile, setSelectedFile] = useState(null);
  const [storageInfo, setStorageInfo] = useState(null);
  const directUploadReady = Boolean(storageInfo?.directUploadReady && ["s3", "r2"].includes(storageInfo?.provider));
  const localDocumentUploadsReady = Boolean(storageInfo?.supportsLocalDocumentLibraryUploads || storageInfo?.documentLibraryProvider === "nex-data-directory");
  const documentLibraryUploadsReady = Boolean(storageInfo?.documentLibraryUploadsReady || directUploadReady || localDocumentUploadsReady);
  const productionStorageNeedsProvider = Boolean(storageInfo && !documentLibraryUploadsReady);
  const filtered = documents.filter((doc) => {
    const haystack = `${doc.title} ${doc.section} ${doc.description} ${doc.name}`.toLowerCase();
    return (section === "All" || doc.section === section) && (!query || haystack.includes(query.toLowerCase()));
  });

  useEffect(() => {
    API.request("/api/health")
      .then((payload) => setStorageInfo(payload?.architecture?.storage || null))
      .catch(() => setStorageInfo(null));
  }, []);

  async function chooseDocument(event) {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    const extension = file.name.split(".").pop().toLowerCase();
    if (!["pdf", "jpg", "jpeg", "png"].includes(extension)) {
      setToast("Documents can be PDF, JPG, JPEG, or PNG.");
      event.target.value = "";
      return;
    }
    if (file.size > 8 * 1024 * 1024) {
      setToast("Documents must be 8MB or smaller for this MVP library.");
      event.target.value = "";
      return;
    }
    const upload = await fileToDataUrl(file);
    setSelectedFile({ ...upload, file });
  }

  async function uploadDocument() {
    const hostedDocument = draft.fileUrl.trim() ? inferDocumentMetaFromUrl(draft.fileUrl) : null;
    if (!selectedFile && !hostedDocument) {
      setToast("Choose a PDF, JPG, JPEG, PNG, or paste a hosted document URL.");
      return;
    }
    if (draft.fileUrl.trim() && !hostedDocument) {
      setToast("Hosted document links must be HTTP/HTTPS URLs ending in PDF, JPG, JPEG, or PNG.");
      return;
    }
    if (selectedFile && productionStorageNeedsProvider) {
      setToast("Direct uploads need Cloudflare R2 or S3 settings first. Use a hosted URL for now or configure object storage.");
      return;
    }
    try {
      let documentPayload = hostedDocument;
      if (selectedFile) {
        const { file, ...serializableFile } = selectedFile;
        documentPayload = serializableFile;
        if (file && directUploadReady) {
          const presigned = await API.request("/api/storage/presign", {
            method: "POST",
            body: JSON.stringify({
              module: "documents",
              name: selectedFile.name,
              type: selectedFile.type,
              size: selectedFile.size
            })
          });
          const uploadResponse = await fetch(presigned.uploadUrl, {
            method: presigned.method || "PUT",
            headers: presigned.headers || { "Content-Type": selectedFile.type },
            body: file
          });
          if (!uploadResponse.ok) {
            throw new Error("Object storage upload failed. Check your storage CORS settings and Render environment variables.");
          }
          documentPayload = {
            ...serializableFile,
            dataUrl: "",
            fileUrl: presigned.fileUrl,
            storageKey: presigned.storageKey,
            storageProvider: presigned.storageProvider
          };
        }
      }
      const saved = await API.request("/api/documents", {
        method: "POST",
        body: JSON.stringify({
          ...documentPayload,
          title: draft.title || documentPayload.name,
          section: draft.section,
          description: draft.description
        })
      });
      setDocuments((current) => [saved, ...current]);
      setDraft({ title: "", section: "Agent Learning", description: "", fileUrl: "" });
      setSelectedFile(null);
      setToast("Document added to Nex Central.");
    } catch (error) {
      setToast(error.message || "Could not upload document.");
    }
  }

  async function deleteDocument(id) {
    try {
      await API.request(`/api/documents/${encodeURIComponent(id)}`, { method: "DELETE" });
      setDocuments((current) => current.filter((doc) => doc.id !== id));
      setToast("Document removed.");
    } catch (error) {
      setToast(error.message || "Could not remove document.");
    }
  }

  function documentLink(doc, { download = false } = {}) {
    const source = doc.fileUrl || doc.dataUrl || "";
    if (!source || !download) return source;
    if (source.startsWith("/api/document-assets/") || source.startsWith("/api/document-library-files/")) {
      return `${source}${source.includes("?") ? "&" : "?"}download=1`;
    }
    return source;
  }

  function absoluteDocumentLink(url) {
    if (!url || url.startsWith("data:")) return url;
    try {
      return new URL(url, window.location.origin).toString();
    } catch {
      return url;
    }
  }

  function openDocument(doc) {
    const url = absoluteDocumentLink(documentLink(doc));
    if (!url) {
      setToast("This document does not have a file link yet.");
      return;
    }
    const opened = window.open(url, "_blank", "noopener,noreferrer");
    if (!opened) {
      window.location.href = url;
    }
  }

  function isMobileDocumentExperience() {
    return Boolean(
      typeof window !== "undefined" &&
        (window.matchMedia?.("(max-width: 768px)")?.matches || /Android|iPhone|iPad|iPod/i.test(window.navigator?.userAgent || ""))
    );
  }

  async function downloadDocument(doc) {
    const url = absoluteDocumentLink(documentLink(doc, { download: true }));
    if (!url) {
      setToast("This document does not have a downloadable file yet.");
      return;
    }
    const mobile = isMobileDocumentExperience();
    if (mobile && !url.startsWith("data:") && navigator.share) {
      try {
        await navigator.share({
          title: doc.title || doc.name || "Nex Central document",
          text: "Open or save this Nex Central document.",
          url
        });
        setToast("Choose Save to Files, download, or your preferred app.");
        return;
      } catch (error) {
        if (error?.name === "AbortError") return;
      }
    }
    const anchor = document.createElement("a");
    anchor.href = url;
    anchor.target = "_blank";
    anchor.rel = "noopener noreferrer";
    anchor.download = doc.name || doc.title || "nex-document";
    document.body.appendChild(anchor);
    anchor.click();
    anchor.remove();
    if (mobile) {
      window.setTimeout(() => {
        const opened = window.open(url, "_blank", "noopener,noreferrer");
        if (!opened) window.location.href = url;
      }, 60);
      setToast("File opened. Use your phone's Share or Save option.");
      return;
    }
    setToast("Download started.");
  }

  async function shareDocument(doc) {
    const url = absoluteDocumentLink(documentLink(doc));
    if (!url) {
      setToast("This document does not have a shareable link yet.");
      return;
    }
    if (url.startsWith("data:")) {
      setToast("Open this file first, then use your browser share menu.");
      return;
    }
    const shareData = {
      title: doc.title || doc.name || "Nex Central document",
      text: "Secure Nex Central document link",
      url
    };
    try {
      if (navigator.share && navigator.canShare?.(shareData) !== false) {
        await navigator.share(shareData);
        return;
      }
      if (navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(url);
        setToast("Secure document link copied. Nex Central login may be required.");
        return;
      }
    } catch (error) {
      if (error?.name === "AbortError") return;
    }
    setToast("Open the document and use your browser share menu.");
  }

  return (
    <section className="portal-page documents-page">
      <div className="module-hero documents-hero">
        <div>
          <p className="eyebrow">Nex Documents</p>
          <h3>Brokerage document library</h3>
          <p>Store agent learning files, buyer and seller marketing documents, and recruiting assets in one clean internal library.</p>
        </div>
        <div className="documents-hero-stats">
          <strong>{documents.length}</strong>
          <span>files loaded</span>
        </div>
      </div>

      <div className="document-section-grid">
        {[{ id: "All", label: "All Documents", icon: "Files", description: "Search the full Nex document library." }, ...documentSections].map((item) => (
          <button key={item.id} className={section === item.id ? "selected" : ""} onClick={() => setSection(item.id)}>
            <Icon name={item.icon} />
            <strong>{item.label}</strong>
            <span>{item.description}</span>
          </button>
        ))}
      </div>

      <div className="document-toolbar">
        <label>
          <Icon name="Search" size={16} />
          <input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search documents, sections, descriptions..." />
        </label>
        <span>{filtered.length} showing</span>
      </div>

      {canManage && (
        <div className="panel document-upload-panel">
          <div className="panel-heading"><div><p className="eyebrow">Admin Upload</p><h3>Add PDF, JPEG, or PNG</h3></div></div>
          <div className="document-upload-grid">
            <Field label="Document title" value={draft.title} onChange={(value) => setDraft((current) => ({ ...current, title: value }))} placeholder="Buyer Consultation Guide" />
            <Field label="Section" value={draft.section} onChange={(value) => setDraft((current) => ({ ...current, section: value }))} as="select" options={documentSections.map((item) => item.id)} />
            <Field label="Description" value={draft.description} onChange={(value) => setDraft((current) => ({ ...current, description: value }))} as="textarea" />
            <div className={classNames("document-storage-note", documentLibraryUploadsReady ? "ready" : "pending")}>
              <Icon name={documentLibraryUploadsReady ? "ShieldCheck" : "CloudAlert"} />
              <span>
                {directUploadReady
                  ? "Direct uploads are connected. Files upload into Nex Central storage automatically."
                  : localDocumentUploadsReady
                    ? "Nex document uploads are active. Files are stored in the app data directory and opened through secure Nex Central links."
                    : "Document uploads need Nex data-directory storage or Cloudflare R2/S3 settings."}
              </span>
            </div>
            <label className="document-file-picker">
              <Icon name="UploadCloud" />
              <span>{selectedFile ? selectedFile.name : "Choose PDF, JPG, JPEG, or PNG"}</span>
              <input type="file" accept={documentAcceptedTypes} onChange={chooseDocument} />
            </label>
            <Field label="Backup hosted URL optional" value={draft.fileUrl} onChange={(value) => setDraft((current) => ({ ...current, fileUrl: value }))} placeholder="Only if the file already has a secure public PDF/image link" />
            <button className="btn primary" onClick={uploadDocument}><Icon name="Plus" /><span>Add Document</span></button>
          </div>
        </div>
      )}

      <div className="document-grid">
        {filtered.map((doc) => {
          const isImage = String(doc.type || "").startsWith("image/");
          const documentUrl = documentLink(doc);
          return (
            <article className="document-card" key={doc.id}>
              <div className="document-preview">
                {isImage ? <img src={documentUrl} alt={doc.title} /> : <Icon name="FileText" size={34} />}
              </div>
              <span>{doc.section}</span>
              <h3 title={doc.title}>{doc.title}</h3>
              <p title={doc.description || doc.name}>{doc.description || doc.name}</p>
              <small title={`${doc.name} - ${chatFileSize(doc.size)}`}>{doc.name} - {chatFileSize(doc.size)}</small>
              <div className="row-actions document-card-actions">
                <button type="button" className="btn secondary small-btn" onClick={() => openDocument(doc)}>
                  <Icon name="Eye" />
                  <span>View</span>
                </button>
                <button type="button" className="btn secondary small-btn" onClick={() => downloadDocument(doc)}>
                  <Icon name="Download" />
                  <span>{isMobileDocumentExperience() ? "Save / Share" : "Download"}</span>
                </button>
                <button type="button" className="btn secondary small-btn" onClick={() => shareDocument(doc)}>
                  <Icon name="Share2" />
                  <span>Share</span>
                </button>
                {canManage && !doc.bundled && <button type="button" className="icon-btn small" onClick={() => deleteDocument(doc.id)} title="Delete document"><Icon name="Trash2" size={15} /></button>}
                {doc.bundled && <em className="document-hosted-pill">Nex hosted</em>}
              </div>
            </article>
          );
        })}
        {!filtered.length && <EmptyState icon="FolderKanban" title="No documents found" body="Upload PDF, JPG, JPEG, or PNG files into one of the document sections." />}
      </div>
    </section>
  );
}

function NexCalculators({ currentUser, setToast }) {
  const [active, setActive] = useState("Mortgage");
  const mortgageExportRef = useRef(null);
  const buyerExportRef = useRef(null);
  const sellerExportRef = useRef(null);
  const [rateData, setRateData] = useState({ rate: 6.75, source: "Nex Market Pulse fallback", live: false, checkedAt: "", autoRefreshMinutes: 5 });
  const [marketPulse, setMarketPulse] = useState(null);
  const [marketPulseRefreshToken, setMarketPulseRefreshToken] = useState(0);
  const [marketDetailsOpen, setMarketDetailsOpen] = useState(false);
  const [rateBusy, setRateBusy] = useState(false);
  const [exportingSheet, setExportingSheet] = useState("");
  const [nextRateCheckAt, setNextRateCheckAt] = useState("");
  const [mortgage, setMortgage] = useState({
    price: 400000,
    downPaymentPercent: 20,
    interestRate: 6.75,
    termYears: 30,
    annualTaxes: 5200,
    annualInsurance: 3600,
    monthlyHoa: 0,
    monthlyPmi: 0
  });
  const [buyerCosts, setBuyerCosts] = useState({
    price: 400000,
    loanAmount: 320000,
    lenderFees: 1800,
    titleSettlement: 1600,
    appraisal: 650,
    inspection: 550,
    recording: 250,
    prepaidEscrow: 5200,
    survey: 350,
    other: 0
  });
  const [sellerNet, setSellerNet] = useState({
    price: 400000,
    countyMode: "Florida Standard",
    commissionRate: 5.5,
    payoff: 250000,
    sellerCredits: 0,
    repairs: 0,
    titleSettlement: 1500,
    hoaEstoppel: 350,
    other: 0
  });

  async function loadCalculatorMarketPulse({ force = false, showToast = false } = {}) {
    setRateBusy(true);
    try {
      const data = await API.request(`/api/market-data/pulse?ts=${Date.now()}${force ? "&refresh=1" : ""}`, { retries: 0 });
      setMarketPulse(data);
      const conventionalRate = (data?.items || []).find((item) => item.id === "30-year-conventional");
      const pulseRate = pulseNumericValue(conventionalRate?.value);
      const autoMinutes = Math.max(1, Number(data?.autoRefreshMinutes || data?.refreshMinutes || 5) || 5);
      setNextRateCheckAt(new Date(Date.now() + autoMinutes * 60 * 1000).toISOString());
      if (pulseRate !== null && pulseRate > 0) {
        const formattedRate = pulseRate.toFixed(2);
        setRateData({
          rate: formattedRate,
          source: conventionalRate?.source || "Nex Market Pulse",
          live: Boolean(conventionalRate?.live),
          date: conventionalRate?.date || "",
          checkedAt: data?.updatedAt || new Date().toISOString(),
          autoRefreshMinutes: autoMinutes,
          providerFrequency: conventionalRate?.note || "Nex Market Pulse uses national average mortgage and market indicators. Verify actual APR, fees, lock terms, and eligibility with the lender."
        });
        setMortgage((current) => ({ ...current, interestRate: formattedRate }));
      } else {
        setRateData((current) => ({
          ...current,
          source: conventionalRate?.source || "Market Pulse unavailable",
          live: false,
          date: conventionalRate?.date || "",
          checkedAt: data?.updatedAt || new Date().toISOString(),
          autoRefreshMinutes: autoMinutes,
          providerFrequency: conventionalRate?.note || "No live 30Y conventional rate is available. Enter or confirm the rate used manually."
        }));
      }
      if (showToast) {
        setToast(conventionalRate?.live ? "Market Pulse refreshed." : data?.error || "Market Pulse refreshed. Some rate items are estimates or unavailable.");
      }
    } catch (error) {
      setMarketPulse({ error: true, items: [], housing: [], disclaimer: "Market Pulse could not load. Check the market data connection." });
      if (showToast) setToast("Market Pulse unavailable. Using editable calculator estimates.");
    } finally {
      setRateBusy(false);
    }
  }

  useEffect(() => {
    loadCalculatorMarketPulse();
  }, []);

  useEffect(() => {
    const autoMinutes = Math.max(1, Number(rateData.autoRefreshMinutes || 5) || 5);
    const interval = window.setInterval(() => {
      loadCalculatorMarketPulse({ force: true });
    }, autoMinutes * 60 * 1000);
    if (!nextRateCheckAt) {
      setNextRateCheckAt(new Date(Date.now() + autoMinutes * 60 * 1000).toISOString());
    }
    return () => window.clearInterval(interval);
  }, [rateData.autoRefreshMinutes]);

  const mortgageResult = calculateMortgagePayment(mortgage);
  const buyerResult = calculateBuyerClosingCosts(buyerCosts);
  const sellerResult = calculateSellerNet(sellerNet);
  const pulseItems = marketPulse?.items || [];
  const pulseHousingItems = marketPulse?.housing || [];
  const agentInfo = calculatorAgentInfo(currentUser);
  const primaryRateItem = pulseItems.find((item) => item.id === "30-year-conventional") || {
    id: "calculator-rate-fallback",
    label: "30Y Conv",
    displayValue: `${(pulseNumericValue(rateData.rate) ?? pulseNumericValue(mortgage.interestRate) ?? 6.75).toFixed(2)}%`,
    note: rateData.source || "Editable calculator estimate"
  };
  const calculatorPulseCards = pulseItems.length ? pulseItems : [primaryRateItem];
  const marketContextRows = [
    ["Rate used", pulseDisplayValue(primaryRateItem, `${(pulseNumericValue(rateData.rate) ?? pulseNumericValue(mortgage.interestRate) ?? 6.75).toFixed(2)}%`)],
    ["Rate source", rateData.source || primaryRateItem.source || "Nex Market Pulse"],
    ["Rate status", primaryRateItem.statusLabel || (rateData.live ? "live" : "estimate")],
    ["Updated", rateData.checkedAt ? titleCaseDate(rateData.checkedAt) : "Checking Market Pulse"]
  ];
  const mortgageRows = [
    ["Loan amount", dollars(mortgageResult.loanAmount)],
    ["Down payment", dollars(mortgageResult.downPayment)],
    ["Principal & interest", dollars(mortgageResult.principalAndInterest)],
    ["Taxes", dollars(mortgageResult.taxes)],
    ["Insurance", dollars(mortgageResult.insurance)],
    ["HOA + PMI", dollars(mortgageResult.hoa + mortgageResult.pmi)]
  ];
  const mortgageAssumptions = [
    ["Purchase price", dollars(mortgage.price)],
    ["Down payment", `${Number(mortgage.downPaymentPercent || 0).toFixed(2).replace(/\.00$/, "")}%`],
    ["Interest rate", `${Number(mortgage.interestRate || 0).toFixed(2)}%`],
    ["Term", `${Number(mortgage.termYears || 30)} years`],
    ["Annual taxes", dollars(mortgage.annualTaxes)],
    ["Annual insurance", dollars(mortgage.annualInsurance)],
    ["Monthly HOA", dollars(mortgage.monthlyHoa)],
    ["Monthly PMI", dollars(mortgage.monthlyPmi)]
  ];
  const buyerRows = [
    ["Mortgage doc stamps", dollars(buyerResult.mortgageDocStamps)],
    ["Nonrecurring intangible tax", dollars(buyerResult.intangibleTax)],
    ["Lender fees", dollars(buyerResult.lenderFees)],
    ["Title / settlement", dollars(buyerResult.titleSettlement)],
    ["Prepaids / escrow", dollars(buyerResult.prepaidEscrow)],
    ["Inspections / appraisal / survey", dollars(buyerResult.inspection + buyerResult.appraisal + buyerResult.survey)]
  ];
  const buyerAssumptions = [
    ["Purchase price", dollars(buyerCosts.price)],
    ["Loan amount", dollars(buyerCosts.loanAmount)],
    ["Appraisal", dollars(buyerCosts.appraisal)],
    ["Inspection", dollars(buyerCosts.inspection)],
    ["Recording", dollars(buyerCosts.recording)],
    ["Survey", dollars(buyerCosts.survey)],
    ["Other", dollars(buyerCosts.other)]
  ];
  const sellerRows = [
    ["Sale price", dollars(sellerResult.price)],
    ["Commission", dollars(sellerResult.commission)],
    ["Seller doc stamps", dollars(sellerResult.deedDocStamps)],
    ["Mortgage payoff", dollars(sellerResult.payoff)],
    ["Credits / repairs", dollars(sellerResult.sellerCredits + sellerResult.repairs)],
    ["Total estimated costs", dollars(sellerResult.totalCosts)]
  ];
  const sellerAssumptions = [
    ["Sale price", dollars(sellerNet.price)],
    ["County doc stamp mode", sellerNet.countyMode],
    ["Commission", `${Number(sellerNet.commissionRate || 0).toFixed(2).replace(/\.00$/, "")}%`],
    ["Mortgage payoff", dollars(sellerNet.payoff)],
    ["Seller credits", dollars(sellerNet.sellerCredits)],
    ["Repairs", dollars(sellerNet.repairs)],
    ["Title / settlement", dollars(sellerNet.titleSettlement)],
    ["HOA / estoppel", dollars(sellerNet.hoaEstoppel)],
    ["Other", dollars(sellerNet.other)]
  ];
  const exportRefs = {
    mortgage: mortgageExportRef,
    buyer: buyerExportRef,
    seller: sellerExportRef
  };

  function updateMortgage(field, value) {
    setMortgage((current) => ({ ...current, [field]: numericInput(value) }));
  }

  function updateBuyer(field, value) {
    setBuyerCosts((current) => ({ ...current, [field]: numericInput(value) }));
  }

  function updateSeller(field, value) {
    setSellerNet((current) => ({ ...current, [field]: field === "countyMode" ? value : numericInput(value) }));
  }

  async function exportCalculatorSheet(sheetId, format) {
    const element = exportRefs[sheetId]?.current;
    if (!element) {
      setToast("Calculator sheet is still preparing. Try again in a moment.");
      return;
    }
    if (!window.html2canvas) {
      setToast("Export library did not load. Refresh Nex Central and try again.");
      return;
    }
    setExportingSheet(`${sheetId}-${format}`);
    setToast(`Preparing ${format.toUpperCase()} estimate sheet...`);
    try {
      if (document.activeElement && document.activeElement.blur) {
        document.activeElement.blur();
        await new Promise((resolve) => setTimeout(resolve, 80));
      }
      if (document.fonts?.ready) await document.fonts.ready.catch(() => {});
      const canvas = await html2canvas(element, {
        scale: 2.5,
        backgroundColor: "#ffffff",
        useCORS: true,
        allowTaint: false
      });
      const image = canvas.toDataURL("image/png", 1);
      const fileBase = `nex-realty-${sheetId}-estimate-${agentInfo.name || "agent"}-${new Date().toISOString().slice(0, 10)}`.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
      if (format === "png") {
        const link = document.createElement("a");
        link.href = image;
        link.download = `${fileBase}.png`;
        document.body.appendChild(link);
        link.click();
        link.remove();
        setToast("PNG estimate sheet downloaded.");
        return;
      }
      const { jsPDF } = window.jspdf || {};
      if (!jsPDF) throw new Error("PDF export library did not load. Refresh Nex Central and try again.");
      const pdf = new jsPDF({
        orientation: canvas.width > canvas.height ? "landscape" : "portrait",
        unit: "px",
        format: [canvas.width, canvas.height]
      });
      pdf.addImage(image, "PNG", 0, 0, canvas.width, canvas.height);
      pdf.save(`${fileBase}.pdf`);
      setToast("PDF estimate sheet downloaded.");
    } catch (error) {
      console.error("Calculator export failed", error);
      setToast(error.message || "Could not export this calculator sheet. Try again after refreshing.");
    } finally {
      setExportingSheet("");
    }
  }

  function renderExportControls(sheetId) {
    const busyPng = exportingSheet === `${sheetId}-png`;
    const busyPdf = exportingSheet === `${sheetId}-pdf`;
    return (
      <div className="calculator-export-controls">
        <div>
          <strong>Branded estimate sheet</strong>
          <small>Exports with {agentInfo.name}, Nex Realty branding, assumptions, and disclaimer.</small>
        </div>
        <div className="calculator-export-buttons">
          <button className="btn secondary compact" type="button" onClick={() => exportCalculatorSheet(sheetId, "png")} disabled={Boolean(exportingSheet)}>
            <Icon name={busyPng ? "LoaderCircle" : "ImageDown"} className={busyPng ? "spin" : ""} />
            <span>PNG</span>
          </button>
          <button className="btn primary compact" type="button" onClick={() => exportCalculatorSheet(sheetId, "pdf")} disabled={Boolean(exportingSheet)}>
            <Icon name={busyPdf ? "LoaderCircle" : "FileDown"} className={busyPdf ? "spin" : ""} />
            <span>PDF</span>
          </button>
        </div>
      </div>
    );
  }

  return (
    <section className="portal-page calculator-page">
      <div className="calculator-market-pulse">
        <div className="calculator-market-pulse-head">
          <div>
            <p className="eyebrow">Nex Calculators</p>
            <h3>Florida planning estimates with Market Pulse context</h3>
            <p>Use mortgage payments, buyer closing costs, and seller net proceeds alongside the current rate, bond, and housing indicators agents ask about most.</p>
          </div>
          <div className="calculator-market-actions">
            <button className="btn secondary compact" type="button" onClick={() => {
              setMarketPulseRefreshToken((value) => value + 1);
              loadCalculatorMarketPulse({ force: true, showToast: true });
            }} disabled={rateBusy}>
              <Icon name={rateBusy ? "LoaderCircle" : "RefreshCw"} className={rateBusy ? "spin" : ""} />
              <span>{rateBusy ? "Refreshing" : "Refresh Pulse"}</span>
            </button>
          </div>
        </div>
        <MarketPulseTicker endpoint="/api/market-data/pulse" variant="central" refreshToken={marketPulseRefreshToken} />
        <details className="calculator-market-details" open={marketDetailsOpen} onToggle={(event) => setMarketDetailsOpen(event.currentTarget.open)}>
          <summary>
            <span><Icon name="ListFilter" size={15} /> View Market Pulse Details</span>
            <small>{calculatorPulseCards.length + pulseHousingItems.length} indicators</small>
          </summary>
          <div className="calculator-market-detail-grid">
            {(calculatorPulseCards.length ? calculatorPulseCards : [{ id: "loading", label: "Market data", displayValue: rateBusy ? "Checking" : "Unavailable", note: "Market indicators loading." }]).map((item) => (
              <article key={item.id || item.label}>
                <span>{item.label}</span>
                <strong>{pulseDisplayValue(item)}{item.indicator && <em className={classNames("pulse-card-indicator", item.trend)}>{item.indicator}</em>}</strong>
                <small>{item.changeLabel && <b>{item.changeLabel}</b>} {item.statusLabel && <i>{item.statusLabel}</i>} {item.note || item.source || "Market indicator"}</small>
              </article>
            ))}
            {pulseHousingItems.map((item) => (
              <article key={item.id || item.label}>
                <span>{item.label}</span>
                <strong>{item.displayValue || pulseDisplayValue(item)}</strong>
                <small>{item.note || "Preview count until live IDX feed is connected."}</small>
              </article>
            ))}
          </div>
        </details>
        <small className="calculator-market-disclaimer">
          {marketPulse?.disclaimer || "Market Pulse is informational only. Actual rates, APR, points, lender fees, taxes, insurance, and eligibility must be verified with the lender and proper professionals."}
          {nextRateCheckAt && !rateBusy ? ` Next auto-check ${titleCaseDate(nextRateCheckAt)}.` : ""}
        </small>
      </div>

      <div className="calculator-tabs">
        {["Mortgage", "Buyer Costs", "Seller Net"].map((tab) => (
          <button key={tab} className={active === tab ? "selected" : ""} onClick={() => setActive(tab)}>{tab}</button>
        ))}
      </div>

      <section className="preapproval-partner-card">
        <div className="preapproval-partner-media">
          <img src={WOLK_MORTGAGE_PARTNER.cardImageUrl} alt={`${WOLK_MORTGAGE_PARTNER.name} with Wolk Mortgage`} />
        </div>
        <div className="preapproval-partner-copy">
          <p className="eyebrow">Preferred Pre-Approval Partner</p>
          <h3>Send buyers to {WOLK_MORTGAGE_PARTNER.name}</h3>
          <p>Matt is the go-to Wolk Mortgage partner for Nex agents when a buyer needs pre-approval support, financing direction, or a clean lender handoff.</p>
          <div className="preapproval-contact-grid">
            <span><Icon name="Mail" size={14} />{WOLK_MORTGAGE_PARTNER.email}</span>
            <span><Icon name="Phone" size={14} />{WOLK_MORTGAGE_PARTNER.phone}</span>
            <span><Icon name="BadgeCheck" size={14} />NMLS {WOLK_MORTGAGE_PARTNER.nmls}</span>
            <span><Icon name="MapPin" size={14} />Tampa, FL</span>
          </div>
        </div>
        <div className="preapproval-partner-actions">
          <button className="btn secondary" type="button" onClick={() => copyToClipboard(WOLK_MORTGAGE_PARTNER.preapprovalUrl, setToast)}><Icon name="Copy" /><span>Copy Link</span></button>
          <a className="btn secondary" href={`mailto:${WOLK_MORTGAGE_PARTNER.email}`}><Icon name="Mail" /><span>Email Matt</span></a>
          <a className="btn secondary" href={WOLK_MORTGAGE_PARTNER.phoneHref}><Icon name="Phone" /><span>Call Matt</span></a>
          <a className="btn primary" href={WOLK_MORTGAGE_PARTNER.preapprovalUrl} target="_blank" rel="noreferrer"><Icon name="ExternalLink" /><span>Open Pre-Approval</span></a>
        </div>
      </section>

      {active === "Mortgage" && (
        <section className="calculator-workspace">
          <div className="panel calculator-inputs">
            <div className="panel-heading"><div><p className="eyebrow">Mortgage</p><h3>Monthly payment estimate</h3></div></div>
            <CalculatorField label="Purchase price" value={mortgage.price} onChange={(value) => updateMortgage("price", value)} />
            <CalculatorField label="Down payment %" value={mortgage.downPaymentPercent} onChange={(value) => updateMortgage("downPaymentPercent", value)} />
            <CalculatorField label="Interest rate %" value={mortgage.interestRate} onChange={(value) => updateMortgage("interestRate", value)} />
            <p className="calculator-rate-note">
              {rateData.providerFrequency || "Market Pulse uses national average mortgage and market indicators. Agents should verify live quote terms with the lender."}
            </p>
            <CalculatorField label="Term years" value={mortgage.termYears} onChange={(value) => updateMortgage("termYears", value)} />
            <CalculatorField label="Annual taxes" value={mortgage.annualTaxes} onChange={(value) => updateMortgage("annualTaxes", value)} />
            <CalculatorField label="Annual insurance" value={mortgage.annualInsurance} onChange={(value) => updateMortgage("annualInsurance", value)} />
            <CalculatorField label="Monthly HOA" value={mortgage.monthlyHoa} onChange={(value) => updateMortgage("monthlyHoa", value)} />
            <CalculatorField label="Monthly PMI" value={mortgage.monthlyPmi} onChange={(value) => updateMortgage("monthlyPmi", value)} />
          </div>
          <CalculatorResultCard
            title="Estimated Monthly Payment"
            primary={dollars(mortgageResult.totalMonthlyPayment)}
            rows={mortgageRows}
            actions={renderExportControls("mortgage")}
          />
        </section>
      )}

      {active === "Buyer Costs" && (
        <section className="calculator-workspace">
          <div className="panel calculator-inputs">
            <div className="panel-heading"><div><p className="eyebrow">Buyer</p><h3>Closing cost estimate</h3></div></div>
            <CalculatorField label="Purchase price" value={buyerCosts.price} onChange={(value) => updateBuyer("price", value)} />
            <CalculatorField label="Loan amount" value={buyerCosts.loanAmount} onChange={(value) => updateBuyer("loanAmount", value)} />
            <CalculatorField label="Lender fees" value={buyerCosts.lenderFees} onChange={(value) => updateBuyer("lenderFees", value)} />
            <CalculatorField label="Title / settlement" value={buyerCosts.titleSettlement} onChange={(value) => updateBuyer("titleSettlement", value)} />
            <CalculatorField label="Appraisal" value={buyerCosts.appraisal} onChange={(value) => updateBuyer("appraisal", value)} />
            <CalculatorField label="Inspection" value={buyerCosts.inspection} onChange={(value) => updateBuyer("inspection", value)} />
            <CalculatorField label="Recording" value={buyerCosts.recording} onChange={(value) => updateBuyer("recording", value)} />
            <CalculatorField label="Prepaids / escrow" value={buyerCosts.prepaidEscrow} onChange={(value) => updateBuyer("prepaidEscrow", value)} />
            <CalculatorField label="Survey" value={buyerCosts.survey} onChange={(value) => updateBuyer("survey", value)} />
            <CalculatorField label="Other" value={buyerCosts.other} onChange={(value) => updateBuyer("other", value)} />
          </div>
          <CalculatorResultCard
            title="Estimated Buyer Cash To Close Add-On"
            primary={dollars(buyerResult.estimatedTotal)}
            rows={buyerRows}
            actions={renderExportControls("buyer")}
          />
        </section>
      )}

      {active === "Seller Net" && (
        <section className="calculator-workspace">
          <div className="panel calculator-inputs">
            <div className="panel-heading"><div><p className="eyebrow">Seller</p><h3>Net sheet estimate</h3></div></div>
            <CalculatorField label="Sale price" value={sellerNet.price} onChange={(value) => updateSeller("price", value)} />
            <Field label="County doc stamp mode" value={sellerNet.countyMode} onChange={(value) => updateSeller("countyMode", value)} as="select" options={["Florida Standard", "Miami-Dade Single-Family"]} />
            <CalculatorField label="Commission %" value={sellerNet.commissionRate} onChange={(value) => updateSeller("commissionRate", value)} />
            <CalculatorField label="Mortgage payoff" value={sellerNet.payoff} onChange={(value) => updateSeller("payoff", value)} />
            <CalculatorField label="Seller credits" value={sellerNet.sellerCredits} onChange={(value) => updateSeller("sellerCredits", value)} />
            <CalculatorField label="Repairs" value={sellerNet.repairs} onChange={(value) => updateSeller("repairs", value)} />
            <CalculatorField label="Title / settlement" value={sellerNet.titleSettlement} onChange={(value) => updateSeller("titleSettlement", value)} />
            <CalculatorField label="HOA / estoppel" value={sellerNet.hoaEstoppel} onChange={(value) => updateSeller("hoaEstoppel", value)} />
            <CalculatorField label="Other" value={sellerNet.other} onChange={(value) => updateSeller("other", value)} />
          </div>
          <CalculatorResultCard
            title="Estimated Seller Net"
            primary={dollars(sellerResult.estimatedNet)}
            rows={sellerRows}
            actions={renderExportControls("seller")}
          />
        </section>
      )}

      <div className="calculator-export-renderer" aria-hidden="true">
        <CalculatorExportSheet
          innerRef={mortgageExportRef}
          title="Mortgage Payment Estimate"
          subtitle="Estimated monthly payment based on the assumptions entered in Nex Central."
          primaryLabel="Estimated Monthly Payment"
          primaryValue={dollars(mortgageResult.totalMonthlyPayment)}
          assumptionRows={mortgageAssumptions}
          resultRows={mortgageRows}
          marketRows={marketContextRows}
          agentInfo={agentInfo}
        />
        <CalculatorExportSheet
          innerRef={buyerExportRef}
          title="Buyer Closing Cost Estimate"
          subtitle="Estimated buyer cash-to-close add-ons for planning conversations."
          primaryLabel="Estimated Buyer Costs"
          primaryValue={dollars(buyerResult.estimatedTotal)}
          assumptionRows={buyerAssumptions}
          resultRows={buyerRows}
          marketRows={marketContextRows}
          agentInfo={agentInfo}
        />
        <CalculatorExportSheet
          innerRef={sellerExportRef}
          title="Seller Net Sheet Estimate"
          subtitle="Estimated seller proceeds based on the sale price, payoff, credits, and cost assumptions entered."
          primaryLabel="Estimated Seller Net"
          primaryValue={dollars(sellerResult.estimatedNet)}
          assumptionRows={sellerAssumptions}
          resultRows={sellerRows}
          marketRows={marketContextRows}
          agentInfo={agentInfo}
        />
      </div>

      <div className="calculator-disclaimer">
        <Icon name="ShieldAlert" />
        <p>{CALCULATOR_ESTIMATE_DISCLAIMER}</p>
      </div>
    </section>
  );
}

function CalculatorField({ label, value, onChange }) {
  return (
    <label className="calculator-field">
      <span>{label}</span>
      <input type="number" min="0" value={value} onChange={(event) => onChange(event.target.value)} />
    </label>
  );
}

function CalculatorResultCard({ title, primary, rows, actions = null }) {
  return (
    <aside className="calculator-results">
      <p className="eyebrow">Result</p>
      <h3>{title}</h3>
      <strong>{primary}</strong>
      <div className="calculator-result-rows">
        {rows.map(([label, value]) => (
          <span key={label}>
            <em>{label}</em>
            <b>{value}</b>
          </span>
        ))}
      </div>
      {actions}
    </aside>
  );
}

function CalculatorExportSheet({ innerRef, title, subtitle, primaryLabel, primaryValue, assumptionRows = [], resultRows = [], marketRows = [], agentInfo = {} }) {
  const safeHeadshot = calculatorSafeImageUrl(agentInfo.headshotUrl);
  const initials = String(agentInfo.name || "NA").split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase() || "NA";
  return (
    <section className="calculator-export-sheet" ref={innerRef}>
      <header>
        <div className="calculator-export-brand">
          <img src={defaultLogoBlackUrl} alt="Nex Realty" />
          <div>
            <span>Nex Realty</span>
            <strong>{title}</strong>
            <small>Prepared {new Date().toLocaleDateString()}</small>
          </div>
        </div>
        <div className="calculator-export-agent">
          {safeHeadshot ? <img src={safeHeadshot} alt={agentInfo.name} /> : <em>{initials}</em>}
          <div>
            <strong>{agentInfo.name}</strong>
            {agentInfo.market && <span>{agentInfo.market}</span>}
            {agentInfo.phone && <span>{agentInfo.phone}</span>}
            {agentInfo.email && <span>{agentInfo.email}</span>}
            {agentInfo.license && <span>License {agentInfo.license}</span>}
          </div>
        </div>
      </header>
      <div className="calculator-export-hero">
        <span>{primaryLabel}</span>
        <strong>{primaryValue}</strong>
        <p>{subtitle}</p>
      </div>
      <div className="calculator-export-grid">
        <CalculatorExportTable title="Assumptions" rows={assumptionRows} />
        <CalculatorExportTable title="Estimate Breakdown" rows={resultRows} />
        <CalculatorExportTable title="Market Context" rows={marketRows} />
      </div>
      <section className="calculator-export-lender">
        <img src={WOLK_MORTGAGE_PARTNER.logoUrl} alt={WOLK_MORTGAGE_PARTNER.company} />
        <div>
          <span>Preferred buyer pre-approval partner</span>
          <strong>{WOLK_MORTGAGE_PARTNER.name}, {WOLK_MORTGAGE_PARTNER.title}</strong>
          <p>{WOLK_MORTGAGE_PARTNER.email} | {WOLK_MORTGAGE_PARTNER.phone} | NMLS {WOLK_MORTGAGE_PARTNER.nmls}</p>
        </div>
      </section>
      <footer>
        <strong>Important estimate disclaimer</strong>
        <p>{CALCULATOR_ESTIMATE_DISCLAIMER}</p>
      </footer>
    </section>
  );
}

function CalculatorExportTable({ title, rows = [] }) {
  return (
    <article className="calculator-export-table">
      <h4>{title}</h4>
      {rows.map(([label, value]) => (
        <div key={label}>
          <span>{label}</span>
          <strong>{value || "--"}</strong>
        </div>
      ))}
    </article>
  );
}

function transactionGuidePriority(guide) {
  const id = String(guide?.id || "").toLowerCase();
  const category = String(guide?.category || "").toLowerCase();
  if (id.includes("cancellation") || id.includes("termination") || id.includes("appraisal")) return "Broker review recommended";
  if (id.includes("under-contract") || id.includes("inspection") || id.includes("closing") || category.includes("transaction")) return "Deadline sensitive";
  if (id.includes("cda") || category.includes("commission")) return "Commission accuracy";
  if (category.includes("listing") || id.includes("offer")) return "Document accuracy";
  return "Workflow guide";
}

function transactionGuideNextAction(guide) {
  const id = String(guide?.id || "").toLowerCase();
  if (id.includes("under-contract")) return "Create or open the transaction, enter every deadline, then upload the executed contract package.";
  if (id.includes("inspection")) return "Confirm the inspection deadline first, then track the signed response or addendum before the window closes.";
  if (id.includes("cda")) return "Audit the file and commission terms before requesting the CDA.";
  if (id.includes("cancellation") || id.includes("termination")) return "Pause and confirm the correct path with broker/admin before sending cancellation language.";
  if (id.includes("new-listing")) return "Verify signed listing authority, disclosures, MLS details, and marketing readiness before launch.";
  if (id.includes("new-buyer") || id.includes("buyer-broker")) return "Save buyer representation paperwork, confirm financing, and set the next follow-up inside CRM.";
  if (id.includes("rental")) return "Confirm lease/application requirements, commission terms, and move-in timing before submitting the file.";
  return "Work through the checklist in order and ask support before guessing on compliance-sensitive details.";
}

function TransactionHelpCenter({ guides, role, setTransactionGuides, setActivePage, setToast }) {
  const [selectedId, setSelectedId] = useState(guides[0]?.id || "");
  const [draft, setDraft] = useState({
    title: "",
    category: "Transaction",
    checklist: "",
    requiredForms: "",
    brokermintReminder: "",
    contact: "Broker/admin team",
    commonMistakes: "",
    supportLabel: "Ask support"
  });
  const guide = guides.find((item) => item.id === selectedId) || guides[0];
  const checklistItems = guide?.checklist || [];
  const requiredForms = guide?.requiredForms || [];
  const commonMistakes = guide?.commonMistakes || [];
  const guideEnhancement = guide ? transactionGuideEnhancements[guide.id] || {
    overview: "Use this guide as a practical internal starting point for the workflow. Confirm the exact documents, deadlines, and compliance requirements with the broker/admin team before acting on transaction-specific issues.",
    reminders: [
      "Verify dates, signatures, required documents, and client instructions before moving to the next step.",
      "Keep Brokermint, client communication, and your own notes aligned so the file is easy to review.",
      "Ask for broker/admin guidance early when money, contract deadlines, compliance, or cancellation language is involved."
    ]
  } : null;
  const canManage = isAdminRole(role);

  useEffect(() => {
    if (!selectedId && guides[0]?.id) setSelectedId(guides[0].id);
  }, [guides, selectedId]);

  async function addGuide() {
    if (!draft.title.trim()) return;
    try {
      const saved = await API.request("/api/transaction-guides", {
        method: "POST",
        body: JSON.stringify(draft)
      });
      setTransactionGuides((current) => [saved, ...current]);
      setSelectedId(saved.id);
      setDraft({
        title: "",
        category: "Transaction",
        checklist: "",
        requiredForms: "",
        brokermintReminder: "",
        contact: "Broker/admin team",
        commonMistakes: "",
        supportLabel: "Ask support"
      });
      setToast("Transaction guide added.");
    } catch (error) {
      setToast(error.message || "Could not add guide.");
    }
  }

  async function deleteGuide(id) {
    try {
      await API.request(`/api/transaction-guides/${encodeURIComponent(id)}`, { method: "DELETE" });
      setTransactionGuides((current) => current.filter((item) => item.id !== id));
      setSelectedId("");
      setToast("Transaction guide removed.");
    } catch (error) {
      setToast(error.message || "Could not remove guide.");
    }
  }

  return (
    <section className="transaction-layout">
      <div className="panel guide-list">
        <div className="panel-heading"><div><p className="eyebrow">Transaction help</p><h3>Guides</h3></div></div>
        {guides.map((item) => (
          <button key={item.id} className={selectedId === item.id ? "selected" : ""} onClick={() => setSelectedId(item.id)}>
            <span>{item.category}</span>
            <strong>{item.title}</strong>
          </button>
        ))}
        {canManage && (
          <div className="guide-admin-card">
            <p className="eyebrow">Admin</p>
            <h4>Add guide</h4>
            <Field label="Title" value={draft.title} onChange={(value) => setDraft((current) => ({ ...current, title: value }))} />
            <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} />
            <Field label="Checklist" value={draft.checklist} onChange={(value) => setDraft((current) => ({ ...current, checklist: value }))} as="textarea" placeholder="One step per line" />
            <Field label="Required forms" value={draft.requiredForms} onChange={(value) => setDraft((current) => ({ ...current, requiredForms: value }))} as="textarea" placeholder="One form per line" />
            <Field label="Brokermint reminder" value={draft.brokermintReminder} onChange={(value) => setDraft((current) => ({ ...current, brokermintReminder: value }))} as="textarea" />
            <Field label="Who to contact" value={draft.contact} onChange={(value) => setDraft((current) => ({ ...current, contact: value }))} />
            <Field label="Common mistakes" value={draft.commonMistakes} onChange={(value) => setDraft((current) => ({ ...current, commonMistakes: value }))} as="textarea" placeholder="One mistake per line" />
            <Field label="Support button label" value={draft.supportLabel} onChange={(value) => setDraft((current) => ({ ...current, supportLabel: value }))} />
            <button className="btn primary" onClick={addGuide}><Icon name="Plus" /><span>Add Guide</span></button>
          </div>
        )}
      </div>
      {guide && (
        <div className="panel guide-detail">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">{guide.category}</p>
              <h3>{guide.title}</h3>
            </div>
            {canManage && (
              <button className="icon-btn small" onClick={() => deleteGuide(guide.id)} title="Delete guide">
                <Icon name="Trash2" size={15} />
              </button>
            )}
          </div>
          {guideEnhancement && (
            <section className="guide-overview-card">
              <div className="guide-overview-main">
                <span className="guide-priority-badge">{transactionGuidePriority(guide)}</span>
                <h4>What this guide is for</h4>
                <p>{guideEnhancement.overview}</p>
              </div>
              <div className="guide-metrics-row">
                <span><strong>{checklistItems.length}</strong> Checklist steps</span>
                <span><strong>{requiredForms.length}</strong> Documents/forms</span>
                <span><strong>{commonMistakes.length}</strong> Mistakes to avoid</span>
              </div>
              <div className="guide-next-action">
                <Icon name="ArrowRightCircle" />
                <div>
                  <strong>Next best action</strong>
                  <p>{transactionGuideNextAction(guide)}</p>
                </div>
              </div>
            </section>
          )}
          <section className="guide-playbook-section">
            <h4>Step-by-step checklist</h4>
            <ol className="guide-step-list">{checklistItems.map((item) => <li key={item}>{item}</li>)}</ol>
          </section>
          <section className="guide-playbook-section">
            <h4>Required forms</h4>
            <ul>{requiredForms.map((item) => <li key={item}>{item}</li>)}</ul>
          </section>
          {guideEnhancement?.reminders?.length > 0 && (
            <section className="guide-reminder-strip">
              <Icon name="ShieldCheck" />
              <div>
                <strong>Best practice reminders</strong>
                <ul>{guideEnhancement.reminders.map((item) => <li key={item}>{item}</li>)}</ul>
              </div>
            </section>
          )}
          <div className="guide-callouts">
            <article><strong>Brokermint reminder</strong><p>{guide.brokermintReminder}</p></article>
            <article><strong>Who to contact</strong><p>{guide.contact}</p></article>
            <article><strong>Common mistakes</strong><ul>{commonMistakes.map((item) => <li key={item}>{item}</li>)}</ul></article>
          </div>
          <button className="btn primary" onClick={() => setActivePage("Support Desk")}><Icon name="LifeBuoy" /><span>{guide.supportLabel || "Ask support"}</span></button>
        </div>
      )}
    </section>
  );
}

function SupportDesk({ currentUser, role, tickets, setSupportTickets, setToast }) {
  const [draft, setDraft] = useState({
    agentName: currentUser?.name || "",
    agentEmail: currentUser?.email || "",
    phone: "",
    category: "General question",
    urgency: "Normal",
    subject: "",
    description: "",
    attachmentName: ""
  });
  const [selectedTicketId, setSelectedTicketId] = useState("");
  const canManage = isAdminRole(role);
  const selectedTicket = tickets.find((ticket) => ticket.id === selectedTicketId) || tickets[0];

  useEffect(() => {
    if (!tickets.length) {
      setSelectedTicketId("");
      return;
    }
    if (!selectedTicketId || !tickets.some((ticket) => ticket.id === selectedTicketId)) {
      setSelectedTicketId(tickets[0].id);
    }
  }, [tickets, selectedTicketId]);

  async function submitTicket() {
    if (!draft.subject.trim()) return;
    try {
      const saved = await API.request("/api/support-tickets", { method: "POST", body: JSON.stringify(draft) });
      setSupportTickets((current) => [saved, ...current]);
      setSelectedTicketId(saved.id);
      setDraft((current) => ({ ...current, subject: "", description: "", attachmentName: "" }));
      setToast("Support ticket submitted.");
    } catch (error) {
      setToast(error.message || "Could not submit ticket.");
    }
  }

  async function updateTicket(id, status) {
    try {
      const saved = await API.request(`/api/support-tickets/${encodeURIComponent(id)}`, { method: "PUT", body: JSON.stringify({ status }) });
      setSupportTickets((current) => current.map((ticket) => (ticket.id === id ? saved : ticket)));
      setToast("Ticket updated.");
    } catch (error) {
      setToast(error.message || "Could not update ticket.");
    }
  }

  return (
    <section className="support-layout">
      <div className="panel">
        <div className="panel-heading"><div><p className="eyebrow">Support Desk</p><h3>Submit a request</h3></div></div>
        <div className="admin-form-grid">
          <Field label="Agent name" value={draft.agentName} onChange={(value) => setDraft((current) => ({ ...current, agentName: value }))} />
          <Field label="Agent email" value={draft.agentEmail} onChange={(value) => setDraft((current) => ({ ...current, agentEmail: value }))} type="email" />
          <Field label="Phone" value={draft.phone} onChange={(value) => setDraft((current) => ({ ...current, phone: value }))} />
          <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} as="select" options={supportCategories} />
          <Field label="Urgency" value={draft.urgency} onChange={(value) => setDraft((current) => ({ ...current, urgency: value }))} as="select" options={supportUrgencies} />
          <Field label="Subject" value={draft.subject} onChange={(value) => setDraft((current) => ({ ...current, subject: value }))} />
          <Field label="Description" value={draft.description} onChange={(value) => setDraft((current) => ({ ...current, description: value }))} as="textarea" />
          <label className="field">
            <span>Optional file</span>
            <input type="file" onChange={(event) => setDraft((current) => ({ ...current, attachmentName: event.target.files?.[0]?.name || "" }))} />
          </label>
        </div>
        <button className="btn primary" onClick={submitTicket}><Icon name="Send" /><span>Submit Ticket</span></button>
      </div>
      <div className="panel">
        <div className="panel-heading"><div><p className="eyebrow">{canManage ? "All tickets" : "My tickets"}</p><h3>Ticket status</h3></div></div>
        <div className="ticket-list">
          {tickets.map((ticket) => (
            <article key={ticket.id} className={classNames(selectedTicket?.id === ticket.id && "selected")}>
              <button className="ticket-summary-button" onClick={() => setSelectedTicketId(ticket.id)}>
                <span>{ticket.category} | {ticket.urgency}</span>
                <strong>{ticket.subject}</strong>
                <p>{ticket.description}</p>
                <em>{ticket.status}</em>
              </button>
              {canManage && <Field label="Status" value={ticket.status} onChange={(value) => updateTicket(ticket.id, value)} as="select" options={ticketStatuses} />}
            </article>
          ))}
          {!tickets.length && <EmptyState icon="LifeBuoy" title="No support tickets yet" body="Submit a request and it will appear here." />}
        </div>
        {selectedTicket && (
          <div className="ticket-detail-card">
            <div className="ticket-detail-head">
              <div>
                <p className="eyebrow">Ticket detail</p>
                <h3>{selectedTicket.subject}</h3>
              </div>
              <span>{selectedTicket.status}</span>
            </div>
            <dl>
              <div><dt>Agent</dt><dd>{selectedTicket.agentName || "Not listed"}</dd></div>
              <div><dt>Email</dt><dd>{selectedTicket.agentEmail || "Not listed"}</dd></div>
              <div><dt>Phone</dt><dd>{selectedTicket.phone || "Not listed"}</dd></div>
              <div><dt>Category</dt><dd>{selectedTicket.category}</dd></div>
              <div><dt>Urgency</dt><dd>{selectedTicket.urgency}</dd></div>
              <div><dt>Submitted</dt><dd>{selectedTicket.createdAt ? new Date(selectedTicket.createdAt).toLocaleString() : "Not listed"}</dd></div>
            </dl>
            <div className="ticket-detail-description">
              <strong>Full description</strong>
              <p>{selectedTicket.description || "No description provided."}</p>
            </div>
            {selectedTicket.attachmentName && (
              <div className="ticket-attachment">
                <Icon name="Paperclip" />
                <span>{selectedTicket.attachmentName}</span>
              </div>
            )}
            {canManage && (
              <Field label="Update status" value={selectedTicket.status} onChange={(value) => updateTicket(selectedTicket.id, value)} as="select" options={ticketStatuses} />
            )}
          </div>
        )}
      </div>
    </section>
  );
}

function AdminPanel({ role, announcements, quickLinks, trainingResources, documents = [], transactionGuides, supportTickets, allowedUsers, setActivePage }) {
  if (!isAdminRole(role)) {
    return <EmptyState icon="ShieldCheck" title="Admin access required" body="This area is for Nex Realty leadership and admin users." />;
  }

  const uniqueAllowedUsers = dedupeUsers(allowedUsers);
  const managedAllowedUsers = uniqueAllowedUsers.filter((user) => !user.recoveryNeedsReview);
  const adminTiles = [
    ["Announcements", announcements.length, "Bulletin Board"],
    ["Quick links", quickLinks.length, "Quick Links"],
    ["Training resources", trainingResources.length, "NexU / Training Center"],
    ["Documents", documents.length, "Documents"],
    ["Transaction guides", transactionGuides.length, "Transaction Help Center"],
    ["Support tickets", supportTickets.length, "Support Desk"],
    ["Website / IDX leads", "Review", "Website Leads / IDX"],
    ["Recruiting SEO", "Launch", "Recruiting SEO"],
    ["Users/agents", managedAllowedUsers.length, "Brand Settings / Admin"],
    ["Marketing templates", "Open", "Template Library"],
    ["Brand settings", "Open", "Brand Settings / Admin"]
  ];

  return (
    <section className="portal-page">
      <div className="module-hero">
        <div>
          <p className="eyebrow">Admin</p>
          <h3>Nex Central controls</h3>
          <p>Manage brokerage content, links, training, guides, support tickets, templates, users, and brand settings.</p>
        </div>
      </div>
      <div className="module-card-grid">
        {adminTiles.map(([label, value, page]) => (
          <button className="module-card" key={label} onClick={() => setActivePage(page)}>
            <Icon name="Settings" />
            <strong>{label}</strong>
            <span>{value}</span>
          </button>
        ))}
      </div>
    </section>
  );
}

const websiteThemeOptions = [
  { id: "clean-white", label: "Clean White" },
  { id: "nex-dark", label: "Nex Dark" },
  { id: "florida-coastal", label: "Florida Coastal" },
  { id: "luxury-black", label: "Luxury Black" },
  { id: "red-accent", label: "Red Accent" }
];
const websiteAccentOptions = [
  { value: "#e30613", label: "Nex Red" },
  { value: "#111318", label: "Nex Black" },
  { value: "#c9a24a", label: "Gold" },
  { value: "#247c8a", label: "Coastal" },
  { value: "#f7f8fb", label: "White" }
];
const websiteBackgroundOptions = websiteThemeOptions.map((option) => option.id);
const frontendLeadMarketAreas = [
  {
    id: "tampa-bay",
    name: "Tampa Bay",
    counties: ["Hillsborough County", "Pinellas County", "Pasco County", "Manatee County", "Sarasota County"],
    cities: ["Tampa", "St. Petersburg", "Clearwater", "Largo", "Brandon", "Riverview", "Wesley Chapel", "Palm Harbor", "Sarasota", "Bradenton"],
    zipCodes: []
  },
  {
    id: "orlando",
    name: "Orlando",
    counties: ["Orange County", "Seminole County", "Osceola County", "Lake County"],
    cities: ["Orlando", "Winter Park", "Kissimmee", "Sanford", "Altamonte Springs", "Clermont", "Winter Garden", "Lake Mary"],
    zipCodes: []
  },
  {
    id: "miami",
    name: "Miami",
    counties: ["Miami-Dade County", "Broward County", "Palm Beach County"],
    cities: ["Miami", "Miami Beach", "Coral Gables", "Fort Lauderdale", "Hollywood", "Pembroke Pines", "Boca Raton", "West Palm Beach"],
    zipCodes: []
  }
];

function textFromList(value) {
  if (Array.isArray(value)) return value.join(", ");
  return String(value || "");
}

function listFromText(value) {
  if (Array.isArray(value)) return value.map((item) => String(item || "").trim()).filter(Boolean);
  return String(value || "").split(",").map((item) => item.trim()).filter(Boolean);
}

function websiteThemeLabel(value) {
  return websiteThemeOptions.find((option) => option.id === value)?.label || "Clean White";
}

function serviceOptionsFromMarketAreas(marketAreas = [], payloadOptions = null) {
  if (payloadOptions) {
    return {
      counties: payloadOptions.counties || [],
      cities: payloadOptions.cities || [],
      zipCodes: payloadOptions.zipCodes || [],
      serviceAreas: payloadOptions.serviceAreas || []
    };
  }
  const areas = (marketAreas || []).length ? marketAreas : frontendLeadMarketAreas;
  const unique = (values) => Array.from(new Set(values.filter(Boolean))).sort((a, b) => String(a).localeCompare(String(b)));
  const counties = unique(areas.flatMap((area) => area.counties || []));
  const cities = unique(areas.flatMap((area) => area.cities || []));
  const zipCodes = unique(areas.flatMap((area) => area.zipCodes || []));
  return {
    counties,
    cities,
    zipCodes,
    serviceAreas: unique([...areas.map((area) => area.name), ...counties, ...cities])
  };
}

function StandardMultiSelect({ label, value, onChange, options = [], helper = "", disabled = false }) {
  const [query, setQuery] = useState("");
  const selected = listFromText(value);
  const normalizedOptions = Array.from(new Set([...options, ...selected].filter(Boolean))).sort((a, b) => String(a).localeCompare(String(b)));
  const visibleOptions = normalizedOptions
    .filter((option) => !query || String(option).toLowerCase().includes(query.toLowerCase()))
    .slice(0, 14);
  function toggle(option) {
    const next = selected.includes(option) ? selected.filter((item) => item !== option) : [...selected, option];
    onChange(next.join(", "));
  }
  return (
    <label className="field standard-multi-select">
      <span>{label}</span>
      <input
        className="standard-multi-search"
        value={query}
        onChange={(event) => setQuery(event.target.value)}
        placeholder={`Search ${String(label || "options").toLowerCase()}`}
        disabled={disabled}
      />
      {selected.length > 0 && (
        <div className="standard-multi-selected">
          {selected.map((option) => (
            <button key={option} type="button" onClick={() => toggle(option)} disabled={disabled}>
              <Icon name="X" size={13} />
              <span>{option}</span>
            </button>
          ))}
        </div>
      )}
      <div className="standard-multi-options">
        {visibleOptions.map((option) => (
          <button key={option} type="button" className={selected.includes(option) ? "selected" : ""} onClick={() => toggle(option)} disabled={disabled}>
            {option}
          </button>
        ))}
        {!visibleOptions.length && <em>{normalizedOptions.length ? "No matching options" : "No standardized options yet"}</em>}
      </div>
      {normalizedOptions.length > visibleOptions.length && <small>Showing the first {visibleOptions.length} matches. Search to narrow the list.</small>}
      {helper && <small>{helper}</small>}
    </label>
  );
}

function leadOptInStatus(user = {}) {
  if (user.active === false || user.licenseActive === false || user.leadRotationEligible === false) return { label: "Inactive / not eligible", short: "Not Eligible", tone: "red" };
  const status = String(user.leadRotationStatus || "inactive").toLowerCase();
  if (user.leadRotationOptIn && status === "active") return { label: "Opted in", short: "Lead Opt-In", tone: "green" };
  if (status === "paused") return { label: "Paused", short: "Lead Paused", tone: "amber" };
  if (status === "suspended") return { label: "Inactive / not eligible", short: "Not Eligible", tone: "red" };
  return { label: "Not opted in", short: "Not in Rotation", tone: "muted" };
}

function serviceAreaSummary(user = {}) {
  const areas = [
    ...(Array.isArray(user.serviceCounties) ? user.serviceCounties : listFromText(user.serviceCounties)),
    ...(Array.isArray(user.serviceCities) ? user.serviceCities : listFromText(user.serviceCities)),
    ...(Array.isArray(user.serviceZipCodes) ? user.serviceZipCodes : listFromText(user.serviceZipCodes))
  ].filter(Boolean);
  if (areas.length) return areas.slice(0, 4).join(", ") + (areas.length > 4 ? ` +${areas.length - 4}` : "");
  return textFromList(user.serviceAreas || user.market) || "No service areas";
}

function companyLeadEligible(user = {}) {
  return Boolean(user.leadRotationOptIn && String(user.leadRotationStatus || "").toLowerCase() === "active" && user.active !== false);
}

function crmSourceLabel(contact = {}) {
  if (contact.sourceDisplayLabel) return contact.sourceDisplayLabel;
  if (contact.companySourced || contact.brokerageGenerated) return contact.paidLead ? "Paid Company Lead" : "Company Lead";
  if (contact.privateLead) return "Private Lead";
  if (contact.manualEntry || contact.leadSourceType === "manual_entry" || contact.leadSourceType === "agent_manual_entry") return "Manual Entry";
  if (contact.agentGenerated || contact.agentOwnedLead) return "Agent-Owned Lead";
  return contact.leadSource || "Unclassified Lead";
}

function sourcePillTone(record = {}) {
  const label = String(record.sourceDisplayLabel || record.leadSourceType || "").toLowerCase();
  if (record.companySourced || record.brokerageGenerated || label.includes("company") || label.includes("brokerage")) return "brokerage";
  if (record.agentGenerated || record.agentOwnedLead || label.includes("agent-owned") || label.includes("private")) return "agent";
  if (record.needsAdminReview || record.manualAssignmentRequired || label.includes("review")) return "review";
  if (record.paidLead || label.includes("paid")) return "brokerage";
  return "";
}

function websiteProfileDraftFromUser(user = {}) {
  return {
    name: user.name || "",
    email: user.email || "",
    phone: user.phone || "",
    headshotUrl: user.headshotUrl || "",
    publicProfileEnabled: user.publicProfileEnabled !== false,
    websiteSlug: user.websiteSlug || user.publicSlug || user.subdomainSlug || "",
    websiteUrl: user.websiteUrl || user.agentWebsiteUrl || user.publicProfileUrl || "",
    websiteStatus: user.websiteStatus || "active",
    publicSlug: user.websiteSlug || user.publicSlug || user.subdomainSlug || "",
    publicBio: user.publicBio || "",
    market: user.market || "",
    primaryMarketArea: user.primaryMarketArea || "",
    serviceAreas: textFromList(user.serviceAreas || user.market),
    serviceCounties: textFromList(user.serviceCounties),
    serviceCities: textFromList(user.serviceCities),
    serviceZipCodes: textFromList(user.serviceZipCodes),
    languages: textFromList(user.languages || "English"),
    specialties: textFromList(user.specialties),
    idxSearchUrl: user.idxSearchUrl || "",
    agentWebsiteHeadline: user.agentWebsiteHeadline || "",
    agentWebsiteTagline: user.agentWebsiteTagline || "",
    agentWebsiteHeroImageUrl: user.agentWebsiteHeroImageUrl || "",
    agentWebsiteBackgroundStyle: user.agentWebsiteBackgroundStyle || "clean-white",
    agentWebsiteAccentColor: user.agentWebsiteAccentColor || "#e30613",
    agentWebsiteCtaLabel: user.agentWebsiteCtaLabel || "Contact me",
    preferredContactMethod: user.preferredContactMethod || "Any",
    calendlyUrl: user.calendlyUrl || "",
    facebookUrl: user.socialLinks?.facebook || "",
    instagramUrl: user.socialLinks?.instagram || "",
    linkedinUrl: user.socialLinks?.linkedin || "",
    commissionPlan: user.commissionPlan || "",
    anniversaryDate: user.anniversaryDate || "",
    role: user.role || "Agent"
  };
}

function publicProfileLink(profile = {}) {
  const value = profile.websiteUrl || profile.agentWebsiteUrl || profile.websitePath || profile.publicProfileUrl || profile.publicProfilePath || "";
  if (!value) return "";
  if (/^https?:\/\//i.test(value)) return value;
  return `${window.location.origin}${value.startsWith("/") ? value : `/${value}`}`;
}

const agentWebsiteSetupSteps = [
  { id: "status", label: "Website Status", icon: "BadgeCheck" },
  { id: "contact", label: "Contact Info", icon: "ContactRound" },
  { id: "service", label: "Service Area", icon: "MapPinned" },
  { id: "style", label: "Website Style", icon: "Palette" },
  { id: "preview", label: "Preview & Leads", icon: "MonitorSmartphone" }
];

function uniqueAgentWebsiteAreas(draft = {}) {
  return [
    ...listFromText(draft.serviceAreas),
    ...listFromText(draft.serviceCounties),
    ...listFromText(draft.serviceCities),
    ...listFromText(draft.serviceZipCodes)
  ].filter((item, index, items) => item && items.indexOf(item) === index);
}

function agentWebsiteSetupStatus(profile = {}, draft = {}, agentWebsite = {}, idx = {}) {
  const missing = [];
  if (!draft.phone) missing.push("phone number");
  if (!draft.email) missing.push("email");
  if (!draft.headshotUrl) missing.push("headshot");
  if (!uniqueAgentWebsiteAreas(draft).length && !draft.market && !draft.primaryMarketArea) missing.push("service area");
  if (!draft.agentWebsiteHeadline) missing.push("headline");

  const published = draft.publicProfileEnabled !== false && String(draft.websiteStatus || profile.websiteStatus || "active").toLowerCase() !== "disabled" && profile.active !== false;
  const idxReady = Boolean(agentWebsite?.idxEnabled || idx?.apiConfigured || idx?.searchUrl || idx?.apiFetchEnabled);
  const dnsReady = Boolean(agentWebsite?.domainStatus?.dnsReady || agentWebsite?.dnsStatus === "live" || agentWebsite?.dnsStatus === "ready");
  const routingReady = Boolean(agentWebsite?.leadRoutingAgentId || profile.leadRoutingAgentId || profile.id);
  const checks = [
    draft.phone,
    draft.email,
    draft.headshotUrl,
    uniqueAgentWebsiteAreas(draft).length || draft.market || draft.primaryMarketArea,
    draft.agentWebsiteHeadline || draft.name,
    published,
    routingReady,
    idxReady
  ];
  const score = Math.round((checks.filter(Boolean).length / checks.length) * 100);
  let label = "Live";
  let tone = "green";
  if (!published) {
    label = "Hidden";
    tone = "muted";
  } else if (missing.length) {
    label = "Setup Needed";
    tone = "amber";
  } else if (!idxReady) {
    label = "IDX Pending";
    tone = "amber";
  } else if (!dnsReady) {
    label = "DNS Pending";
    tone = "blue";
  }
  return { label, tone, score, missing, published, idxReady, dnsReady, routingReady };
}

function AgentWebsiteManager({ currentUser, setCurrentUser, brand, setToast, setActivePage }) {
  const [draft, setDraft] = useState(() => websiteProfileDraftFromUser(currentUser));
  const [profile, setProfile] = useState(currentUser || {});
  const [agentWebsite, setAgentWebsite] = useState(null);
  const [recentLeads, setRecentLeads] = useState([]);
  const [leadRoutingStatus, setLeadRoutingStatus] = useState("");
  const [websiteAccess, setWebsiteAccess] = useState({ canUseAgentWebsite: true, agentWebsiteMode: "agent", agentWebsiteAccessMessage: "" });
  const [idx, setIdx] = useState(null);
  const [marketAreas, setMarketAreas] = useState(frontendLeadMarketAreas);
  const [serviceAreaOptions, setServiceAreaOptions] = useState(serviceOptionsFromMarketAreas(frontendLeadMarketAreas));
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [activeStep, setActiveStep] = useState("status");
  const [advancedOpen, setAdvancedOpen] = useState(false);

  useEffect(() => {
    let cancelled = false;
    API.request("/api/me/website")
      .then((payload) => {
        if (cancelled) return;
        setProfile(payload.profile || currentUser || {});
        setAgentWebsite(payload.agentWebsite || null);
        setRecentLeads(payload.recentLeads || []);
        setLeadRoutingStatus(payload.leadRoutingStatus || "");
        setWebsiteAccess({
          canUseAgentWebsite: payload.canUseAgentWebsite !== false,
          agentWebsiteMode: payload.agentWebsiteMode || "agent",
          agentWebsiteAccessMessage: payload.agentWebsiteAccessMessage || ""
        });
        setDraft(websiteProfileDraftFromUser(payload.profile || currentUser || {}));
        setIdx(payload.idx || null);
        setMarketAreas(payload.marketAreas || frontendLeadMarketAreas);
        setServiceAreaOptions(serviceOptionsFromMarketAreas(payload.marketAreas || frontendLeadMarketAreas, payload.serviceAreaOptions));
      })
      .catch((error) => setToast(error.message || "Could not load website profile."))
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [currentUser?.email, setToast]);

  function update(field, value) {
    setDraft((current) => ({ ...current, [field]: value }));
  }

  function togglePublished(nextPublished) {
    setDraft((current) => ({
      ...current,
      publicProfileEnabled: nextPublished,
      websiteStatus: nextPublished ? "active" : "disabled"
    }));
  }

  async function saveWebsiteProfile() {
    setSaving(true);
    try {
      const savePayload = {
        ...draft,
        publicSlug: draft.websiteSlug,
        websiteSlug: draft.websiteSlug,
        socialLinks: {
          facebook: draft.facebookUrl,
          instagram: draft.instagramUrl,
          linkedin: draft.linkedinUrl
        }
      };
      const payload = await API.request("/api/me/website", {
        method: "PUT",
        body: JSON.stringify(savePayload)
      });
      setProfile(payload.profile || profile);
      setAgentWebsite(payload.agentWebsite || null);
      setRecentLeads(payload.recentLeads || []);
      setLeadRoutingStatus(payload.leadRoutingStatus || "");
      setWebsiteAccess({
        canUseAgentWebsite: payload.canUseAgentWebsite !== false,
        agentWebsiteMode: payload.agentWebsiteMode || "agent",
        agentWebsiteAccessMessage: payload.agentWebsiteAccessMessage || ""
      });
      setDraft(websiteProfileDraftFromUser(payload.profile || draft));
      setIdx(payload.idx || idx);
      setMarketAreas(payload.marketAreas || marketAreas);
      setServiceAreaOptions(serviceOptionsFromMarketAreas(payload.marketAreas || marketAreas, payload.serviceAreaOptions));
      if (payload.profile) setCurrentUser(payload.profile);
      setToast("Agent website profile updated.");
      return true;
    } catch (error) {
      setToast(error.message || "Could not save website profile.");
      return false;
    } finally {
      setSaving(false);
    }
  }

  async function saveAndContinueWebsiteSetup() {
    const saved = await saveWebsiteProfile();
    if (!saved) return;
    if (nextStepIndex >= agentWebsiteSetupSteps.length - 1) {
      setToast("Website saved. Your visitor preview and lead routing are ready to review.");
      return;
    }
    setActiveStep(nextStep);
  }

  function onHeadshotChange(event) {
    const file = Array.from(event.target.files || [])[0];
    if (!file || !file.type.startsWith("image/")) return;
    const reader = new FileReader();
    reader.onload = () => update("headshotUrl", reader.result);
    reader.readAsDataURL(file);
  }

  if (!loading && websiteAccess.canUseAgentWebsite === false) {
    return (
      <section className="portal-page agent-website-page">
        <div className="module-hero agent-website-hero">
          <div>
            <p className="eyebrow">My Website</p>
            <h3>Agent website controls</h3>
            <p>Active agent accounts receive their own IDX-enabled website automatically. Admin accounts manage and preview those websites from the admin tools.</p>
          </div>
          <div className="agent-website-status">
            <span>Admin view</span>
            <strong>Control center</strong>
            <small>No personal public site</small>
          </div>
        </div>
        <div className="panel agent-website-admin-notice">
          <div className="agent-website-admin-copy">
            <Icon name="ShieldCheck" />
            <div>
              <p className="eyebrow">Admin account</p>
              <h3>Admins do not publish personal agent websites</h3>
              <p>{websiteAccess.agentWebsiteAccessMessage || "Use Website Leads / IDX to preview, test, disable, and manage active agent websites."}</p>
            </div>
          </div>
          <div className="agent-command-grid">
            <div className="agent-command-field">
              <span>Active agents</span>
              <strong>Automatic websites</strong>
              <small>Each active agent gets a clean slug and IDX-enabled public site when their account is created.</small>
            </div>
            <div className="agent-command-field">
              <span>Live URL format</span>
              <strong>agent-slug.nexrealtygroup.com</strong>
              <small>The fallback path also works while DNS or certificates finish connecting.</small>
            </div>
            <div className="agent-command-field">
              <span>Lead routing</span>
              <strong>Direct to agent CRM</strong>
              <small>Leads from an agent website stay assigned to that agent unless the agent is inactive or disabled.</small>
            </div>
            <div className="agent-command-field">
              <span>Admin control</span>
              <strong>Website Leads / IDX</strong>
              <small>Preview agent sites, disable sites, test routing, and review website health from the admin dashboard.</small>
            </div>
          </div>
          <div className="agent-website-admin-actions">
            <button className="btn primary" type="button" onClick={() => setActivePage?.("Website Leads / IDX")}>
              <Icon name="Globe2" />
              <span>Open Agent Website Controls</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => setActivePage?.("Directory")}>
              <Icon name="UsersRound" />
              <span>Review Agent Directory</span>
            </button>
          </div>
        </div>
      </section>
    );
  }

  const previewProfile = { ...profile, ...draft };
  const profileUrl = publicProfileLink({ websiteUrl: agentWebsite?.currentUrl || agentWebsite?.websiteUrl || profile.websiteUrl || draft.websiteUrl || agentWebsite?.agentWebsiteUrl || profile.agentWebsiteUrl });
  const futureUrl = agentWebsite?.futureUrl || agentWebsite?.futureSubdomainUrl || profile.agentSubdomainUrl || "";
  const headline = draft.agentWebsiteHeadline || `Search Florida homes with ${draft.name || "your Nex Realty agent"}`;
  const tagline = draft.agentWebsiteTagline || "Search homes, ask questions, request showings, and get local guidance under Nex Realty LLC.";
  const selectedAreas = uniqueAgentWebsiteAreas(draft);
  const serviceAreas = selectedAreas.slice(0, 6);
  const specialties = textFromList(draft.specialties).split(",").map((item) => item.trim()).filter(Boolean).slice(0, 6);
  const setupStatus = agentWebsiteSetupStatus(profile, draft, agentWebsite, idx);
  const routeLabel = setupStatus.published ? (leadRoutingStatus || `Leads from this website route to ${draft.name || "you"}.`) : "Hidden sites route new inquiries to Nex admin fallback.";
  const listingStatus = setupStatus.idxReady ? "Brokerage IDX search is connected" : "Search is being prepared";
  const nextStepIndex = agentWebsiteSetupSteps.findIndex((step) => step.id === activeStep);
  const nextStep = agentWebsiteSetupSteps[Math.min(agentWebsiteSetupSteps.length - 1, nextStepIndex + 1)]?.id || "preview";

  function renderSetupStep() {
    if (activeStep === "status") {
      return (
        <div className="agent-website-step-body">
          <div className="agent-command-grid">
            <div className="agent-command-field">
              <span>Website visibility</span>
              <button className={classNames("agent-publish-toggle", setupStatus.published && "on")} type="button" onClick={() => togglePublished(!setupStatus.published)}>
                <i />
                <strong>{setupStatus.published ? "Published" : "Hidden"}</strong>
              </button>
            </div>
            <div className="agent-command-field">
              <span>Current website link</span>
              <strong>{profileUrl || "Creating your website link"}</strong>
              <small>{setupStatus.dnsReady ? "This is your live public agent website." : "This fallback link works while your subdomain finishes connecting."}</small>
            </div>
            <div className="agent-command-field">
              <span>{setupStatus.dnsReady ? "Agent subdomain" : "Future subdomain"}</span>
              <strong>{futureUrl || "Reserved after DNS is connected"}</strong>
              <small>{setupStatus.dnsReady ? "Wildcard DNS is live, so agent subdomains work automatically." : "DNS Pending until the final domain is configured."}</small>
            </div>
            <div className="agent-command-field">
              <span>IDX search</span>
              <strong>{listingStatus}</strong>
              <small>{setupStatus.idxReady ? "Visitors can search brokerage IDX listings from your site." : "Visitors will see a clean preparation message instead of a broken search."}</small>
            </div>
            <div className="agent-command-field">
              <span>Lead routing</span>
              <strong>{setupStatus.routingReady ? "Direct to your Nex CRM" : "Needs review"}</strong>
              <small>{routeLabel}</small>
            </div>
            <div className="agent-command-field">
              <span>Setup checklist</span>
              <strong>{setupStatus.score}% complete</strong>
              <small>{setupStatus.missing.length ? `Add ${setupStatus.missing.join(", ")}.` : "Your core setup is complete."}</small>
            </div>
          </div>
        </div>
      );
    }
    if (activeStep === "contact") {
      return (
        <div className="agent-website-step-body">
          <div className="agent-website-form-grid simplified">
            <Field label="Display name" value={draft.name} onChange={(value) => update("name", value)} />
            <Field label="Email" value={draft.email} onChange={(value) => update("email", value)} type="email" />
            <Field label="Phone" value={draft.phone} onChange={(value) => update("phone", value)} />
            <Field label="Preferred contact method" value={draft.preferredContactMethod} onChange={(value) => update("preferredContactMethod", value)} as="select" options={["Any", "Call", "Text", "Email", "Schedule online"]} />
            <Field label="Scheduling link" value={draft.calendlyUrl} onChange={(value) => update("calendlyUrl", value)} placeholder="https://calendly.com/..." />
            <Field label="Bio" value={draft.publicBio} onChange={(value) => update("publicBio", value)} as="textarea" placeholder="Short professional agent bio." />
          </div>
          <label className="file-drop agent-website-headshot-upload">
            {draft.headshotUrl ? <img src={draft.headshotUrl} alt="" /> : <Icon name="ImagePlus" size={20} />}
            <span>Upload/update headshot</span>
            <input type="file" accept="image/*" onChange={onHeadshotChange} />
          </label>
        </div>
      );
    }
    if (activeStep === "service") {
      return (
        <div className="agent-website-step-body">
          <div className="agent-service-picker-head">
            <div>
              <strong>Selected service areas</strong>
              <span>{selectedAreas.length ? `${selectedAreas.length} area${selectedAreas.length === 1 ? "" : "s"} selected` : "Choose the areas visitors should see."}</span>
            </div>
            <div className="agent-selected-area-row">
              {selectedAreas.slice(0, 12).map((area) => <em key={area}>{area}</em>)}
              {!selectedAreas.length && <em>No service areas selected yet</em>}
            </div>
          </div>
          <div className="agent-website-form-grid simplified">
            <Field label="Service region" value={draft.market} onChange={(value) => update("market", value)} as="select" options={["", "Tampa Bay", "Orlando", "Miami", "Treasure Coast", "Other"]} />
            <MarketAreaSelect label="Main service market" value={draft.primaryMarketArea} onChange={(value) => update("primaryMarketArea", value)} marketAreas={marketAreas} />
            <StandardMultiSelect label="Service areas" value={draft.serviceAreas} onChange={(value) => update("serviceAreas", value)} options={serviceAreaOptions.serviceAreas} helper="Search and choose only what you want visitors to see." />
            <StandardMultiSelect label="Service counties" value={draft.serviceCounties} onChange={(value) => update("serviceCounties", value)} options={serviceAreaOptions.counties} />
            <StandardMultiSelect label="Service cities" value={draft.serviceCities} onChange={(value) => update("serviceCities", value)} options={serviceAreaOptions.cities} />
            <Field label="Service ZIP codes" value={draft.serviceZipCodes} onChange={(value) => update("serviceZipCodes", value)} placeholder="33602, 33701" />
          </div>
        </div>
      );
    }
    if (activeStep === "style") {
      return (
        <div className="agent-website-step-body">
          <div className="agent-website-form-grid simplified">
            <Field label="Website headline" value={draft.agentWebsiteHeadline} onChange={(value) => update("agentWebsiteHeadline", value)} placeholder="Search Florida homes with me" />
            <Field label="Button text" value={draft.agentWebsiteCtaLabel} onChange={(value) => update("agentWebsiteCtaLabel", value)} placeholder="Ask me a question" />
            <Field label="Website subheadline" value={draft.agentWebsiteTagline} onChange={(value) => update("agentWebsiteTagline", value)} as="textarea" placeholder="Tell buyers and sellers how you help." />
          </div>
          <div className="agent-website-style-panel clean">
            <div>
              <p className="eyebrow">Your website style</p>
              <h3>Choose a Nex-approved look</h3>
            </div>
            <div className="agent-theme-options">
              {websiteThemeOptions.map((option) => (
                <button key={option.id} type="button" className={draft.agentWebsiteBackgroundStyle === option.id ? "selected" : ""} onClick={() => update("agentWebsiteBackgroundStyle", option.id)}>
                  <span className={`theme-swatch ${option.id}`} />
                  {option.label}
                </button>
              ))}
            </div>
            <div className="agent-accent-options">
              {websiteAccentOptions.map((option) => (
                <button key={option.value} type="button" className={draft.agentWebsiteAccentColor === option.value ? "selected" : ""} onClick={() => update("agentWebsiteAccentColor", option.value)} title={option.label}>
                  <span style={{ background: option.value }} />
                  {option.label}
                </button>
              ))}
            </div>
          </div>
          <button className="agent-advanced-toggle" type="button" onClick={() => setAdvancedOpen((value) => !value)}>
            <Icon name={advancedOpen ? "ChevronUp" : "ChevronDown"} />
            <span>Advanced website settings</span>
          </button>
          {advancedOpen && (
            <div className="agent-website-form-grid simplified advanced">
              <Field label="Background image" value={draft.agentWebsiteHeroImageUrl} onChange={(value) => update("agentWebsiteHeroImageUrl", value)} placeholder="https://..." />
              <Field label="Languages" value={draft.languages} onChange={(value) => update("languages", value)} placeholder="English, Spanish" />
              <Field label="Specialties" value={draft.specialties} onChange={(value) => update("specialties", value)} placeholder="Buyers, Listings, Luxury, Investors" />
              <Field label="Facebook" value={draft.facebookUrl} onChange={(value) => update("facebookUrl", value)} placeholder="https://facebook.com/..." />
              <Field label="Instagram" value={draft.instagramUrl} onChange={(value) => update("instagramUrl", value)} placeholder="https://instagram.com/..." />
              <Field label="LinkedIn" value={draft.linkedinUrl} onChange={(value) => update("linkedinUrl", value)} placeholder="https://linkedin.com/in/..." />
            </div>
          )}
        </div>
      );
    }
    return (
      <div className="agent-website-step-body">
        <div className="agent-recent-leads command">
          <div>
            <p className="eyebrow">Leads from your website</p>
            <h3>{recentLeads.length ? `${recentLeads.length} recent lead${recentLeads.length === 1 ? "" : "s"}` : "No website leads yet"}</h3>
          </div>
          {recentLeads.length ? (
            <div className="agent-recent-lead-list">
              {recentLeads.map((lead) => (
                <article key={lead.id}>
                  <strong>{lead.name || "New website lead"}</strong>
                  <span>{lead.leadIntent || lead.idxIntent || lead.type || "Website inquiry"}</span>
                  <small>{lead.createdAt ? new Date(lead.createdAt).toLocaleString() : "New"}</small>
                </article>
              ))}
            </div>
          ) : (
            <p className="muted">When someone asks a question, requests a showing, saves a search, or asks about home value from your website, it will appear here.</p>
          )}
        </div>
        <div className="agent-command-grid">
          <div className="agent-command-field">
            <span>Routing confirmation</span>
            <strong>{setupStatus.routingReady ? "Ready" : "Needs admin review"}</strong>
            <small>{routeLabel}</small>
          </div>
          <div className="agent-command-field">
            <span>Preview as visitor</span>
            <strong>{profileUrl ? "Available" : "Creating link"}</strong>
            <small>Open your public site exactly how a visitor will see it.</small>
          </div>
        </div>
      </div>
    );
  }

  return (
    <section className="portal-page agent-website-page">
      <div className="module-hero agent-website-hero">
        <div>
          <p className="eyebrow">My Website</p>
          <h3>Your Nex agent website</h3>
          <p>Check your live link, confirm leads route to you, update what visitors see, and preview your IDX-enabled agent website.</p>
        </div>
        <div className="agent-website-status">
          <span>Website status</span>
          <strong>{setupStatus.label}</strong>
          <small>{setupStatus.score}% complete</small>
        </div>
      </div>

      {loading ? (
        <EmptyState icon="LoaderCircle" title="Loading your website" body="Getting your link, visitor preview, and recent website leads." />
      ) : (
        <div className="agent-website-command-layout">
          <aside className="agent-website-command-sidebar">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Your Website Link</p>
                <h3>{profileUrl ? "Ready to share" : "Being created"}</h3>
              </div>
              <span className={classNames("status-badge", setupStatus.tone)}>{setupStatus.label}</span>
            </div>

            <div className="agent-website-link-box">
              <div>
                <strong>Current website link</strong>
                <span>{profileUrl || "Your website link will appear here once your profile is active."}</span>
              </div>
              <button className="btn secondary compact" type="button" onClick={() => profileUrl ? copyToClipboard(profileUrl, setToast) : setToast("No website link is available yet.")}>
                <Icon name="Copy" />
                <span>Copy Link</span>
              </button>
              {profileUrl && (
                <button className="btn primary compact" type="button" onClick={() => window.open(profileUrl, "_blank", "noopener,noreferrer")}>
                  <Icon name="ExternalLink" />
                  <span>View My Website</span>
                </button>
              )}
            </div>

            <div className="agent-website-readiness plain">
              <span><strong>Lead routing</strong>{setupStatus.routingReady ? "Direct to your Nex CRM" : "Needs admin review"}</span>
              <span><strong>IDX/search</strong>{listingStatus}</span>
              <span><strong>DNS</strong>{setupStatus.dnsReady ? "Subdomain ready" : "DNS pending"}</span>
            </div>
            <div className="agent-setup-score">
              <div>
                <strong>{setupStatus.score}% complete</strong>
                <span>{setupStatus.missing.length ? `Next: add ${setupStatus.missing[0]}.` : "Core setup complete."}</span>
              </div>
              <meter min="0" max="100" value={setupStatus.score}>{setupStatus.score}%</meter>
            </div>

            <div className="agent-website-step-list" aria-label="Website setup steps">
              {agentWebsiteSetupSteps.map((step, index) => (
                <button key={step.id} type="button" className={activeStep === step.id ? "active" : ""} onClick={() => setActiveStep(step.id)}>
                  <Icon name={step.icon} />
                  <span>{index + 1}. {step.label}</span>
                </button>
              ))}
            </div>
          </aside>

          <article className="panel agent-website-editor command">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Step {nextStepIndex + 1} of {agentWebsiteSetupSteps.length}</p>
                <h3>{agentWebsiteSetupSteps.find((step) => step.id === activeStep)?.label || "Website setup"}</h3>
              </div>
              <button className="btn primary" type="button" onClick={saveWebsiteProfile} disabled={saving}>
                <Icon name={saving ? "LoaderCircle" : "Save"} className={saving ? "spin" : ""} />
                <span>{saving ? "Saving" : "Save Website"}</span>
              </button>
            </div>
            <div className="agent-next-action-bar">
              <Icon name="ListChecks" />
              <span>{setupStatus.missing.length ? `Next recommended action: add ${setupStatus.missing[0]}.` : "Next recommended action: preview your site and confirm lead routing."}</span>
            </div>
            {renderSetupStep()}
            <div className="agent-step-actions sticky">
              <button className="btn secondary" type="button" onClick={() => setActiveStep(agentWebsiteSetupSteps[Math.max(0, nextStepIndex - 1)]?.id || "status")} disabled={nextStepIndex <= 0}>Previous Step</button>
              <button className="btn secondary" type="button" onClick={() => profileUrl ? window.open(profileUrl, "_blank", "noopener,noreferrer") : setToast("No website link is available yet.")}>
                <Icon name="Eye" />
                <span>Preview as visitor</span>
              </button>
              <button className="btn primary" type="button" onClick={saveAndContinueWebsiteSetup} disabled={saving}>
                <span>{nextStepIndex >= agentWebsiteSetupSteps.length - 1 ? "Save Website" : "Save & Continue"}</span>
                <Icon name="ArrowRight" />
              </button>
            </div>
          </article>

          <aside className="panel agent-website-preview-panel command">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Live preview</p>
                <h3>What visitors see</h3>
              </div>
              <span className="status-badge">{websiteThemeLabel(draft.agentWebsiteBackgroundStyle)}</span>
            </div>
            <div
              className={classNames("agent-site-preview-card", `theme-${draft.agentWebsiteBackgroundStyle || "clean-white"}`)}
              style={{
                "--agent-site-accent": draft.agentWebsiteAccentColor || brand.primaryColor,
                backgroundImage: draft.agentWebsiteHeroImageUrl ? `linear-gradient(120deg, rgba(255,255,255,.92), rgba(255,255,255,.74)), url(${draft.agentWebsiteHeroImageUrl})` : ""
              }}
            >
              <div className="agent-site-preview-copy">
                <span>Nex Realty LLC</span>
                <h2>{headline}</h2>
                <p>{tagline}</p>
                <div className="agent-site-preview-tags">
                  {[...serviceAreas, ...specialties].slice(0, 5).map((item) => <em key={item}>{item}</em>)}
                </div>
                <button type="button">{draft.agentWebsiteCtaLabel || "Contact me"}</button>
              </div>
              <div className="agent-site-preview-agent">
                <UserAvatar user={{ ...previewProfile, headshotUrl: draft.headshotUrl }} size="lg" />
                <strong>{draft.name || currentUser?.name}</strong>
                <span>{draft.phone || "Add phone"}</span>
                <small>{draft.email || currentUser?.email}</small>
              </div>
            </div>
          </aside>
        </div>
      )}
    </section>
  );
}

function leadSourceLabel(lead) {
  if (lead.sourceDisplayLabel) return lead.sourceDisplayLabel;
  if (lead.manualAssignmentRequired) return "Needs Manual Assignment";
  if (lead.leadSourceType === "recruiting_agent_inquiry" || lead.type === "recruiting") return "Recruiting / Agent Inquiry";
  if (lead.agentGenerated) return "Agent Website Lead";
  if (lead.leadSourceType === "paid_brokerage_lead") return "Paid Brokerage Lead";
  if (lead.leadSourceType === "organic_brokerage_lead") return "Organic Brokerage Lead";
  if (lead.brokerageGenerated) return "Brokerage Generated Lead";
  if (lead.needsAdminReview) return "Needs Admin Review";
  return lead.leadSourceType || "Website Lead";
}

function MarketAreaSelect({ label = "Primary market area", value, onChange, marketAreas = [], disabled = false }) {
  const activeMarkets = (marketAreas || []).filter((area) => area.active !== false);
  return (
    <label className="field">
      <span>{label}</span>
      <select value={value || ""} onChange={(event) => onChange(event.target.value)} disabled={disabled}>
        <option value="">Select market</option>
        {activeMarkets.map((area) => (
          <option key={area.id} value={area.id}>{area.name}</option>
        ))}
      </select>
    </label>
  );
}

function NexLeads({ currentUser, role, setToast, setActivePage }) {
  const [data, setData] = useState({ leads: [], myLeads: [], agents: [], marketAreas: [], serviceAreaOptions: null, summary: {}, settings: {}, terms: {}, agent: null, permissions: {} });
  const [loading, setLoading] = useState(true);
  const [filter, setFilter] = useState("All");
  const [draft, setDraft] = useState({ primaryMarketArea: "", serviceCounties: "", serviceCities: "", serviceZipCodes: "", maxActiveBrokerageLeads: 10, buyerLeadsEnabled: true, sellerLeadsEnabled: true, rentalLeadsEnabled: true, investorLeadsEnabled: true });
  const [editingAgentId, setEditingAgentId] = useState("");
  const [agentAreaDraft, setAgentAreaDraft] = useState({ primaryMarketArea: "", serviceCounties: "", serviceCities: "", serviceZipCodes: "", maxActiveBrokerageLeads: 10 });
  const [marketAreaDrafts, setMarketAreaDrafts] = useState({});
  const [newMarketDraft, setNewMarketDraft] = useState({ name: "", counties: "", cities: "", zipCodes: "" });
  const canViewAll = isAdminRole(role);

  function syncMarketAreaDrafts(marketAreas = []) {
    setMarketAreaDrafts(Object.fromEntries((marketAreas || []).map((area) => [
      area.id,
      {
        name: area.name || "",
        counties: textFromList(area.counties),
        cities: textFromList(area.cities),
        zipCodes: textFromList(area.zipCodes),
        active: area.active !== false
      }
    ])));
  }

  async function loadLeads() {
    setLoading(true);
    try {
      const payload = await API.request("/api/lead-rotation/bootstrap");
      setData(payload);
      const user = payload.me || currentUser || {};
      const marketAreas = payload.marketAreas || [];
      setDraft({
        primaryMarketArea: user.primaryMarketArea || payload.agent?.primaryMarketArea || marketAreas[0]?.id || "",
        serviceCounties: textFromList(user.serviceCounties || user.serviceAreas || user.market),
        serviceCities: textFromList(user.serviceCities),
        serviceZipCodes: textFromList(user.serviceZipCodes),
        maxActiveBrokerageLeads: user.maxActiveBrokerageLeads || payload.settings?.maxActiveBrokerageLeadsPerAgent || 10,
        buyerLeadsEnabled: user.buyerLeadsEnabled !== false,
        sellerLeadsEnabled: user.sellerLeadsEnabled !== false,
        rentalLeadsEnabled: user.rentalLeadsEnabled !== false,
        investorLeadsEnabled: user.investorLeadsEnabled !== false
      });
      syncMarketAreaDrafts(marketAreas);
    } catch (error) {
      setToast(error.message || "Could not load Nex Leads.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadLeads();
  }, []);

  async function saveRotationSettings(extra = {}) {
    try {
      const payload = await API.request("/api/lead-rotation/me", {
        method: "PUT",
        body: JSON.stringify({
          ...draft,
          ...extra,
          serviceCounties: draft.serviceCounties,
          serviceCities: draft.serviceCities,
          serviceZipCodes: draft.serviceZipCodes
        })
      });
      setData(payload);
      setToast(extra.acceptTerms ? "You are opted in to Nex generated lead rotation." : "Lead rotation settings saved.");
    } catch (error) {
      setToast(error.message || "Could not save lead settings.");
    }
  }

  async function updateLead(lead, action, body = {}) {
    try {
      const response = await API.request(`/api/website-leads/${encodeURIComponent(lead.id)}`, {
        method: "PUT",
        body: JSON.stringify({ action, ...body })
      });
      setData(response.bootstrap || data);
      setToast(action === "accept" ? "Lead accepted." : action === "decline" ? "Lead moved to admin review." : "Lead updated.");
    } catch (error) {
      setToast(error.message || "Could not update lead.");
    }
  }

  function openAgentAreaEditor(agent) {
    setEditingAgentId(agent.id);
    setAgentAreaDraft({
      primaryMarketArea: agent.primaryMarketArea || "",
      serviceCounties: textFromList(agent.serviceCounties || agent.serviceAreas),
      serviceCities: textFromList(agent.serviceCities),
      serviceZipCodes: textFromList(agent.serviceZipCodes),
      maxActiveBrokerageLeads: agent.maxActiveBrokerageLeads || data.settings?.maxActiveBrokerageLeadsPerAgent || 10
    });
  }

  async function updateAgentRotation(agent, patch = {}, message = "Lead rotation updated.") {
    if (!canViewAll) return;
    try {
      const payload = await API.request(`/api/lead-rotation/agents/${encodeURIComponent(agent.id || agent.userId || agent.email)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      setData(payload);
      setToast(message);
      if (patch.primaryMarketArea || patch.serviceCounties || patch.serviceCities || patch.serviceZipCodes || patch.maxActiveBrokerageLeads) {
        setEditingAgentId("");
      }
    } catch (error) {
      setToast(error.message || "Could not update lead rotation.");
    }
  }

  async function saveMarketArea(id) {
    if (!canViewAll) return;
    const draftArea = marketAreaDrafts[id] || {};
    try {
      const payload = await API.request(`/api/lead-rotation/market-areas/${encodeURIComponent(id)}`, {
        method: "PUT",
        body: JSON.stringify(draftArea)
      });
      setData(payload);
      syncMarketAreaDrafts(payload.marketAreas || []);
      setToast("Market area mapping saved.");
    } catch (error) {
      setToast(error.message || "Could not save market area.");
    }
  }

  async function addMarketArea() {
    if (!canViewAll || !newMarketDraft.name.trim()) return;
    try {
      const payload = await API.request("/api/lead-rotation/market-areas", {
        method: "POST",
        body: JSON.stringify(newMarketDraft)
      });
      setData(payload);
      syncMarketAreaDrafts(payload.marketAreas || []);
      setNewMarketDraft({ name: "", counties: "", cities: "", zipCodes: "" });
      setToast("Market area added.");
    } catch (error) {
      setToast(error.message || "Could not add market area.");
    }
  }

  const leads = (canViewAll ? data.leads : data.myLeads || data.leads || []).filter((lead) => {
    if (filter === "All") return true;
    if (filter === "Brokerage") return lead.brokerageGenerated;
    if (filter === "Agent Website") return lead.agentGenerated;
    if (filter === "Recruiting") return lead.type === "recruiting" || lead.leadSourceType === "recruiting_agent_inquiry";
    if (filter === "Review") return lead.needsAdminReview || !lead.assignedAgentEmail;
    return true;
  });
  const agentProfile = data.agent || {};
  const acceptedTerms = Boolean(agentProfile.acceptedTerms || (data.me?.acceptedBrokerageLeadTermsAt && data.me?.acceptedBrokerageLeadTermsVersion === data.terms?.version));
  const optedIn = Boolean(data.me?.leadRotationOptIn);
  const activeStatus = data.me?.leadRotationStatus || "inactive";
  const marketAreas = data.marketAreas || [];
  const serviceAreaOptions = serviceOptionsFromMarketAreas(marketAreas, data.serviceAreaOptions);
  const myLeadOptStatus = leadOptInStatus(data.me || {});

  return (
    <section className="portal-page nex-leads-page">
      <div className="module-hero nex-leads-hero">
        <div>
          <p className="eyebrow">Nex Leads</p>
          <h3>Brokerage lead rotation and accountability</h3>
          <p>Protect agent-owned website leads, route Nex generated leads fairly, and keep follow-up accountable from the first minute.</p>
        </div>
        <div className="idx-launch-card">
          <Icon name="Route" />
          <strong>{myLeadOptStatus.short}</strong>
          <span>{acceptedTerms ? "Terms accepted" : "Terms required"}</span>
        </div>
      </div>

      <div className="website-lead-stats">
        {[
          ["Brokerage generated", data.summary?.brokerageGenerated || 0, "Building2"],
          ["Agent website leads", data.summary?.agentGenerated || 0, "Globe2"],
          ["Recruiting inquiries", data.summary?.recruiting || 0, "UserRoundPlus"],
          ["Follow-up due", data.summary?.followUpDue || 0, "Clock3"],
          ["Accepted", data.summary?.accepted || 0, "BadgeCheck"],
          ["Review needed", data.summary?.reviewRequired || 0, "ShieldAlert"]
        ].map(([label, value, icon]) => (
          <article key={label}>
            <Icon name={icon} />
            <span>{label}</span>
            <strong>{value}</strong>
          </article>
        ))}
      </div>

      <div className="website-lead-grid nex-leads-grid">
        <article className="panel nex-lead-optin-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Agent opt-in</p>
              <h3>Nex Generated Lead Rotation</h3>
            </div>
            <span className={classNames("lead-source-pill", myLeadOptStatus.tone === "green" && "brokerage", myLeadOptStatus.tone === "amber" && "review", myLeadOptStatus.tone === "red" && "review")}>{myLeadOptStatus.label}</span>
          </div>
          <p className="muted-text">
            Nex generated leads come from the main brokerage website, company IDX, paid campaigns, and company SEO. Personal agent website/subdomain leads are routed directly to you and do not carry the additional brokerage-generated lead fee.
          </p>
          <div className="lead-terms-box">
            <strong>Required acknowledgement</strong>
            <p>{data.terms?.text}</p>
          </div>
          <div className="lead-settings-grid">
            <MarketAreaSelect label="Primary market area" value={draft.primaryMarketArea} onChange={(value) => setDraft((current) => ({ ...current, primaryMarketArea: value }))} marketAreas={marketAreas} />
            <StandardMultiSelect label="Service counties" value={draft.serviceCounties} onChange={(value) => setDraft((current) => ({ ...current, serviceCounties: value }))} options={serviceAreaOptions.counties} />
            <StandardMultiSelect label="Service cities" value={draft.serviceCities} onChange={(value) => setDraft((current) => ({ ...current, serviceCities: value }))} options={serviceAreaOptions.cities} />
            <Field label="Service ZIP codes" value={draft.serviceZipCodes} onChange={(value) => setDraft((current) => ({ ...current, serviceZipCodes: value }))} placeholder="33602, 33701" />
            <Field label="Max active Nex leads" value={draft.maxActiveBrokerageLeads} onChange={(value) => setDraft((current) => ({ ...current, maxActiveBrokerageLeads: value }))} />
          </div>
          <div className="lead-type-toggles">
            {[
              ["buyerLeadsEnabled", "Buyers"],
              ["sellerLeadsEnabled", "Sellers"],
              ["rentalLeadsEnabled", "Rentals"],
              ["investorLeadsEnabled", "Investors"]
            ].map(([key, label]) => (
              <label key={key}>
                <input type="checkbox" checked={Boolean(draft[key])} onChange={(event) => setDraft((current) => ({ ...current, [key]: event.target.checked }))} />
                <span>{label}</span>
              </label>
            ))}
          </div>
          <div className="lead-action-row">
            <button className="btn primary" onClick={() => saveRotationSettings({ acceptTerms: true })}>
              <Icon name="BadgeCheck" />
              <span>{acceptedTerms ? "Save and Stay Active" : "Accept Terms & Opt In"}</span>
            </button>
            <button className="btn secondary" onClick={() => saveRotationSettings({ leadRotationOptIn: false, leadRotationStatus: "paused" })}>
              <Icon name="Pause" />
              <span>Pause Rotation</span>
            </button>
          </div>
        </article>

        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Performance</p>
              <h3>Lead accountability score</h3>
            </div>
          </div>
          <div className="lead-score-ring">
            <strong>{agentProfile.leadPerformanceScore || 75}</strong>
            <span>Current score</span>
          </div>
          <div className="idx-sync-summary">
            <div><span>Active Nex leads</span><em>{agentProfile.currentActiveBrokerageLeads || 0}</em></div>
            <div><span>Primary market</span><em>{agentProfile.primaryMarketAreaName || "Not set"}</em></div>
            <div><span>Terms</span><em>{acceptedTerms ? "Accepted" : "Needed"}</em></div>
            <div><span>Eligible now</span><em>{agentProfile.eligibleNow ? "Yes" : "No"}</em></div>
          </div>
        </article>
      </div>

      <div className="panel website-leads-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">{canViewAll ? "All routed leads" : "My leads"}</p>
            <h3>Lead accountability board</h3>
          </div>
          <button className="btn secondary compact" onClick={loadLeads} disabled={loading}>
            <Icon name={loading ? "LoaderCircle" : "RefreshCcw"} className={loading ? "spin" : ""} />
            <span>{loading ? "Loading" : "Refresh"}</span>
          </button>
        </div>
        <div className="website-lead-toolbar">
          <Field label="Filter" value={filter} onChange={setFilter} as="select" options={["All", "Brokerage", "Agent Website", "Recruiting", "Review"]} />
        </div>
        <div className="website-lead-list">
          {leads.map((lead) => (
            <article key={lead.id} className={lead.brokerageGenerated ? "brokerage-lead-card" : lead.agentGenerated ? "agent-lead-card" : ""}>
              <div className="website-lead-main">
                <span className={classNames("lead-source-pill", sourcePillTone(lead))}>{leadSourceLabel(lead)}</span>
                <strong>{lead.name}</strong>
                <p>{[lead.email, lead.phone].filter(Boolean).join(" | ")}</p>
                <small>{[lead.city, lead.county, lead.zip].filter(Boolean).join(", ") || lead.sourcePage || "No location listed"}</small>
                {lead.matchedMarketAreaName && <small>Market: {lead.matchedMarketAreaName}</small>}
                <em>{lead.feeDisclosure || lead.classificationReason}</em>
              </div>
              <div className="website-lead-route">
                <em>{lead.assignmentReason || "unassigned"}</em>
                <strong>{lead.assignedAgentName || lead.assignedAgentEmail || "Admin queue"}</strong>
                <span>{lead.status || lead.leadStatus || "New"}</span>
              </div>
              <div className="website-lead-actions">
                {lead.brokerageGenerated && !lead.acceptedByAgentAt && lead.assignedAgentEmail && (
                  <button className="btn primary compact" onClick={() => updateLead(lead, "accept")}>
                    <Icon name="Check" />
                    <span>Accept</span>
                  </button>
                )}
                {lead.assignedAgentEmail && !["Closed", "Lost"].includes(lead.status) && (
                  <button className="btn secondary compact" onClick={() => updateLead(lead, "followup", { method: "Call", notes: "Follow-up logged from Nex Leads.", nextFollowUpDate: new Date(Date.now() + 86400000).toISOString() })}>
                    <Icon name="PhoneCall" />
                    <span>Log Follow-Up</span>
                  </button>
                )}
                <button className="btn secondary compact" onClick={() => setActivePage("Nex CRM")}>
                  <Icon name="UsersRound" />
                  <span>CRM</span>
                </button>
              </div>
            </article>
          ))}
          {!leads.length && <EmptyState icon="Route" title="No leads in this view" body="Brokerage-generated, agent website, and recruiting leads will appear here once captured." />}
        </div>
      </div>

      {canViewAll && (
        <>
          <div className="panel lead-market-mapping-panel">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Admin market mapping</p>
                <h3>Primary lead markets</h3>
              </div>
              <span className="lead-source-pill brokerage">Brokerage leads only</span>
            </div>
            <p className="muted-text">Main Nex brokerage-generated leads are matched to one of these markets before round-robin. Agent website/subdomain leads bypass this and go directly to the originating agent.</p>
            <div className="lead-market-area-grid">
              {marketAreas.map((area) => {
                const areaDraft = marketAreaDrafts[area.id] || { name: area.name, counties: textFromList(area.counties), cities: textFromList(area.cities), zipCodes: textFromList(area.zipCodes), active: area.active !== false };
                return (
                  <article key={area.id} className={areaDraft.active ? "" : "inactive"}>
                    <div className="lead-market-card-heading">
                      <strong>{area.name}</strong>
                      <label>
                        <input type="checkbox" checked={areaDraft.active !== false} onChange={(event) => setMarketAreaDrafts((current) => ({ ...current, [area.id]: { ...areaDraft, active: event.target.checked } }))} />
                        <span>Active</span>
                      </label>
                    </div>
                    <Field label="Market name" value={areaDraft.name} onChange={(value) => setMarketAreaDrafts((current) => ({ ...current, [area.id]: { ...areaDraft, name: value } }))} />
                    <Field label="Counties" value={areaDraft.counties} onChange={(value) => setMarketAreaDrafts((current) => ({ ...current, [area.id]: { ...areaDraft, counties: value } }))} as="textarea" placeholder="Pinellas County, Hillsborough County" />
                    <Field label="Cities" value={areaDraft.cities} onChange={(value) => setMarketAreaDrafts((current) => ({ ...current, [area.id]: { ...areaDraft, cities: value } }))} as="textarea" placeholder="Tampa, St. Petersburg" />
                    <Field label="ZIPs" value={areaDraft.zipCodes} onChange={(value) => setMarketAreaDrafts((current) => ({ ...current, [area.id]: { ...areaDraft, zipCodes: value } }))} placeholder="Optional ZIP list" />
                    <button className="btn primary compact" onClick={() => saveMarketArea(area.id)}>
                      <Icon name="Save" />
                      <span>Save Market</span>
                    </button>
                  </article>
                );
              })}
              <article className="lead-market-add-card">
                <strong>Add future market</strong>
                <Field label="Market name" value={newMarketDraft.name} onChange={(value) => setNewMarketDraft((current) => ({ ...current, name: value }))} placeholder="Treasure Coast" />
                <Field label="Counties" value={newMarketDraft.counties} onChange={(value) => setNewMarketDraft((current) => ({ ...current, counties: value }))} placeholder="Martin County, St. Lucie County" />
                <Field label="Cities" value={newMarketDraft.cities} onChange={(value) => setNewMarketDraft((current) => ({ ...current, cities: value }))} placeholder="Stuart, Port St. Lucie" />
                <Field label="ZIPs" value={newMarketDraft.zipCodes} onChange={(value) => setNewMarketDraft((current) => ({ ...current, zipCodes: value }))} placeholder="Optional ZIP list" />
                <button className="btn secondary compact" onClick={addMarketArea} disabled={!newMarketDraft.name.trim()}>
                  <Icon name="Plus" />
                  <span>Add Market</span>
                </button>
              </article>
            </div>
          </div>

          <div className="panel">
            <div className="panel-heading">
              <div>
                <p className="eyebrow">Admin rotation view</p>
                <h3>Opted-in agents and eligibility</h3>
              </div>
              <button className="btn secondary compact" onClick={() => setActivePage("Website Leads / IDX")}>
                <Icon name="Globe2" />
                <span>Website / IDX</span>
              </button>
            </div>
            <div className="lead-agent-table">
              {(data.agents || []).map((agent) => (
                <article key={agent.id}>
                  <div>
                    <strong>{agent.name}</strong>
                    <span>{agent.primaryMarketAreaName || agent.market || "No primary market"} {agent.serviceCounties?.length ? `| ${agent.serviceCounties.slice(0, 2).join(", ")}` : ""}</span>
                    <em>{leadOptInStatus(agent).short} | score {agent.leadPerformanceScore}</em>
                    <small>{agent.acceptedTerms ? "Terms accepted" : "Terms needed"} | Active leads {agent.currentActiveBrokerageLeads || 0} | Max {agent.maxActiveBrokerageLeads || 10} | Last assigned {agent.lastBrokerageLeadAssignedAt ? new Date(agent.lastBrokerageLeadAssignedAt).toLocaleDateString() : "never"}</small>
                    <div className="lead-agent-actions">
                      <button className="btn primary compact" onClick={() => updateAgentRotation(agent, { acceptTerms: true }, `${agent.name} is active in Nex lead rotation.`)}>
                        <Icon name="Play" />
                        <span>Activate</span>
                      </button>
                      <button className="btn secondary compact" onClick={() => updateAgentRotation(agent, { leadRotationOptIn: false, leadRotationStatus: "paused" }, `${agent.name} is paused from Nex lead rotation.`)}>
                        <Icon name="Pause" />
                        <span>Pause</span>
                      </button>
                      <button className="btn danger-soft compact" onClick={() => updateAgentRotation(agent, { leadRotationOptIn: false, leadRotationStatus: "suspended" }, `${agent.name} is suspended from Nex lead rotation.`)}>
                        <Icon name="ShieldAlert" />
                        <span>Suspend</span>
                      </button>
                      <button className="btn secondary compact" onClick={() => (editingAgentId === agent.id ? setEditingAgentId("") : openAgentAreaEditor(agent))}>
                        <Icon name="MapPinned" />
                        <span>Edit Rotation</span>
                      </button>
                    </div>
                  </div>
                  {editingAgentId === agent.id && (
                    <div className="lead-agent-area-editor">
                      <MarketAreaSelect label="Primary market" value={agentAreaDraft.primaryMarketArea} onChange={(value) => setAgentAreaDraft((current) => ({ ...current, primaryMarketArea: value }))} marketAreas={marketAreas} />
                      <StandardMultiSelect label="Counties" value={agentAreaDraft.serviceCounties} onChange={(value) => setAgentAreaDraft((current) => ({ ...current, serviceCounties: value }))} options={serviceAreaOptions.counties} />
                      <StandardMultiSelect label="Cities" value={agentAreaDraft.serviceCities} onChange={(value) => setAgentAreaDraft((current) => ({ ...current, serviceCities: value }))} options={serviceAreaOptions.cities} />
                      <Field label="ZIPs" value={agentAreaDraft.serviceZipCodes} onChange={(value) => setAgentAreaDraft((current) => ({ ...current, serviceZipCodes: value }))} placeholder="33602, 33701" />
                      <Field label="Max active leads" value={agentAreaDraft.maxActiveBrokerageLeads} onChange={(value) => setAgentAreaDraft((current) => ({ ...current, maxActiveBrokerageLeads: value }))} />
                      <button className="btn primary compact" onClick={() => updateAgentRotation(agent, agentAreaDraft, `${agent.name}'s lead rotation settings were saved.`)}>
                        <Icon name="Save" />
                        <span>Save Rotation</span>
                      </button>
                    </div>
                  )}
                </article>
              ))}
            </div>
          </div>
        </>
      )}
    </section>
  );
}

function WebsiteLeadCenter({ role, setActivePage, setToast }) {
  const [data, setData] = useState({ leads: [], idxQueue: [], searchEvents: [], savedSearches: [], favoriteProperties: [], syncRuns: [], routingRules: [], leadHistory: [], agents: [], summary: {}, idx: {}, idxProvider: {} });
  const [loading, setLoading] = useState(true);
  const [filter, setFilter] = useState("All");
  const [query, setQuery] = useState("");
  const [routingDraft, setRoutingDraft] = useState({ name: "", matchType: "county", matchValue: "", eligibleAgentIds: [] });

  const canView = isAdminRole(role);
  const webhookUrl = `${window.location.origin}/api/public/idx-leads`;
  const samplePayload = JSON.stringify({
    name: "Jane Buyer",
    email: "jane@example.com",
    phone: "813-555-0100",
    type: "buyer",
    city: "Tampa",
    county: "Hillsborough County",
    leadSource: "OSI IDX",
    idxIntent: "Saved Search",
    sourcePage: "propertysearch.nexrealtygroup.com",
    sourceAgentEmail: "agent@mynexrealty.com",
    notes: "Viewed 123 Main St and registered on OSI IDX."
  }, null, 2);

  async function loadWebsiteLeads() {
    if (!canView) return;
    setLoading(true);
    try {
      const payload = await API.request("/api/website-leads");
      setData({
        leads: payload.leads || [],
        idxQueue: payload.idxQueue || [],
        searchEvents: payload.searchEvents || [],
        savedSearches: payload.savedSearches || [],
        favoriteProperties: payload.favoriteProperties || [],
        syncRuns: payload.syncRuns || [],
        routingRules: payload.routingRules || [],
        leadHistory: payload.leadHistory || [],
        agents: payload.agents || [],
        summary: payload.summary || {},
        idx: payload.idx || {},
        idxProvider: payload.idxProvider || payload.idx || {}
      });
    } catch (error) {
      setToast(error.message || "Could not load website leads.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadWebsiteLeads();
  }, []);

  function toggleRoutingAgent(agentId) {
    setRoutingDraft((current) => {
      const hasAgent = current.eligibleAgentIds.includes(agentId);
      return {
        ...current,
        eligibleAgentIds: hasAgent ? current.eligibleAgentIds.filter((id) => id !== agentId) : [...current.eligibleAgentIds, agentId]
      };
    });
  }

  async function addRoutingRule() {
    if (!routingDraft.matchValue.trim()) {
      setToast("Add a county, city, or ZIP before saving the route.");
      return;
    }
    if (!routingDraft.eligibleAgentIds.length) {
      setToast("Select at least one eligible agent for this route.");
      return;
    }
    try {
      const rule = await API.request("/api/website-routing-rules", {
        method: "POST",
        body: JSON.stringify({ ...routingDraft, active: true })
      });
      setData((current) => ({ ...current, routingRules: [rule, ...(current.routingRules || [])] }));
      setRoutingDraft({ name: "", matchType: "county", matchValue: "", eligibleAgentIds: [] });
      setToast("Website lead route added.");
    } catch (error) {
      setToast(error.message || "Could not add routing rule.");
    }
  }

  async function toggleRoutingRule(rule) {
    try {
      const saved = await API.request(`/api/website-routing-rules/${encodeURIComponent(rule.id)}`, {
        method: "PUT",
        body: JSON.stringify({ active: rule.active === false })
      });
      setData((current) => ({
        ...current,
        routingRules: (current.routingRules || []).map((item) => (item.id === saved.id ? saved : item))
      }));
      setToast(saved.active === false ? "Route paused." : "Route reactivated.");
    } catch (error) {
      setToast(error.message || "Could not update routing rule.");
    }
  }

  if (!canView) {
    return <EmptyState icon="ShieldCheck" title="Admin access required" body="Website and IDX lead routing is an admin-only launch control area." />;
  }

  const leads = data.leads.filter((lead) => {
    const idxMatch = /idx|property inquiry|showing request|saved search|agent idx/i.test(`${lead.leadSource} ${lead.idxProvider} ${lead.idxIntent}`);
    const matchesFilter =
      filter === "All" ||
      (filter === "IDX" && idxMatch) ||
      (filter === "Unassigned" && !lead.assignedAgentEmail) ||
      (filter === "Recruiting" && lead.type === "recruiting") ||
      (filter === "Brokerage Generated" && lead.brokerageGenerated) ||
      (filter === "Agent Generated" && lead.agentGenerated) ||
      (filter === "Needs Review" && lead.needsAdminReview);
    const haystack = [lead.name, lead.email, lead.phone, lead.city, lead.county, lead.leadSource, lead.idxIntent, lead.assignedAgentName, lead.assignedAgentEmail, lead.sourcePage].join(" ").toLowerCase();
    return matchesFilter && (!query || haystack.includes(query.toLowerCase()));
  });
  const readyAgents = data.agents.filter((agent) => agent.subdomainSlug);
  const checklist = [
    ["OSI hosted subdomain", data.idx?.subdomainUrl || data.idx?.searchUrl || "Waiting on OSI"],
    ["Zapier webhook endpoint", webhookUrl],
    ["Published agent profiles", `${data.summary.publishedAgents || readyAgents.length} active`],
    ["Agent IDX URLs", `${data.summary.agentsWithIdxUrls || 0} configured`],
    ["IDX lead queue", `${data.idxQueue.length} captured`],
    ["Search activity events", `${data.searchEvents.length} tracked`],
    ["Saved search capture", `${data.savedSearches.length} saved`],
    ["Favorite property capture", `${data.favoriteProperties.length} favorited`]
  ];
  const readiness = data.idxProvider?.readiness || [];

  return (
    <section className="portal-page website-lead-center">
      <div className="module-hero website-lead-hero">
        <div>
          <p className="eyebrow">Website / IDX</p>
          <h3>Public lead routing control center</h3>
          <p>Monitor Nex website inquiries, OSI IDX/Zapier captures, agent page routing, and launch readiness from one admin view.</p>
        </div>
        <div className="idx-launch-card">
          <Icon name="RadioTower" />
          <strong>{data.idx?.provider || "OSI IDX"}</strong>
          <span>{data.idx?.integrationMethod === "subdomain-hosted" ? "Hosted subdomain mode" : "IDX configuration ready"}</span>
        </div>
      </div>

      <div className="website-lead-stats">
        {[
          ["Total website leads", data.summary.totalLeads || 0, "Globe2"],
          ["IDX leads", data.summary.idxLeads || 0, "SearchCheck"],
          ["Brokerage generated", data.summary.brokerageGeneratedLeads || 0, "Building2"],
          ["Agent generated", data.summary.agentGeneratedLeads || 0, "Route"],
          ["Search events", data.summary.searchEvents || 0, "MousePointerClick"],
          ["Saved searches", data.summary.savedSearches || 0, "BellPlus"],
          ["Favorites", data.summary.favoriteProperties || 0, "Heart"],
          ["Unassigned", data.summary.unassignedLeads || 0, "UserRoundX"],
          ["Published agents", data.summary.publishedAgents || readyAgents.length, "BadgeCheck"]
        ].map(([label, value, icon]) => (
          <article key={label}>
            <Icon name={icon} />
            <span>{label}</span>
            <strong>{value}</strong>
          </article>
        ))}
      </div>

      <div className="website-lead-grid">
        <article className="panel idx-setup-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">OSI / Zapier setup</p>
              <h3>Ready for provider handoff</h3>
            </div>
            <button className="btn secondary compact" onClick={() => copyToClipboard(webhookUrl, setToast)}>
              <Icon name="Copy" />
              <span>Copy Webhook</span>
            </button>
          </div>
          <div className="idx-checklist">
            {checklist.map(([label, value]) => (
              <div key={label}>
                <Icon name="CheckCircle2" />
                <span>{label}</span>
                <strong>{value}</strong>
              </div>
            ))}
          </div>
          <div className="idx-payload-box">
            <div>
              <strong>Webhook payload example</strong>
              <button className="icon-btn small" onClick={() => copyToClipboard(samplePayload, setToast)} title="Copy sample payload">
                <Icon name="Copy" size={15} />
              </button>
            </div>
            <pre>{samplePayload}</pre>
          </div>
        </article>

        <article className="panel idx-agent-readiness">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Agent pages</p>
              <h3>Profile and IDX readiness</h3>
            </div>
            <button className="btn secondary compact" onClick={() => setActivePage("Brand Settings / Admin")}>
              <Icon name="Settings" />
              <span>Edit agents</span>
            </button>
          </div>
          <div className="idx-agent-list">
            {readyAgents.slice(0, 8).map((agent) => (
              <article key={agent.id}>
                <div className="public-avatar small">{agent.headshot ? <img src={agent.headshot} alt={agent.name} /> : publicInitials(agent.name)}</div>
                <div>
                  <strong>{agent.name}</strong>
                  <span>/site/agents/{agent.subdomainSlug}</span>
                  <em>{agent.idxSearchUrl ? "IDX URL set" : "Needs OSI agent URL later"}</em>
                </div>
              </article>
            ))}
            {!readyAgents.length && <p>No published agent profiles yet. Add agent public profile details under Brand Settings / Admin.</p>}
          </div>
        </article>
      </div>

      <div className="website-lead-grid">
        <article className="panel idx-provider-readiness">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Provider-neutral backend</p>
              <h3>Bridge / MLS Grid / RESO readiness</h3>
            </div>
          </div>
          <div className="idx-readiness-grid">
            {readiness.map((item) => (
              <div key={item.key} className={item.ready ? "ready" : "pending"}>
                <Icon name={item.ready ? "CheckCircle2" : "CircleDashed"} />
                <span>{item.label}</span>
                <strong>{item.value}</strong>
              </div>
            ))}
          </div>
        </article>

        <article className="panel idx-provider-readiness">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Future direct IDX</p>
              <h3>API sync status</h3>
            </div>
            <button
              className="btn secondary compact"
              onClick={async () => {
                try {
                  const response = await API.request("/api/idx-provider/sync-runs", {
                    method: "POST",
                    body: JSON.stringify({ action: "readiness-check" })
                  });
                  setData((current) => ({ ...current, syncRuns: [response.run, ...(current.syncRuns || [])] }));
                  setToast(response.run?.message || "IDX readiness check recorded.");
                } catch (error) {
                  setToast(error.message || "Could not record IDX readiness check.");
                }
              }}
            >
              <Icon name="RefreshCcw" />
              <span>Check Readiness</span>
            </button>
            <button
              className="btn primary compact"
              onClick={async () => {
                try {
                  const response = await API.request("/api/idx-provider/test-connection", {
                    method: "POST",
                    body: JSON.stringify({ limit: 3 })
                  });
                  setData((current) => ({ ...current, idxProvider: response.status || current.idxProvider, syncRuns: [response.run, ...(current.syncRuns || [])] }));
                  setToast(response.run?.message || "IDX provider test recorded.");
                } catch (error) {
                  setToast(error.message || "Could not test IDX provider.");
                }
              }}
            >
              <Icon name="SearchCheck" />
              <span>Test Provider</span>
            </button>
          </div>
          <div className="idx-sync-summary">
            <strong>{data.idxProvider?.apiReady ? "Direct API credentials detected" : "Direct API not configured yet"}</strong>
            <p>
              The backend is ready for an approved Bridge Interactive, MLS Grid, RESO Web API, IDX Broker, or similar provider. Test Provider can verify the approved feed before public fetch is enabled. External consumer fetches stay disabled until credentials, dataset approval, MLS display rules, and `IDX_API_FETCH_ENABLED=true` are configured.
            </p>
            {(data.syncRuns || []).slice(0, 4).map((run) => (
              <div key={run.id}>
                <span>{run.status}</span>
                <em>{run.message}</em>
              </div>
            ))}
          </div>
        </article>
      </div>

      <div className="panel website-leads-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Captured leads</p>
            <h3>Website and IDX inquiries</h3>
          </div>
          <button className="btn secondary compact" onClick={loadWebsiteLeads} disabled={loading}>
            <Icon name={loading ? "LoaderCircle" : "RefreshCcw"} className={loading ? "spin" : ""} />
            <span>{loading ? "Loading" : "Refresh"}</span>
          </button>
        </div>
        <div className="website-lead-toolbar">
          <Field label="Search leads" value={query} onChange={setQuery} placeholder="Search name, email, county, source, assigned agent..." />
          <Field label="Filter" value={filter} onChange={setFilter} as="select" options={["All", "IDX", "Brokerage Generated", "Agent Generated", "Unassigned", "Recruiting", "Needs Review"]} />
        </div>
        <div className="website-lead-list">
          {leads.map((lead) => (
            <article key={lead.id}>
              <div className="website-lead-main">
                <span className={classNames("lead-source-pill", sourcePillTone(lead))}>{leadSourceLabel(lead)}</span>
                <strong>{lead.name}</strong>
                <p>{[lead.email, lead.phone].filter(Boolean).join(" | ")}</p>
                <small>{[lead.city, lead.county, lead.zip].filter(Boolean).join(", ") || lead.sourcePage || "No location listed"}</small>
                <em>{lead.feeDisclosure || lead.classificationReason}</em>
              </div>
              <div className="website-lead-route">
                <em>{lead.assignmentReason || "unassigned"}</em>
                <strong>{lead.assignedAgentName || lead.assignedAgentEmail || "Admin queue"}</strong>
                <span>{lead.idxIntent || lead.type}</span>
              </div>
              <div className="website-lead-actions">
                <span>{lead.createdAt ? new Date(lead.createdAt).toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }) : "New"}</span>
                <button className="btn secondary compact" onClick={() => setActivePage("Nex CRM")}>
                  <Icon name="UsersRound" />
                  <span>Open CRM</span>
                </button>
              </div>
            </article>
          ))}
          {!leads.length && <EmptyState icon="Globe2" title="No leads match this view" body="New public website and OSI IDX leads will appear here once forms or Zapier start sending them." />}
        </div>
      </div>

      <div className="website-lead-grid">
        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">IDX activity</p>
              <h3>Search and listing behavior</h3>
            </div>
          </div>
          <div className="idx-queue-list">
            {data.searchEvents.slice(0, 8).map((item) => (
              <div key={item.id}>
                <strong>{item.eventType || "search"}</strong>
                <span>{[item.rawEvent?.city || item.criteria?.city, item.rawEvent?.county || item.criteria?.county, item.listingId || item.mlsNumber].filter(Boolean).join(" | ") || item.sourcePage || "IDX event captured"}</span>
                <em>{item.sourceAgentEmail || item.leadEmail || item.provider || "Anonymous visitor"}</em>
              </div>
            ))}
            {!data.searchEvents.length && <p>No IDX search events yet. Future MLS Grid/native search behavior will populate this without changing CRM routing.</p>}
          </div>
        </article>

        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Saved searches</p>
              <h3>Buyer alerts and listing intent</h3>
            </div>
          </div>
          <div className="idx-queue-list">
            {data.savedSearches.slice(0, 8).map((item) => (
              <div key={item.id}>
                <strong>{item.name || item.email}</strong>
                <span>{[item.criteria?.city, item.criteria?.county, item.criteria?.status].filter(Boolean).join(" | ") || "Search criteria captured"}</span>
                <em>{item.assignedAgentName || item.assignedAgentEmail || "Admin queue"}</em>
              </div>
            ))}
            {!data.savedSearches.length && <p>No saved searches yet. Nex website forms and future IDX API searches can populate this.</p>}
          </div>
        </article>

        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Favorite properties</p>
              <h3>Listing interest signals</h3>
            </div>
          </div>
          <div className="idx-queue-list">
            {data.favoriteProperties.slice(0, 8).map((item) => (
              <div key={item.id}>
                <strong>{item.property?.address || item.property?.mlsNumber || item.name || item.email}</strong>
                <span>{[item.property?.city, item.property?.price, item.provider].filter(Boolean).join(" | ")}</span>
                <em>{item.assignedAgentName || item.assignedAgentEmail || "Admin queue"}</em>
              </div>
            ))}
            {!data.favoriteProperties.length && <p>No property favorites yet. This is ready for the future IDX search experience.</p>}
          </div>
        </article>
      </div>

      <div className="website-lead-grid">
        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Routing rules</p>
              <h3>Geographic assignment</h3>
            </div>
          </div>
          <div className="idx-route-builder">
            <div className="idx-route-fields">
              <Field label="Route name" value={routingDraft.name} onChange={(value) => setRoutingDraft((current) => ({ ...current, name: value }))} placeholder="Tampa Bay buyers" />
              <Field label="Match by" value={routingDraft.matchType} onChange={(value) => setRoutingDraft((current) => ({ ...current, matchType: value }))} as="select" options={["county", "city", "zip"]} />
              <Field label="County, city, or ZIP" value={routingDraft.matchValue} onChange={(value) => setRoutingDraft((current) => ({ ...current, matchValue: value }))} placeholder="Hillsborough County" />
            </div>
            <div className="idx-route-agents">
              <span>Eligible agents</span>
              <div>
                {readyAgents.map((agent) => (
                  <label key={agent.id} className={routingDraft.eligibleAgentIds.includes(agent.id) ? "selected" : ""}>
                    <input type="checkbox" checked={routingDraft.eligibleAgentIds.includes(agent.id)} onChange={() => toggleRoutingAgent(agent.id)} />
                    <span>{agent.name}</span>
                  </label>
                ))}
                {!readyAgents.length && <em>Add public agent profiles before creating routing rules.</em>}
              </div>
            </div>
            <button className="btn primary compact" onClick={addRoutingRule}>
              <Icon name="Route" />
              <span>Add Route</span>
            </button>
          </div>
          <div className="idx-rule-list">
            {data.routingRules.map((rule) => (
              <div key={rule.id}>
                <strong>{rule.name || rule.matchValue}</strong>
                <span>{rule.matchType}: {rule.matchValue}</span>
                <em>{rule.active === false ? "Inactive" : "Active"} - {(rule.eligibleAgents || []).map((agent) => agent.name).join(", ") || `${rule.eligibleAgentIds?.length || 0} agent(s)`}</em>
                <button className="btn secondary compact" onClick={() => toggleRoutingRule(rule)}>
                  <Icon name={rule.active === false ? "Play" : "Pause"} />
                  <span>{rule.active === false ? "Reactivate" : "Pause"}</span>
                </button>
              </div>
            ))}
          </div>
        </article>

        <article className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">IDX capture queue</p>
              <h3>Latest OSI/Zapier records</h3>
            </div>
          </div>
          <div className="idx-queue-list">
            {data.idxQueue.slice(0, 8).map((item) => (
              <div key={item.id}>
                <strong>{item.leadName || item.leadEmail || "IDX lead"}</strong>
                <span>{item.provider} - {item.idxIntent || item.sourceSystem}</span>
                <em>{item.assignedAgentName || item.assignedAgentEmail || "Admin queue"}</em>
              </div>
            ))}
            {!data.idxQueue.length && <p>No IDX queue records yet. This will populate after OSI/Zapier posts to the webhook.</p>}
          </div>
        </article>
      </div>
    </section>
  );
}

function RecruitingSeoCenter({ role, setToast }) {
  const [data, setData] = useState({ pages: [], blogPosts: [], faqs: [], plans: [], leads: [], leadActivity: [], competitors: [], markets: [], summary: {} });
  const [loading, setLoading] = useState(true);
  const [query, setQuery] = useState("");
  const [selectedPageId, setSelectedPageId] = useState("");
  const [pageDraft, setPageDraft] = useState(null);
  const [planDrafts, setPlanDrafts] = useState({});

  const canView = isAdminRole(role);

  async function loadRecruitingSeo() {
    if (!canView) return;
    setLoading(true);
    try {
      const payload = await API.request("/api/recruiting-seo/bootstrap?pageSize=500");
      const leads = Array.isArray(payload.leads) ? payload.leads : payload.leads?.items || [];
      setData({ ...payload, leads });
      const nextPlanDrafts = {};
      (payload.plans || []).forEach((plan) => {
        nextPlanDrafts[plan.id] = {
          monthlyFee: plan.monthlyFee,
          joinFee: plan.joinFee,
          split: plan.split,
          cap: plan.cap,
          transactionFee: plan.transactionFee,
          npsEligible: Boolean(plan.npsEligible),
          bestFor: plan.bestFor || ""
        };
      });
      setPlanDrafts(nextPlanDrafts);
      if (!selectedPageId && payload.pages?.[0]) {
        setSelectedPageId(payload.pages[0].id);
        setPageDraft(payload.pages[0]);
      }
    } catch (error) {
      setToast(error.message || "Could not load recruiting SEO backend.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadRecruitingSeo();
  }, []);

  function selectPage(page) {
    setSelectedPageId(page.id);
    setPageDraft({ ...page, keywordsText: (page.keywords || []).join(", ") });
  }

  function updatePageDraft(field, value) {
    setPageDraft((current) => ({ ...(current || {}), [field]: value }));
  }

  async function saveSelectedPage() {
    if (!pageDraft?.id) return;
    try {
      const saved = await API.request(`/api/recruiting-seo/pages/${encodeURIComponent(pageDraft.id)}`, {
        method: "PUT",
        body: JSON.stringify({
          ...pageDraft,
          keywords: String(pageDraft.keywordsText || "").split(",").map((item) => item.trim()).filter(Boolean)
        })
      });
      setData((current) => ({
        ...current,
        pages: (current.pages || []).map((page) => (page.id === saved.id ? saved : page))
      }));
      setPageDraft({ ...saved, keywordsText: (saved.keywords || []).join(", ") });
      setToast("Recruiting SEO page saved.");
    } catch (error) {
      setToast(error.message || "Could not save recruiting page.");
    }
  }

  function updatePlanDraft(planId, field, value) {
    setPlanDrafts((current) => ({
      ...current,
      [planId]: { ...(current[planId] || {}), [field]: value }
    }));
  }

  async function savePlan(plan) {
    try {
      const saved = await API.request(`/api/recruiting-seo/plans/${encodeURIComponent(plan.id)}`, {
        method: "PUT",
        body: JSON.stringify(planDrafts[plan.id] || {})
      });
      setData((current) => ({
        ...current,
        plans: (current.plans || []).map((item) => (item.id === saved.id ? saved : item))
      }));
      setToast(`${saved.name} updated.`);
    } catch (error) {
      setToast(error.message || "Could not update commission plan.");
    }
  }

  async function updateLead(lead, patch) {
    try {
      const saved = await API.request(`/api/recruiting-seo/leads/${encodeURIComponent(lead.id)}`, {
        method: "PUT",
        body: JSON.stringify({ ...lead, ...patch })
      });
      setData((current) => ({
        ...current,
        leads: (current.leads || []).map((item) => (item.id === saved.id ? saved : item))
      }));
      setToast("Recruiting lead updated.");
    } catch (error) {
      setToast(error.message || "Could not update recruiting lead.");
    }
  }

  if (!canView) {
    return <EmptyState icon="ShieldCheck" title="Admin access required" body="Recruiting SEO controls are for Nex Realty admin users." />;
  }

  const pages = (data.pages || []).filter((page) => {
    const haystack = [page.title, page.slug, page.category, page.searchIntent, page.metaTitle, page.metaDescription].join(" ").toLowerCase();
    return !query || haystack.includes(query.toLowerCase());
  });
  const leads = (data.leads || []).filter((lead) => {
    const haystack = [lead.name, lead.email, lead.phone, lead.currentBrokerage, lead.countyMarket, lead.interestedPlan, lead.sourcePage, lead.scoreLabel].join(" ").toLowerCase();
    return !query || haystack.includes(query.toLowerCase());
  });

  return (
    <section className="portal-page recruiting-seo-center">
      <div className="module-hero recruiting-seo-hero">
        <div>
          <p className="eyebrow">Recruiting SEO</p>
          <h3>Florida agent recruiting content engine</h3>
          <p>Manage indexable recruiting landing pages, comparison pages, city pages, commission plan data, lead capture, scoring, and organic source attribution.</p>
        </div>
        <button className="btn primary" type="button" onClick={() => window.open("/api/recruiting-seo/leads/export", "_blank")}>
          <Icon name="Download" />
          <span>Export Leads</span>
        </button>
      </div>

      <div className="website-lead-stats">
        {[
          ["SEO pages", data.summary?.pages || data.pages.length, "Files"],
          ["Published", data.summary?.publishedPages || 0, "Globe2"],
          ["Recruiting leads", data.summary?.leads || data.leads.length, "UserPlus"],
          ["Hot leads", data.summary?.hotLeads || 0, "Flame"],
          ["Blog drafts", data.summary?.blogDrafts || 0, "Newspaper"],
          ["Markets", data.summary?.markets || data.markets.length, "MapPin"]
        ].map(([label, value, icon]) => (
          <article key={label}>
            <Icon name={icon} />
            <span>{label}</span>
            <strong>{value}</strong>
          </article>
        ))}
      </div>

      <div className="panel activity-toolbar">
        <Field label="Search SEO backend" value={query} onChange={setQuery} placeholder="Search pages, leads, markets, plans..." />
        <button className="btn secondary" onClick={loadRecruitingSeo} disabled={loading}>
          <Icon name={loading ? "LoaderCircle" : "RefreshCcw"} className={loading ? "spin" : ""} />
          <span>{loading ? "Loading" : "Refresh"}</span>
        </button>
      </div>

      <div className="recruiting-seo-grid">
        <article className="panel recruiting-page-list-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Landing pages</p>
              <h3>Published SEO inventory</h3>
            </div>
          </div>
          <div className="recruiting-page-list">
            {pages.map((page) => (
              <button key={page.id} className={selectedPageId === page.id ? "selected" : ""} onClick={() => selectPage(page)} type="button">
                <strong>{page.h1 || page.title}</strong>
                <span>{page.path} - {page.category}</span>
                <em>{page.status}{page.noindex ? " - noindex" : ""}</em>
              </button>
            ))}
          </div>
        </article>

        <article className="panel recruiting-page-editor-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Page editor</p>
              <h3>{pageDraft?.slug || "Select a page"}</h3>
            </div>
            <button className="btn primary compact" onClick={saveSelectedPage} disabled={!pageDraft}>
              <Icon name="Save" />
              <span>Save</span>
            </button>
          </div>
          {pageDraft ? (
            <div className="recruiting-editor-grid">
              <Field label="Slug" value={pageDraft.slug || ""} onChange={(value) => updatePageDraft("slug", value)} />
              <Field label="Status" value={pageDraft.status || "published"} onChange={(value) => updatePageDraft("status", value)} as="select" options={["published", "draft"]} />
              <Field label="Category" value={pageDraft.category || ""} onChange={(value) => updatePageDraft("category", value)} />
              <Field label="Search intent" value={pageDraft.searchIntent || ""} onChange={(value) => updatePageDraft("searchIntent", value)} />
              <Field label="Meta title" value={pageDraft.metaTitle || ""} onChange={(value) => updatePageDraft("metaTitle", value)} />
              <Field label="Meta description" value={pageDraft.metaDescription || ""} onChange={(value) => updatePageDraft("metaDescription", value)} as="textarea" />
              <Field label="H1" value={pageDraft.h1 || ""} onChange={(value) => updatePageDraft("h1", value)} />
              <Field label="Subheadline" value={pageDraft.subheadline || ""} onChange={(value) => updatePageDraft("subheadline", value)} as="textarea" />
              <Field label="Keywords" value={pageDraft.keywordsText || (pageDraft.keywords || []).join(", ")} onChange={(value) => updatePageDraft("keywordsText", value)} as="textarea" />
              <label className="toggle-row">
                <input type="checkbox" checked={Boolean(pageDraft.noindex)} onChange={(event) => updatePageDraft("noindex", event.target.checked)} />
                <span>Noindex this page</span>
              </label>
            </div>
          ) : (
            <EmptyState icon="Files" title="Choose a page" body="Select a recruiting page to edit its title, meta description, H1, status, and keywords." />
          )}
        </article>
      </div>

      <div className="recruiting-seo-grid">
        <article className="panel recruiting-leads-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Recruiting leads</p>
              <h3>Lead score and source tracking</h3>
            </div>
          </div>
          <div className="recruiting-lead-list">
            {leads.slice(0, 60).map((lead) => (
              <article key={lead.id}>
                <div>
                  <strong>{lead.name}</strong>
                  <span>{lead.email} {lead.phone ? `- ${lead.phone}` : ""}</span>
                  <small>{lead.currentBrokerage || "Brokerage not entered"} - {lead.countyMarket || "Market not entered"}</small>
                </div>
                <em className={String(lead.scoreLabel || "").toLowerCase()}>{lead.scoreLabel || "New"} {lead.score || 0}</em>
                <select value={lead.followUpStatus || "Not contacted"} onChange={(event) => updateLead(lead, { followUpStatus: event.target.value })}>
                  {["Not contacted", "Contacted", "Discovery booked", "Packet sent", "Nurture", "Joined", "Not a fit"].map((option) => <option key={option}>{option}</option>)}
                </select>
              </article>
            ))}
            {!leads.length && <EmptyState icon="UserPlus" title="No recruiting leads yet" body="SEO forms will populate this list and also create CRM contacts." />}
          </div>
        </article>

        <article className="panel recruiting-plan-admin-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Commission plans</p>
              <h3>Global recruiting plan data</h3>
            </div>
          </div>
          <div className="recruiting-plan-admin-list">
            {(data.plans || []).map((plan) => {
              const draft = planDrafts[plan.id] || plan;
              return (
                <article key={plan.id}>
                  <strong>{plan.name}</strong>
                  <div className="recruiting-plan-mini-grid">
                    <Field label="Monthly" value={draft.monthlyFee} onChange={(value) => updatePlanDraft(plan.id, "monthlyFee", value)} />
                    <Field label="Join fee" value={draft.joinFee} onChange={(value) => updatePlanDraft(plan.id, "joinFee", value)} />
                    <Field label="Split" value={draft.split} onChange={(value) => updatePlanDraft(plan.id, "split", value)} />
                    <Field label="Cap" value={draft.cap} onChange={(value) => updatePlanDraft(plan.id, "cap", value)} />
                    <Field label="Transaction fee" value={draft.transactionFee} onChange={(value) => updatePlanDraft(plan.id, "transactionFee", value)} />
                    <label className="toggle-row">
                      <input type="checkbox" checked={Boolean(draft.npsEligible)} onChange={(event) => updatePlanDraft(plan.id, "npsEligible", event.target.checked)} />
                      <span>NPS eligible</span>
                    </label>
                  </div>
                  <Field label="Best for" value={draft.bestFor || ""} onChange={(value) => updatePlanDraft(plan.id, "bestFor", value)} as="textarea" />
                  <button className="btn secondary compact" onClick={() => savePlan(plan)}>
                    <Icon name="Save" />
                    <span>Save {plan.shortLabel || plan.name}</span>
                  </button>
                </article>
              );
            })}
          </div>
        </article>
      </div>
    </section>
  );
}

function CommunicationCenter({ currentUser, role, setToast, setCurrentUser }) {
  const isAdmin = isAdminRole(role);
  const [data, setData] = useState({ notifications: [], preferences: {}, admin: null, providerStatus: {} });
  const [preferences, setPreferences] = useState({});
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [verificationCode, setVerificationCode] = useState("");
  const [verificationChallenge, setVerificationChallenge] = useState(null);
  const [messageDraft, setMessageDraft] = useState({
    title: "",
    message: "",
    audience: "all",
    marketArea: "tampa-bay",
    priority: "normal",
    deliveryChannels: ["in_app", "email"]
  });
  const [recipientPreview, setRecipientPreview] = useState(null);

  async function loadCommunication() {
    setIsLoading(true);
    try {
      const payload = await API.request("/api/notifications/bootstrap");
      setData(payload);
      setPreferences(payload.preferences || {});
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not load Communication Center."));
    } finally {
      setIsLoading(false);
    }
  }

  useEffect(() => {
    loadCommunication();
  }, []);

  const notifications = data.notifications || [];
  const unreadCount = notifications.filter((notification) => !notification.read).length;
  const deliveryLogs = data.admin?.deliveryLogs || [];
  const marketAreas = data.admin?.marketAreas?.length ? data.admin.marketAreas : [
    { id: "tampa-bay", name: "Tampa Bay" },
    { id: "orlando", name: "Orlando" },
    { id: "miami", name: "Miami" }
  ];

  function updatePreference(field, value) {
    setPreferences((current) => ({ ...current, [field]: value }));
  }

  function toggleMessageChannel(channel) {
    setMessageDraft((current) => {
      const set = new Set(current.deliveryChannels || []);
      if (set.has(channel)) set.delete(channel);
      else set.add(channel);
      return { ...current, deliveryChannels: Array.from(set.size ? set : new Set(["in_app"])) };
    });
  }

  async function savePreferences() {
    setIsSaving(true);
    try {
      const response = await API.request("/api/notifications/preferences", {
        method: "POST",
        body: JSON.stringify(preferences)
      });
      setPreferences(response.preferences || {});
      if (response.user) setCurrentUser(response.user);
      setToast("Notification preferences saved.");
      await loadCommunication();
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not save notification preferences."));
    } finally {
      setIsSaving(false);
    }
  }

  async function sendPhoneCode() {
    try {
      const response = await API.request("/api/auth/phone/send-code", {
        method: "POST",
        body: JSON.stringify({ phoneMobile: preferences.phoneMobile || preferences.phoneMobileE164 })
      });
      setVerificationChallenge(response);
      setToast(response.debugCode ? `Verification code sent. Dev code: ${response.debugCode}` : response.message || "Verification code sent.");
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not send verification code."));
    }
  }

  async function verifyPhoneCode() {
    try {
      const response = await API.request("/api/auth/phone/verify-code", {
        method: "POST",
        body: JSON.stringify({ challengeId: verificationChallenge?.challengeId, code: verificationCode })
      });
      if (response.user) setCurrentUser(response.user);
      setVerificationCode("");
      setVerificationChallenge(null);
      setToast("Phone number verified.");
      await loadCommunication();
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not verify phone number."));
    }
  }

  async function markNotificationRead(notificationId) {
    try {
      const saved = await API.request(`/api/notifications/${encodeURIComponent(notificationId)}/read`, { method: "POST", body: JSON.stringify({ read: true }) });
      setData((current) => ({
        ...current,
        notifications: (current.notifications || []).map((notification) => notification.id === notificationId ? saved : notification)
      }));
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not update notification."));
    }
  }

  async function previewAdminMessage() {
    try {
      const response = await API.request("/api/admin/messages/send", {
        method: "POST",
        body: JSON.stringify({ ...messageDraft, previewOnly: true })
      });
      setRecipientPreview(response);
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not preview recipients."));
    }
  }

  async function sendAdminMessage() {
    try {
      const response = await API.request("/api/admin/messages/send", {
        method: "POST",
        body: JSON.stringify(messageDraft)
      });
      setToast(`Message sent to ${response.recipients?.length || 0} recipient(s).`);
      setMessageDraft((current) => ({ ...current, title: "", message: "" }));
      setRecipientPreview(null);
      await loadCommunication();
    } catch (error) {
      setToast(friendlyNetworkError(error, "Could not send message."));
    }
  }

  if (isLoading) {
    return (
      <section className="portal-page">
        <div className="panel-card">
          <p className="eyebrow">Communication Center</p>
          <h1>Loading notifications...</h1>
        </div>
      </section>
    );
  }

  return (
    <section className="portal-page communication-center-page">
      <div className="section-hero communication-hero">
        <div>
          <p className="eyebrow">Communication Center</p>
          <h1>Alerts, messages, and verification in one place.</h1>
          <p>Manage how Nex Central reaches you for leads, deadlines, production reminders, announcements, and security codes.</p>
        </div>
        <div className="hero-stat-grid">
          <StatCard icon="BellRing" label="Unread" value={unreadCount} />
          <StatCard icon="MessageSquareText" label="SMS provider" value={data.providerStatus?.configured ? "Ready" : "Not live"} tone={data.providerStatus?.configured ? "red" : "light"} />
        </div>
      </div>

      <div className="communication-grid">
        <article className="panel-card">
          <div className="panel-header-row">
            <div>
              <p className="eyebrow">My Preferences</p>
              <h3>How Nex Central should reach you</h3>
            </div>
            <span className={classNames("status-pill", preferences.phoneVerifiedAt && "success")}>
              {preferences.phoneVerifiedAt ? "Phone verified" : "Phone not verified"}
            </span>
          </div>
          <div className="form-grid two">
            <Field label="Mobile phone" value={preferences.phoneMobile || ""} onChange={(value) => updatePreference("phoneMobile", value)} type="tel" placeholder="813-555-0123" />
            <Field label="Preferred channels" value={(preferences.preferredNotificationChannels || []).join(", ")} onChange={(value) => updatePreference("preferredNotificationChannels", value.split(",").map((item) => item.trim()))} placeholder="in_app, email, sms" />
          </div>
          <div className="communication-toggle-grid">
            <label className="toggle-row"><input type="checkbox" checked={preferences.emailNotificationsEnabled !== false} onChange={(event) => updatePreference("emailNotificationsEnabled", event.target.checked)} /> Email alerts</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.smsLeadAlertsEnabled)} onChange={(event) => updatePreference("smsLeadAlertsEnabled", event.target.checked)} /> SMS lead alerts</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.smsTaskRemindersEnabled)} onChange={(event) => updatePreference("smsTaskRemindersEnabled", event.target.checked)} /> SMS task reminders</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.smsAnnouncementsEnabled)} onChange={(event) => updatePreference("smsAnnouncementsEnabled", event.target.checked)} /> SMS announcements</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.smsMarketingOptIn)} onChange={(event) => updatePreference("smsMarketingOptIn", event.target.checked)} /> Announcement SMS opt-in</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.smsSecurityEnabled)} onChange={(event) => updatePreference("smsSecurityEnabled", event.target.checked)} /> Security code SMS</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.pushNotificationsEnabled)} onChange={(event) => updatePreference("pushNotificationsEnabled", event.target.checked)} /> Browser push ready</label>
            <label className="toggle-row"><input type="checkbox" checked={Boolean(preferences.twoFactorEnabled)} onChange={(event) => updatePreference("twoFactorEnabled", event.target.checked)} /> Two-factor login</label>
          </div>
          {preferences.smsOptOutAt && <p className="inline-warning">This number opted out of SMS on {titleCaseDate(preferences.smsOptOutAt)}. Reply START through the SMS provider to opt back in.</p>}
          <div className="row-actions">
            <button className="btn secondary" onClick={sendPhoneCode}><Icon name="ShieldCheck" /> Verify Phone</button>
            <button className="btn primary" onClick={savePreferences} disabled={isSaving}><Icon name={isSaving ? "LoaderCircle" : "Save"} className={isSaving ? "spin" : ""} /> Save Preferences</button>
          </div>
          {verificationChallenge && (
            <div className="verification-inline">
              <Field label={`Code sent to ${verificationChallenge.maskedPhone || "your phone"}`} value={verificationCode} onChange={setVerificationCode} placeholder="6-digit code" />
              <button className="btn primary" onClick={verifyPhoneCode}>Confirm Code</button>
            </div>
          )}
        </article>

        <article className="panel-card notification-center">
          <div className="panel-header-row">
            <div>
              <p className="eyebrow">Notification Bell</p>
              <h3>Recent alerts</h3>
            </div>
            <button className="btn secondary compact" onClick={loadCommunication}><Icon name="RefreshCw" /> Refresh</button>
          </div>
          <div className="notification-list">
            {notifications.slice(0, 20).map((notification) => (
              <article key={notification.id} className={classNames(!notification.read && "unread")}>
                <div>
                  <span>{notification.priority || "normal"} | {notification.notificationType || notification.notification_type || "alert"}</span>
                  <strong>{notification.title}</strong>
                  <p>{notification.message}</p>
                  <em>{titleCaseDate(notification.createdAt || notification.created_at)} {notification.deliveredSmsAt ? "| SMS sent" : notification.failedSmsReason ? `| SMS: ${notification.failedSmsReason}` : ""}</em>
                </div>
                <div className="row-actions">
                  {notification.actionUrl && <button className="btn secondary compact" onClick={() => { window.location.href = notification.actionUrl; }}>Open</button>}
                  {!notification.read && <button className="btn primary compact" onClick={() => markNotificationRead(notification.id)}>Mark Read</button>}
                </div>
              </article>
            ))}
            {!notifications.length && <p className="empty-state">No notifications yet.</p>}
          </div>
        </article>
      </div>

      {isAdmin && (
        <div className="communication-admin-grid">
          <article className="panel-card">
            <p className="eyebrow">Admin Messaging</p>
            <h3>Send a Nex Central announcement</h3>
            <div className="form-grid two">
              <Field label="Title" value={messageDraft.title} onChange={(value) => setMessageDraft((current) => ({ ...current, title: value }))} placeholder="Training reminder" />
              <Field label="Priority" value={messageDraft.priority} onChange={(value) => setMessageDraft((current) => ({ ...current, priority: value }))} as="select" options={["low", "normal", "high", "urgent"]} />
              <Field label="Audience" value={messageDraft.audience} onChange={(value) => setMessageDraft((current) => ({ ...current, audience: value }))} as="select" options={["all", "agents", "staff", "admins", "market", "lead_rotation", "new_agents"]} />
              {messageDraft.audience === "market" && <MarketAreaSelect label="Market area" value={messageDraft.marketArea} onChange={(value) => setMessageDraft((current) => ({ ...current, marketArea: value }))} marketAreas={marketAreas} />}
            </div>
            <Field label="Message" value={messageDraft.message} onChange={(value) => setMessageDraft((current) => ({ ...current, message: value }))} as="textarea" placeholder="Keep SMS-friendly messages short and clear." />
            <div className="communication-toggle-grid compact">
              {["in_app", "email", "sms", "push"].map((channel) => (
                <label key={channel} className="toggle-row">
                  <input type="checkbox" checked={(messageDraft.deliveryChannels || []).includes(channel)} onChange={() => toggleMessageChannel(channel)} />
                  {channel.replace("_", " ").toUpperCase()}
                </label>
              ))}
            </div>
            {messageDraft.deliveryChannels.includes("sms") && <p className="inline-warning">SMS sends only go to agents who opted in and have not replied STOP. Announcement texts may include opt-out language.</p>}
            <div className="row-actions">
              <button className="btn secondary" onClick={previewAdminMessage}><Icon name="UsersRound" /> Preview Recipients</button>
              <button className="btn primary" onClick={sendAdminMessage}><Icon name="Send" /> Send Message</button>
            </div>
            {recipientPreview && (
              <div className="recipient-preview">
                <strong>{recipientPreview.count} recipient(s)</strong>
                <p>Channels: {(recipientPreview.channels || []).join(", ")}</p>
                <div>
                  {(recipientPreview.recipients || []).slice(0, 8).map((recipient) => (
                    <span key={recipient.id || recipient.email}>{recipient.name || recipient.email}{recipient.smsEligible ? " | SMS" : ""}</span>
                  ))}
                </div>
              </div>
            )}
          </article>

          <article className="panel-card">
            <p className="eyebrow">Delivery Logs</p>
            <h3>Recent sends</h3>
            <div className="delivery-log-list">
              {deliveryLogs.slice(0, 18).map((log) => (
                <div key={log.id}>
                  <strong>{log.channel?.toUpperCase()} - {log.status}</strong>
                  <span>{log.userEmail || log.phoneMasked || "System"} | {titleCaseDate(log.createdAt)}</span>
                  {log.reason && <em>{log.reason}</em>}
                </div>
              ))}
              {!deliveryLogs.length && <p className="empty-state">No delivery logs yet.</p>}
            </div>
          </article>
        </div>
      )}
    </section>
  );
}

const ACTIVITY_ALL = "All";

function activityModule(item) {
  return item.activityModule || "Nex Central";
}

function activityIcon(item) {
  return item.activityIcon || "Activity";
}

function activityTitle(item) {
  if (item.activityTitle) return item.activityTitle;
  const action = String(item.action || "activity").replace(/_/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
  return `${item.userName || item.userEmail || "System"} ${action.charAt(0).toLowerCase()}${action.slice(1)}`;
}

function activityDetail(item) {
  return item.activitySummary || `${activityModule(item)} activity recorded in Nex Central.`;
}

function activityDateInRange(item, range) {
  if (!range || range === "Any time") return true;
  const created = item.createdAt ? new Date(item.createdAt).getTime() : 0;
  if (!created) return false;
  const now = Date.now();
  if (range === "Today") return new Date(created).toDateString() === new Date().toDateString();
  if (range === "Last 7 days") return now - created <= 7 * 86400000;
  if (range === "Last 30 days") return now - created <= 30 * 86400000;
  return true;
}

function activityAudienceMatches(item, audience) {
  if (!audience || audience === "Everyone") return true;
  const role = String(item.userRole || "").toLowerCase();
  if (audience === "Admins only") return role.includes("admin");
  if (audience === "Agents only") return role === "agent";
  return true;
}

function countedActivityPhrase(item, count) {
  const phrase = item.activityPluralPhrase || item.activityPhrase || "completed this activity";
  if (/activity|preferences|settings|content|coaching|search activity|connection|verification|rotation/i.test(phrase)) {
    return `${phrase} ${count} times`;
  }
  return phrase.replace(/^(\w+)\s+/, `$1 ${count} `);
}

function groupPlatformActivity(items = []) {
  const sorted = [...items].sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
  const groups = [];
  const windowMs = 5 * 60 * 1000;
  for (const item of sorted) {
    const latest = groups[groups.length - 1];
    const itemTime = item.createdAt ? new Date(item.createdAt).getTime() : 0;
    const latestOldest = latest?.oldestAt ? new Date(latest.oldestAt).getTime() : 0;
    if (
      latest &&
      latest.groupKey === (item.activityGroupKey || item.id) &&
      itemTime &&
      latestOldest &&
      Math.abs(latestOldest - itemTime) <= windowMs
    ) {
      latest.items.push(item);
      latest.count += 1;
      latest.oldestAt = item.createdAt || latest.oldestAt;
    } else {
      groups.push({
        id: item.id,
        groupKey: item.activityGroupKey || item.id,
        items: [item],
        count: 1,
        newestAt: item.createdAt,
        oldestAt: item.createdAt
      });
    }
  }
  return groups;
}

function groupedActivityTitle(group) {
  const first = group.items[0] || {};
  if (group.count <= 1) return activityTitle(first);
  return `${first.userName || first.userEmail || "System"} ${countedActivityPhrase(first, group.count)}`;
}

function groupedActivityDetail(group) {
  const first = group.items[0] || {};
  if (group.count <= 1) return activityDetail(first);
  return `${activityDetail(first)} Grouped ${group.count} similar actions from the same user within a few minutes.`;
}

function activityOptionValues(logs, selector) {
  return [ACTIVITY_ALL, ...Array.from(new Set(logs.map(selector).filter(Boolean))).sort()];
}

function PlatformActivity({ currentUser, role, setToast }) {
  const [logs, setLogs] = useState([]);
  const [query, setQuery] = useState("");
  const [userFilter, setUserFilter] = useState(ACTIVITY_ALL);
  const [roleFilter, setRoleFilter] = useState(ACTIVITY_ALL);
  const [moduleFilter, setModuleFilter] = useState(ACTIVITY_ALL);
  const [categoryFilter, setCategoryFilter] = useState(ACTIVITY_ALL);
  const [actionTypeFilter, setActionTypeFilter] = useState(ACTIVITY_ALL);
  const [dateRange, setDateRange] = useState("Any time");
  const [audienceFilter, setAudienceFilter] = useState("Everyone");
  const [importantOnly, setImportantOnly] = useState(false);
  const [loading, setLoading] = useState(true);
  const [activityMeta, setActivityMeta] = useState({ scope: "", canViewAll: false });
  const isAdmin = isAdminRole(role);
  const canSeeTechnical = role === "Super Admin" || currentUser?.role === "Super Admin";

  async function loadActivity() {
    setLoading(true);
    try {
      const payload = await API.request(`/api/audit-logs?limit=100&scope=${isAdmin ? "all" : "mine"}`);
      setLogs(Array.isArray(payload) ? payload : payload.items || []);
      if (!Array.isArray(payload)) {
        setActivityMeta({ scope: payload.scope || (isAdmin ? "all" : "mine"), canViewAll: Boolean(payload.canViewAll) });
      }
    } catch (error) {
      setToast(error.message || "Could not load platform activity.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadActivity();
  }, []);

  const userOptions = activityOptionValues(logs, (item) => item.userName || item.userEmail);
  const roleOptions = activityOptionValues(logs, (item) => item.userRole);
  const moduleOptions = activityOptionValues(logs, activityModule);
  const categoryOptions = activityOptionValues(logs, (item) => item.activityCategory || "System");
  const actionTypeOptions = activityOptionValues(logs, (item) => item.activityActionType || "Activity");

  const filteredLogs = logs.filter((item) => {
    const haystack = [
      item.activitySearchText,
      activityTitle(item),
      activityModule(item),
      item.activityCategory,
      item.activityActionType,
      item.userName,
      item.userEmail,
      item.userRole,
      activityDetail(item)
    ].filter(Boolean).join(" ").toLowerCase();
    const matchesQuery = !query || haystack.includes(query.toLowerCase());
    const matchesUser = userFilter === ACTIVITY_ALL || item.userName === userFilter || item.userEmail === userFilter;
    const matchesRole = roleFilter === ACTIVITY_ALL || item.userRole === roleFilter;
    const matchesModule = moduleFilter === ACTIVITY_ALL || activityModule(item) === moduleFilter;
    const matchesCategory = categoryFilter === ACTIVITY_ALL || (item.activityCategory || "System") === categoryFilter;
    const matchesAction = actionTypeFilter === ACTIVITY_ALL || (item.activityActionType || "Activity") === actionTypeFilter;
    const matchesDate = activityDateInRange(item, dateRange);
    const matchesAudience = activityAudienceMatches(item, audienceFilter);
    const matchesImportant = !importantOnly || Boolean(item.activityImportant);
    return matchesQuery && matchesUser && matchesRole && matchesModule && matchesCategory && matchesAction && matchesDate && matchesAudience && matchesImportant;
  });
  const groupedLogs = groupPlatformActivity(filteredLogs);

  return (
    <section className="portal-page activity-page">
      <div className="module-hero activity-hero">
        <div>
          <p className="eyebrow">Activity</p>
          <h3>{isAdmin ? "Platform activity timeline" : "My Nex Central activity"}</h3>
          <p>
            {isAdmin
              ? "This page shows recent activity across Nex Central so admins can see what users are doing, track important changes, and monitor account activity."
              : "This page shows your recent Nex Central activity in plain English, including sign-ins, messages, profile updates, files, and task changes."}
          </p>
        </div>
        <div className="activity-scope-card">
          <Icon name={isAdmin ? "ShieldCheck" : "UserCheck"} />
          <strong>{activityMeta.canViewAll || isAdmin ? "Admin view" : "Agent view"}</strong>
          <span>{activityMeta.canViewAll || isAdmin ? "Everyone included" : currentUser?.email}</span>
        </div>
      </div>

      <div className="panel activity-toolbar">
        <Field label="Search activity" value={query} onChange={setQuery} placeholder="Search chat, login, documents, transactions, agent profile..." />
        <Field label="User" value={userFilter} onChange={setUserFilter} as="select" options={userOptions} />
        <Field label="Role" value={roleFilter} onChange={setRoleFilter} as="select" options={roleOptions} />
        <Field label="Module" value={moduleFilter} onChange={setModuleFilter} as="select" options={moduleOptions} />
        <Field label="Category" value={categoryFilter} onChange={setCategoryFilter} as="select" options={categoryOptions} />
        <Field label="Action" value={actionTypeFilter} onChange={setActionTypeFilter} as="select" options={actionTypeOptions} />
        <Field label="Date" value={dateRange} onChange={setDateRange} as="select" options={["Any time", "Today", "Last 7 days", "Last 30 days"]} />
        <Field label="Audience" value={audienceFilter} onChange={setAudienceFilter} as="select" options={["Everyone", "Admins only", "Agents only"]} />
        <div className="activity-toolbar-actions">
          <button className={classNames("btn", importantOnly ? "primary" : "secondary")} onClick={() => setImportantOnly((value) => !value)} type="button">
            <Icon name="ShieldCheck" />
            <span>Important only</span>
          </button>
          <button className="btn secondary" onClick={loadActivity} disabled={loading} type="button">
            <Icon name={loading ? "LoaderCircle" : "RefreshCcw"} className={loading ? "spin" : ""} />
            <span>{loading ? "Loading" : "Refresh"}</span>
          </button>
        </div>
      </div>

      <div className="activity-summary-strip">
        <span><strong>{groupedLogs.length}</strong> visible item{groupedLogs.length === 1 ? "" : "s"}</span>
        <span><strong>{filteredLogs.filter((item) => item.activityImportant).length}</strong> important</span>
        <span><strong>{logs.length}</strong> recent records reviewed</span>
      </div>

      <div className="activity-feed">
        {groupedLogs.map((group) => {
          const item = group.items[0] || {};
          const module = activityModule(item);
          const icon = activityIcon(item);
          const technicalItems = group.items.slice(0, 6);
          return (
            <article className={classNames("activity-item", item.activityImportant && "important")} key={group.id}>
              <div className="activity-icon"><Icon name={icon} /></div>
              <div>
                <div className="activity-item-head">
                  <strong>{groupedActivityTitle(group)}</strong>
                  <span>{titleCaseDate(group.newestAt)}</span>
                </div>
                <p>{groupedActivityDetail(group)}</p>
                <div className="activity-meta">
                  <em>{module}</em>
                  <span>{item.activityCategory || "System"}</span>
                  <span className="activity-role-badge">{item.userRole || "System"}</span>
                  <span>{item.userName || item.userEmail || "System"}</span>
                  {item.userEmail && <span>{item.userEmail}</span>}
                  {item.activityActionType && <span>{item.activityActionType}</span>}
                  {item.activityImportant && <span className="activity-important-badge">Important</span>}
                  {group.count > 1 && <span>{group.count} grouped</span>}
                </div>
                {canSeeTechnical && (
                  <details className="activity-technical">
                    <summary>Technical Details</summary>
                    {technicalItems.map((technical) => (
                      <div className="activity-technical-grid" key={technical.id}>
                        <span>Route</span><code>{technical.technicalDetails?.route || technical.path || "Not recorded"}</code>
                        <span>Method</span><code>{technical.technicalDetails?.method || technical.method || "Not recorded"}</code>
                        <span>Event ID</span><code>{technical.technicalDetails?.eventId || technical.id}</code>
                        <span>Timestamp</span><code>{technical.technicalDetails?.timestamp || technical.createdAt}</code>
                        <span>IP</span><code>{technical.technicalDetails?.ip || "Not recorded"}</code>
                        <span>User agent</span><code>{technical.technicalDetails?.userAgent || "Not recorded"}</code>
                      </div>
                    ))}
                    {group.items.length > technicalItems.length && <p className="activity-technical-more">{group.items.length - technicalItems.length} more grouped technical record{group.items.length - technicalItems.length === 1 ? "" : "s"} hidden.</p>}
                  </details>
                )}
              </div>
            </article>
          );
        })}
        {!loading && !groupedLogs.length && (
          <EmptyState icon="Activity" title="No activity found" body="Activity will appear here as users sign in, update records, send messages, create leads, upload documents, and manage transactions." />
        )}
      </div>
    </section>
  );
}

const agentIntelBlankFilters = {
  search: "",
  market: "All",
  city: "All",
  state: "All",
  status: "All",
  role: "All",
  planType: "All",
  capStatus: "All",
  productionLevel: "All",
  crmActivityLevel: "All",
  trainingStatus: "All",
  lastLogin: "All",
  minCommission: "",
  maxCommission: "",
  minClosed: "",
  maxClosed: "",
  minPending: "",
  minLeads: "",
  minConversion: "",
  maxConversion: "",
  joinFrom: "",
  joinTo: "",
  activeLeadsOnly: false,
  overdueOnly: false,
  missingProfileOnly: false
};

const agentIntelPresets = [
  ["all", "All agents"],
  ["new", "New agents"],
  ["top", "Top producers"],
  ["near-cap", "Near cap"],
  ["over-cap", "Over cap"],
  ["no-login", "No recent login"],
  ["leads-no-follow-up", "Leads no follow-up"],
  ["low-conversion", "Low conversion"],
  ["missing-profile", "Missing profile"],
  ["no-closed", "No closings"],
  ["pending", "Pending deals"],
  ["needs-training", "Needs training"],
  ["active-week", "Active this week"],
  ["inactive-30", "Inactive 30+ days"]
];

const agentIntelColumns = [
  ["name", "Agent"],
  ["email", "Email"],
  ["phone", "Phone"],
  ["location", "Location"],
  ["market", "Market"],
  ["accountStatus", "Status"],
  ["role", "Role"],
  ["planType", "Plan"],
  ["capStatus", "Cap"],
  ["commissionEarnedYtd", "Commission YTD"],
  ["brokerageRevenueYtd", "Brokerage Revenue"],
  ["closedTransactionsYtd", "Closed"],
  ["pendingTransactions", "Pending"],
  ["activeLeads", "Active Leads"],
  ["totalLeadsReceived", "Total Leads"],
  ["leadConversionRate", "Conversion"],
  ["lastLeadAssignedAt", "Last Lead"],
  ["lastLoginAt", "Last Login"],
  ["daysSinceLastLogin", "Days Out"],
  ["crmActivityLevel", "CRM"],
  ["chatActivityLevel", "Chat"],
  ["trainingStatus", "NexU"],
  ["joinDate", "Join Date"],
  ["adminNotes", "Notes"]
];

const agentIntelNumberKeys = new Set([
  "commissionEarnedYtd",
  "brokerageRevenueYtd",
  "closedTransactionsYtd",
  "pendingTransactions",
  "activeLeads",
  "totalLeadsReceived",
  "leadConversionRate",
  "daysSinceLastLogin",
  "capProgressPercent"
]);

function agentIntelOptionList(values = []) {
  return ["All", ...Array.from(new Set(values.filter(Boolean))).sort((a, b) => String(a).localeCompare(String(b)))];
}

function agentIntelDateValue(value) {
  if (!value) return 0;
  const time = new Date(value).getTime();
  return Number.isNaN(time) ? 0 : time;
}

function agentIntelDownloadCsv(rows, mode = "contact") {
  const headers = mode === "contact"
    ? [
        ["name", "Agent name"],
        ["phone", "Phone number"],
        ["email", "Email address"],
        ["market", "Location / market"]
      ]
    : agentIntelColumns.map(([key, label]) => [key, label]);
  const body = rows.map((row) => headers.map(([key]) => {
    if (key === "market" && mode === "contact") return csvEscape(row.location || row.market || "");
    if (key === "leadConversionRate") return `${row[key] || 0}%`;
    if (["commissionEarnedYtd", "brokerageRevenueYtd", "capRemaining"].includes(key)) return row[key] || 0;
    if (key === "lastLeadAssignedAt" || key === "lastLoginAt" || key === "joinDate") return row[key] || "";
    if (key === "adminNotes") return row.adminNotes || "";
    return row[key] ?? "";
  }).map(csvEscape).join(","));
  const csv = [headers.map(([, label]) => csvEscape(label)).join(","), ...body].join("\n");
  downloadBlob(new Blob([csv], { type: "text/csv;charset=utf-8" }), mode === "contact" ? "nex-agent-contact-export.csv" : "nex-agent-intelligence-export.csv");
}

function AgentIntelligence({ role, setToast, setActivePage }) {
  const [payload, setPayload] = useState({ agents: [], staffActivity: [], summary: {}, filters: {}, generatedAt: "" });
  const [loading, setLoading] = useState(true);
  const [filters, setFilters] = useState(agentIntelBlankFilters);
  const [preset, setPreset] = useState("all");
  const [sort, setSort] = useState({ key: "name", direction: "asc" });
  const [selectedAgentId, setSelectedAgentId] = useState("");
  const isAdmin = isAdminRole(role);

  async function loadAgentIntelligence() {
    if (!isAdmin) return;
    setLoading(true);
    try {
      const next = await API.request("/api/agent-intelligence/bootstrap");
      setPayload({
        agents: next.agents || [],
        staffActivity: next.staffActivity || [],
        summary: next.summary || {},
        filters: next.filters || {},
        generatedAt: next.generatedAt || ""
      });
    } catch (error) {
      setToast(error.message || "Could not load Agent Intelligence.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadAgentIntelligence();
  }, [isAdmin]);

  const agents = payload.agents || [];
  const staffActivity = payload.staffActivity || [];
  const optionFilters = payload.filters || {};
  const updateFilter = (key, value) => setFilters((current) => ({ ...current, [key]: value }));

  function applyPreset(nextPreset) {
    setPreset(nextPreset);
    setFilters((current) => ({
      ...agentIntelBlankFilters,
      search: current.search,
      ...(nextPreset === "top" ? { productionLevel: "Top producer" } : {}),
      ...(nextPreset === "near-cap" ? { capStatus: "Near cap" } : {}),
      ...(nextPreset === "over-cap" ? { capStatus: "Over cap" } : {}),
      ...(nextPreset === "no-login" || nextPreset === "inactive-30" ? { lastLogin: "30+ days or never" } : {}),
      ...(nextPreset === "missing-profile" ? { missingProfileOnly: true } : {}),
      ...(nextPreset === "no-closed" ? { minClosed: "0", maxClosed: "0" } : {}),
      ...(nextPreset === "pending" ? { minPending: "1" } : {}),
      ...(nextPreset === "needs-training" ? { trainingStatus: "Needs attention" } : {}),
      ...(nextPreset === "active-week" ? { lastLogin: "Last 7 days" } : {}),
      ...(nextPreset === "leads-no-follow-up" ? { activeLeadsOnly: true, overdueOnly: true } : {}),
      ...(nextPreset === "low-conversion" ? { minLeads: "1", maxConversion: "15" } : {}),
      ...(nextPreset === "new" ? { joinFrom: new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString().slice(0, 10) } : {})
    }));
  }

  function toggleSort(key) {
    setSort((current) => ({
      key,
      direction: current.key === key && current.direction === "asc" ? "desc" : "asc"
    }));
  }

  const filteredAgents = useMemo(() => {
    const minNumber = (value) => (value === "" || value === null || typeof value === "undefined" ? null : Number(value));
    const search = filters.search.toLowerCase().trim();
    const minCommission = minNumber(filters.minCommission);
    const maxCommission = minNumber(filters.maxCommission);
    const minClosed = minNumber(filters.minClosed);
    const maxClosed = minNumber(filters.maxClosed);
    const minPending = minNumber(filters.minPending);
    const minLeads = minNumber(filters.minLeads);
    const minConversion = minNumber(filters.minConversion);
    const maxConversion = minNumber(filters.maxConversion);
    return agents
      .filter((agent) => {
        const matchesSearch = !search || String(agent.searchText || "").includes(search) || [agent.name, agent.email, agent.phone, agent.location, agent.market].filter(Boolean).join(" ").toLowerCase().includes(search);
        const matchesMarket = filters.market === "All" || agent.market === filters.market;
        const matchesCity = filters.city === "All" || agent.city === filters.city;
        const matchesState = filters.state === "All" || agent.state === filters.state;
        const matchesStatus = filters.status === "All" || agent.accountStatus === filters.status;
        const matchesRole = filters.role === "All" || agent.role === filters.role;
        const matchesPlan = filters.planType === "All" || agent.planType === filters.planType;
        const matchesCap = filters.capStatus === "All" || agent.capStatus === filters.capStatus;
        const matchesProduction = filters.productionLevel === "All" || agent.productionLevel === filters.productionLevel;
        const matchesCrm = filters.crmActivityLevel === "All" || agent.crmActivityLevel === filters.crmActivityLevel;
        const matchesTraining = filters.trainingStatus === "All" || agent.trainingStatus === filters.trainingStatus;
        const days = agent.daysSinceLastLogin;
        const matchesLogin =
          filters.lastLogin === "All" ||
          (filters.lastLogin === "Last 7 days" && days !== null && days <= 7) ||
          (filters.lastLogin === "Last 30 days" && days !== null && days <= 30) ||
          (filters.lastLogin === "30+ days or never" && (days === null || days >= 30)) ||
          (filters.lastLogin === "Never logged in" && days === null);
        const matchesJoinFrom = !filters.joinFrom || (agent.joinDate && String(agent.joinDate).slice(0, 10) >= filters.joinFrom);
        const matchesJoinTo = !filters.joinTo || (agent.joinDate && String(agent.joinDate).slice(0, 10) <= filters.joinTo);
        const matchesNumbers =
          (minCommission === null || Number(agent.commissionEarnedYtd || 0) >= minCommission) &&
          (maxCommission === null || Number(agent.commissionEarnedYtd || 0) <= maxCommission) &&
          (minClosed === null || Number(agent.closedTransactionsYtd || 0) >= minClosed) &&
          (maxClosed === null || Number(agent.closedTransactionsYtd || 0) <= maxClosed) &&
          (minPending === null || Number(agent.pendingTransactions || 0) >= minPending) &&
          (minLeads === null || Number(agent.totalLeadsReceived || 0) >= minLeads) &&
          (minConversion === null || Number(agent.leadConversionRate || 0) >= minConversion) &&
          (maxConversion === null || Number(agent.leadConversionRate || 0) <= maxConversion);
        const matchesBooleans =
          (!filters.activeLeadsOnly || agent.hasActiveLeads) &&
          (!filters.overdueOnly || agent.hasOverdueFollowUps) &&
          (!filters.missingProfileOnly || agent.hasMissingProfileInfo);
        return matchesSearch && matchesMarket && matchesCity && matchesState && matchesStatus && matchesRole && matchesPlan && matchesCap && matchesProduction && matchesCrm && matchesTraining && matchesLogin && matchesJoinFrom && matchesJoinTo && matchesNumbers && matchesBooleans;
      })
      .sort((a, b) => {
        const key = sort.key;
        const aValue = key === "lastLoginAt" || key === "lastLeadAssignedAt" || key === "joinDate" ? agentIntelDateValue(a[key]) : a[key];
        const bValue = key === "lastLoginAt" || key === "lastLeadAssignedAt" || key === "joinDate" ? agentIntelDateValue(b[key]) : b[key];
        const result = agentIntelNumberKeys.has(key)
          ? Number(aValue ?? -1) - Number(bValue ?? -1)
          : String(aValue ?? "").localeCompare(String(bValue ?? ""));
        return sort.direction === "asc" ? result : -result;
      });
  }, [agents, filters, sort]);
  const selectedAgent = filteredAgents.find((agent) => (agent.id || agent.email) === selectedAgentId) || agents.find((agent) => (agent.id || agent.email) === selectedAgentId) || null;

  const summaryCards = [
    ["Total agents", payload.summary.totalAgents || 0, "UsersRound", "All synced profiles"],
    ["Active agents", payload.summary.activeAgents || 0, "UserCheck", "Able to work"],
    ["New this month", payload.summary.newAgentsThisMonth || 0, "Sparkles", "Recently added"],
    ["No recent login", payload.summary.agentsNotLoggedInRecently || 0, "Clock3", "30+ days or never"],
    ["Leads assigned", payload.summary.totalLeadsAssigned || 0, "Route", "CRM and website"],
    ["Avg conversion", `${payload.summary.averageLeadConversionRate || 0}%`, "Target", "Lead conversion"],
    ["YTD commission", formatCurrency(payload.summary.totalYtdCommission || 0), "BadgeDollarSign", "Gross commission"],
    ["Brokerage revenue", formatCurrency(payload.summary.totalYtdBrokerageRevenue || 0), "Landmark", "Plan/cap revenue"],
    ["Near cap", payload.summary.agentsNearCap || 0, "Gauge", "80%+ progress"],
    ["Over cap", payload.summary.agentsOverCap || 0, "BadgeCheck", "Cap reached"],
    ["Pending files", payload.summary.pendingTransactions || 0, "FileClock", "Open transactions"],
    ["Overdue follow-ups", payload.summary.agentsWithOverdueFollowUps || 0, "AlertTriangle", "Needs attention"]
  ];

  function renderCell(agent, key) {
    if (key === "name") {
      return (
        <div className="agent-intel-agent-cell">
          <UserAvatar user={agent} size="sm" />
          <span>
            <strong>{agent.name}</strong>
            <small>{agent.email}</small>
          </span>
        </div>
      );
    }
    if (key === "accountStatus") return <span className={classNames("agent-intel-badge", `status-${slugify(agent.accountStatus)}`)}>{agent.accountStatus}</span>;
    if (key === "role") return <span className="agent-intel-soft-badge">{agent.role}</span>;
    if (key === "capStatus") {
      return (
        <span className={classNames("agent-intel-badge", `cap-${slugify(agent.capStatus)}`)}>
          {agent.capStatus}
          {agent.capProgressPercent !== null && <small>{agent.capProgressPercent}%</small>}
        </span>
      );
    }
    if (key === "commissionEarnedYtd" || key === "brokerageRevenueYtd") return formatCurrency(agent[key] || 0);
    if (key === "leadConversionRate") return `${agent.leadConversionRate || 0}%`;
    if (key === "lastLeadAssignedAt" || key === "lastLoginAt") return agent[key] ? titleCaseDate(agent[key]) : "Never";
    if (key === "daysSinceLastLogin") return agent.daysSinceLastLogin === null ? "Never" : `${agent.daysSinceLastLogin}d`;
    if (key === "crmActivityLevel" || key === "chatActivityLevel") return <span className={classNames("agent-intel-soft-badge", `level-${slugify(agent[key])}`)}>{agent[key]}</span>;
    if (key === "trainingStatus") return <span>{agent.trainingProgressPercent === null ? agent.trainingStatus : `${agent.trainingStatus} (${agent.trainingProgressPercent}%)`}</span>;
    if (key === "joinDate") return agent.joinDate ? formatDate(agent.joinDate) : "Not set";
    if (key === "adminNotes") return agent.adminNotes || (agent.hasMissingProfileInfo ? `Missing: ${agent.missingProfileItems.join(", ")}` : "-");
    return agent[key] || "-";
  }

  function renderAgentReport() {
    if (!selectedAgent) return null;
    const reportCards = [
      ["Plan", selectedAgent.planType || "Not set", "BriefcaseBusiness"],
      ["Cap status", selectedAgent.capStatus || "Not tracked", "Gauge"],
      ["Cap remaining", selectedAgent.capRemaining === null || typeof selectedAgent.capRemaining === "undefined" ? "N/A" : formatCurrency(selectedAgent.capRemaining), "CircleDollarSign"],
      ["Commission YTD", formatCurrency(selectedAgent.commissionEarnedYtd || 0), "BadgeDollarSign"],
      ["Brokerage revenue", formatCurrency(selectedAgent.brokerageRevenueYtd || 0), "Landmark"],
      ["Closed YTD", selectedAgent.closedTransactionsYtd || 0, "CheckCircle2"],
      ["Pending files", selectedAgent.pendingTransactions || 0, "FileClock"],
      ["Lead conversion", `${selectedAgent.leadConversionRate || 0}%`, "Target"]
    ];
    const nextActions = [
      selectedAgent.hasMissingProfileInfo && `Complete profile fields: ${selectedAgent.missingProfileItems.join(", ")}`,
      selectedAgent.hasOverdueFollowUps && `${selectedAgent.overdueFollowUps} overdue CRM follow-up${selectedAgent.overdueFollowUps === 1 ? "" : "s"}`,
      selectedAgent.daysSinceLastLogin === null && "Agent has never logged into Nex Central",
      Number(selectedAgent.daysSinceLastLogin || 0) >= 30 && "Agent has not logged in for 30+ days",
      selectedAgent.capStatus === "Near cap" && "Agent is approaching cap; review cap math before next DA",
      selectedAgent.productionPlanStatus === "No plan" && "No Production Game Plan saved yet"
    ].filter(Boolean);
    return (
      <div className="agent-intel-detail-drawer" role="dialog" aria-modal="true" aria-label="Agent intelligence report">
        <div className="agent-intel-detail-backdrop" onClick={() => setSelectedAgentId("")} />
        <aside className="agent-intel-detail-panel">
          <div className="agent-intel-detail-head">
            <div className="agent-intel-agent-cell">
              <UserAvatar user={selectedAgent} size="lg" />
              <span>
                <strong>{selectedAgent.name}</strong>
                <small>{selectedAgent.email}</small>
                <small>{selectedAgent.phone || "No phone on file"} - {selectedAgent.market || "No market"}</small>
              </span>
            </div>
            <button className="icon-btn" type="button" onClick={() => setSelectedAgentId("")} title="Close report"><Icon name="X" /></button>
          </div>
          <div className="agent-intel-detail-scroll">
            <section className="agent-intel-report-section">
              <div className="agent-intel-report-title">
                <p className="eyebrow">Admin-only report</p>
                <h3>{selectedAgent.name}'s intelligence recap</h3>
                <span>This report is visible to admins only. Agents see only their own basic profile and read-only plan facts.</span>
              </div>
              <div className="agent-intel-report-grid">
                {reportCards.map(([label, value, icon]) => (
                  <article key={label}>
                    <Icon name={icon} />
                    <span>{label}</span>
                    <strong>{value}</strong>
                  </article>
                ))}
              </div>
            </section>

            <section className="agent-intel-report-section">
              <div className="agent-intel-report-title">
                <h4>Engagement and activity</h4>
              </div>
              <div className="agent-intel-report-list">
                <span><strong>Last login</strong>{selectedAgent.lastLoginAt ? titleCaseDate(selectedAgent.lastLoginAt) : "Never"}</span>
                <span><strong>CRM activity</strong>{selectedAgent.crmActivityLevel} - {selectedAgent.crmActivityCount30d || 0} actions in 30 days</span>
                <span><strong>Nex Chat activity</strong>{selectedAgent.chatActivityLevel} - {selectedAgent.chatActivityCount30d || 0} messages in 30 days</span>
                <span><strong>NexU status</strong>{selectedAgent.trainingProgressPercent === null ? selectedAgent.trainingStatus : `${selectedAgent.trainingStatus} (${selectedAgent.trainingProgressPercent}%)`}</span>
                <span><strong>Lead rotation</strong>{selectedAgent.leadRotationOptIn ? selectedAgent.leadRotationStatus : "Not opted in"}</span>
                <span><strong>Accepted lead terms</strong>{selectedAgent.acceptedBrokerageLeadTerms ? "Yes" : "No"}</span>
              </div>
            </section>

            <section className="agent-intel-report-section">
              <div className="agent-intel-report-title">
                <h4>Lead and profile accountability</h4>
              </div>
              <div className="agent-intel-report-list">
                <span><strong>Total leads received</strong>{selectedAgent.totalLeadsReceived || 0}</span>
                <span><strong>Active leads</strong>{selectedAgent.activeLeads || 0}</span>
                <span><strong>Last lead assigned</strong>{selectedAgent.lastLeadAssignedAt ? titleCaseDate(selectedAgent.lastLeadAssignedAt) : "Never"}</span>
                <span><strong>Service counties</strong>{selectedAgent.serviceCounties?.length ? selectedAgent.serviceCounties.join(", ") : "Not set"}</span>
                <span><strong>Service cities</strong>{selectedAgent.serviceCities?.length ? selectedAgent.serviceCities.join(", ") : "Not set"}</span>
                <span><strong>Service ZIPs</strong>{selectedAgent.serviceZipCodes?.length ? selectedAgent.serviceZipCodes.join(", ") : "Not set"}</span>
              </div>
              <div className="agent-intel-next-actions">
                <strong>Admin notes / next actions</strong>
                {nextActions.length ? nextActions.map((item) => <span key={item}>{item}</span>) : <span>No obvious action flags right now.</span>}
                {selectedAgent.adminNotes && <em>{selectedAgent.adminNotes}</em>}
              </div>
            </section>

            <div className="agent-intel-detail-actions">
              <button className="btn secondary" type="button" onClick={() => agentIntelDownloadCsv([selectedAgent], "full")}>
                <Icon name="FileDown" />
                <span>Export Report CSV</span>
              </button>
              <button className="btn primary" type="button" onClick={() => { setSelectedAgentId(""); setActivePage?.("Admin Panel"); }}>
                <Icon name="UserRoundCog" />
                <span>Open User Management</span>
              </button>
            </div>
          </div>
        </aside>
      </div>
    );
  }

  if (!isAdmin) {
    return <EmptyState icon="ShieldAlert" title="Admin-only page" body="Agent Intelligence is only available to Nex admins and super admins." />;
  }

  return (
    <section className="agent-intel-page">
      <div className="agent-intel-header">
        <div>
          <p className="eyebrow">Admin command center</p>
          <h2>Agent Intelligence</h2>
          <p>Live agent data synced from profiles, commissions, transactions, leads, CRM, chat, production, and login activity.</p>
        </div>
        <div className="agent-intel-actions">
          <button className="btn secondary" type="button" onClick={loadAgentIntelligence} disabled={loading}>
            <Icon name={loading ? "LoaderCircle" : "RefreshCcw"} className={loading ? "spin" : ""} />
            <span>{loading ? "Refreshing" : "Refresh"}</span>
          </button>
          <button className="btn secondary" type="button" onClick={() => agentIntelDownloadCsv(filteredAgents, "contact")}>
            <Icon name="Download" />
            <span>Contact CSV</span>
          </button>
          <button className="btn primary" type="button" onClick={() => agentIntelDownloadCsv(filteredAgents, "full")}>
            <Icon name="FileDown" />
            <span>Full Export</span>
          </button>
        </div>
      </div>

      <div className="agent-intel-summary-grid">
        {summaryCards.map(([label, value, icon, detail]) => (
          <article className="agent-intel-summary-card" key={label}>
            <Icon name={icon} />
            <span>{label}</span>
            <strong>{value}</strong>
            <small>{detail}</small>
          </article>
        ))}
      </div>

      <div className="agent-intel-filter-shell">
        <div className="agent-intel-preset-row">
          {agentIntelPresets.map(([key, label]) => (
            <button key={key} type="button" className={classNames(preset === key && "active")} onClick={() => applyPreset(key)}>{label}</button>
          ))}
        </div>
        <div className="agent-intel-filter-grid">
          <Field label="Search" value={filters.search} onChange={(value) => updateFilter("search", value)} placeholder="Name, email, phone, market, plan..." />
          <Field label="Market" value={filters.market} onChange={(value) => updateFilter("market", value)} as="select" options={agentIntelOptionList(optionFilters.markets)} />
          <Field label="City" value={filters.city} onChange={(value) => updateFilter("city", value)} as="select" options={agentIntelOptionList(optionFilters.cities)} />
          <Field label="State" value={filters.state} onChange={(value) => updateFilter("state", value)} as="select" options={agentIntelOptionList(optionFilters.states)} />
          <Field label="Status" value={filters.status} onChange={(value) => updateFilter("status", value)} as="select" options={agentIntelOptionList(optionFilters.statuses)} />
          <Field label="Role" value={filters.role} onChange={(value) => updateFilter("role", value)} as="select" options={agentIntelOptionList(optionFilters.roles)} />
          <Field label="Plan" value={filters.planType} onChange={(value) => updateFilter("planType", value)} as="select" options={agentIntelOptionList(optionFilters.planTypes)} />
          <Field label="Cap status" value={filters.capStatus} onChange={(value) => updateFilter("capStatus", value)} as="select" options={agentIntelOptionList(optionFilters.capStatuses)} />
          <Field label="Last login" value={filters.lastLogin} onChange={(value) => updateFilter("lastLogin", value)} as="select" options={["All", "Last 7 days", "Last 30 days", "30+ days or never", "Never logged in"]} />
        </div>
        <details className="agent-intel-advanced-filters">
          <summary>Advanced filters</summary>
          <div className="agent-intel-filter-grid">
            <Field label="Production level" value={filters.productionLevel} onChange={(value) => updateFilter("productionLevel", value)} as="select" options={agentIntelOptionList(optionFilters.productionLevels)} />
            <Field label="CRM activity" value={filters.crmActivityLevel} onChange={(value) => updateFilter("crmActivityLevel", value)} as="select" options={agentIntelOptionList(optionFilters.crmActivityLevels)} />
            <Field label="NexU progress" value={filters.trainingStatus} onChange={(value) => updateFilter("trainingStatus", value)} as="select" options={agentIntelOptionList(optionFilters.trainingStatuses)} />
            <Field label="Min commission" value={filters.minCommission} onChange={(value) => updateFilter("minCommission", value)} type="number" />
            <Field label="Max commission" value={filters.maxCommission} onChange={(value) => updateFilter("maxCommission", value)} type="number" />
            <Field label="Min closed" value={filters.minClosed} onChange={(value) => updateFilter("minClosed", value)} type="number" />
            <Field label="Min pending" value={filters.minPending} onChange={(value) => updateFilter("minPending", value)} type="number" />
            <Field label="Min leads" value={filters.minLeads} onChange={(value) => updateFilter("minLeads", value)} type="number" />
            <Field label="Min conversion %" value={filters.minConversion} onChange={(value) => updateFilter("minConversion", value)} type="number" />
            <Field label="Join from" value={filters.joinFrom} onChange={(value) => updateFilter("joinFrom", value)} type="date" />
            <Field label="Join to" value={filters.joinTo} onChange={(value) => updateFilter("joinTo", value)} type="date" />
          </div>
          <div className="agent-intel-toggle-row">
            <label><input type="checkbox" checked={filters.activeLeadsOnly} onChange={(event) => updateFilter("activeLeadsOnly", event.target.checked)} /> Has active leads</label>
            <label><input type="checkbox" checked={filters.overdueOnly} onChange={(event) => updateFilter("overdueOnly", event.target.checked)} /> Has overdue follow-ups</label>
            <label><input type="checkbox" checked={filters.missingProfileOnly} onChange={(event) => updateFilter("missingProfileOnly", event.target.checked)} /> Missing profile info</label>
          </div>
        </details>
      </div>

      <div className="agent-intel-table-shell agent-intel-staff-shell">
        <div className="agent-intel-table-head">
          <div>
            <strong>{staffActivity.length}</strong>
            <span>admin/staff records</span>
          </div>
          <small>Operational oversight: login, online signal, and file-review activity</small>
        </div>
        <div className="agent-intel-staff-grid">
          {staffActivity.map((staff) => (
            <article key={staff.id || staff.email} className={classNames(staff.isOnline && "online")}>
              <div>
                <UserAvatar user={staff} size="sm" />
                <span>
                  <strong>{staff.name || staff.email}</strong>
                  <small>{staff.role} - {staff.directoryType}</small>
                </span>
              </div>
              <p><strong>{staff.isOnline ? "Online now" : "Not currently online"}</strong>{staff.lastSeenAt ? `Last seen ${titleCaseDate(staff.lastSeenAt)}` : "No active session"}</p>
              <p><strong>Last login</strong>{staff.lastLoginAt ? titleCaseDate(staff.lastLoginAt) : "Never"}</p>
              <p><strong>File review activity</strong>{staff.recentFileReviewCount || 0} in 30 days{staff.lastFileReviewAt ? ` - last ${titleCaseDate(staff.lastFileReviewAt)}` : ""}</p>
              <p><strong>Recent activity</strong>{staff.recentActivityTitle || "No recent activity logged"}{staff.recentActivityModule ? ` (${staff.recentActivityModule})` : ""}</p>
            </article>
          ))}
          {!staffActivity.length && <p className="muted-text">No admin or staff records found.</p>}
        </div>
      </div>

      <div className="agent-intel-table-shell">
        <div className="agent-intel-table-head">
          <div>
            <strong>{filteredAgents.length}</strong>
            <span>visible agents</span>
          </div>
          <small>Last synced {payload.generatedAt ? titleCaseDate(payload.generatedAt) : "after refresh"}</small>
        </div>
        <div className="agent-intel-table-scroll">
          <table className="agent-intel-table">
            <thead>
              <tr>
                {agentIntelColumns.map(([key, label]) => (
                  <th key={key}>
                    <button type="button" onClick={() => toggleSort(key)}>
                      <span>{label}</span>
                      <Icon name={sort.key === key ? (sort.direction === "asc" ? "ChevronUp" : "ChevronDown") : "ChevronsUpDown"} size={13} />
                    </button>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filteredAgents.map((agent) => (
                <tr key={agent.id || agent.email} className="agent-intel-click-row" onClick={() => setSelectedAgentId(agent.id || agent.email)}>
                  {agentIntelColumns.map(([key]) => <td key={key}>{renderCell(agent, key)}</td>)}
                </tr>
              ))}
            </tbody>
          </table>
          {!loading && !filteredAgents.length && (
            <EmptyState icon="SearchX" title="No agents match" body="Adjust the filters or clear presets to see more synced agent records." />
          )}
        </div>
      </div>
      {renderAgentReport()}
    </section>
  );
}

function ChatMessage({ message, setToast }) {
  if (message.type === "assistant" && message.output) {
    return (
      <div className="message assistant">
        <div className="message-bubble rich">
          <ComplianceNotice text={message.output.complianceReminder} />
          <MarketingOutput output={message.output} setToast={setToast} />
        </div>
      </div>
    );
  }

  return (
    <div className={classNames("message", message.type)}>
      <div className="message-bubble">
        <p>{message.text}</p>
      </div>
    </div>
  );
}

function ChatWorkspace({ messages, prompt, setPrompt, onSubmit, isGenerating, output, setToast, onQuickAction = null }) {
  return (
    <section className="chat-layout">
      <div className="chat-card">
        <div className="prompt-starters">
          {promptStarters.map((starter) => (
            <button key={starter.label} type="button" onClick={() => setPrompt(starter.prompt)}>
              <Icon name="Sparkles" size={15} />
              <span>{starter.label}</span>
            </button>
          ))}
        </div>
        <div className="copy-action-row">
          {copyQuickActions.map(([label, action]) => (
            <button key={label} type="button" onClick={() => (onQuickAction ? onQuickAction(`${action}\n\nCurrent copy:\n${output?.primary || prompt || "Use current Nex Realty campaign details."}`) : setPrompt(action))}>
              {label}
            </button>
          ))}
        </div>
        <div className="chat-stream">
          {messages.map((message) => (
            <ChatMessage key={message.id} message={message} setToast={setToast} />
          ))}
        </div>
        <form className="chat-composer" onSubmit={onSubmit}>
          <textarea
            value={prompt}
            onChange={(event) => setPrompt(event.target.value)}
            placeholder='Try "Create a Facebook post, flyer copy, email blast, and text message for this listing."'
            rows={3}
          />
          <button className="btn primary" type="submit" disabled={isGenerating}>
            <Icon name={isGenerating ? "LoaderCircle" : "Send"} className={isGenerating ? "spin" : ""} />
            <span>{isGenerating ? "Working" : "Send"}</span>
          </button>
        </form>
      </div>

      <div className="panel output-panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Structured output</p>
            <h3>Marketing set</h3>
          </div>
        </div>
        {output ? (
          <MarketingOutput output={output} setToast={setToast} compact />
        ) : (
          <EmptyState icon="FileText" title="Generated content appears here" body="Every request returns copy, headline, CTA, hashtags, email, SMS, and flyer-ready text." />
        )}
      </div>
    </section>
  );
}

function MarketingOutput({ output, setToast = () => {}, compact = false }) {
  const sections = [
    ["Primary marketing copy", output.primary],
    ["Short version", output.shortVersion],
    ["Long version", output.longVersion],
    ["Flyer-ready copy", output.flyerReadyCopy],
    ["Email version", output.emailVersion],
    ["SMS version", output.smsVersion]
  ];

  return (
    <div className={classNames("marketing-output", compact && "compact")}>
      <div className="output-header">
        <div>
          <p className="eyebrow">{output.marketingType}</p>
          <h3>{output.suggestedHeadline}</h3>
        </div>
        <button
          className="icon-btn"
          onClick={() =>
            copyToClipboard(
              sections.map(([label, value]) => `${label}\n${value}`).join("\n\n"),
              setToast
            )
          }
          title="Copy all output"
        >
          <Icon name="Copy" />
        </button>
      </div>

      {!compact && output.missingSuggestions && output.missingSuggestions.length > 0 && (
        <div className="suggestion-strip">
          Add later for sharper output: {output.missingSuggestions.join(", ")}.
        </div>
      )}

      <div className="output-grid">
        {sections.map(([label, value]) => (
          <article className="output-card" key={label}>
            <div className="output-card-head">
              <span>{label}</span>
              <button className="icon-btn small" onClick={() => copyToClipboard(value, setToast)} title={`Copy ${label}`}>
                <Icon name="Copy" size={15} />
              </button>
            </div>
            <p>{value}</p>
          </article>
        ))}
      </div>

      {output.hashtags && output.hashtags.length > 0 && (
        <div className="hashtag-row">
          {output.hashtags.map((tag) => (
            <span key={tag}>{tag}</span>
          ))}
        </div>
      )}
    </div>
  );
}

function ComplianceNotice({ text }) {
  return (
    <div className="compliance-notice">
      <Icon name="ShieldCheck" size={18} />
      <p>{text}</p>
    </div>
  );
}

function EmptyState({ icon, title, body }) {
  return (
    <div className="empty-state">
      <Icon name={icon} size={28} />
      <h3>{title}</h3>
      <p>{body}</p>
    </div>
  );
}

function Field({ label, value, onChange, placeholder = "", type = "text", as = "input", options = [], disabled = false }) {
  return (
    <label className="field">
      <span>{label}</span>
      {as === "select" ? (
        <select value={value} onChange={(event) => onChange(event.target.value)} disabled={disabled}>
          {options.map((option) => (
            <option key={option} value={option}>
              {option}
            </option>
          ))}
        </select>
      ) : as === "textarea" ? (
        <textarea value={value} onChange={(event) => onChange(event.target.value)} placeholder={placeholder} rows={4} disabled={disabled} />
      ) : (
        <input value={value} onChange={(event) => onChange(event.target.value)} placeholder={placeholder} type={type} disabled={disabled} />
      )}
    </label>
  );
}

function RangeField({ label, value, onChange, min, max, step = 1, suffix = "" }) {
  return (
    <label className="field range-field">
      <span>
        {label}
        <strong>{value}{suffix}</strong>
      </span>
      <input
        type="range"
        min={min}
        max={max}
        step={step}
        value={value}
        onChange={(event) => onChange(Number(event.target.value))}
      />
    </label>
  );
}

function InputPanel({ fields, setFields, agentHeadshot, setAgentHeadshot, propertyPhotos, setPropertyPhotos }) {
  function update(name, value) {
    setFields((current) => ({ ...current, [name]: value }));
  }

  async function onHeadshotChange(event) {
    const files = Array.from((event.target && event.target.files) || event.files || []);
    const file = files[0];
    if (!file) return;
    setAgentHeadshot(await fileToDataUrl(file));
  }

  async function onPhotoChange(event) {
    const files = Array.from((event.target && event.target.files) || event.files || []);
    const uploads = await Promise.all(files.map(fileToDataUrl));
    setPropertyPhotos((current) => [...current, ...uploads].slice(0, 8));
  }

  return (
    <aside className="input-panel">
      <div className="panel-heading sticky-heading">
        <div>
          <p className="eyebrow">Optional details</p>
          <h3>Agent and property inputs</h3>
        </div>
      </div>

      <div className="form-stack">
        <section className="form-section">
          <h4>Marketing setup</h4>
          <Field label="Marketing type" value={fields.marketingType} onChange={(value) => update("marketingType", value)} as="select" options={marketingTypes} />
          <Field label="Tone" value={fields.tone} onChange={(value) => update("tone", value)} as="select" options={toneOptions} />
          <Field label="Platform" value={fields.platform} onChange={(value) => update("platform", value)} as="select" options={platformOptions} />
        </section>

        <section className="form-section">
          <h4>Agent</h4>
          <Field label="Agent name" value={fields.agentName} onChange={(value) => update("agentName", value)} placeholder="Jordan Taylor" />
          <Field label="Agent phone" value={fields.agentPhone} onChange={(value) => update("agentPhone", value)} placeholder="555-010-2026" />
          <Field label="Agent email" value={fields.agentEmail} onChange={(value) => update("agentEmail", value)} placeholder="agent@nexrealty.com" />
          <FileDrop label="Agent headshot" onChange={onHeadshotChange} preview={agentHeadshot && agentHeadshot.dataUrl} />
        </section>

        <section className="form-section">
          <h4>Property</h4>
          <Field label="Property address" value={fields.propertyAddress} onChange={(value) => update("propertyAddress", value)} placeholder="123 Main Street" />
          <div className="split-fields">
            <Field label="City" value={fields.city} onChange={(value) => update("city", value)} />
            <Field label="State" value={fields.state} onChange={(value) => update("state", value)} />
            <Field label="Zip" value={fields.zip} onChange={(value) => update("zip", value)} />
          </div>
          <Field label="Price" value={fields.price} onChange={(value) => update("price", value)} placeholder="$725,000" />
          <div className="split-fields">
            <Field label="Beds" value={fields.bedrooms} onChange={(value) => update("bedrooms", value)} />
            <Field label="Baths" value={fields.bathrooms} onChange={(value) => update("bathrooms", value)} />
            <Field label="Garage" value={fields.garageSpaces} onChange={(value) => update("garageSpaces", value)} />
          </div>
          <div className="split-fields">
            <Field label="Sq ft" value={fields.squareFootage} onChange={(value) => update("squareFootage", value)} />
            <Field label="Lot size" value={fields.lotSize} onChange={(value) => update("lotSize", value)} />
          </div>
          <Field label="Property type" value={fields.propertyType} onChange={(value) => update("propertyType", value)} placeholder="Single family, condo, townhome" />
          <Field
            label="Status"
            value={fields.status}
            onChange={(value) => update("status", value)}
            as="select"
            options={["For sale", "For rent", "Sold", "Open house", "Price drop"]}
          />
          <Field label="Open house date and time" type="datetime-local" value={fields.openHouseDateTime} onChange={(value) => update("openHouseDateTime", value)} />
          <Field label="Available date for rentals" type="date" value={fields.rentalAvailableDate} onChange={(value) => update("rentalAvailableDate", value)} />
          <Field label="Property highlights" value={fields.propertyHighlights} onChange={(value) => update("propertyHighlights", value)} as="textarea" placeholder="Renovated kitchen, private yard, smart home features..." />
          <Field label="MLS remarks" value={fields.mlsRemarks} onChange={(value) => update("mlsRemarks", value)} as="textarea" placeholder="Paste MLS remarks or rough notes." />
          <Field label="Call-to-action" value={fields.cta} onChange={(value) => update("cta", value)} />
          <FileDrop label="Property photos" multiple onChange={onPhotoChange} count={propertyPhotos.length} />
          {propertyPhotos.length > 0 && (
            <div className="photo-thumb-grid">
              {propertyPhotos.map((photo, index) => (
                <button key={`${photo.name}-${index}`} onClick={() => setPropertyPhotos((current) => current.filter((_, itemIndex) => itemIndex !== index))} title="Remove photo">
                  <img src={photo.dataUrl} alt={photo.name} />
                </button>
              ))}
            </div>
          )}
        </section>
      </div>
    </aside>
  );
}

function FileDrop({ label, onChange, preview, count, multiple = false }) {
  function handleDrop(event) {
    event.preventDefault();
    const files = Array.from(event.dataTransfer.files || []).filter((file) => file.type.startsWith("image/"));
    if (files.length) onChange({ files: multiple ? files : files.slice(0, 1) });
  }

  return (
    <label className="file-drop" onDragOver={(event) => event.preventDefault()} onDrop={handleDrop}>
      {preview ? <img src={preview} alt="" /> : <Icon name="UploadCloud" size={19} />}
      <span>{label}</span>
      {typeof count === "number" && <em>{count} selected</em>}
      <input type="file" accept="image/*" onChange={onChange} multiple={multiple} />
    </label>
  );
}

function ChoiceGrid({ label, value, options, onChange }) {
  return (
    <div className="choice-group">
      <p>{label}</p>
      <div className="choice-grid">
        {options.map((option) => (
          <button
            key={option.id}
            className={classNames("choice-chip", value === option.id && "selected")}
            onClick={() => onChange(option.id)}
            type="button"
          >
            {option.icon && <Icon name={option.icon} size={16} />}
            <span>{option.name}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

function getCanvasTextFitClass(value) {
  const text = String(value || "").trim();
  const compactLength = text.replace(/\s/g, "").length;
  const isWebOrEmail = /(^https?:\/\/|^www\.|@|\.[a-z]{2,}(\/|$))/i.test(text);

  if (isWebOrEmail && compactLength > 34) return "fit-url fit-extreme";
  if (isWebOrEmail && compactLength > 16) return "fit-url";
  if (compactLength > 64) return "fit-extreme";
  if (compactLength > 44) return "fit-very-long";
  if (compactLength > 28) return "fit-long";
  return "";
}

function EditableCanvasText({ as = "span", value, placeholder = "Click to edit", onCommit, onSelect, className = "", multiline = false, style = {}, autoFit = true }) {
  const Tag = as;
  const displayValue = value || placeholder;
  const fitClass = autoFit ? getCanvasTextFitClass(displayValue) : "";
  const [isEditing, setIsEditing] = useState(false);

  function commit(event) {
    const nextValue = event.currentTarget.textContent.trim();
    setIsEditing(false);
    onCommit(nextValue);
  }

  function handleKeyDown(event) {
    if (!multiline && event.key === "Enter") {
      event.preventDefault();
      event.currentTarget.blur();
    }
    if (event.key === "Escape") {
      event.currentTarget.textContent = displayValue;
      setIsEditing(false);
      event.currentTarget.blur();
    }
  }

  return (
    <Tag
      className={classNames("canvas-editable", fitClass, isEditing && "is-editing", className)}
      contentEditable
      suppressContentEditableWarning
      tabIndex={0}
      onClick={(event) => {
        event.stopPropagation();
        if (onSelect) onSelect();
      }}
      onFocus={() => {
        setIsEditing(true);
        if (onSelect) onSelect();
      }}
      onBlur={commit}
      onKeyDown={handleKeyDown}
      title="Click to edit directly"
      style={style}
    >
      {displayValue}
    </Tag>
  );
}

function ResizeHandles({ active, elementId, onStart }) {
  if (!active) return null;
  return (
    <span className="resize-handles" aria-hidden="true">
      {["nw", "ne", "sw", "se"].map((corner) => (
        <i key={corner} className={`handle-${corner}`} onPointerDown={(event) => onStart(event, elementId)} />
      ))}
    </span>
  );
}

function TemplateSelector({ templates, selectedTemplateId, onSelect, brand }) {
  return (
    <div className="template-picker">
      {templates.map((template) => (
        <button
          key={template.id}
          className={classNames("template-preset", selectedTemplateId === template.id && "selected")}
          onClick={() => onSelect(template.id)}
          type="button"
          style={{ "--accent": template.accent || "#e30613" }}
        >
          <Wordmark brand={brand} compact variant="dark" className="template-card-logo" />
          <span>{template.category}</span>
          <strong>{template.headline}</strong>
          <em>{template.badge}</em>
        </button>
      ))}
    </div>
  );
}

function StockPhotoTray({ onAddStockPhoto }) {
  const [activeCategory, setActiveCategory] = useState("All");
  const [imageUrl, setImageUrl] = useState("");
  const categories = ["All", ...Array.from(new Set(studioStockPhotoPresets.map((photo) => photo.category)))];
  const filtered = activeCategory === "All" ? studioStockPhotoPresets : studioStockPhotoPresets.filter((photo) => photo.category === activeCategory);
  const stockQuery = activeCategory === "All" ? "luxury real estate" : `${activeCategory} real estate`;

  function addImageUrl() {
    const url = imageUrl.trim();
    if (!/^https?:\/\//i.test(url)) return;
    onAddStockPhoto({
      id: `stock-url-${Date.now()}`,
      title: "Pasted stock image",
      category: "Custom",
      source: "Image URL",
      dataUrl: url
    });
    setImageUrl("");
  }

  return (
    <div className="stock-tray">
      <div className="stock-tabs">
        {categories.map((category) => (
          <button
            key={category}
            className={activeCategory === category ? "selected" : ""}
            onClick={() => setActiveCategory(category)}
            type="button"
          >
            {category}
          </button>
        ))}
      </div>
      <div className="stock-url-import">
        <input value={imageUrl} onChange={(event) => setImageUrl(event.target.value)} placeholder="Paste a royalty-free image URL" />
        <button type="button" onClick={addImageUrl} disabled={!imageUrl.trim()}>
          <Icon name="Plus" size={14} />
          <span>Add</span>
        </button>
      </div>
      <button
        className="stock-search-button"
        type="button"
        onClick={() => window.open(`https://www.pexels.com/search/${encodeURIComponent(stockQuery)}/`, "_blank", "noopener,noreferrer")}
      >
        <Icon name="Search" size={15} />
        <span>Pexels stock search</span>
      </button>
      <div className="stock-grid">
        {filtered.map((photo) => (
          <button key={photo.id} className="stock-card" onClick={() => onAddStockPhoto(photo)} type="button">
            <img src={photo.dataUrl} alt={photo.title} crossOrigin={String(photo.dataUrl || "").startsWith("http") ? "anonymous" : undefined} />
            <span>{photo.title}</span>
            {photo.source && <em>{photo.source}</em>}
          </button>
        ))}
      </div>
    </div>
  );
}

function FlyerBuilder({
  brand,
  fields,
  setFields,
  templates,
  selectedTemplateId,
  setSelectedTemplateId,
  flyerCopy,
  setFlyerCopy,
  propertyPhotos,
  agentHeadshot,
  flyerRef,
  onDownloadPdf,
  onDownloadPng,
  onDownloadVideo,
  onGenerate,
  onAddStockPhoto
}) {
  const selectedTemplate = templates.find((template) => template.id === selectedTemplateId);
  const selectedFormat = getCreativeFormat(flyerCopy.canvasFormat);

  function updateFlyerCopy(name, value) {
    setFlyerCopy((current) => ({ ...current, [name]: value }));
  }

  function updateField(name, value) {
    if (!setFields) return;
    setFields((current) => ({ ...current, [name]: value }));
  }

  function selectTemplate(templateId) {
    const template = templates.find((item) => item.id === templateId);
    setSelectedTemplateId(templateId);
    if (template) {
      setFlyerCopy((current) => ({
        ...current,
        headline: template.headline || current.headline,
        badge: template.badge || current.badge,
        layout: template.style || current.layout
      }));
    }
  }

  return (
    <section className="flyer-builder-grid">
      <div className="panel builder-controls studio-controls">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Design Studio</p>
            <h3>Templates, visuals, and copy</h3>
          </div>
        </div>

        <section className="studio-block">
          <p className="studio-label">Template</p>
          <TemplateSelector templates={templates} selectedTemplateId={selectedTemplateId} onSelect={selectTemplate} brand={brand} />
        </section>

        <section className="studio-block">
          <p className="studio-label">Design options</p>
          <ChoiceGrid label="Format" value={flyerCopy.canvasFormat || "letter-flyer"} options={creativeFormatOptions} onChange={(value) => updateFlyerCopy("canvasFormat", value)} />
          <ChoiceGrid label="Layout" value={flyerCopy.layout || selectedTemplate?.style || "classic"} options={flyerLayoutOptions} onChange={(value) => updateFlyerCopy("layout", value)} />
          <ChoiceGrid label="Finish" value={flyerCopy.finish || "red-signature"} options={flyerFinishOptions} onChange={(value) => updateFlyerCopy("finish", value)} />
          <ChoiceGrid label="Photo" value={flyerCopy.photoTreatment || "dramatic-overlay"} options={photoTreatmentOptions} onChange={(value) => updateFlyerCopy("photoTreatment", value)} />
          <div className="format-note">
            <Icon name="Ruler" size={15} />
            <span>{selectedFormat.name}: {selectedFormat.exportLabel}</span>
          </div>
        </section>

        <section className="studio-block">
          <p className="studio-label">Stock visuals</p>
          <StockPhotoTray onAddStockPhoto={onAddStockPhoto} />
        </section>

        <section className="studio-block copy-studio-block">
          <p className="studio-label">Editable copy</p>
          <Field label="Headline" value={flyerCopy.headline} onChange={(value) => updateFlyerCopy("headline", value)} />
          <Field label="Badge" value={flyerCopy.badge} onChange={(value) => updateFlyerCopy("badge", value)} />
          <Field label="Flyer body" value={flyerCopy.body} onChange={(value) => updateFlyerCopy("body", value)} as="textarea" />
          <Field label="CTA" value={flyerCopy.cta} onChange={(value) => updateFlyerCopy("cta", value)} />
        </section>

        <div className="button-grid">
          <button className="btn secondary" onClick={onGenerate}>
            <Icon name="RefreshCw" />
            <span>Regenerate Copy</span>
          </button>
          <button className="btn primary" onClick={onDownloadPdf}>
            <Icon name="Download" />
            <span>PDF</span>
          </button>
          <button className="btn dark" onClick={onDownloadPng}>
            <Icon name="ImageDown" />
            <span>PNG</span>
          </button>
          <button className="btn secondary" onClick={() => onDownloadVideo(flyerCopy.videoOrientation || "vertical")}>
            <Icon name="Clapperboard" />
            <span>Quick Video</span>
          </button>
        </div>
      </div>

      <FlyerPreview
        brand={brand}
        fields={fields}
        templates={templates}
        selectedTemplateId={selectedTemplateId}
        flyerCopy={flyerCopy}
        propertyPhotos={propertyPhotos}
        agentHeadshot={agentHeadshot}
        flyerRef={flyerRef}
        onUpdateField={updateField}
        onUpdateFlyer={updateFlyerCopy}
      />
    </section>
  );
}

function FlyerPreview({
  brand,
  fields,
  templates,
  selectedTemplateId,
  flyerCopy,
  propertyPhotos,
  agentHeadshot,
  flyerRef,
  onSelectElement = () => {},
  selectedElement = "",
  selectedElements = [],
  onUpdateField = () => {},
  onUpdateFlyer = () => {},
  onUpdateFlyerLive = onUpdateFlyer,
  onReplacePhoto = () => {},
  onRemovePhoto = () => {},
  onHeadshotUpload = () => {},
  previewZoom = 100,
  showSafeGuides = true
}) {
  const template = templates.find((item) => item.id === selectedTemplateId) || templates[0] || {};
  const accent = flyerCopy.accentColor || template.accent || brand.primaryColor;
  const layout = flyerCopy.layout || template.style || "classic";
  const finish = flyerCopy.finish || "red-signature";
  const photoTreatment = flyerCopy.photoTreatment || "dramatic-overlay";
  const format = getCreativeFormat(flyerCopy.canvasFormat);
  const flyerLogoVariant = finish === "black-luxury" ? "dark" : "light";
  const studioInk = finish === "black-luxury" ? "#ffffff" : readableInkColor(flyerCopy.backgroundColor || "#ffffff");
  const studioMutedInk = studioInk === "#ffffff" ? "rgb(255 255 255 / 0.68)" : "#626a76";
  const headline = flyerCopy.headline || template.headline || fields.marketingType.toUpperCase();
  const badge = flyerCopy.badge || template.badge || fields.status || "Featured";
  const templateLabel = /business card/i.test(fields.marketingType || template.name || "")
    ? "AGENT CARD"
    : fields.marketingType || template.name || "Nex Realty Flyer";
  const heroPhoto = propertyPhotos[0];
  const supporting = propertyPhotos.slice(1, 4);
  const address = fields.propertyAddress || "123 Nex Realty Drive";
  const cityLine = [fields.city || "Your City", fields.state || "ST", fields.zip].filter(Boolean).join(", ");
  const price = money(fields.price) || "Price Upon Request";
  const openHouse = titleCaseDate(fields.openHouseDateTime);
  const headlineDrag = useRef(null);
  const resizeDrag = useRef(null);
  const selectedSet = new Set(selectedElements.length ? selectedElements : [selectedElement]);
  const qrCodeUrl = getQrCodeUrl(flyerCopy.qrUrl || flyerCopy.agentWebsite || "https://mynexrealty.com");

  function isSelected(elementId) {
    return selectedSet.has(elementId);
  }

  function startHeadlineDrag(event) {
    if (event.target.closest("[contenteditable='true']")) return;
    onSelectElement("headline", event);
    event.currentTarget.setPointerCapture?.(event.pointerId);
    headlineDrag.current = {
      pointerId: event.pointerId,
      startX: event.clientX,
      startY: event.clientY,
      offsetX: Number(flyerCopy.headlineOffsetX) || 0,
      offsetY: Number(flyerCopy.headlineOffsetY) || 0
    };
  }

  function moveHeadlineDrag(event) {
    if (!headlineDrag.current || headlineDrag.current.pointerId !== event.pointerId) return;
    const nextX = Math.round(headlineDrag.current.offsetX + event.clientX - headlineDrag.current.startX);
    const nextY = Math.round(headlineDrag.current.offsetY + event.clientY - headlineDrag.current.startY);
    onUpdateFlyerLive("headlineOffsetX", nextX);
    onUpdateFlyerLive("headlineOffsetY", nextY);
  }

  function endHeadlineDrag(event) {
    if (headlineDrag.current?.pointerId === event.pointerId) {
      headlineDrag.current = null;
    }
  }

  function startElementResize(event, elementId) {
    event.preventDefault();
    event.stopPropagation();
    onSelectElement(elementId, event);
    event.currentTarget.setPointerCapture?.(event.pointerId);
    resizeDrag.current = {
      pointerId: event.pointerId,
      elementId,
      startX: event.clientX,
      startY: event.clientY,
      headlineWidth: Number(flyerCopy.headlineWidth) || 360,
      fontScale: Number(flyerCopy.fontScale) || 100,
      heroHeight: Number(flyerCopy.heroHeight) || 274,
      layerScale: Number(flyerCopy[`${elementId}Scale`]) || 100,
      qrScale: Number(flyerCopy.qrScale) || 100
    };
  }

  function moveElementResize(event) {
    const drag = resizeDrag.current;
    if (!drag || drag.pointerId !== event.pointerId) return;
    const deltaX = event.clientX - drag.startX;
    const deltaY = event.clientY - drag.startY;
    if (drag.elementId === "headline") {
      onUpdateFlyerLive("headlineWidth", Math.round(clampStudioNumber(drag.headlineWidth + deltaX, 160, 720)));
      onUpdateFlyerLive("fontScale", Math.round(clampStudioNumber(drag.fontScale + deltaY / 2, 70, 170)));
      return;
    }
    if (drag.elementId === "media") {
      onUpdateFlyerLive("heroHeight", Math.round(clampStudioNumber(drag.heroHeight + deltaY, 140, 560)));
      return;
    }
    if (drag.elementId === "qr") {
      onUpdateFlyerLive("qrScale", Math.round(clampStudioNumber(drag.qrScale + (deltaX + deltaY) / 4, 70, 180)));
      return;
    }
    onUpdateFlyerLive(`${drag.elementId}Scale`, Math.round(clampStudioNumber(drag.layerScale + (deltaX + deltaY) / 4, 70, 180)));
  }

  function endElementResize(event) {
    if (resizeDrag.current?.pointerId === event.pointerId) {
      resizeDrag.current = null;
    }
  }

  if (format.id === "email-signature") {
    return (
      <div className="preview-shell email-signature-preview-shell">
        <div className="canvas-edit-hint">
          <Icon name="MousePointerClick" size={14} />
          <span>Click any signature text to edit. Click the headshot to replace it.</span>
        </div>
        <StudioEmailSignatureCanvas
          brand={brand}
          fields={fields}
          flyerCopy={flyerCopy}
          agentHeadshot={agentHeadshot}
          flyerRef={flyerRef}
          selectedElement={selectedElement}
          selectedElements={selectedElements}
          onSelectElement={onSelectElement}
          onUpdateField={onUpdateField}
          onUpdateFlyer={onUpdateFlyer}
          onHeadshotUpload={onHeadshotUpload}
          previewZoom={previewZoom}
        />
      </div>
    );
  }

  if (format.id === "business-card") {
    return (
      <div className="preview-shell business-card-preview-shell">
        <div className="canvas-edit-hint">
          <Icon name="MousePointerClick" size={14} />
          <span>Click text to edit. Switch sides to design the front and back.</span>
        </div>
        <div className="studio-card-side-tabs">
          {["front", "back"].map((side) => (
            <button key={side} className={(flyerCopy.businessCardSide || "front") === side ? "selected" : ""} onClick={() => onUpdateFlyer("businessCardSide", side)} type="button">
              {side === "front" ? "Front Side" : "Back Side"}
            </button>
          ))}
        </div>
        <StudioBusinessCardCanvas
          brand={brand}
          fields={fields}
          flyerCopy={flyerCopy}
          agentHeadshot={agentHeadshot}
          flyerRef={flyerRef}
          selectedElement={selectedElement}
          selectedElements={selectedElements}
          onSelectElement={onSelectElement}
          onUpdateField={onUpdateField}
          onUpdateFlyer={onUpdateFlyer}
          onUpdateFlyerLive={onUpdateFlyerLive}
          onHeadshotUpload={onHeadshotUpload}
          previewZoom={previewZoom}
          showSafeGuides={showSafeGuides}
        />
      </div>
    );
  }

  return (
    <div className="preview-shell">
      <div className="canvas-edit-hint">
        <Icon name="MousePointerClick" size={14} />
        <span>Click text to edit directly. Drag the headline block to reposition it.</span>
      </div>
      <div
        className={classNames("flyer-page studio-flyer", showSafeGuides && "show-safe-guides", `layout-${slugify(layout)}`, `finish-${slugify(finish)}`, `photo-${slugify(photoTreatment)}`, `format-${slugify(format.id)}`)}
        ref={flyerRef}
        style={{
          "--accent": accent,
          "--nex-red": brand.primaryColor,
          "--brand-gold": brand.gold,
          "--canvas-aspect": `${format.width} / ${format.height}`,
          "--headline-scale": `${(flyerCopy.fontScale || 100) / 100}`,
          "--headline-weight": flyerCopy.fontWeight || 900,
          "--headline-width": `${flyerCopy.headlineWidth || 360}px`,
          "--hero-height": `${flyerCopy.heroHeight || 274}px`,
          "--text-align": flyerCopy.textAlign || "left",
          "--studio-bg-color": flyerCopy.backgroundColor || "#ffffff",
          "--studio-bg-image": flyerCopy.backgroundImage ? `url("${flyerCopy.backgroundImage}")` : "none",
          "--studio-bg-opacity": `${(flyerCopy.backgroundOpacity || 0) / 100}`,
          "--studio-ink": studioInk,
          "--studio-muted-ink": studioMutedInk,
          zoom: `${previewZoom / 100}`
        }}
      >
        <header className="flyer-top">
          <div
            className={classNames("studio-logo-layer canvas-scalable-layer", isSelected("logo") && "selected-element")}
            style={layerScaleStyle(flyerCopy, "logo")}
            onClick={(event) => onSelectElement("logo", event)}
          >
            <Wordmark brand={brand} compact variant={flyerLogoVariant} />
          </div>
          <div className="flyer-template-label">
            <EditableCanvasText value={templateLabel} onCommit={(value) => onUpdateField("marketingType", value)} onSelect={() => onSelectElement("headline")} />
          </div>
        </header>

        <section
          className={classNames("flyer-hero", isSelected("media") && "selected-element")}
          onClick={(event) => onSelectElement("media", event)}
          onPointerMove={moveElementResize}
          onPointerUp={endElementResize}
          onPointerCancel={endElementResize}
        >
          <div
            className={classNames("flyer-headline draggable-headline", isSelected("headline") && "selected-element")}
            style={{ transform: `translate(${Number(flyerCopy.headlineOffsetX) || 0}px, ${Number(flyerCopy.headlineOffsetY) || 0}px)` }}
            onPointerDown={startHeadlineDrag}
            onPointerMove={moveHeadlineDrag}
            onPointerUp={endHeadlineDrag}
            onPointerCancel={endHeadlineDrag}
          >
            <EditableCanvasText value={badge} onCommit={(value) => onUpdateFlyer("badge", value)} onSelect={() => onSelectElement("headline")} />
            <EditableCanvasText as="h2" value={headline} onCommit={(value) => onUpdateFlyer("headline", value)} onSelect={() => onSelectElement("headline")} />
            <ResizeHandles active={isSelected("headline")} elementId="headline" onStart={startElementResize} />
          </div>
          {heroPhoto ? (
            <img src={heroPhoto.dataUrl} alt={heroPhoto.name} crossOrigin={String(heroPhoto.dataUrl || "").startsWith("http") ? "anonymous" : undefined} style={{ objectFit: (flyerCopy.heroImageFit || "Cover").toLowerCase(), objectPosition: flyerCopy.heroImagePosition || "center" }} />
          ) : (
            <div className="photo-placeholder">
              <Icon name="Image" size={38} />
              <span>Upload a property photo</span>
            </div>
          )}
          <div className="canvas-image-toolbar">
            <label>
              <Icon name="ImagePlus" size={13} />
              <span>{heroPhoto ? "Replace photo" : "Add photo"}</span>
              <input type="file" accept="image/*" onChange={(event) => onReplacePhoto(event, 0)} />
            </label>
            {heroPhoto && (
              <button type="button" onClick={(event) => { event.stopPropagation(); onRemovePhoto(0); }}>
                <Icon name="Trash2" size={13} />
                <span>Remove</span>
              </button>
            )}
          </div>
          <ResizeHandles active={isSelected("media")} elementId="media" onStart={startElementResize} />
        </section>

        <section className="flyer-photo-strip">
          {[0, 1, 2].map((slot) => {
            const photoIndex = slot + 1;
            const photo = supporting[slot];
            return (
              <div
                key={slot}
                className={classNames("mini-photo-slot", isSelected(`photo-${photoIndex}`) && "selected-element")}
                onClick={(event) => onSelectElement(`photo-${photoIndex}`, event)}
              >
                {photo ? (
                  <img src={photo.dataUrl} alt={photo.name} crossOrigin={String(photo.dataUrl || "").startsWith("http") ? "anonymous" : undefined} />
                ) : (
                  <div className="mini-placeholder">
                    <Icon name="Image" size={18} />
                    <span>Add photo</span>
                  </div>
                )}
                <div className="mini-photo-actions">
                  <label>
                    <Icon name="ImagePlus" size={12} />
                    <span>{photo ? "Replace" : "Add"}</span>
                    <input type="file" accept="image/*" onChange={(event) => onReplacePhoto(event, photoIndex)} />
                  </label>
                  {photo && (
                    <button type="button" onClick={(event) => { event.stopPropagation(); onRemovePhoto(photoIndex); }}>
                      <Icon name="Trash2" size={12} />
                      <span>Remove</span>
                    </button>
                  )}
                </div>
              </div>
            );
          })}
        </section>

        <section className="flyer-details">
          <div
            className={classNames("address-block canvas-scalable-layer", isSelected("address") && "selected-element")}
            style={layerScaleStyle(flyerCopy, "address")}
            onClick={(event) => onSelectElement("address", event)}
            onPointerMove={moveElementResize}
            onPointerUp={endElementResize}
            onPointerCancel={endElementResize}
          >
            <Icon name="MapPin" size={21} />
            <div>
              <EditableCanvasText as="strong" value={address} onCommit={(value) => onUpdateField("propertyAddress", value)} onSelect={() => onSelectElement("address")} />
              <EditableCanvasText value={cityLine} onCommit={(value) => onUpdateField("city", value)} onSelect={() => onSelectElement("address")} />
            </div>
            <ResizeHandles active={isSelected("address")} elementId="address" onStart={startElementResize} />
          </div>

          {flyerCopy.showPrice !== false && (
            <div
              className={classNames("price-block canvas-scalable-layer", isSelected("price") && "selected-element")}
              style={layerScaleStyle(flyerCopy, "price")}
              onClick={(event) => onSelectElement("price", event)}
              onPointerMove={moveElementResize}
              onPointerUp={endElementResize}
              onPointerCancel={endElementResize}
            >
              <EditableCanvasText value={fields.status || "For sale"} onCommit={(value) => onUpdateField("status", value)} onSelect={() => onSelectElement("price")} />
              <EditableCanvasText as="strong" value={price} onCommit={(value) => onUpdateField("price", value)} onSelect={() => onSelectElement("price")} />
              <ResizeHandles active={isSelected("price")} elementId="price" onStart={startElementResize} />
            </div>
          )}
        </section>

        {flyerCopy.showStats !== false && (
          <section
            className={classNames("stats-strip canvas-scalable-layer", isSelected("stats") && "selected-element")}
            style={layerScaleStyle(flyerCopy, "stats")}
            onClick={(event) => onSelectElement("stats", event)}
            onPointerMove={moveElementResize}
            onPointerUp={endElementResize}
            onPointerCancel={endElementResize}
          >
            <FeatureStat icon="BedDouble" label="Beds" value={fields.bedrooms || "-"} onCommit={(value) => onUpdateField("bedrooms", value)} />
            <FeatureStat icon="Bath" label="Baths" value={fields.bathrooms || "-"} onCommit={(value) => onUpdateField("bathrooms", value)} />
            <FeatureStat icon="Car" label="Garage" value={fields.garageSpaces || "-"} onCommit={(value) => onUpdateField("garageSpaces", value)} />
            <FeatureStat icon="Ruler" label="Sq Ft" value={fields.squareFootage || "-"} onCommit={(value) => onUpdateField("squareFootage", value)} />
            <ResizeHandles active={isSelected("stats")} elementId="stats" onStart={startElementResize} />
          </section>
        )}

        {(openHouse || fields.rentalAvailableDate) && (
          <section className="event-band">
            <Icon name="CalendarDays" size={18} />
            <span>
              {openHouse ? `Open House: ${openHouse}` : `Available: ${fields.rentalAvailableDate}`}
            </span>
          </section>
        )}

        <section
          className={classNames("flyer-copy-block canvas-scalable-layer", isSelected("body") && "selected-element")}
          style={layerScaleStyle(flyerCopy, "body")}
          onClick={(event) => onSelectElement("body", event)}
          onPointerMove={moveElementResize}
          onPointerUp={endElementResize}
          onPointerCancel={endElementResize}
        >
          <EditableCanvasText as="p" value={flyerCopy.body || "Premium Nex Realty marketing copy will appear here after generation."} multiline onCommit={(value) => onUpdateFlyer("body", value)} onSelect={() => onSelectElement("body")} />
          <EditableCanvasText as="strong" value={flyerCopy.cta || fields.cta || "Schedule Your Tour Today"} onCommit={(value) => onUpdateFlyer("cta", value)} onSelect={() => onSelectElement("body")} />
          <ResizeHandles active={isSelected("body")} elementId="body" onStart={startElementResize} />
        </section>

        {flyerCopy.showQr && (
          <section
            className={classNames("qr-design-block canvas-scalable-layer", isSelected("qr") && "selected-element")}
            style={layerScaleStyle(flyerCopy, "qr")}
            onClick={(event) => onSelectElement("qr", event)}
            onPointerMove={moveElementResize}
            onPointerUp={endElementResize}
            onPointerCancel={endElementResize}
          >
            <div>
              <img className="qr-generated-image" src={qrCodeUrl} alt="Generated QR code" crossOrigin="anonymous" />
            </div>
            <span>{flyerCopy.qrUrl || flyerCopy.agentWebsite || "Scan for more info"}</span>
            <ResizeHandles active={isSelected("qr")} elementId="qr" onStart={startElementResize} />
          </section>
        )}

        <footer className="flyer-footer">
          {flyerCopy.showAgent !== false && (
            <div
              className={classNames("agent-block canvas-scalable-layer", isSelected("agent") && "selected-element")}
              style={layerScaleStyle(flyerCopy, "agent")}
              onClick={(event) => onSelectElement("agent", event)}
              onPointerMove={moveElementResize}
              onPointerUp={endElementResize}
              onPointerCancel={endElementResize}
            >
              {agentHeadshot ? (
                <img src={agentHeadshot.dataUrl} alt={fields.agentName || "Agent headshot"} />
              ) : (
                <div className="agent-placeholder">
                  <Icon name="User" size={22} />
                </div>
              )}
              <label className="agent-headshot-replace" title="Replace headshot">
                <Icon name="ImagePlus" size={12} />
                <input type="file" accept="image/*" onChange={onHeadshotUpload} />
              </label>
              <div>
                <EditableCanvasText as="strong" value={fields.agentName || "Nex Realty Agent"} onCommit={(value) => onUpdateField("agentName", value)} onSelect={() => onSelectElement("agent")} />
                <EditableCanvasText value={[fields.agentPhone, fields.agentEmail].filter(Boolean).join(" | ") || "agent@nexrealty.com"} onCommit={(value) => onUpdateField("agentPhone", value)} onSelect={() => onSelectElement("agent")} />
                {(flyerCopy.agentWebsite || flyerCopy.agentLicense) && <EditableCanvasText as="em" value={[flyerCopy.agentWebsite, flyerCopy.agentLicense].filter(Boolean).join(" | ")} onCommit={(value) => onUpdateFlyer("agentWebsite", value)} onSelect={() => onSelectElement("agent")} />}
              </div>
              <ResizeHandles active={isSelected("agent")} elementId="agent" onStart={startElementResize} />
            </div>
          )}
          {flyerCopy.showDisclaimer !== false && (
            <EditableCanvasText
              as="p"
              className={classNames("canvas-scalable-layer", isSelected("disclaimer") && "selected-element")}
              value={flyerCopy.footer || brand.defaultDisclaimer}
              multiline
              onCommit={(value) => onUpdateFlyer("footer", value)}
              onSelect={() => onSelectElement("disclaimer")}
              style={layerScaleStyle(flyerCopy, "disclaimer")}
            />
          )}
        </footer>
      </div>
    </div>
  );
}

function StudioEmailSignatureCanvas({ brand, fields, flyerCopy, agentHeadshot, flyerRef, selectedElement, selectedElements = [], onSelectElement, onUpdateField = () => {}, onUpdateFlyer = () => {}, onHeadshotUpload = () => {}, previewZoom = 100 }) {
  const agentName = fields.agentName || "Nex Realty Agent";
  const title = flyerCopy.agentTitle || "Real Estate Professional";
  const phone = fields.agentPhone || "555-010-2026";
  const email = fields.agentEmail || "agent@nexrealty.com";
  const website = flyerCopy.agentWebsite || "mynexrealty.com";
  const license = flyerCopy.agentLicense || "Advertised by Nex Realty";
  const selectedSet = new Set(selectedElements.length ? selectedElements : [selectedElement]);
  const isSelected = (elementId) => selectedSet.has(elementId);
  const initials = agentName
    .split(" ")
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0])
    .join("")
    .toUpperCase();

  return (
    <article
      className="studio-email-signature-canvas"
      ref={flyerRef}
      style={{
        "--accent": flyerCopy.accentColor || brand.primaryColor,
        "--card-gold": brand.gold,
        zoom: `${previewZoom / 100}`
      }}
    >
      <div
        className={classNames("email-signature-photo", isSelected("media") && "selected-element")}
        onClick={(event) => onSelectElement("media", event)}
      >
        {agentHeadshot ? <img src={agentHeadshot.dataUrl} alt={agentName} crossOrigin={String(agentHeadshot.dataUrl || "").startsWith("http") ? "anonymous" : undefined} /> : <strong>{initials || "NX"}</strong>}
        <label title="Replace headshot">
          <Icon name="ImagePlus" size={13} />
          <span>Replace</span>
          <input type="file" accept="image/*" onChange={onHeadshotUpload} />
        </label>
      </div>

      <div
        className={classNames("email-signature-main", isSelected("agent") && "selected-element")}
        onClick={(event) => onSelectElement("agent", event)}
      >
        <Wordmark brand={brand} compact variant="light" />
        <EditableCanvasText as="h2" value={agentName} onCommit={(value) => onUpdateField("agentName", value)} onSelect={() => onSelectElement("agent")} />
        <EditableCanvasText as="p" value={title} onCommit={(value) => onUpdateFlyer("agentTitle", value)} onSelect={() => onSelectElement("agent")} />
        <EditableCanvasText as="small" value={license} onCommit={(value) => onUpdateFlyer("agentLicense", value)} onSelect={() => onSelectElement("disclaimer")} />
      </div>

      <div
        className={classNames("email-signature-contact", isSelected("body") && "selected-element")}
        onClick={(event) => onSelectElement("body", event)}
      >
        <span><Icon name="Phone" size={14} /><EditableCanvasText value={phone} onCommit={(value) => onUpdateField("agentPhone", value)} onSelect={() => onSelectElement("body")} /></span>
        <span><Icon name="Mail" size={14} /><EditableCanvasText value={email} onCommit={(value) => onUpdateField("agentEmail", value)} onSelect={() => onSelectElement("body")} /></span>
        <span><Icon name="Globe" size={14} /><EditableCanvasText value={website} onCommit={(value) => onUpdateFlyer("agentWebsite", value)} onSelect={() => onSelectElement("body")} /></span>
      </div>
    </article>
  );
}

function StudioBusinessCardCanvas({ brand, fields, flyerCopy, agentHeadshot, flyerRef, selectedElement, selectedElements = [], onSelectElement, onUpdateField = () => {}, onUpdateFlyer = () => {}, onUpdateFlyerLive = onUpdateFlyer, onHeadshotUpload = () => {}, previewZoom = 100, showSafeGuides = true }) {
  const agentName = fields.agentName || "Nex Realty Agent";
  const title = flyerCopy.agentTitle || "Real Estate Professional";
  const phone = fields.agentPhone || "555-010-2026";
  const email = fields.agentEmail || "agent@nexrealty.com";
  const website = flyerCopy.agentWebsite || "nexrealty.com";
  const social = flyerCopy.agentSocial || "@nexrealty";
  const license = flyerCopy.agentLicense || "Advertised by Nex Realty";
  const initials = agentName
    .split(" ")
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0])
    .join("")
    .toUpperCase();
  const side = flyerCopy.businessCardSide || "front";
  const selectedSet = new Set(selectedElements.length ? selectedElements : [selectedElement]);
  const qrCodeUrl = getQrCodeUrl(flyerCopy.qrUrl || website);
  const isSelected = (elementId) => selectedSet.has(elementId);
  const cardDrag = useRef(null);
  const businessCardBackground = flyerCopy.businessCardBackgroundColor || "#ffffff";
  const cardInk = readableInkColor(businessCardBackground) === "#ffffff" ? "#ffffff" : "#111318";
  const cardLogoVariant = cardInk === "#ffffff" ? "dark" : "light";

  function cardLayerStyle(elementId) {
    return layerScaleStyle(flyerCopy, elementId);
  }

  function startCardLayerDrag(event, elementId) {
    if (event.target.closest("[contenteditable='true'], input, label, button")) return;
    onSelectElement(elementId, event);
    event.currentTarget.setPointerCapture?.(event.pointerId);
    cardDrag.current = {
      pointerId: event.pointerId,
      elementId,
      startX: event.clientX,
      startY: event.clientY,
      offsetX: Number(flyerCopy[`${elementId}OffsetX`]) || 0,
      offsetY: Number(flyerCopy[`${elementId}OffsetY`]) || 0
    };
  }

  function moveCardLayerDrag(event) {
    const drag = cardDrag.current;
    if (!drag || drag.pointerId !== event.pointerId) return;
    onUpdateFlyerLive(`${drag.elementId}OffsetX`, Math.round(drag.offsetX + event.clientX - drag.startX));
    onUpdateFlyerLive(`${drag.elementId}OffsetY`, Math.round(drag.offsetY + event.clientY - drag.startY));
  }

  function endCardLayerDrag(event) {
    if (cardDrag.current?.pointerId === event.pointerId) {
      cardDrag.current = null;
    }
  }

  if (side === "back") {
    return (
      <article
        className={classNames("studio-business-card-canvas studio-business-card-back", showSafeGuides && "show-safe-guides")}
        ref={flyerRef}
        style={{
          "--accent": flyerCopy.accentColor || brand.primaryColor,
          "--card-gold": brand.gold,
          "--headline-scale": `${(flyerCopy.fontScale || 100) / 100}`,
          "--studio-bg-color": businessCardBackground,
          "--studio-bg-image": flyerCopy.backgroundImage ? `url("${flyerCopy.backgroundImage}")` : "none",
          "--studio-bg-opacity": `${(flyerCopy.backgroundOpacity || 0) / 100}`,
          "--studio-card-ink": cardInk,
          zoom: `${previewZoom / 100}`
        }}
      >
        <div
          className={classNames("studio-card-back-brand studio-card-layer canvas-scalable-layer", isSelected("logo") && "selected-element")}
          style={cardLayerStyle("logo")}
          onPointerDown={(event) => startCardLayerDrag(event, "logo")}
          onPointerMove={moveCardLayerDrag}
          onPointerUp={endCardLayerDrag}
          onPointerCancel={endCardLayerDrag}
        >
          <Wordmark brand={brand} compact variant={cardLogoVariant} />
          <EditableCanvasText
            as="strong"
            value={flyerCopy.cta || "Modern brokerage. Bold marketing. Smarter moves."}
            onCommit={(value) => onUpdateFlyer("cta", value)}
            onSelect={() => onSelectElement("body")}
          />
        </div>
        <section className="studio-card-back-grid">
          <div
            className={classNames("studio-card-qr-block studio-card-layer canvas-scalable-layer", isSelected("qr") && "selected-element")}
            style={cardLayerStyle("qr")}
            onClick={(event) => onSelectElement("qr", event)}
            onPointerDown={(event) => startCardLayerDrag(event, "qr")}
            onPointerMove={moveCardLayerDrag}
            onPointerUp={endCardLayerDrag}
            onPointerCancel={endCardLayerDrag}
          >
            <img className="qr-generated-image" src={qrCodeUrl} alt="Generated QR code" crossOrigin="anonymous" />
            <span>QR / Lead Link</span>
          </div>
          <div
            className={classNames("studio-card-back-copy studio-card-layer canvas-scalable-layer", isSelected("body") && "selected-element")}
            style={cardLayerStyle("body")}
            onPointerDown={(event) => startCardLayerDrag(event, "body")}
            onPointerMove={moveCardLayerDrag}
            onPointerUp={endCardLayerDrag}
            onPointerCancel={endCardLayerDrag}
          >
            <EditableCanvasText as="h2" value={website} onCommit={(value) => onUpdateFlyer("agentWebsite", value)} onSelect={() => onSelectElement("body")} />
            <EditableCanvasText value={social} onCommit={(value) => onUpdateFlyer("agentSocial", value)} onSelect={() => onSelectElement("body")} />
            <EditableCanvasText as="p" value={license} multiline onCommit={(value) => onUpdateFlyer("agentLicense", value)} onSelect={() => onSelectElement("disclaimer")} />
          </div>
        </section>
        <div
          className={classNames("studio-card-layer canvas-scalable-layer", isSelected("disclaimer") && "selected-element")}
          style={cardLayerStyle("disclaimer")}
          onPointerDown={(event) => startCardLayerDrag(event, "disclaimer")}
          onPointerMove={moveCardLayerDrag}
          onPointerUp={endCardLayerDrag}
          onPointerCancel={endCardLayerDrag}
        >
          <EditableCanvasText
            className="studio-card-back-footer"
            value={flyerCopy.footer || brand.defaultDisclaimer}
            multiline
            onCommit={(value) => onUpdateFlyer("footer", value)}
            onSelect={() => onSelectElement("disclaimer")}
          />
        </div>
      </article>
    );
  }

  return (
    <article
      className={classNames("studio-business-card-canvas", showSafeGuides && "show-safe-guides")}
      ref={flyerRef}
      style={{
        "--accent": flyerCopy.accentColor || brand.primaryColor,
        "--card-gold": brand.gold,
        "--headline-scale": `${(flyerCopy.fontScale || 100) / 100}`,
        "--studio-bg-color": businessCardBackground,
        "--studio-bg-image": flyerCopy.backgroundImage ? `url("${flyerCopy.backgroundImage}")` : "none",
        "--studio-bg-opacity": `${(flyerCopy.backgroundOpacity || 0) / 100}`,
        "--studio-card-ink": cardInk,
        zoom: `${previewZoom / 100}`
      }}
    >
      <div
        className={classNames("studio-card-brand studio-card-layer canvas-scalable-layer", isSelected("logo") && "selected-element")}
        style={cardLayerStyle("logo")}
        onPointerDown={(event) => startCardLayerDrag(event, "logo")}
        onPointerMove={moveCardLayerDrag}
        onPointerUp={endCardLayerDrag}
        onPointerCancel={endCardLayerDrag}
      >
        <Wordmark brand={brand} compact variant={cardLogoVariant} />
        <EditableCanvasText value={license} multiline onCommit={(value) => onUpdateFlyer("agentLicense", value)} onSelect={() => onSelectElement("disclaimer")} />
      </div>

      <section
        className={classNames("studio-card-main studio-card-layer canvas-scalable-layer", isSelected("agent") && "selected-element")}
        style={cardLayerStyle("agent")}
        onClick={(event) => onSelectElement("agent", event)}
        onPointerDown={(event) => startCardLayerDrag(event, "agent")}
        onPointerMove={moveCardLayerDrag}
        onPointerUp={endCardLayerDrag}
        onPointerCancel={endCardLayerDrag}
      >
        <div className="studio-card-agent-copy">
          <EditableCanvasText as="p" value={title} onCommit={(value) => onUpdateFlyer("agentTitle", value)} onSelect={() => onSelectElement("agent")} />
          <EditableCanvasText as="h2" value={agentName} onCommit={(value) => onUpdateField("agentName", value)} onSelect={() => onSelectElement("agent")} />
          <EditableCanvasText as="em" value={flyerCopy.cta || "Modern brokerage. Bold marketing. Smarter moves."} multiline onCommit={(value) => onUpdateFlyer("cta", value)} onSelect={() => onSelectElement("body")} />
        </div>
        <div className="studio-card-headshot">
          {agentHeadshot ? <img src={agentHeadshot.dataUrl} alt={agentName} crossOrigin={String(agentHeadshot.dataUrl || "").startsWith("http") ? "anonymous" : undefined} /> : <strong>{initials || "NX"}</strong>}
          <label className="canvas-headshot-button" title="Replace headshot">
            <Icon name="ImagePlus" size={13} />
            <input type="file" accept="image/*" onChange={onHeadshotUpload} />
          </label>
        </div>
      </section>

      <section
        className={classNames("studio-card-contact studio-card-layer canvas-scalable-layer", isSelected("body") && "selected-element")}
        style={cardLayerStyle("body")}
        onClick={(event) => onSelectElement("body", event)}
        onPointerDown={(event) => startCardLayerDrag(event, "body")}
        onPointerMove={moveCardLayerDrag}
        onPointerUp={endCardLayerDrag}
        onPointerCancel={endCardLayerDrag}
      >
        <span><Icon name="Phone" size={13} /><EditableCanvasText value={phone} onCommit={(value) => onUpdateField("agentPhone", value)} onSelect={() => onSelectElement("body")} /></span>
        <span><Icon name="Mail" size={13} /><EditableCanvasText value={email} onCommit={(value) => onUpdateField("agentEmail", value)} onSelect={() => onSelectElement("body")} /></span>
      </section>
    </article>
  );
}

function QuickVideoBuilder({ brand, fields, flyerCopy, setFlyerCopy, propertyPhotos, onAddStockPhoto, onGenerate, onDownloadVideo }) {
  const orientation = getVideoOrientation(flyerCopy.videoOrientation || "vertical");
  const heroPhoto = propertyPhotos[0];

  function update(name, value) {
    setFlyerCopy((current) => ({ ...current, [name]: value }));
  }

  return (
    <section className="video-builder-grid">
      <div className="panel builder-controls studio-controls">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Quick Video</p>
            <h3>Reels and horizontal videos</h3>
          </div>
        </div>

        <section className="studio-block">
          <p className="studio-label">Video format</p>
          <ChoiceGrid label="Orientation" value={flyerCopy.videoOrientation || "vertical"} options={videoOrientationOptions} onChange={(value) => update("videoOrientation", value)} />
          <div className="format-note">
            <Icon name="Clapperboard" size={15} />
            <span>{orientation.name}: {orientation.label}</span>
          </div>
        </section>

        <section className="studio-block">
          <p className="studio-label">Video copy</p>
          <Field label="Headline" value={flyerCopy.headline} onChange={(value) => update("headline", value)} />
          <Field label="Badge" value={flyerCopy.badge} onChange={(value) => update("badge", value)} />
          <Field label="CTA" value={flyerCopy.cta} onChange={(value) => update("cta", value)} />
          <Field label="Short script / caption" value={flyerCopy.body} onChange={(value) => update("body", value)} as="textarea" />
        </section>

        <section className="studio-block">
          <p className="studio-label">Stock visuals</p>
          <StockPhotoTray onAddStockPhoto={onAddStockPhoto} />
        </section>

        <div className="button-grid video-buttons">
          <button className="btn secondary" onClick={onGenerate}>
            <Icon name="RefreshCw" />
            <span>Regenerate Copy</span>
          </button>
          <button className="btn primary" onClick={() => onDownloadVideo("vertical")}>
            <Icon name="Smartphone" />
            <span>Vertical Reel</span>
          </button>
          <button className="btn dark" onClick={() => onDownloadVideo("horizontal")}>
            <Icon name="MonitorPlay" />
            <span>Horizontal Video</span>
          </button>
        </div>
      </div>

      <div className="video-preview-shell">
        <article
          className={classNames("video-preview-frame", `orientation-${orientation.id}`)}
          style={{
            "--video-bg": heroPhoto ? `url("${heroPhoto.dataUrl}")` : `url("${stockPhotoPresets[0]?.dataUrl}")`,
            "--card-red": brand.primaryColor,
            "--card-gold": brand.gold
          }}
        >
          <div className="video-preview-overlay">
            <Wordmark brand={brand} compact variant="dark" />
            <span>{flyerCopy.badge || fields.status || "Featured"}</span>
            <h3>{flyerCopy.headline || fields.marketingType || "Nex Realty"}</h3>
            <p>{fields.propertyAddress || flyerCopy.body || "Quick branded Nex video preview"}</p>
            <strong>{flyerCopy.cta || fields.cta || "Schedule Your Tour Today"}</strong>
          </div>
        </article>
      </div>
    </section>
  );
}

function BusinessCardBuilder({
  brand,
  fields,
  agentHeadshot,
  setAgentHeadshot,
  businessCardCopy,
  setBusinessCardCopy,
  businessCardFrontRef,
  businessCardBackRef,
  onDownloadFrontPdf,
  onDownloadBackPdf,
  onDownloadFrontPng,
  onDownloadBackPng,
  onPrint
}) {
  async function onBusinessHeadshotChange(event) {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    setAgentHeadshot(await fileToDataUrl(file));
  }

  function useAgentInfo() {
    setBusinessCardCopy((current) => ({
      ...current,
      displayName: current.displayName || fields.agentName,
      email: current.email || fields.agentEmail,
      phone: current.phone || fields.agentPhone
    }));
  }

  return (
    <section className="business-card-layout">
      <div className="panel builder-controls business-card-controls">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Business Card</p>
            <h3>Agent print design</h3>
          </div>
          <button className="btn secondary small-btn" onClick={useAgentInfo}>
            <Icon name="UserRoundCheck" />
            <span>Use Agent Info</span>
          </button>
        </div>

        <Field label="Card style" value={businessCardCopy.style} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, style: value }))} as="select" options={businessCardStyles} />
        <Field label="Display name" value={businessCardCopy.displayName} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, displayName: value }))} placeholder={fields.agentName || "Avery Morgan"} />
        <Field label="Card email" value={businessCardCopy.email} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, email: value }))} type="email" placeholder={fields.agentEmail || "agent@nexrealty.com"} />
        <Field label="Card phone" value={businessCardCopy.phone} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, phone: value }))} placeholder={fields.agentPhone || "555-010-2026"} />
        <Field label="Website" value={businessCardCopy.website} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, website: value }))} />
        <Field label="Social account" value={businessCardCopy.social} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, social: value }))} placeholder="@nexrealty" />
        <Field label="Agent title" value={businessCardCopy.title} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, title: value }))} />
        <Field label="License / office line" value={businessCardCopy.licenseLine} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, licenseLine: value }))} />
        <Field label="Card tagline" value={businessCardCopy.tagline} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, tagline: value }))} />

        <label className="business-headshot-upload">
          {agentHeadshot ? (
            <img src={agentHeadshot.dataUrl} alt="Selected headshot" />
          ) : (
            <span>
              <Icon name="ImagePlus" size={24} />
            </span>
          )}
          <strong>Upload card headshot</strong>
          <em>Use a clean square or portrait photo. Then adjust crop below.</em>
          <input type="file" accept="image/*" onChange={onBusinessHeadshotChange} />
        </label>

        <div className="card-control-group">
          <p>Headshot</p>
          <Field label="Shape" value={businessCardCopy.headshotShape} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, headshotShape: value }))} as="select" options={headshotShapes} />
          <Field label="Fit" value={businessCardCopy.headshotFit} onChange={(value) => setBusinessCardCopy((current) => ({ ...current, headshotFit: value }))} as="select" options={headshotFitOptions} />
          <RangeField label="Zoom" value={businessCardCopy.headshotZoom} min={80} max={180} suffix="%" onChange={(value) => setBusinessCardCopy((current) => ({ ...current, headshotZoom: value }))} />
          <RangeField label="Horizontal" value={businessCardCopy.headshotX} min={-40} max={40} suffix="%" onChange={(value) => setBusinessCardCopy((current) => ({ ...current, headshotX: value }))} />
          <RangeField label="Vertical" value={businessCardCopy.headshotY} min={-40} max={40} suffix="%" onChange={(value) => setBusinessCardCopy((current) => ({ ...current, headshotY: value }))} />
        </div>

        <div className="print-note">
          Export the front and back as separate files, then upload both sides when ordering cards.
        </div>

        <div className="business-card-buttons">
          <button className="btn primary" onClick={onDownloadFrontPdf}>
            <Icon name="Download" />
            <span>Front PDF</span>
          </button>
          <button className="btn primary" onClick={onDownloadBackPdf}>
            <Icon name="Download" />
            <span>Back PDF</span>
          </button>
          <button className="btn dark" onClick={onDownloadFrontPng}>
            <Icon name="ImageDown" />
            <span>Front PNG</span>
          </button>
          <button className="btn dark" onClick={onDownloadBackPng}>
            <Icon name="ImageDown" />
            <span>Back PNG</span>
          </button>
          <button className="btn secondary" onClick={onPrint}>
            <Icon name="ExternalLink" />
            <span>VistaPrint</span>
          </button>
        </div>
      </div>

      <BusinessCardPreview
        brand={brand}
        fields={fields}
        agentHeadshot={agentHeadshot}
        businessCardCopy={businessCardCopy}
        businessCardFrontRef={businessCardFrontRef}
        businessCardBackRef={businessCardBackRef}
      />
    </section>
  );
}

function BusinessCardPreview({ brand, fields, agentHeadshot, businessCardCopy, businessCardFrontRef, businessCardBackRef }) {
  const agentName = businessCardCopy.displayName || fields.agentName || "Nex Realty Agent";
  const phone = businessCardCopy.phone || fields.agentPhone || "555-010-2026";
  const email = businessCardCopy.email || fields.agentEmail || "agent@nexrealty.com";
  const website = businessCardCopy.website || "nexrealty.com";
  const social = businessCardCopy.social || "@nexrealty";
  const styleClass = `style-${(businessCardCopy.style || "Signature Red").toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
  const frontLogoVariant = businessCardCopy.style === "Executive Black" ? "dark" : "light";
  const backLogoVariant = businessCardCopy.style === "Executive Black" ? "dark" : "light";
  const headshotStyle = {
    objectFit: (businessCardCopy.headshotFit || "Cover").toLowerCase(),
    transform: `translate(${businessCardCopy.headshotX || 0}%, ${businessCardCopy.headshotY || 0}%) scale(${(businessCardCopy.headshotZoom || 100) / 100})`
  };
  const initials = agentName
    .split(" ")
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0])
    .join("")
    .toUpperCase();

  return (
    <div className="business-preview-shell">
      <div className="business-card-proof">
        <div>
          <p className="proof-label">Front</p>
          <article className={classNames("print-card card-front immersive-card", styleClass)} ref={businessCardFrontRef} style={{ "--card-red": brand.primaryColor, "--card-gold": brand.gold }}>
            <div className="print-safe-area">
              <header className="card-header-line">
                <Wordmark brand={brand} compact variant={frontLogoVariant} />
                <span>{businessCardCopy.licenseLine || "Advertised by Nex Realty"}</span>
              </header>

              <section className="card-identity-row">
                <div className="card-name-block">
                  <p>{businessCardCopy.title || "Real Estate Professional"}</p>
                  <h3>{agentName}</h3>
                  <em>{businessCardCopy.tagline || "Modern brokerage. Bold marketing. Smarter moves."}</em>
                </div>
                <div className={classNames("card-headshot", `shape-${(businessCardCopy.headshotShape || "Square").toLowerCase()}`)}>
                  {agentHeadshot ? <img src={agentHeadshot.dataUrl} alt={agentName} style={headshotStyle} /> : <strong>{initials || "NX"}</strong>}
                </div>
              </section>

              <section className="card-contact-grid">
                <BusinessContact icon="Phone" label="Call" value={phone} />
                <BusinessContact icon="Mail" label="Email" value={email} />
                <BusinessContact icon="Globe" label="Web" value={website} />
                <BusinessContact icon="AtSign" label="Social" value={social} />
              </section>
            </div>
          </article>
        </div>

        <div>
          <p className="proof-label">Back</p>
          <article className={classNames("print-card card-back immersive-card", styleClass)} ref={businessCardBackRef} style={{ "--card-red": brand.primaryColor, "--card-gold": brand.gold }}>
            <div className="print-safe-area back-safe-area">
              <Wordmark brand={brand} compact variant={backLogoVariant} />
              <div className="back-message">
                <h3>{businessCardCopy.tagline || "Modern brokerage. Bold marketing. Smarter moves."}</h3>
                <p>{businessCardCopy.title || "Real Estate Professional"} | {agentName}</p>
              </div>
              <div className="back-footer">
                <div className="qr-card">
                  <Icon name="QrCode" size={38} />
                  <span>{website}<small>{social}</small></span>
                </div>
                <p>Equal Housing Opportunity. Information deemed reliable but not guaranteed.</p>
              </div>
            </div>
          </article>
        </div>
      </div>
    </div>
  );
}

function BusinessContact({ icon, label, value }) {
  return (
    <div>
      <Icon name={icon} size={15} />
      <p>{label}</p>
      <span>{value}</span>
    </div>
  );
}

function FeatureStat({ icon, label, value, onCommit }) {
  return (
    <div>
      <Icon name={icon} size={21} />
      {onCommit ? (
        <EditableCanvasText as="strong" value={value} onCommit={onCommit} />
      ) : (
        <strong>{value}</strong>
      )}
      <span>{label}</span>
    </div>
  );
}

function SavedProjects({ projects, loadProject, duplicateProject, deleteProject, brand }) {
  return (
    <section className="panel saved-projects-panel">
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Saved projects</p>
          <h3>Marketing project library</h3>
        </div>
      </div>
      {projects.length ? (
        <div className="project-grid">
          {projects.map((project) => (
            <article className="project-card" key={project.id}>
              <ProjectThumbnail project={project} brand={brand} />
              <p className="eyebrow">{project.fields && project.fields.marketingType}</p>
              <h4>{project.title}</h4>
              <p>{project.output ? project.output.primary : "Saved project"}</p>
              <div className="project-card-foot">
                <span>Edited {new Date(project.updatedAt || project.createdAt).toLocaleDateString()}</span>
                <button className="btn secondary small-btn" onClick={() => loadProject(project)}>
                  <Icon name="FolderOpen" />
                  <span>Open</span>
                </button>
                <button className="btn secondary small-btn" onClick={() => duplicateProject(project)}>
                  <Icon name="CopyPlus" />
                  <span>Duplicate</span>
                </button>
                <button className="btn danger-soft small-btn" onClick={() => deleteProject(project.id)}>
                  <Icon name="Trash2" />
                  <span>Delete</span>
                </button>
              </div>
            </article>
          ))}
        </div>
      ) : (
        <EmptyState icon="FolderOpen" title="No saved projects yet" body="Save a generated campaign or flyer to see it here." />
      )}
    </section>
  );
}

function BrandSettings({ brand, setBrand, saveBrand, role, allowedUsers, setAllowedUsers, setAgentDirectory, setToast }) {
  async function updateLogo(event, key) {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    const upload = await fileToDataUrl(file);
    setBrand((current) => ({ ...current, [key]: upload.dataUrl }));
  }

  const disabled = !isAdminRole(role);

  return (
    <div className="settings-stack">
      <section className="settings-grid">
        <div className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Admin</p>
              <h3>Brand settings</h3>
            </div>
          </div>
          {disabled && <div className="suggestion-strip">Admin access is required to edit brokerage-wide defaults.</div>}

          <div className={classNames("settings-form", disabled && "muted")}>
            <Field label="Company name" value={brand.companyName} onChange={(value) => setBrand((current) => ({ ...current, companyName: value }))} />
            <div className="brand-logo-manager">
              <div className="logo-swatch light">
                <Wordmark brand={brand} variant="light" />
                <label className="field">
                  <span>Black-letter logo for light backgrounds</span>
                  <input type="file" accept="image/*" onChange={(event) => updateLogo(event, "logoBlackDataUrl")} disabled={disabled} />
                </label>
              </div>
              <div className="logo-swatch dark">
                <Wordmark brand={brand} variant="dark" />
                <label className="field">
                  <span>White-letter logo for dark backgrounds</span>
                  <input type="file" accept="image/*" onChange={(event) => updateLogo(event, "logoWhiteDataUrl")} disabled={disabled} />
                </label>
              </div>
            </div>
            <div className="color-grid">
              {[
                ["Primary red", "primaryColor"],
                ["Black", "black"],
                ["Charcoal", "charcoal"],
                ["White", "white"],
                ["Gold accent", "gold"]
              ].map(([label, key]) => (
                <label className="field color-field" key={key}>
                  <span>{label}</span>
                  <input type="color" value={brand[key]} onChange={(event) => setBrand((current) => ({ ...current, [key]: event.target.value }))} disabled={disabled} />
                </label>
              ))}
            </div>
            <Field label="Default disclaimer" value={brand.defaultDisclaimer} onChange={(value) => setBrand((current) => ({ ...current, defaultDisclaimer: value }))} as="textarea" />
            <Field label="Recruiting disclaimer" value={brand.recruitingDisclaimer} onChange={(value) => setBrand((current) => ({ ...current, recruitingDisclaimer: value }))} as="textarea" />
            <button className="btn primary" onClick={saveBrand} disabled={disabled}>
              <Icon name="Save" />
              <span>Save Brand Settings</span>
            </button>
          </div>
        </div>

        <div className="settings-side">
          <div className="panel brand-preview-panel">
            <p className="eyebrow">Preview</p>
            <div className="brand-preview" style={{ "--brand-red": brand.primaryColor, "--brand-gold": brand.gold }}>
              <Wordmark brand={brand} variant="dark" />
              <h3>Modern, bold, high-performance real estate marketing.</h3>
              <p>{brand.defaultDisclaimer}</p>
            </div>
          </div>
          {!disabled && <AdminDealSpinner setToast={setToast} />}
        </div>
      </section>

      <AccessManager allowedUsers={allowedUsers} setAllowedUsers={setAllowedUsers} setAgentDirectory={setAgentDirectory} role={role} setToast={setToast} />
    </div>
  );
}

const dealSpinnerSymbols = [
  { label: "Closing", icon: "Handshake" },
  { label: "Listing", icon: "Home" },
  { label: "Hot Lead", icon: "Flame" },
  { label: "CMA", icon: "LineChart" },
  { label: "NexU", icon: "GraduationCap" },
  { label: "Open House", icon: "MapPin" },
  { label: "Coffee", icon: "Coffee" }
];

const dealSpinnerRewards = {
  triple: [
    "Bragging rights on the admin board",
    "Pick the next team hype song",
    "One official Nex victory lap",
    "Choose the next meeting icebreaker"
  ],
  pair: [
    "Coffee-run pass",
    "NexU shoutout badge",
    "Pick tomorrow's dashboard quote",
    "Lead follow-up champ title"
  ],
  mix: [
    "Permission to say 'pipeline secured'",
    "One desk high-five credit",
    "Marketing Studio power-user badge",
    "Open house playlist authority"
  ]
};

function randomDealSymbol() {
  return dealSpinnerSymbols[Math.floor(Math.random() * dealSpinnerSymbols.length)];
}

function dealSpinnerOutcome(reels) {
  const labels = reels.map((item) => item.label);
  const uniqueCount = new Set(labels).size;
  const level = uniqueCount === 1 ? "triple" : uniqueCount === 2 ? "pair" : "mix";
  const rewardList = dealSpinnerRewards[level];
  const reward = rewardList[Math.floor(Math.random() * rewardList.length)];
  const title = level === "triple" ? "Triple Nex Win" : level === "pair" ? "Two-of-a-kind Deal Boost" : "Daily Admin Win";
  return {
    id: crypto.randomUUID ? crypto.randomUUID() : `spin-${Date.now()}`,
    title,
    reward,
    reels: labels.join(" / "),
    createdAt: new Date().toISOString()
  };
}

function AdminDealSpinner({ setToast }) {
  const [reels, setReels] = useState(() => [dealSpinnerSymbols[0], dealSpinnerSymbols[1], dealSpinnerSymbols[2]]);
  const [isSpinning, setIsSpinning] = useState(false);
  const [result, setResult] = useState(null);
  const [history, setHistory] = useState(() => {
    try {
      return JSON.parse(localStorage.getItem("nex-admin-deal-spinner-history") || "[]");
    } catch (error) {
      return [];
    }
  });

  function saveHistory(item) {
    const next = [item, ...history].slice(0, 5);
    setHistory(next);
    localStorage.setItem("nex-admin-deal-spinner-history", JSON.stringify(next));
  }

  function spin() {
    if (isSpinning) return;
    setIsSpinning(true);
    setResult(null);
    let ticks = 0;
    const timer = window.setInterval(() => {
      const nextReels = [randomDealSymbol(), randomDealSymbol(), randomDealSymbol()];
      setReels(nextReels);
      ticks += 1;
      if (ticks >= 16) {
        window.clearInterval(timer);
        const finalReels = [randomDealSymbol(), randomDealSymbol(), randomDealSymbol()];
        const outcome = dealSpinnerOutcome(finalReels);
        setReels(finalReels);
        setResult(outcome);
        saveHistory(outcome);
        setIsSpinning(false);
        setToast(`${outcome.title}: ${outcome.reward}`);
      }
    }, 85);
  }

  return (
    <div className="panel admin-spinner-panel">
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Admin fun</p>
          <h3>Nex Deal Spinner</h3>
        </div>
        <span className="spinner-safe-badge">No cash value</span>
      </div>
      <p className="admin-spinner-copy">A real-estate themed admin-only mini game for quick team morale. No wagering, no money, no prizes of value.</p>
      <div className={classNames("deal-spinner-reels", isSpinning && "spinning")}>
        {reels.map((symbol, index) => (
          <article key={`${symbol.label}-${index}`}>
            <Icon name={symbol.icon} size={26} />
            <strong>{symbol.label}</strong>
          </article>
        ))}
      </div>
      <button className="btn primary" onClick={spin} disabled={isSpinning}>
        <Icon name={isSpinning ? "LoaderCircle" : "Sparkles"} className={isSpinning ? "spin" : ""} />
        <span>{isSpinning ? "Spinning" : "Spin For A Team Win"}</span>
      </button>
      {result && (
        <div className="spinner-result-card">
          <strong>{result.title}</strong>
          <span>{result.reels}</span>
          <p>{result.reward}</p>
        </div>
      )}
      {history.length > 0 && (
        <div className="spinner-history">
          {history.map((item) => (
            <span key={item.id}>{item.title} - {item.reward}</span>
          ))}
        </div>
      )}
    </div>
  );
}

function AccessManager({ allowedUsers, setAllowedUsers, setAgentDirectory, role, setToast }) {
  const marketOptions = ["Tampa Bay", "Orlando", "Miami", "Other"];
  const primaryMarketAreas = frontendLeadMarketAreas;
  const adminServiceAreaOptions = serviceOptionsFromMarketAreas(primaryMarketAreas);
  const today = new Date().toISOString().slice(0, 10);
  const [draft, setDraft] = useState({ name: "", email: "", phone: "", market: "Tampa Bay", primaryMarketArea: "tampa-bay", directoryType: "Agent", headshotUrl: "", commissionPlan: "Nex Premium", anniversaryDate: today, publicProfileEnabled: true, publicSlug: "", publicBio: "", serviceAreas: "", languages: "English", specialties: "", idxSearchUrl: "", leadRotationOptIn: false, leadRotationStatus: "inactive", maxActiveBrokerageLeads: 10, serviceCounties: "", serviceCities: "", serviceZipCodes: "", role: "Agent", password: "", active: true, sendWelcomeEmail: true });
  const [bulkDraft, setBulkDraft] = useState({ entries: "", defaultMarket: "Tampa Bay", defaultPrimaryMarketArea: "tampa-bay", defaultDirectoryType: "Agent", defaultCommissionPlan: "Nex Premium", defaultAnniversaryDate: today, defaultRole: "Agent", defaultPassword: "", sendWelcomeEmail: true });
  const [filters, setFilters] = useState({
    status: "Active",
    search: "",
    market: "All",
    role: "All",
    plan: "All",
    leadRotation: "All",
    directoryType: "All",
    publish: "All",
    missing: "All",
    serviceAreas: "All",
    welcome: "All",
    lastLogin: "All",
    leadEligible: "All"
  });
  const [sort, setSort] = useState({ key: "name", direction: "asc" });
  const [selectedIds, setSelectedIds] = useState([]);
  const [selectedUserId, setSelectedUserId] = useState("");
  const [showAddUser, setShowAddUser] = useState(false);
  const [showImportUsers, setShowImportUsers] = useState(false);
  const [bulkLeadStatus, setBulkLeadStatus] = useState("paused");
  const [bulkMarket, setBulkMarket] = useState("Tampa Bay");
  const [editing, setEditing] = useState({});
  const [passwords, setPasswords] = useState({});
  const [resetLink, setResetLink] = useState("");
  const [resetDelivery, setResetDelivery] = useState(null);
  const [welcomeSendState, setWelcomeSendState] = useState({});
  const [welcomeConfirmUser, setWelcomeConfirmUser] = useState(null);
  const [welcomePreviewUser, setWelcomePreviewUser] = useState(null);
  const [bulkResult, setBulkResult] = useState(null);
  const [recoveringUsers, setRecoveringUsers] = useState(false);
  const anonymousUserKeysRef = useRef(new WeakMap());
  const anonymousUserKeySeedRef = useRef(0);
  const disabled = !isAdminRole(role);
  const uniqueAllowedUsers = useMemo(() => dedupeUsers(allowedUsers), [allowedUsers]);
  const reviewUserCount = uniqueAllowedUsers.filter((user) => user.recoveryNeedsReview).length;
  const managedUsers = useMemo(() => uniqueAllowedUsers.filter((user) => !user.recoveryNeedsReview), [uniqueAllowedUsers]);
  const activeUserCount = managedUsers.filter((user) => user.active !== false && user.licenseActive !== false).length;
  const archivedUserCount = managedUsers.filter((user) => user.active === false).length;
  const inactiveUserCount = managedUsers.filter((user) => user.active !== false && user.licenseActive === false).length;
  const userIdFor = (user) => {
    const key = getUserDedupeKey(user);
    if (key) return key;
    if (!user || typeof user !== "object") return "";
    if (!anonymousUserKeysRef.current.has(user)) {
      anonymousUserKeySeedRef.current += 1;
      anonymousUserKeysRef.current.set(user, `anonymous-user:${anonymousUserKeySeedRef.current}`);
    }
    return anonymousUserKeysRef.current.get(user);
  };
  const selectedUser = uniqueAllowedUsers.find((user) => userIdFor(user) === selectedUserId) || null;
  const userStatus = (user) => user.active === false ? "Archived" : user.licenseActive === false ? "Inactive" : "Active";
  const missingProfileItems = (user) => [
    !user.name && "Name",
    !user.email && "Email",
    !user.phone && !user.phoneMobile && "Phone",
    !user.market && "Market",
    !user.commissionPlan && "Plan",
    !user.headshotUrl && "Headshot",
    user.directoryType === "Agent" && user.publicProfileEnabled !== false && !user.publicSlug && "Public Profile Link"
  ].filter(Boolean);
  const optionList = (values) => ["All", ...Array.from(new Set(values.filter(Boolean))).sort((a, b) => String(a).localeCompare(String(b)))];
  const marketFilterOptions = optionList([...uniqueAllowedUsers.map((user) => user.market), ...marketOptions]);
  const roleFilterOptions = optionList(uniqueAllowedUsers.map((user) => user.role));
  const planFilterOptions = optionList([...uniqueAllowedUsers.map((user) => user.commissionPlan), ...commissionPlanOptions]);
  const leadRotationOptions = ["All", "Opted in", "Not opted in", "Paused", "Not eligible", "active", "paused", "inactive", "suspended"];
  const directoryTypeFilterOptions = optionList([...uniqueAllowedUsers.map((user) => user.directoryType), ...directoryTypeOptions]);
  async function refreshUsersFromServer(confirmEmail = "") {
    const response = await API.request("/api/users");
    const users = Array.isArray(response?.items) ? response.items : Array.isArray(response) ? response : [];
    const nextUsers = uniqueSortedUsers(users);
    setAllowedUsers(nextUsers);
    if (setAgentDirectory) setAgentDirectory(nextUsers);
    if (confirmEmail && !nextUsers.some((user) => normalizeEmail(user.email) === normalizeEmail(confirmEmail))) {
      setToast(`Nex Central created ${confirmEmail}, but it was not found after refresh. Try Recover Missing Invites before adding it again.`);
    }
    return nextUsers;
  }

  function mergeUsers(users) {
    setAllowedUsers((current) => uniqueSortedUsers([...current, ...users]));
    if (setAgentDirectory) {
      setAgentDirectory((current) => uniqueSortedUsers([...current, ...users]));
    }
  }

  async function addUser() {
    if (!draft.email.trim()) return;
    try {
      const saved = await API.request("/api/users", {
        method: "POST",
        body: JSON.stringify(draft)
      });
      mergeUsers([saved]);
      const refreshedUsers = await refreshUsersFromServer(saved.email || draft.email);
      const savedEmail = normalizeEmail(saved.email || draft.email);
      const refreshedUser = refreshedUsers.find((user) => normalizeEmail(user.email) === savedEmail) || saved;
      setSelectedUserId(userIdFor(refreshedUser));
      setFilters((current) => ({ ...current, status: "All", search: savedEmail }));
      if (saved.setupLink) {
        setResetLink(saved.setupLink);
        setResetDelivery({
          user: saved.name || saved.email,
          sent: Boolean(saved.delivery?.sent),
          provider: saved.delivery?.provider || "console",
          reason: saved.delivery?.reason || ""
        });
      }
      setDraft({ name: "", email: "", phone: "", market: "Tampa Bay", primaryMarketArea: "tampa-bay", directoryType: "Agent", headshotUrl: "", commissionPlan: "Nex Premium", anniversaryDate: today, publicProfileEnabled: true, publicSlug: "", publicBio: "", serviceAreas: "", languages: "English", specialties: "", idxSearchUrl: "", leadRotationOptIn: false, leadRotationStatus: "inactive", maxActiveBrokerageLeads: 10, serviceCounties: "", serviceCities: "", serviceZipCodes: "", role: "Agent", password: "", active: true, sendWelcomeEmail: true });
      setShowAddUser(false);
      setToast(saved.message || (saved.updatedExisting ? "Existing user restored and updated." : saved.alreadyExists ? "Existing profile opened." : "User account added."));
    } catch (error) {
      setToast(error.message || "Could not add user.");
    }
  }

  async function importUsers() {
    if (!bulkDraft.entries.trim()) return;
    try {
      const response = await API.request("/api/users/bulk", {
        method: "POST",
        body: JSON.stringify(bulkDraft)
      });
      mergeUsers(response.created || []);
      await refreshUsersFromServer();
      setBulkResult(response);
      const firstFallback = (response.deliveries || []).find((item) => !item.delivery?.sent && item.setupLink);
      if (firstFallback) {
        setResetLink(firstFallback.setupLink);
        setResetDelivery({ user: firstFallback.email, sent: false, provider: "console", reason: firstFallback.delivery?.reason || "" });
      }
      setToast(response.message || "Bulk import complete.");
    } catch (error) {
      setToast(error.message || "Could not import users.");
    }
  }

  function editableUser(user) {
    return editing[userIdFor(user)] || {
      name: user.name || "",
      email: user.email || "",
      phone: user.phone || "",
      market: user.market || "Tampa Bay",
      primaryMarketArea: user.primaryMarketArea || "tampa-bay",
      directoryType: user.directoryType || "Agent",
      headshotUrl: user.headshotUrl || "",
      commissionPlan: user.commissionPlan || "Nex Premium",
      anniversaryDate: user.anniversaryDate || "",
      publicProfileEnabled: user.publicProfileEnabled !== false,
      publicSlug: user.publicSlug || "",
      publicBio: user.publicBio || "",
      serviceAreas: Array.isArray(user.serviceAreas) ? user.serviceAreas.join(", ") : user.serviceAreas || "",
      languages: Array.isArray(user.languages) ? user.languages.join(", ") : user.languages || "English",
      specialties: Array.isArray(user.specialties) ? user.specialties.join(", ") : user.specialties || "",
      idxSearchUrl: user.idxSearchUrl || "",
      leadRotationOptIn: Boolean(user.leadRotationOptIn),
      leadRotationStatus: user.leadRotationStatus || "inactive",
      maxActiveBrokerageLeads: user.maxActiveBrokerageLeads || 10,
      serviceCounties: Array.isArray(user.serviceCounties) ? user.serviceCounties.join(", ") : user.serviceCounties || "",
      serviceCities: Array.isArray(user.serviceCities) ? user.serviceCities.join(", ") : user.serviceCities || "",
      serviceZipCodes: Array.isArray(user.serviceZipCodes) ? user.serviceZipCodes.join(", ") : user.serviceZipCodes || "",
      role: user.role || "Agent",
      active: user.active !== false
    };
  }

  async function readHeadshotFile(file) {
    if (!file) return "";
    if (!String(file.type || "").startsWith("image/")) {
      setToast("Choose an image file for the headshot.");
      return "";
    }
    if (Number(file.size || 0) > 6 * 1024 * 1024) {
      setToast("Headshot image is too large. Use a smaller image under 6 MB.");
      return "";
    }
    const upload = await resizeImageFileToDataUrl(file);
    if (!upload.dataUrl || upload.dataUrl.length > 900000) {
      setToast("Headshot could not be compressed enough. Try a smaller image.");
      return "";
    }
    return upload.dataUrl || "";
  }

  async function updateDraftHeadshot(event) {
    const dataUrl = await readHeadshotFile(event.target.files?.[0]);
    if (dataUrl) setDraft((current) => ({ ...current, headshotUrl: dataUrl }));
    event.target.value = "";
  }

  async function updateEditingHeadshot(user, event) {
    const dataUrl = await readHeadshotFile(event.target.files?.[0]);
    if (dataUrl) {
      setEditing((current) => ({
        ...current,
        [userIdFor(user)]: { ...editableUser(user), headshotUrl: dataUrl }
      }));
    }
    event.target.value = "";
  }

  async function saveUser(user) {
    const patch = editableUser(user);
    try {
      const saved = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
      mergeUsers([saved]);
      setEditing((current) => {
        const next = { ...current };
        delete next[userIdFor(user)];
        return next;
      });
      setSelectedUserId(userIdFor(saved));
      setToast("User updated.");
    } catch (error) {
      setToast(error.message || "Could not update user.");
    }
  }

  async function toggleUser(user) {
    const nextActive = user.active === false;
    setEditing((current) => ({
      ...current,
      [userIdFor(user)]: { ...editableUser(user), active: nextActive }
    }));
    try {
      const saved = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}`, {
        method: "PUT",
        body: JSON.stringify({ ...editableUser(user), active: nextActive })
      });
      mergeUsers([saved]);
      setToast(nextActive ? "User reactivated." : "User deactivated.");
    } catch (error) {
      setToast(error.message || "Could not update user status.");
    }
  }

  async function updatePassword(user) {
    const password = passwords[userIdFor(user)] || "";
    if (!password) return;
    try {
      const saved = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}/password`, {
        method: "POST",
        body: JSON.stringify({ password, forcePasswordChange: true })
      });
      mergeUsers([saved]);
      setPasswords((current) => ({ ...current, [userIdFor(user)]: "" }));
      setToast("Password updated. User will be prompted to change it.");
    } catch (error) {
      setToast(error.message || "Could not update password.");
    }
  }

  async function generateResetLink(user) {
    try {
      const response = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}/reset-link`, { method: "POST" });
      if (response.user) mergeUsers([response.user]);
      setResetLink(response.resetLink || "");
      setResetDelivery({
        user: user.name || user.email,
        sent: Boolean(response.delivery?.sent),
        provider: response.delivery?.provider || "console",
        reason: response.delivery?.reason || ""
      });
      setToast(response.delivery?.sent ? "Password reset email sent." : response.message || "Password reset link generated.");
    } catch (error) {
      setToast(error.message || "Could not generate reset link.");
    }
  }

  function welcomePreviewFor(user) {
    const firstName = String(user?.name || "").trim().split(/\s+/)[0] || "there";
    return {
      subject: "Welcome to Nex Central - Your Agent Hub Is Ready",
      body: [
        `Hi ${firstName},`,
        "",
        "Welcome to Nex Central.",
        "",
        "Your Nex Central account has been created, and you now have access to the tools built to help you stay connected, organized, and supported as a Nex Realty agent.",
        "",
        "Inside Nex Central, you will be able to access Nex CRM, Nex Chat, transaction tools, document support, NexU training, marketing resources, Market Pulse, calculators, dashboards, production tools, and website/IDX features as they continue rolling out.",
        "",
        "To get started, click the secure setup button in the email to create your password and log in.",
        "",
        "Welcome to Nex. We are excited to have you with us.",
        "",
        "Nex Realty"
      ].join("\n")
    };
  }

  async function sendWelcomeEmail(user) {
    const id = userIdFor(user);
    const recipient = user?.email || "";
    setWelcomeSendState((current) => ({
      ...current,
      [id]: { status: "sending", message: "Sending welcome email..." }
    }));
    try {
      const response = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}/welcome`, { method: "POST" });
      if (response.user) mergeUsers([response.user]);
      setResetLink(response.setupLink || "");
      setResetDelivery({
        user: user.name || user.email,
        sent: Boolean(response.delivery?.sent),
        provider: response.delivery?.provider || "console",
        reason: response.delivery?.reason || ""
      });
      const message = response.message || `Welcome email sent to ${recipient}.`;
      setWelcomeSendState((current) => ({
        ...current,
        [id]: {
          status: "success",
          message: response.delivery?.sent ? `Welcome email sent to ${recipient}.` : `Welcome setup link generated for ${recipient}.`,
          sentAt: response.user?.welcomeEmailLastSentAt || new Date().toISOString()
        }
      }));
      setToast(message);
    } catch (error) {
      const message = error.message || "Welcome email could not be sent. Please try again.";
      setWelcomeSendState((current) => ({
        ...current,
        [id]: { status: "error", message }
      }));
      setToast(message);
    }
  }

  async function recoverMissingInvites() {
    setRecoveringUsers(true);
    try {
      const response = await API.request("/api/users/recover-welcome-audits", { method: "POST" });
      mergeUsers(response.created || []);
      await refreshUsersFromServer();
      setFilters((current) => ({ ...current, status: "Active", search: "", welcome: "All" }));
      setToast(response.message || "Invite recovery complete.");
    } catch (error) {
      setToast(error.message || "Could not recover missing invite records.");
    } finally {
      setRecoveringUsers(false);
    }
  }

  function updateEditing(user, patch) {
    setEditing((current) => ({
      ...current,
      [userIdFor(user)]: { ...editableUser(user), ...patch }
    }));
  }

  function userSearchText(user) {
    return [
      user.name,
      user.email,
      user.phone,
      user.phoneMobile,
      user.phoneMobileE164,
      user.market,
      user.primaryMarketArea,
      leadOptInStatus(user).label,
      serviceAreaSummary(user),
      user.role,
      user.directoryType,
      user.commissionPlan,
      user.publicSlug,
      user.publicProfilePath,
      user.agentSubdomainUrl,
      Array.isArray(user.serviceAreas) ? user.serviceAreas.join(" ") : user.serviceAreas,
      Array.isArray(user.serviceCounties) ? user.serviceCounties.join(" ") : user.serviceCounties,
      Array.isArray(user.serviceCities) ? user.serviceCities.join(" ") : user.serviceCities,
      Array.isArray(user.serviceZipCodes) ? user.serviceZipCodes.join(" ") : user.serviceZipCodes
    ].filter(Boolean).join(" ").toLowerCase();
  }

  const filterBaseUsers = filters.status === "Needs review" ? uniqueAllowedUsers.filter((user) => user.recoveryNeedsReview) : managedUsers;
  const filteredUsers = filterBaseUsers
    .filter((user) => {
      const status = userStatus(user);
      const query = filters.search.toLowerCase().trim();
      const matchesStatus = filters.status === "All users" || filters.status === "Needs review" || filters.status === status;
      const matchesSearch = !query || userSearchText(user).includes(query);
      const matchesMarket = filters.market === "All" || user.market === filters.market;
      const matchesRole = filters.role === "All" || user.role === filters.role;
      const matchesPlan = filters.plan === "All" || user.commissionPlan === filters.plan;
      const matchesDirectory = filters.directoryType === "All" || user.directoryType === filters.directoryType;
      const matchesPublish =
        filters.publish === "All" ||
        (filters.publish === "Published" && user.publicProfileEnabled !== false) ||
        (filters.publish === "Unpublished" && user.publicProfileEnabled === false);
      const matchesMissing =
        filters.missing === "All" ||
        (filters.missing === "Missing info" && missingProfileItems(user).length > 0) ||
        (filters.missing === "Complete profiles" && missingProfileItems(user).length === 0);
      const matchesLeadRotation =
        filters.leadRotation === "All" ||
        (filters.leadRotation === "Opted in" && user.leadRotationOptIn) ||
        (filters.leadRotation === "Not opted in" && !user.leadRotationOptIn) ||
        (filters.leadRotation === "Paused" && String(user.leadRotationStatus || "").toLowerCase() === "paused") ||
        (filters.leadRotation === "Not eligible" && leadOptInStatus(user).tone === "red") ||
        user.leadRotationStatus === filters.leadRotation;
      const hasServiceAreas = listFromText(user.serviceCounties).length || listFromText(user.serviceCities).length || listFromText(user.serviceZipCodes).length || listFromText(user.serviceAreas).length;
      const matchesServiceAreas =
        filters.serviceAreas === "All" ||
        (filters.serviceAreas === "Has service areas" && hasServiceAreas) ||
        (filters.serviceAreas === "No service areas selected" && !hasServiceAreas);
      const matchesWelcome =
        filters.welcome === "All" ||
        (filters.welcome === "Welcome sent" && user.welcomeEmailLastSentAt) ||
        (filters.welcome === "Welcome not sent" && !user.welcomeEmailLastSentAt) ||
        (filters.welcome === "Setup completed" && user.welcomeEmailSetupCompletedAt);
      const lastLoginAt = user.lastLoginAt ? new Date(user.lastLoginAt).getTime() : 0;
      const daysSinceLogin = lastLoginAt ? (Date.now() - lastLoginAt) / 86400000 : Infinity;
      const matchesLastLogin =
        filters.lastLogin === "All" ||
        (filters.lastLogin === "Logged in last 30 days" && daysSinceLogin <= 30) ||
        (filters.lastLogin === "No recent login" && daysSinceLogin > 30 && daysSinceLogin < Infinity) ||
        (filters.lastLogin === "Never logged in" && !lastLoginAt);
      const matchesLeadEligible =
        filters.leadEligible === "All" ||
        (filters.leadEligible === "Company lead eligible" && companyLeadEligible(user)) ||
        (filters.leadEligible === "Not company lead eligible" && !companyLeadEligible(user));
      return matchesStatus && matchesSearch && matchesMarket && matchesRole && matchesPlan && matchesDirectory && matchesPublish && matchesMissing && matchesLeadRotation && matchesServiceAreas && matchesWelcome && matchesLastLogin && matchesLeadEligible;
    })
    .sort((a, b) => {
      const valueFor = (user) => {
        if (sort.key === "status") return userStatus(user);
        if (sort.key === "leadRotationStatus") return user.leadRotationStatus || "inactive";
        if (sort.key === "leadOptInStatus") return leadOptInStatus(user).label;
        if (sort.key === "serviceAreas") return serviceAreaSummary(user);
        if (sort.key === "welcomeEmailLastSentAt") return new Date(user.welcomeEmailLastSentAt || 0).getTime();
        if (sort.key === "lastLoginAt" || sort.key === "anniversaryDate" || sort.key === "createdAt") return new Date(user[sort.key] || 0).getTime();
        return user[sort.key] || "";
      };
      const result = typeof valueFor(a) === "number" ? valueFor(a) - valueFor(b) : String(valueFor(a)).localeCompare(String(valueFor(b)));
      return sort.direction === "asc" ? result : -result;
    });

  function toggleSort(key) {
    setSort((current) => ({ key, direction: current.key === key && current.direction === "asc" ? "desc" : "asc" }));
  }

  function toggleSelected(user) {
    const id = userIdFor(user);
    setSelectedIds((current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]);
  }

  function selectedUsers() {
    const selected = new Set(selectedIds);
    return uniqueAllowedUsers.filter((user) => selected.has(userIdFor(user)));
  }

  async function bulkPatchUsers(users, patch, label) {
    if (!users.length) return;
    let success = 0;
    for (const user of users) {
      try {
        const saved = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}`, {
          method: "PUT",
          body: JSON.stringify({ ...editableUser(user), ...patch })
        });
        mergeUsers([saved]);
        success += 1;
      } catch (error) {
        setToast(error.message || `Could not update ${user.name || user.email}.`);
      }
    }
    setSelectedIds([]);
    setToast(`${label}: ${success} user${success === 1 ? "" : "s"} updated.`);
  }

  async function bulkSendWelcome(users) {
    let success = 0;
    for (const user of users) {
      try {
        const response = await API.request(`/api/users/${encodeURIComponent(user.id || user.email)}/welcome`, { method: "POST" });
        if (response.user) mergeUsers([response.user]);
        success += 1;
      } catch (error) {
        setToast(error.message || `Could not send welcome email to ${user.name || user.email}.`);
      }
    }
    setToast(`Welcome setup sent/generated for ${success} user${success === 1 ? "" : "s"}.`);
  }

  function exportUsers(users, mode = "full") {
    const rows = dedupeUsers(users.length ? users : filteredUsers);
    const headers = mode === "vendor"
      ? [["name", "Name"], ["phone", "Phone"], ["email", "Email"], ["market", "Location / market"]]
      : [["name", "Name"], ["email", "Email"], ["phone", "Phone"], ["market", "Market"], ["role", "Role"], ["directoryType", "Directory type"], ["commissionPlan", "Commission plan"], ["leadOptIn", "Lead Opt-In Status"], ["leadRotationStatus", "Lead rotation"], ["serviceAreas", "Service Areas"], ["welcomeEmailLastSentAt", "Welcome Email Sent"], ["active", "Active"], ["lastLoginAt", "Last login"], ["anniversaryDate", "Anniversary date"], ["publicSlug", "Public Profile Link"]];
    const csv = [
      headers.map(([, label]) => csvEscape(label)).join(","),
      ...rows.map((user) => headers.map(([key]) => {
        if (key === "phone") return csvEscape(user.phoneMobileE164 || user.phoneMobile || user.phone || "");
        if (key === "active") return csvEscape(user.active === false ? "Archived" : "Active");
        if (key === "market" && mode === "vendor") return csvEscape(user.market || user.primaryMarketArea || "");
        if (key === "leadOptIn") return csvEscape(leadOptInStatus(user).label);
        if (key === "serviceAreas") return csvEscape(serviceAreaSummary(user));
        return csvEscape(user[key] ?? "");
      }).join(","))
    ].join("\n");
    downloadBlob(new Blob([csv], { type: "text/csv;charset=utf-8" }), mode === "vendor" ? "nex-user-vendor-contact-list.csv" : "nex-user-management-export.csv");
  }

  function sortButton(key, label) {
    return (
      <button type="button" onClick={() => toggleSort(key)}>
        <span>{label}</span>
        <Icon name={sort.key === key ? (sort.direction === "asc" ? "ChevronUp" : "ChevronDown") : "ChevronsUpDown"} size={13} />
      </button>
    );
  }

  const selectedWelcomeState = selectedUser ? (welcomeSendState[userIdFor(selectedUser)] || {}) : {};
  const selectedLeadStatus = selectedUser ? leadOptInStatus(selectedUser) : null;
  const selectedUserCount = selectedUsers().length;
  const welcomeModalUser = welcomeConfirmUser || welcomePreviewUser;
  const welcomeModalMode = welcomeConfirmUser ? "send" : "preview";
  const welcomeModalState = welcomeModalUser ? (welcomeSendState[userIdFor(welcomeModalUser)] || {}) : {};
  const welcomeModalPreview = welcomeModalUser ? welcomePreviewFor(welcomeModalUser) : null;

  return (
    <div className="panel access-panel access-command-center">
      <div className="access-command-header">
        <div>
          <p className="eyebrow">User management</p>
          <h3>Users, agents, and staff</h3>
          <p>Search, filter, edit, archive, restore, and export Nex Central users without scrolling through every profile field.</p>
        </div>
        <div className="access-command-actions">
          <button className="btn secondary" type="button" onClick={() => setShowImportUsers((value) => !value)} disabled={disabled}>
            <Icon name="Upload" />
            <span>Import Users</span>
          </button>
          <button className="btn secondary" type="button" onClick={recoverMissingInvites} disabled={disabled || recoveringUsers}>
            <Icon name={recoveringUsers ? "LoaderCircle" : "RefreshCcw"} className={recoveringUsers ? "spin" : ""} />
            <span>{recoveringUsers ? "Recovering" : "Recover Missing Invites"}</span>
          </button>
          <button className="btn primary" type="button" onClick={() => setShowAddUser((value) => !value)} disabled={disabled}>
            <Icon name="UserPlus" />
            <span>Add / Restore User</span>
          </button>
        </div>
      </div>
      {disabled && <div className="suggestion-strip">Only admins can manage Nex Central users.</div>}
      <div className="access-summary-strip">
        <span><strong>{managedUsers.length}</strong>Managed users</span>
        <span><strong>{activeUserCount}</strong>Active</span>
        <span><strong>{archivedUserCount}</strong>Archived</span>
        <span><strong>{inactiveUserCount}</strong>Inactive</span>
        <span><strong>{managedUsers.filter((user) => user.leadRotationOptIn).length}</strong>Lead rotation</span>
        <span><strong>{managedUsers.filter((user) => missingProfileItems(user).length > 0).length}</strong>Missing info</span>
        {reviewUserCount > 0 && <span><strong>{reviewUserCount}</strong>Needs review</span>}
      </div>

      {showAddUser && (
      <div className={classNames("access-form access-create-panel", disabled && "muted")}>
        <div className="access-form-note">
          <strong>Add or restore a user</strong>
          <span>If the email already belongs to an archived or review profile, Nex Central restores that same account so CRM, leads, website, and login history stay connected.</span>
        </div>
        <Field label="Name" value={draft.name} onChange={(value) => setDraft((current) => ({ ...current, name: value }))} placeholder="Avery Morgan" />
        <Field label="Email" value={draft.email} onChange={(value) => setDraft((current) => ({ ...current, email: value }))} type="email" placeholder="agent@nexrealty.com" />
        <Field label="Phone" value={draft.phone} onChange={(value) => setDraft((current) => ({ ...current, phone: value }))} type="tel" placeholder="(555) 555-5555" />
        <Field label="Region" value={draft.market} onChange={(value) => setDraft((current) => ({ ...current, market: value }))} as="select" options={marketOptions} />
        <MarketAreaSelect label="Lead rotation market" value={draft.primaryMarketArea} onChange={(value) => setDraft((current) => ({ ...current, primaryMarketArea: value }))} marketAreas={primaryMarketAreas} disabled={disabled} />
        <Field label="Directory type" value={draft.directoryType} onChange={(value) => setDraft((current) => ({ ...current, directoryType: value }))} as="select" options={directoryTypeOptions} />
        <div className="user-headshot-field">
          <UserAvatar user={draft} size="md" />
          <label>
            <span>Headshot</span>
            <input type="file" accept="image/*" onChange={updateDraftHeadshot} disabled={disabled} />
          </label>
        </div>
        <Field label="Headshot URL optional" value={draft.headshotUrl} onChange={(value) => setDraft((current) => ({ ...current, headshotUrl: value }))} placeholder="Paste hosted image URL or upload above" />
        <Field label="Commission plan" value={draft.commissionPlan} onChange={(value) => setDraft((current) => ({ ...current, commissionPlan: value }))} as="select" options={commissionPlanOptions} />
        <Field label="Anniversary date" value={draft.anniversaryDate} onChange={(value) => setDraft((current) => ({ ...current, anniversaryDate: value }))} type="date" />
        <label className="toggle-field">
          <input type="checkbox" checked={draft.publicProfileEnabled} onChange={(event) => setDraft((current) => ({ ...current, publicProfileEnabled: event.target.checked }))} />
          <span>Publish agent website profile</span>
        </label>
        <Field label="Public Profile Link" value={draft.publicSlug} onChange={(value) => setDraft((current) => ({ ...current, publicSlug: value }))} placeholder="jane-smith" />
        <StandardMultiSelect label="Service areas" value={draft.serviceAreas} onChange={(value) => setDraft((current) => ({ ...current, serviceAreas: value }))} options={adminServiceAreaOptions.serviceAreas} />
        <Field label="Languages" value={draft.languages} onChange={(value) => setDraft((current) => ({ ...current, languages: value }))} placeholder="English, Spanish" />
        <Field label="Specialties" value={draft.specialties} onChange={(value) => setDraft((current) => ({ ...current, specialties: value }))} placeholder="Buyer Agent, Listing Agent, Luxury" />
        <Field label="Agent IDX URL optional" value={draft.idxSearchUrl} onChange={(value) => setDraft((current) => ({ ...current, idxSearchUrl: value }))} placeholder="https://propertysearch.nexrealtygroup.com/agent-name" />
        <label className="toggle-field">
          <input type="checkbox" checked={draft.leadRotationOptIn} onChange={(event) => setDraft((current) => ({ ...current, leadRotationOptIn: event.target.checked, leadRotationStatus: event.target.checked ? "active" : "inactive" }))} />
          <span>Opt in to Nex generated lead rotation</span>
        </label>
        <Field label="Lead rotation status" value={draft.leadRotationStatus} onChange={(value) => setDraft((current) => ({ ...current, leadRotationStatus: value }))} as="select" options={["inactive", "active", "paused", "suspended"]} />
        <Field label="Max active Nex leads" value={draft.maxActiveBrokerageLeads} onChange={(value) => setDraft((current) => ({ ...current, maxActiveBrokerageLeads: value }))} />
        <StandardMultiSelect label="Lead counties" value={draft.serviceCounties} onChange={(value) => setDraft((current) => ({ ...current, serviceCounties: value }))} options={adminServiceAreaOptions.counties} />
        <StandardMultiSelect label="Lead cities" value={draft.serviceCities} onChange={(value) => setDraft((current) => ({ ...current, serviceCities: value }))} options={adminServiceAreaOptions.cities} />
        <Field label="Lead ZIPs" value={draft.serviceZipCodes} onChange={(value) => setDraft((current) => ({ ...current, serviceZipCodes: value }))} placeholder="33602, 33701" />
        <Field label="Public bio" value={draft.publicBio} onChange={(value) => setDraft((current) => ({ ...current, publicBio: value }))} as="textarea" placeholder="Short consumer-facing agent bio" />
        <Field label="Role" value={draft.role} onChange={(value) => setDraft((current) => ({ ...current, role: value }))} as="select" options={["Agent", "Admin", "Super Admin"]} />
        <Field label="Temporary password" value={draft.password} onChange={(value) => setDraft((current) => ({ ...current, password: value }))} type="password" placeholder="Optional, at least 8 characters" />
        <label className="toggle-field">
          <input type="checkbox" checked={draft.sendWelcomeEmail} onChange={(event) => setDraft((current) => ({ ...current, sendWelcomeEmail: event.target.checked }))} />
          <span>Send welcome setup email</span>
        </label>
        <button className="btn primary" onClick={addUser} disabled={disabled}>
          <Icon name="UserPlus" />
          <span>Add / Restore User</span>
        </button>
      </div>
      )}

      {showImportUsers && (
      <div className={classNames("bulk-user-import", disabled && "muted")}>
        <div>
          <p className="eyebrow">Bulk invite</p>
          <h4>Import users</h4>
          <p>Paste one user per line. Use: Name, email, phone, region, directory type. Default regions now include Tampa Bay, Orlando, and Miami.</p>
        </div>
        <Field label="User list" value={bulkDraft.entries} onChange={(value) => setBulkDraft((current) => ({ ...current, entries: value }))} as="textarea" placeholder={"Jane Agent, jane@nexrealty.com, 813-555-0199, Tampa Bay, Agent\nNex Support, support@nexrealty.com, 407-555-0144, Orlando, Staff"} />
        <div className="bulk-user-grid">
          <Field label="Default region" value={bulkDraft.defaultMarket} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultMarket: value }))} as="select" options={marketOptions} />
          <MarketAreaSelect label="Default lead market" value={bulkDraft.defaultPrimaryMarketArea} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultPrimaryMarketArea: value }))} marketAreas={primaryMarketAreas} disabled={disabled} />
          <Field label="Default directory type" value={bulkDraft.defaultDirectoryType} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultDirectoryType: value }))} as="select" options={directoryTypeOptions} />
          <Field label="Default plan" value={bulkDraft.defaultCommissionPlan} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultCommissionPlan: value }))} as="select" options={commissionPlanOptions} />
          <Field label="Default anniversary" value={bulkDraft.defaultAnniversaryDate} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultAnniversaryDate: value }))} type="date" />
          <Field label="Default role" value={bulkDraft.defaultRole} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultRole: value }))} as="select" options={["Agent", "Admin", "Super Admin"]} />
          <Field label="Optional stock password" value={bulkDraft.defaultPassword} onChange={(value) => setBulkDraft((current) => ({ ...current, defaultPassword: value }))} type="password" placeholder="At least 8 characters" />
        </div>
        <label className="toggle-field">
          <input type="checkbox" checked={bulkDraft.sendWelcomeEmail} onChange={(event) => setBulkDraft((current) => ({ ...current, sendWelcomeEmail: event.target.checked }))} />
          <span>Send welcome setup emails after import</span>
        </label>
        <button className="btn primary" onClick={importUsers} disabled={disabled || !bulkDraft.entries.trim()}>
          <Icon name="Upload" />
          <span>Import Users</span>
        </button>
        {bulkResult && (
          <div className="bulk-result-box">
            <strong>{bulkResult.message}</strong>
            {!!bulkResult.skipped?.length && <p>Skipped: {bulkResult.skipped.map((item) => `${item.email || "blank"} (${item.reason})`).join(", ")}</p>}
            {!!bulkResult.deliveries?.length && <p>{bulkResult.deliveries.filter((item) => item.delivery?.sent).length} welcome email(s) sent. {bulkResult.deliveries.filter((item) => !item.delivery?.sent).length} setup link(s) available as fallback.</p>}
          </div>
        )}
      </div>
      )}

      {resetLink && (
        <div className="reset-link-box">
          <strong>{resetDelivery?.sent ? "Email sent" : "Secure reset link"}</strong>
          <small>
            {resetDelivery?.sent
              ? `An email was sent to ${resetDelivery.user} through ${resetDelivery.provider || "email"}.`
              : `Email was not confirmed as sent${resetDelivery?.reason ? ` (${resetDelivery.reason})` : ""}. Copy this link and send it to the agent manually.`}
          </small>
          <p>{resetLink}</p>
          <button className="btn secondary" onClick={() => copyToClipboard(resetLink, setToast)}>
            <Icon name="Copy" />
            <span>Copy Link</span>
          </button>
        </div>
      )}

      <div className="user-management-toolbar">
        <div className="user-status-tabs">
          {["Active", "Archived", "Inactive", "Needs review", "All users"].map((status) => (
            <button key={status} type="button" className={filters.status === status ? "active" : ""} onClick={() => setFilters((current) => ({ ...current, status }))}>{status}</button>
          ))}
        </div>
        <div className="user-management-filter-grid">
          <Field label="Search" value={filters.search} onChange={(value) => setFilters((current) => ({ ...current, search: value }))} placeholder="Name, email, phone, region, county, ZIP, slug..." />
          <Field label="Region" value={filters.market} onChange={(value) => setFilters((current) => ({ ...current, market: value }))} as="select" options={marketFilterOptions} />
          <Field label="Role" value={filters.role} onChange={(value) => setFilters((current) => ({ ...current, role: value }))} as="select" options={roleFilterOptions} />
          <Field label="Plan" value={filters.plan} onChange={(value) => setFilters((current) => ({ ...current, plan: value }))} as="select" options={planFilterOptions} />
          <Field label="Lead rotation" value={filters.leadRotation} onChange={(value) => setFilters((current) => ({ ...current, leadRotation: value }))} as="select" options={leadRotationOptions} />
          <Field label="Directory type" value={filters.directoryType} onChange={(value) => setFilters((current) => ({ ...current, directoryType: value }))} as="select" options={directoryTypeFilterOptions} />
          <Field label="Profile" value={filters.publish} onChange={(value) => setFilters((current) => ({ ...current, publish: value }))} as="select" options={["All", "Published", "Unpublished"]} />
          <Field label="Profile health" value={filters.missing} onChange={(value) => setFilters((current) => ({ ...current, missing: value }))} as="select" options={["All", "Missing info", "Complete profiles"]} />
          <Field label="Service areas" value={filters.serviceAreas} onChange={(value) => setFilters((current) => ({ ...current, serviceAreas: value }))} as="select" options={["All", "Has service areas", "No service areas selected"]} />
          <Field label="Welcome email" value={filters.welcome} onChange={(value) => setFilters((current) => ({ ...current, welcome: value }))} as="select" options={["All", "Welcome sent", "Welcome not sent", "Setup completed"]} />
          <Field label="Login" value={filters.lastLogin} onChange={(value) => setFilters((current) => ({ ...current, lastLogin: value }))} as="select" options={["All", "Logged in last 30 days", "No recent login", "Never logged in"]} />
          <Field label="Company leads" value={filters.leadEligible} onChange={(value) => setFilters((current) => ({ ...current, leadEligible: value }))} as="select" options={["All", "Company lead eligible", "Not company lead eligible"]} />
        </div>
      </div>

      <div className="user-bulk-toolbar">
        <div>
          <strong>{filteredUsers.length}</strong>
          <span>visible</span>
          <strong>{selectedUserCount}</strong>
          <span>selected</span>
        </div>
        <button className="btn secondary small-btn" type="button" onClick={() => exportUsers(filteredUsers, "full")}><Icon name="Download" /><span>Export Visible</span></button>
        <button className="btn secondary small-btn" type="button" onClick={() => exportUsers(selectedUsers(), "full")} disabled={!selectedUserCount}><Icon name="FileDown" /><span>Export Selected</span></button>
        <button className="btn secondary small-btn" type="button" onClick={() => exportUsers(filteredUsers, "vendor")}><Icon name="ContactRound" /><span>Vendor CSV</span></button>
        <button className="btn danger-soft small-btn" type="button" onClick={() => bulkPatchUsers(selectedUsers(), { active: false }, "Archive selected")} disabled={disabled || !selectedUserCount}><Icon name="Archive" /><span>Archive</span></button>
        <button className="btn secondary small-btn" type="button" onClick={() => bulkPatchUsers(selectedUsers(), { active: true }, "Restore selected")} disabled={disabled || !selectedUserCount}><Icon name="ArchiveRestore" /><span>Restore</span></button>
        <button className="btn secondary small-btn" type="button" onClick={() => bulkSendWelcome(selectedUsers())} disabled={disabled || !selectedUserCount}><Icon name="Send" /><span>Welcome</span></button>
        <Field label="Lead status" value={bulkLeadStatus} onChange={setBulkLeadStatus} as="select" options={["inactive", "active", "paused", "suspended"]} disabled={disabled || !selectedUserCount} />
        <button className="btn secondary small-btn" type="button" onClick={() => bulkPatchUsers(selectedUsers(), { leadRotationStatus: bulkLeadStatus, leadRotationOptIn: bulkLeadStatus === "active" }, "Lead rotation updated")} disabled={disabled || !selectedUserCount}><Icon name="Route" /><span>Apply</span></button>
        <Field label="Market" value={bulkMarket} onChange={setBulkMarket} as="select" options={marketOptions} disabled={disabled || !selectedUserCount} />
        <button className="btn secondary small-btn" type="button" onClick={() => bulkPatchUsers(selectedUsers(), { market: bulkMarket }, "Market assigned")} disabled={disabled || !selectedUserCount}><Icon name="MapPin" /><span>Assign</span></button>
      </div>

      <div className="user-management-table-shell">
        <table className="user-management-table">
          <thead>
            <tr>
              <th><input type="checkbox" checked={filteredUsers.length > 0 && filteredUsers.every((user) => selectedIds.includes(userIdFor(user)))} onChange={(event) => setSelectedIds(event.target.checked ? Array.from(new Set(filteredUsers.map(userIdFor).filter(Boolean))) : [])} /></th>
              <th>{sortButton("name", "Agent")}</th>
              <th>{sortButton("market", "Region")}</th>
              <th>{sortButton("role", "Role")}</th>
              <th>{sortButton("commissionPlan", "Plan")}</th>
              <th>{sortButton("leadOptInStatus", "Lead opt-in")}</th>
              <th>{sortButton("leadRotationStatus", "Lead rotation")}</th>
              <th>{sortButton("serviceAreas", "Service areas")}</th>
              <th>{sortButton("welcomeEmailLastSentAt", "Welcome")}</th>
              <th>{sortButton("status", "Account")}</th>
              <th>{sortButton("lastLoginAt", "Last login")}</th>
              <th>{sortButton("anniversaryDate", "Anniversary")}</th>
              <th>{sortButton("createdAt", "Added")}</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {filteredUsers.map((user) => {
              const id = userIdFor(user);
              const status = userStatus(user);
              const missing = missingProfileItems(user);
              const leadStatus = leadOptInStatus(user);
              return (
                <tr key={id}>
                  <td><input type="checkbox" checked={selectedIds.includes(id)} onChange={() => toggleSelected(user)} /></td>
                  <td>
                    <div className="user-table-agent">
                      <UserAvatar user={user} size="sm" />
                      <span>
                        <strong>{user.name || user.email}</strong>
                        <small>{user.email}</small>
                        <small>{user.phoneMobileE164 || user.phoneMobile || user.phone || "No phone"}</small>
                      </span>
                    </div>
                  </td>
                  <td>{user.market || "No region"}</td>
                  <td><span className="access-pill">{user.role || "Agent"}</span></td>
                  <td>{user.commissionPlan || "Nex Premium"}</td>
                  <td>
                    <span className={classNames("access-pill", leadStatus.tone === "green" && "green", leadStatus.tone === "red" && "red", leadStatus.tone === "amber" && "amber", leadStatus.tone === "muted" && "muted")}>
                      {leadStatus.short}
                    </span>
                  </td>
                  <td>
                    <span className={classNames("access-pill", user.leadRotationStatus === "active" && "green", user.leadRotationStatus === "suspended" && "red")}>
                      {user.leadRotationOptIn ? user.leadRotationStatus || "active" : "not opted in"}
                    </span>
                  </td>
                  <td><small>{serviceAreaSummary(user)}</small></td>
                  <td>
                    <span className={classNames("access-pill", user.welcomeEmailLastSentAt && "green", !user.welcomeEmailLastSentAt && "muted")}>
                      {user.welcomeEmailLastSentAt ? "Sent" : "Not sent"}
                    </span>
                    {user.welcomeEmailSetupCompletedAt && <small className="missing-profile-note">Setup used</small>}
                  </td>
                  <td>
                    <span className={classNames("access-pill", status === "Active" && "green", status === "Archived" && "muted", status === "Inactive" && "red")}>{status}</span>
                    {!!missing.length && <small className="missing-profile-note">Missing {missing.length}</small>}
                    {user.recoveryNeedsReview && <small className="missing-profile-note">Review recovered info</small>}
                  </td>
                  <td>{user.lastLoginAt ? titleCaseDate(user.lastLoginAt) : "Never"}</td>
                  <td>{user.anniversaryDate ? formatDate(user.anniversaryDate) : "Not set"}</td>
                  <td>{user.createdAt ? formatDate(user.createdAt) : "Not set"}</td>
                  <td>
                    <div className="user-table-actions">
                      <button className="btn secondary small-btn" type="button" onClick={() => setSelectedUserId(id)}><Icon name="Pencil" /><span>Edit</span></button>
                      <button className={classNames("btn small-btn", user.active === false ? "secondary" : "danger-soft")} type="button" onClick={() => toggleUser(user)} disabled={disabled}>
                        <Icon name={user.active === false ? "ArchiveRestore" : "Archive"} />
                        <span>{user.active === false ? "Restore" : "Archive"}</span>
                      </button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        {!filteredUsers.length && <p className="access-empty">No users match those filters.</p>}
      </div>

      {selectedUser && (
        <div className="user-detail-drawer" role="dialog" aria-modal="true" aria-label="User profile detail">
          <div className="user-detail-backdrop" onClick={() => setSelectedUserId("")} />
          <aside className="user-detail-panel">
            <div className="user-detail-header">
              <div className="user-profile-strip">
                <UserAvatar user={selectedUser} size="lg" />
                <div>
                  <strong>{selectedUser.name || selectedUser.email}</strong>
                  <span>{selectedUser.email}</span>
                  <em>{selectedUser.directoryType || "Agent"} - {selectedUser.role || "Agent"} - {selectedUser.market || "No region"}</em>
                </div>
              </div>
              <button className="icon-btn" type="button" onClick={() => setSelectedUserId("")} title="Close user detail"><Icon name="X" /></button>
            </div>
            <div className="user-detail-scroll">
              <section className="user-detail-section">
                <div className="user-detail-section-head"><h4>Core profile</h4><span>Synced across Nex Central</span></div>
                <div className="user-edit-grid">
                  <Field label="Name" value={editableUser(selectedUser).name} onChange={(value) => updateEditing(selectedUser, { name: value })} />
                  <Field label="Email" value={editableUser(selectedUser).email} onChange={(value) => updateEditing(selectedUser, { email: value })} type="email" />
                  <Field label="Phone" value={editableUser(selectedUser).phone} onChange={(value) => updateEditing(selectedUser, { phone: value })} type="tel" />
                  <Field label="Region" value={editableUser(selectedUser).market} onChange={(value) => updateEditing(selectedUser, { market: value })} as="select" options={marketOptions} />
                  <Field label="Directory type" value={editableUser(selectedUser).directoryType} onChange={(value) => updateEditing(selectedUser, { directoryType: value })} as="select" options={directoryTypeOptions} />
                  <Field label="Role" value={editableUser(selectedUser).role} onChange={(value) => updateEditing(selectedUser, { role: value })} as="select" options={["Agent", "Admin", "Super Admin"]} />
                </div>
                <div className="user-headshot-field compact">
                  <UserAvatar user={editableUser(selectedUser)} size="md" />
                  <label>
                    <span>Upload headshot</span>
                    <input type="file" accept="image/*" onChange={(event) => updateEditingHeadshot(selectedUser, event)} disabled={disabled} />
                  </label>
                </div>
                <Field label="Headshot URL" value={editableUser(selectedUser).headshotUrl} onChange={(value) => updateEditing(selectedUser, { headshotUrl: value })} placeholder="Optional image URL" />
              </section>

              <section className="user-detail-section">
                <div className="user-detail-section-head"><h4>Commission and website</h4><span>Feeds caps, public profile, and reporting</span></div>
                <div className="user-edit-grid">
                <Field label="Commission plan" value={editableUser(selectedUser).commissionPlan} onChange={(value) => updateEditing(selectedUser, { commissionPlan: value })} as="select" options={commissionPlanOptions} />
                <Field label="Anniversary date" value={editableUser(selectedUser).anniversaryDate} onChange={(value) => updateEditing(selectedUser, { anniversaryDate: value })} type="date" />
                <label className="toggle-field">
                  <input type="checkbox" checked={editableUser(selectedUser).publicProfileEnabled} onChange={(event) => updateEditing(selectedUser, { publicProfileEnabled: event.target.checked })} />
                  <span>Publish profile</span>
                </label>
                <Field label="Public Profile Link" value={editableUser(selectedUser).publicSlug} onChange={(value) => updateEditing(selectedUser, { publicSlug: value })} placeholder="jane-smith" />
                <StandardMultiSelect label="Service areas" value={editableUser(selectedUser).serviceAreas} onChange={(value) => updateEditing(selectedUser, { serviceAreas: value })} options={adminServiceAreaOptions.serviceAreas} helper="Controls public website profile filtering and service-area display." />
                <Field label="Languages" value={editableUser(selectedUser).languages} onChange={(value) => updateEditing(selectedUser, { languages: value })} placeholder="English, Spanish" />
                <Field label="Specialties" value={editableUser(selectedUser).specialties} onChange={(value) => updateEditing(selectedUser, { specialties: value })} placeholder="Buyer Agent, Luxury" />
                <Field label="Agent IDX URL" value={editableUser(selectedUser).idxSearchUrl} onChange={(value) => updateEditing(selectedUser, { idxSearchUrl: value })} placeholder="https://propertysearch.nexrealtygroup.com/agent-name" />
                </div>
              </section>

              <section className="user-detail-section">
                <div className="user-detail-section-head"><h4>Lead routing</h4><span>Controls Nex generated lead eligibility</span></div>
                <div className="user-routing-snapshot">
                  <span><strong>Lead Opt-In Status</strong><em className={classNames("access-pill", selectedLeadStatus?.tone === "green" && "green", selectedLeadStatus?.tone === "red" && "red", selectedLeadStatus?.tone === "amber" && "amber", selectedLeadStatus?.tone === "muted" && "muted")}>{selectedLeadStatus?.label || "Not set"}</em></span>
                  <span><strong>Date opted in</strong>{selectedUser.leadOptedInAt ? titleCaseDate(selectedUser.leadOptedInAt) : "Not recorded"}</span>
                  <span><strong>Rotation status</strong>{selectedUser.leadRotationStatus || "inactive"}</span>
                  <span><strong>Company lead eligible</strong>{companyLeadEligible(selectedUser) ? "Yes" : "No"}</span>
                  <span><strong>Max active Nex leads</strong>{selectedUser.maxActiveBrokerageLeads || 10}</span>
                  <span><strong>Markets/service areas</strong>{serviceAreaSummary(selectedUser)}</span>
                </div>
                <div className="user-edit-grid">
                <MarketAreaSelect label="Lead rotation market" value={editableUser(selectedUser).primaryMarketArea} onChange={(value) => updateEditing(selectedUser, { primaryMarketArea: value })} marketAreas={primaryMarketAreas} disabled={disabled} />
                <label className="toggle-field">
                  <input type="checkbox" checked={editableUser(selectedUser).leadRotationOptIn} onChange={(event) => updateEditing(selectedUser, { leadRotationOptIn: event.target.checked, leadRotationStatus: event.target.checked ? "active" : "inactive" })} />
                  <span>Nex generated lead rotation</span>
                </label>
                <Field label="Lead rotation status" value={editableUser(selectedUser).leadRotationStatus} onChange={(value) => updateEditing(selectedUser, { leadRotationStatus: value })} as="select" options={["inactive", "active", "paused", "suspended"]} />
                <Field label="Max active Nex leads" value={editableUser(selectedUser).maxActiveBrokerageLeads} onChange={(value) => updateEditing(selectedUser, { maxActiveBrokerageLeads: value })} />
                <StandardMultiSelect label="Lead counties" value={editableUser(selectedUser).serviceCounties} onChange={(value) => updateEditing(selectedUser, { serviceCounties: value })} options={adminServiceAreaOptions.counties} />
                <StandardMultiSelect label="Lead cities" value={editableUser(selectedUser).serviceCities} onChange={(value) => updateEditing(selectedUser, { serviceCities: value })} options={adminServiceAreaOptions.cities} />
                <Field label="Lead ZIPs" value={editableUser(selectedUser).serviceZipCodes} onChange={(value) => updateEditing(selectedUser, { serviceZipCodes: value })} placeholder="33602, 33701" />
                </div>
              </section>

              <section className="user-detail-section">
                <div className="user-detail-section-head"><h4>Bio and access</h4><span>Profile story, password, and setup links</span></div>
                <div className="user-edit-grid">
                  <Field label="Public bio" value={editableUser(selectedUser).publicBio} onChange={(value) => updateEditing(selectedUser, { publicBio: value })} as="textarea" placeholder="Consumer-facing bio" />
                  <Field label="New password" value={passwords[userIdFor(selectedUser)] || ""} onChange={(value) => setPasswords((current) => ({ ...current, [userIdFor(selectedUser)]: value }))} type="password" placeholder="Set/change password" />
                </div>
              <div className="user-profile-link-row">
                <Icon name="Globe2" />
                <span>{selectedUser.publicProfileEnabled === false ? "Profile unpublished" : selectedUser.publicProfilePath || `/site/agents/${editableUser(selectedUser).publicSlug || "agent"}`}</span>
                {selectedUser.agentSubdomainUrl && <em>{selectedUser.agentSubdomainUrl}</em>}
              </div>
              <div className={classNames("welcome-meta-card", selectedWelcomeState.status)}>
                <div>
                  <Icon name="Mail" />
                  <span>
                    <strong>Welcome email</strong>
                    <small>{selectedUser.welcomeEmailLastSentAt ? `Last sent ${titleCaseDate(selectedUser.welcomeEmailLastSentAt)}` : "Not sent yet"}</small>
                  </span>
                </div>
                <div>
                  <span>
                    <strong>{selectedUser.welcomeEmailLastSentBy || "No sender recorded"}</strong>
                    <small>{selectedUser.welcomeEmailLastSentByEmail || selectedUser.welcomeEmailLastDeliveryStatus || "Send a branded setup email when this account is ready."}</small>
                  </span>
                  {selectedUser.welcomeEmailLastDeliveryStatus && (
                    <em>{selectedUser.welcomeEmailLastDeliveryStatus === "sent" ? "Email sent" : "Setup link generated"}</em>
                  )}
                </div>
                <div>
                  <span>
                    <strong>Setup/password link</strong>
                    <small>{selectedUser.welcomeEmailSetupCompletedAt ? `Used ${titleCaseDate(selectedUser.welcomeEmailSetupCompletedAt)}` : "Not used yet or not tracked before this update"}</small>
                  </span>
                  <span>
                    <strong>Login/account</strong>
                    <small>{selectedUser.lastLoginAt ? `Last login ${titleCaseDate(selectedUser.lastLoginAt)}` : "Never logged in"} | Created {selectedUser.createdAt ? formatDate(selectedUser.createdAt) : "not recorded"}</small>
                  </span>
                </div>
                {selectedUser.recoveryNeedsReview && (
                  <p className="warning-text">
                    This profile was rebuilt from invite activity. Review phone, market, role, service area, and website details before resending the welcome email.
                  </p>
                )}
                <div>
                  <span>
                    <strong>Password reset</strong>
                    <small>{selectedUser.passwordResetLastRequestedAt ? `Last requested ${titleCaseDate(selectedUser.passwordResetLastRequestedAt)}` : "No reset link requested yet"}</small>
                  </span>
                  <span>
                    <strong>{selectedUser.passwordResetLastDeliveryStatus === "sent" ? "Email sent" : selectedUser.passwordResetLastDeliveryStatus === "pending" ? "Sending" : selectedUser.passwordResetLastDeliveryStatus ? "Link generated" : "No delivery status"}</strong>
                    <small>{[selectedUser.passwordResetLastProvider, selectedUser.passwordResetLastError].filter(Boolean).join(" | ") || "Click Reset Link to send or generate a secure link."}</small>
                  </span>
                </div>
                {selectedWelcomeState.message && <p>{selectedWelcomeState.message}</p>}
              </div>
              <div className="user-action-row">
                <button className="btn primary" onClick={() => saveUser(selectedUser)} disabled={disabled}>
                  <Icon name="Save" />
                  <span>Save Profile</span>
                </button>
                <button className="btn secondary" onClick={() => updatePassword(selectedUser)} disabled={disabled || !passwords[userIdFor(selectedUser)]}>
                  <Icon name="KeyRound" />
                  <span>Set Password</span>
                </button>
                <button className="btn secondary" onClick={() => generateResetLink(selectedUser)} disabled={disabled || selectedUser.active === false}>
                  <Icon name="Mail" />
                  <span>Reset Link</span>
                </button>
                <button className="btn secondary" onClick={() => setWelcomePreviewUser(selectedUser)} disabled={disabled || selectedUser.active === false}>
                  <Icon name="Eye" />
                  <span>Preview Email</span>
                </button>
                <button className="btn secondary" onClick={() => setWelcomeConfirmUser(selectedUser)} disabled={disabled || selectedUser.active === false || selectedWelcomeState.status === "sending"}>
                  <Icon name="Send" />
                  <span>{selectedWelcomeState.status === "sending" ? "Sending..." : selectedUser.welcomeEmailLastSentAt ? "Resend Welcome Email" : "Welcome Email"}</span>
                </button>
                <button className={classNames("btn", selectedUser.active === false ? "secondary" : "danger-soft")} onClick={() => toggleUser(selectedUser)} disabled={disabled}>
                  <Icon name={selectedUser.active === false ? "ArchiveRestore" : "Archive"} />
                  <span>{selectedUser.active === false ? "Restore" : "Archive"}</span>
                </button>
              </div>
              </section>
            </div>
          </aside>
        </div>
      )}

      {welcomeModalUser && (
        <div className="welcome-modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="welcome-email-modal-title">
          <div className="welcome-modal">
            <div className="welcome-modal-header">
              <div>
                <p className="eyebrow">{welcomeModalMode === "send" ? "Confirm send" : "Preview email"}</p>
                <h3 id="welcome-email-modal-title">{welcomeModalMode === "send" ? "Send welcome email?" : "Welcome email preview"}</h3>
                <p>{welcomeModalUser.name || "This agent"} will receive a secure password setup link at {welcomeModalUser.email}.</p>
              </div>
              <button className="icon-btn" type="button" onClick={() => { setWelcomeConfirmUser(null); setWelcomePreviewUser(null); }} title="Close welcome email modal"><Icon name="X" /></button>
            </div>
            <div className="welcome-email-summary">
              <span><strong>Recipient</strong>{welcomeModalUser.name || welcomeModalUser.email}</span>
              <span><strong>Email</strong>{welcomeModalUser.email}</span>
              <span><strong>Setup link</strong>Generated when sent, expires in 60 minutes</span>
            </div>
            {welcomeModalPreview && (
              <div className="welcome-email-preview">
                <strong>{welcomeModalPreview.subject}</strong>
                <pre>{welcomeModalPreview.body}</pre>
              </div>
            )}
            {welcomeModalMode === "send" && (
              <p className="welcome-modal-note">
                This sends a branded Nex Central onboarding email and creates a secure password setup link. Plain text passwords are never emailed.
              </p>
            )}
            {welcomeModalState.message && (
              <div className={classNames("welcome-send-status", welcomeModalState.status)}>
                {welcomeModalState.status === "sending" && <Icon name="LoaderCircle" />}
                {welcomeModalState.status === "success" && <Icon name="CheckCircle2" />}
                {welcomeModalState.status === "error" && <Icon name="AlertTriangle" />}
                <span>{welcomeModalState.message}</span>
              </div>
            )}
            <div className="welcome-modal-actions">
              <button className="btn secondary" type="button" onClick={() => { setWelcomeConfirmUser(null); setWelcomePreviewUser(null); }}>
                <Icon name="X" />
                <span>{welcomeModalState.status === "success" ? "Close" : "Cancel"}</span>
              </button>
              {welcomeModalMode === "preview" ? (
                <button className="btn primary" type="button" onClick={() => { setWelcomePreviewUser(null); setWelcomeConfirmUser(welcomeModalUser); }} disabled={disabled || welcomeModalUser.active === false}>
                  <Icon name="Send" />
                  <span>Send Welcome Email</span>
                </button>
              ) : (
                <button className="btn primary" type="button" onClick={() => sendWelcomeEmail(welcomeModalUser)} disabled={disabled || welcomeModalUser.active === false || welcomeModalState.status === "sending" || welcomeModalState.status === "success"}>
                  <Icon name="Send" />
                  <span>{welcomeModalState.status === "success" ? "Sent" : welcomeModalState.status === "sending" ? "Sending welcome email..." : "Send Welcome Email"}</span>
                </button>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function TemplateLibrary({ templates, setTemplates, brand, role, setSelectedTemplateId, setFields, setActivePage, setToast }) {
  const [draft, setDraft] = useState({
    name: "",
    category: "Custom",
    headline: "",
    badge: "",
    accent: brand.primaryColor,
    style: "classic"
  });
  const [query, setQuery] = useState("");
  const [category, setCategory] = useState("All");
  const [favorites, setFavorites] = useState(() => JSON.parse(localStorage.getItem("nex-template-favorites") || "[]"));
  const [recent, setRecent] = useState(() => JSON.parse(localStorage.getItem("nex-template-recent") || "[]"));
  const disabled = !isAdminRole(role);
  const categories = ["All", "Favorites", "Recently Used", ...Array.from(new Set(templates.map((template) => template.category || "Custom")))];
  const filteredTemplates = templates.filter((template) => {
    const search = `${template.name} ${template.category} ${template.headline} ${template.badge}`.toLowerCase();
    const matchesSearch = !query || search.includes(query.toLowerCase());
    const matchesCategory =
      category === "All" ||
      (category === "Favorites" && favorites.includes(template.id)) ||
      (category === "Recently Used" && recent.includes(template.id)) ||
      template.category === category;
    return matchesSearch && matchesCategory;
  });

  async function addTemplate() {
    if (!draft.name.trim()) return;
    try {
      const saved = await API.request("/api/templates", {
        method: "POST",
        body: JSON.stringify(draft)
      });
      setTemplates((current) => [saved, ...current]);
      setDraft({ name: "", category: "Custom", headline: "", badge: "", accent: brand.primaryColor, style: "classic" });
      setToast("Template added.");
    } catch (error) {
      setToast(error.message || "Could not add template.");
    }
  }

  async function updateTemplate(id, patch) {
    const currentTemplate = templates.find((template) => template.id === id) || {};
    let saved;
    try {
      saved = await API.request(`/api/templates/${encodeURIComponent(id)}`, {
        method: "PUT",
        body: JSON.stringify(patch)
      });
    } catch (error) {
      saved = await API.request("/api/templates", {
        method: "POST",
        body: JSON.stringify({ ...currentTemplate, ...patch, id })
      });
    }
    setTemplates((current) => current.map((template) => (template.id === id ? saved : template)));
  }

  async function deleteTemplate(id) {
    try {
      await API.request(`/api/templates/${encodeURIComponent(id)}`, { method: "DELETE" });
      setTemplates((current) => current.filter((template) => template.id !== id));
      setToast("Template deleted.");
    } catch (error) {
      setToast(error.message || "Could not delete template.");
    }
  }

  function useTemplate(template) {
    setSelectedTemplateId(template.id);
    setFields((current) => ({ ...current, marketingType: template.name }));
    const nextRecent = [template.id, ...recent.filter((id) => id !== template.id)].slice(0, 8);
    setRecent(nextRecent);
    localStorage.setItem("nex-template-recent", JSON.stringify(nextRecent));
    setActivePage("Marketing Studio");
  }

  function toggleFavorite(id) {
    const next = favorites.includes(id) ? favorites.filter((item) => item !== id) : [id, ...favorites];
    setFavorites(next);
    localStorage.setItem("nex-template-favorites", JSON.stringify(next));
  }

  return (
    <section className="template-layout premium-template-library">
      <div className="panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Template Library</p>
            <h3>Template library</h3>
          </div>
        </div>
        <input className="studio-search" value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search campaign, listing, social, recruiting..." />
        <div className="studio-filter-row">
          {categories.map((item) => (
            <button key={item} className={category === item ? "selected" : ""} onClick={() => setCategory(item)}>{item}</button>
          ))}
        </div>
        {disabled && <div className="suggestion-strip">Switch to Admin role to add or edit reusable templates.</div>}
        <div className={classNames("template-editor", disabled && "muted")}>
          <Field label="Template name" value={draft.name} onChange={(value) => setDraft((current) => ({ ...current, name: value }))} placeholder="Buyer Seminar Flyer" />
          <Field label="Category" value={draft.category} onChange={(value) => setDraft((current) => ({ ...current, category: value }))} />
          <Field label="Headline" value={draft.headline} onChange={(value) => setDraft((current) => ({ ...current, headline: value }))} placeholder="BUYER SEMINAR" />
          <Field label="Badge" value={draft.badge} onChange={(value) => setDraft((current) => ({ ...current, badge: value }))} placeholder="Free Event" />
          <Field label="Layout style" value={draft.style} onChange={(value) => setDraft((current) => ({ ...current, style: value }))} as="select" options={flyerLayoutOptions.map((option) => option.id)} />
          <label className="field color-field">
            <span>Accent</span>
            <input type="color" value={draft.accent} onChange={(event) => setDraft((current) => ({ ...current, accent: event.target.value }))} disabled={disabled} />
          </label>
          <button className="btn primary" onClick={addTemplate} disabled={disabled}>
            <Icon name="Plus" />
            <span>Add Template</span>
          </button>
        </div>
      </div>

      <div className="template-grid">
        {filteredTemplates.map((template) => (
          <article className="template-card" key={template.id}>
            <MiniTemplatePreview template={template} brand={brand} />
            <p>{template.category}</p>
            <input value={template.name} onChange={(event) => updateTemplate(template.id, { name: event.target.value })} disabled={disabled} />
            <input value={template.headline} onChange={(event) => updateTemplate(template.id, { headline: event.target.value })} disabled={disabled} />
            <span>{template.badge}</span>
            <span>{template.style || "classic"}</span>
            <div className="template-card-actions">
              <button className="btn secondary small-btn" onClick={() => useTemplate(template)}><Icon name="MousePointerClick" /><span>Use</span></button>
              <button className="icon-btn small" onClick={() => toggleFavorite(template.id)} title="Favorite">
                <Icon name={favorites.includes(template.id) ? "Star" : "StarOff"} size={15} />
              </button>
              {!disabled && <button className="icon-btn small" onClick={() => deleteTemplate(template.id)} title="Delete template"><Icon name="Trash2" size={15} /></button>}
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

function SocialGenerator({ output, setToast }) {
  return (
    <section className="panel">
      <div className="panel-heading">
        <div>
          <p className="eyebrow">Social media</p>
          <h3>Captions, hashtags, reels, and posts</h3>
        </div>
      </div>
      {output ? (
        <MarketingOutput output={output} setToast={setToast} />
      ) : (
        <EmptyState icon="Megaphone" title="Generate a social campaign" body="Choose Facebook, Instagram, LinkedIn, Story, or Reel Script in the input panel." />
      )}
    </section>
  );
}

function EmailSmsGenerator({ output, setToast }) {
  if (!output) {
    return (
      <section className="panel">
        <EmptyState icon="Mail" title="Generate email and SMS copy" body="Ask the assistant for listing announcements, open house invites, nurture messages, recruiting emails, and text scripts." />
      </section>
    );
  }

  return (
    <section className="email-sms-grid">
      <article className="panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">Email</p>
            <h3>Ready-to-send draft</h3>
          </div>
          <button className="icon-btn" onClick={() => copyToClipboard(output.emailVersion, setToast)} title="Copy email">
            <Icon name="Copy" />
          </button>
        </div>
        <pre className="copy-pre">{output.emailVersion}</pre>
      </article>
      <article className="panel">
        <div className="panel-heading">
          <div>
            <p className="eyebrow">SMS</p>
            <h3>Short text script</h3>
          </div>
          <button className="icon-btn" onClick={() => copyToClipboard(output.smsVersion, setToast)} title="Copy SMS">
            <Icon name="Copy" />
          </button>
        </div>
        <p className="sms-card">{output.smsVersion}</p>
      </article>
    </section>
  );
}

const PUBLIC_SITE_BASE = "/site";
const PUBLIC_PROPERTY_GATE_LIMIT = 2;
const PUBLIC_PROPERTY_GATE_COUNT_KEY = "nex-public-property-view-count";
const PUBLIC_PROPERTY_GATE_REGISTERED_KEY = "nex-public-property-search-registered";
const PUBLIC_LISTING_SOURCE_AGENT_KEY = "nex-public-listing-source-agent";
const PUBLIC_CONSUMER_SESSION_KEY = "nex-public-consumer-session";
const NEX_AGENT_PORTAL_URL = "https://www.mynexcentral.com/";
// mynexcentral.com is the private agent portal. The public consumer host moves to nexrealtygroup.com when DNS is ready.
const PUBLIC_BROKERAGE_WEBSITE_HOSTS = ["nexrealtygroup.com", "www.nexrealtygroup.com"];
const publicSiteAliases = {
  "/search": "/site/search",
  "/idx": "/site/search",
  "/homes-for-sale": "/site/homes/florida-homes-for-sale",
  "/property-search": "/site/search",
  "/buy": "/site/buy",
  "/sell": "/site/sell",
  "/rent": "/site/rent",
  "/agents": "/site/agents",
  "/join-nex": "/site/join",
  "/careers": "/site/join",
  "/best-florida-brokerage": "/site/brokerage/best-florida-brokerage",
  "/new-agent-friendly-real-estate-brokerage": "/site/brokerage/new-agent-friendly-real-estate-brokerage",
  "/exp-realty-alternative": "/site/brokerage/exp-realty-alternative",
  "/keller-williams-alternative": "/site/brokerage/keller-williams-alternative",
  "/contact": "/site/contact",
  "/privacy": "/site/privacy-policy",
  "/privacy-policy": "/site/privacy-policy",
  "/terms": "/site/terms-and-conditions",
  "/terms-and-conditions": "/site/terms-and-conditions",
  "/terms-and-services": "/site/terms-and-conditions",
  "/terms-of-service": "/site/terms-and-conditions",
  "/terms-of-use": "/site/terms-and-conditions",
  "/sms-consent": "/site/sms-consent",
  "/sms-opt-in": "/site/sms-consent",
  "/text-consent": "/site/sms-consent",
  "/texting-terms": "/site/sms-consent",
  "/sms-notice": "/site/sms-notice",
  "/nex-central-sms-notice": "/site/sms-notice",
  "/internal-sms-notice": "/site/sms-notice",
  "/agent-sms-notice": "/site/sms-notice",
  "/nex-central-sms-consent": "/site/nex-central-sms-consent",
  "/nex-central-sms-opt-in": "/site/nex-central-sms-consent",
  "/internal-sms-consent": "/site/nex-central-sms-consent",
  "/agent-sms-consent": "/site/nex-central-sms-consent"
};
[
  "join-nex-realty",
  "best-florida-brokerage",
  "florida-real-estate-brokerage",
  "100-percent-commission-real-estate-brokerage-florida",
  "real-estate-brokerage-commission-plans-florida",
  "cloud-based-real-estate-brokerage-florida",
  "real-estate-brokerage-with-training-florida",
  "real-estate-brokerage-for-new-agents-florida",
  "real-estate-brokerage-for-producing-agents-florida",
  "real-estate-team-brokerage-florida",
  "nex-realty-vs-exp-realty",
  "nex-realty-vs-real-brokerage",
  "nex-realty-vs-lpt-realty",
  "nex-realty-vs-keller-williams",
  "nex-realty-vs-remax",
  "nex-realty-vs-century-21",
  "nex-realty-vs-future-home-realty",
  "real-estate-brokerage-tampa",
  "real-estate-brokerage-st-petersburg",
  "real-estate-brokerage-clearwater",
  "real-estate-brokerage-orlando",
  "real-estate-brokerage-miami",
  "real-estate-brokerage-fort-lauderdale",
  "real-estate-brokerage-west-palm-beach",
  "real-estate-brokerage-lakeland",
  "real-estate-brokerage-sarasota",
  "real-estate-brokerage-naples",
  "real-estate-brokerage-jacksonville",
  "real-estate-brokerage-treasure-coast"
].forEach((slug) => {
  publicSiteAliases[`/${slug}`] = `/site/recruiting/${slug}`;
});

const publicSiteNav = [
  ["Home Search", "/site/search"],
  ["Buy", "/site/buy"],
  ["Sell", "/site/sell"],
  ["Join Nex", "/site/join"],
  ["About", "/site/about"],
  ["Contact/Login", "/site/contact"]
];

const publicConsumerSearchSeoPages = [
  {
    slug: "florida-homes-for-sale",
    title: "Florida Homes for Sale",
    h1: "Florida homes for sale",
    intro: "Search Florida homes with local Nex Realty guidance for showings, questions, saved searches, and next steps.",
    filters: { status: "For Sale" },
    leadTitle: "Save a Florida home search",
    leadType: "buyer",
    leadIntent: "Save search",
    cta: "Save Search",
    related: ["tampa-homes-for-sale", "orlando-homes-for-sale", "miami-homes-for-sale", "florida-pool-homes"]
  },
  ...[
    ["tampa-homes-for-sale", "Tampa Homes for Sale", "Tampa homes for sale", "Search homes in Tampa, compare neighborhoods, request showings, and ask a local Nex agent for help.", { search: "Tampa", status: "For Sale" }],
    ["st-petersburg-homes-for-sale", "St. Petersburg Homes for Sale", "St. Petersburg homes for sale", "Explore St. Petersburg homes, condos, waterfront options, and Gulf Coast neighborhoods with Nex Realty.", { search: "St. Petersburg", status: "For Sale" }],
    ["clearwater-homes-for-sale", "Clearwater Homes for Sale", "Clearwater homes for sale", "Browse Clearwater homes and condos near beaches, central Pinellas, and surrounding communities.", { search: "Clearwater", status: "For Sale" }],
    ["orlando-homes-for-sale", "Orlando Homes for Sale", "Orlando homes for sale", "Search Orlando homes for sale, from Central Florida neighborhoods to relocation and investment options.", { search: "Orlando", status: "For Sale" }],
    ["miami-homes-for-sale", "Miami Homes for Sale", "Miami homes for sale", "Search Miami homes, condos, and luxury properties with Nex Realty local guidance.", { search: "Miami", status: "For Sale" }]
  ].map(([slug, title, h1, intro, filters]) => ({
    slug,
    title,
    h1,
    intro,
    filters,
    leadTitle: `Get ${h1.replace(/^[a-z]/, (char) => char.toUpperCase())} alerts`,
    leadType: "buyer",
    leadIntent: "Get new listing alerts",
    cta: "Get Listing Alerts",
    related: ["florida-homes-for-sale", "florida-open-houses", "florida-price-reduced-homes", "florida-pool-homes"]
  })),
  {
    slug: "pinellas-county-condos",
    title: "Pinellas County Condos for Sale",
    h1: "Pinellas County condos for sale",
    intro: "Search condos in Pinellas County, including Gulf Coast, St. Petersburg, Clearwater, and nearby communities.",
    filters: { county: "Pinellas", propertyType: "Condominium", status: "For Sale" },
    leadTitle: "Send me Pinellas condo alerts",
    leadType: "buyer",
    leadIntent: "Get new listing alerts",
    cta: "Get Condo Alerts",
    related: ["st-petersburg-homes-for-sale", "clearwater-homes-for-sale", "florida-waterfront-homes", "florida-condos-for-sale"]
  },
  ...[
    ["florida-waterfront-homes", "Florida Waterfront Homes for Sale", "Florida waterfront homes", "Search waterfront homes across Florida and ask Nex Realty for local guidance on insurance, inspections, flood zones, and showing logistics.", { search: "waterfront", status: "For Sale" }, "Waterfront"],
    ["tampa-bay-waterfront-homes", "Tampa Bay Waterfront Homes for Sale", "Tampa Bay waterfront homes", "Explore waterfront homes across Tampa Bay, including Hillsborough, Pinellas, Pasco, and nearby coastal communities.", { search: "Tampa Bay waterfront", status: "For Sale" }, "Waterfront"],
    ["florida-pool-homes", "Florida Pool Homes for Sale", "Florida pool homes", "Search Florida homes with pools and request help comparing outdoor space, insurance, maintenance, and neighborhood fit.", { search: "pool", status: "For Sale" }, "Pool Homes"],
    ["florida-condos-for-sale", "Florida Condos for Sale", "Florida condos for sale", "Search Florida condos and get help understanding HOA, condo association, insurance, financing, and lifestyle considerations.", { propertyType: "Condominium", status: "For Sale" }, "Condos"],
    ["florida-townhomes-for-sale", "Florida Townhomes for Sale", "Florida townhomes for sale", "Browse Florida townhomes and ask a Nex agent for help comparing fees, communities, and resale factors.", { propertyType: "Townhouse", status: "For Sale" }, "Townhomes"],
    ["florida-new-listings", "Florida New Listings", "New listings in Florida", "See fresh Florida listings and request alerts when homes matching your search hit the market.", { status: "For Sale" }, "New Listings"],
    ["florida-open-houses", "Florida Open Houses", "Florida open houses", "Find open house opportunities and ask Nex Realty for private showing options when open-house times are not available.", { search: "open house", status: "For Sale" }, "Open Houses"],
    ["florida-price-reduced-homes", "Florida Price Reduced Homes", "Price reduced homes in Florida", "Search price reduced homes and ask a Nex agent about negotiation strategy, condition, and market context.", { search: "price reduced", status: "For Sale" }, "Price Reduced"],
    ["florida-luxury-homes", "Florida Luxury Homes for Sale", "Florida luxury homes", "Search luxury homes across Florida with guidance around privacy, showings, financing, insurance, and local market positioning.", { search: "luxury", status: "For Sale", minPrice: "1000000" }, "Luxury"]
  ].map(([slug, title, h1, intro, filters, lifestyle]) => ({
    slug,
    title,
    h1,
    intro,
    filters,
    lifestyle,
    leadTitle: `Get ${lifestyle.toLowerCase()} updates`,
    leadType: "buyer",
    leadIntent: "Get property updates",
    cta: "Get Updates",
    related: ["florida-homes-for-sale", "tampa-homes-for-sale", "orlando-homes-for-sale", "miami-homes-for-sale"]
  })),
  {
    slug: "florida-first-time-home-buyer",
    title: "Florida First-Time Home Buyer Help",
    h1: "Florida first-time home buyer help",
    intro: "Start your first home search with guidance around budget, pre-approval, showings, offers, inspections, insurance, and closing steps.",
    filters: { status: "For Sale" },
    leadTitle: "Schedule a buyer consultation",
    leadType: "buyer",
    leadIntent: "Schedule buyer consultation",
    cta: "Schedule Consultation",
    related: ["florida-homes-for-sale", "florida-condos-for-sale", "florida-townhomes-for-sale", "florida-open-houses"]
  },
  {
    slug: "florida-home-value",
    title: "Florida Home Value Estimate",
    h1: "Find out what your Florida home is worth",
    intro: "Request a local home value review and seller strategy from Nex Realty before you decide when and how to sell.",
    filters: { status: "For Sale" },
    leadTitle: "Request a home value estimate",
    leadType: "seller",
    leadIntent: "Request home value estimate",
    cta: "Request Home Value",
    related: ["tampa-homes-for-sale", "st-petersburg-homes-for-sale", "orlando-homes-for-sale", "miami-homes-for-sale"]
  }
];

const publicConsumerSearchSeoPageMap = Object.fromEntries(publicConsumerSearchSeoPages.map((page) => [page.slug, page]));

publicConsumerSearchSeoPages.forEach((page) => {
  publicSiteAliases[`/${page.slug}`] = `/site/homes/${page.slug}`;
});

const publicCoveredAreas = [
  "Apollo Beach",
  "Brandon",
  "Clearwater",
  "Dunedin",
  "Gulfport",
  "Largo",
  "Lithia",
  "Lutz",
  "Madeira Beach",
  "Miami",
  "Orlando",
  "Palm Harbor",
  "Plant City",
  "Riverview",
  "Saint Petersburg",
  "Safety Harbor",
  "Seminole",
  "St Pete Beach",
  "Tampa",
  "Tarpon Springs",
  "Temple Terrace",
  "Treasure Island",
  "Valrico",
  "Wesley Chapel"
];

const publicLegalPages = {
  "privacy-policy": {
    eyebrow: "Privacy Policy",
    title: "Nex Realty Privacy Policy",
    updated: "Last updated: June 2026",
    intro:
      "This Privacy Policy explains how Nex Realty collects, uses, protects, and shares information submitted through Nex Realty websites, Nex Central, property search forms, recruiting forms, agent pages, communication tools, and related services.",
    sections: [
      {
        title: "Information We Collect",
        body:
          "We may collect information you provide directly, including your name, email address, phone number, property search criteria, property address, preferred market, real estate needs, agent recruiting information, account details, communication preferences, and messages submitted through forms or Nex Central."
      },
      {
        title: "How We Use Information",
        body:
          "We use information to respond to inquiries, route leads to the appropriate Nex Realty agent or management team, provide real estate services, manage Nex Central accounts, send operational alerts, support transaction and production workflows, improve our website, prevent fraud, and comply with legal, MLS, brokerage, security, and regulatory obligations."
      },
      {
        title: "Text Messaging And SMS Consent",
        body:
          "If you provide a mobile number and opt in, Nex Realty may send text messages related to real estate inquiries, property search activity, agent communications, Nex Central account alerts, lead notifications, reminders, administrative announcements, and security verification codes. Message frequency varies. Message and data rates may apply. Reply STOP to opt out and HELP for help."
      },
      {
        title: "Mobile Information Is Not Sold Or Shared For Marketing",
        body:
          "Mobile phone numbers, SMS consent, text messaging opt-in data, and text messaging originator information will not be sold, rented, or shared with third parties or affiliates for their marketing or promotional purposes. We may share information with service providers only as needed to operate our systems, deliver messages, support real estate services, comply with law, or protect security."
      },
      {
        title: "Lead Routing And Agent Pages",
        body:
          "Consumer inquiries from the main Nex Realty website, IDX/search pages, agent profile pages, agent subdomains, and recruiting pages may be routed to Nex Realty agents, staff, or management based on the source, location, service area, inquiry type, and internal routing rules."
      },
      {
        title: "Cookies, Analytics, And Website Data",
        body:
          "Our websites may use cookies, analytics, local storage, and similar technologies to remember preferences, measure website performance, improve user experience, support saved searches, prevent abuse, and understand how visitors interact with Nex Realty pages."
      },
      {
        title: "How We Protect Information",
        body:
          "We use reasonable administrative, technical, and organizational safeguards designed to protect personal information. No online system can be guaranteed completely secure, so users should avoid sending sensitive information unless requested through an approved secure channel."
      },
      {
        title: "Your Choices",
        body:
          "You may request updates to your contact information, ask to stop receiving marketing communications, reply STOP to opt out of eligible text messages, or contact Nex Realty for privacy questions. Some account, transaction, compliance, security, or legal records may need to be retained."
      },
      {
        title: "Contact",
        body:
          "For privacy questions, contact Nex Realty at info@mynexrealty.com or 772-403-1259. Mailing address: Nex Realty, 710 94th Avenue N., #302, St. Petersburg, FL 33702."
      }
    ]
  },
  "terms-and-conditions": {
    eyebrow: "Terms & Conditions",
    title: "Nex Realty Terms & Conditions",
    updated: "Last updated: June 2026",
    intro:
      "These Terms & Conditions describe the terms for using Nex Realty websites, Nex Central, property search tools, lead forms, agent pages, recruiting pages, communication tools, and related services.",
    sections: [
      {
        title: "Use Of The Website And Services",
        body:
          "By using Nex Realty websites or submitting information through our forms, you agree to use the services for lawful purposes and to provide accurate information. Nex Realty may update, suspend, or change website features at any time."
      },
      {
        title: "Real Estate Information",
        body:
          "Property information, market data, estimates, calculators, AI-assisted content, and search tools are provided for general informational purposes only. Listings, prices, availability, taxes, fees, measurements, schools, financing terms, and market data should be independently verified by buyers, sellers, renters, agents, MLS/provider data, lenders, title companies, inspectors, attorneys, or other appropriate professionals."
      },
      {
        title: "No Legal, Tax, Or Financial Advice",
        body:
          "Nex Realty does not provide legal, tax, lending, insurance, accounting, or investment advice through the website. Users should consult qualified professionals before making legal, financial, or real estate decisions."
      },
      {
        title: "SMS/Text Messaging Terms",
        body:
          "By providing your mobile phone number and opting in, you agree to receive text messages from Nex Realty related to real estate services, property inquiries, account alerts, lead notifications, reminders, administrative announcements, and security verification. Message frequency varies. Message and data rates may apply. Reply STOP to opt out and HELP for help. Consent to receive text messages is not a condition of purchasing goods or services."
      },
      {
        title: "Opt-Out And Help",
        body:
          "You may opt out of eligible text messages by replying STOP. You may request help by replying HELP or contacting Nex Realty at info@mynexrealty.com or 772-403-1259. Some security, account, compliance, or transaction-related communications may still be provided where permitted or required."
      },
      {
        title: "IDX, MLS, And Third-Party Data",
        body:
          "Some property search information may be supplied by MLS, IDX, data providers, listing brokers, vendors, or third-party platforms. Nex Realty does not guarantee the accuracy, completeness, update frequency, or availability of third-party data. Provider-required attribution, disclaimers, and usage restrictions apply where shown."
      },
      {
        title: "User Submissions And Lead Routing",
        body:
          "When you submit a form, request information, create search access, contact an agent, or request recruiting information, Nex Realty may route that inquiry to an appropriate agent, staff member, broker, admin, or management contact based on source, geography, service area, and inquiry type."
      },
      {
        title: "Intellectual Property",
        body:
          "Nex Realty names, branding, site content, page designs, templates, software, workflows, and other materials are owned by Nex Realty or its licensors and may not be copied, scraped, resold, or misused without permission."
      },
      {
        title: "Limitation Of Liability",
        body:
          "To the fullest extent permitted by law, Nex Realty is not liable for indirect, incidental, special, consequential, or punitive damages arising from use of the website, unavailable services, third-party data, communication delays, or reliance on informational content."
      },
      {
        title: "Contact",
        body:
          "For questions about these terms, contact Nex Realty at info@mynexrealty.com or 772-403-1259. Mailing address: Nex Realty, 710 94th Avenue N., #302, St. Petersburg, FL 33702."
      }
    ]
  },
  "sms-consent": {
    eyebrow: "SMS Consent",
    title: "Nex Realty SMS Consent & Opt-In",
    updated: "Last updated: June 2026",
    intro:
      "This page explains how Nex Realty LLC collects text messaging consent and provides a public opt-in path for SMS campaign review.",
    sections: [
      {
        title: "How visitors opt in",
        body:
          "Visitors opt in from public Nex Realty pages by entering their name, email address, and mobile phone number, choosing or describing their real estate inquiry, and actively checking the unchecked SMS consent box before submitting."
      },
      {
        title: "Consent shown beside the checkbox",
        body:
          "I agree that Nex Realty LLC and its agents, representatives, and trusted service providers may contact me about my inquiry by phone, text message, email, or automated technology. Consent is not required to purchase goods or services. Message and data rates may apply. I can opt out at any time."
      },
      {
        title: "Message frequency and help",
        body:
          "Message frequency varies based on the inquiry, account activity, property search activity, saved searches, lead notifications, reminders, administrative announcements, and security verification needs. Recipients can reply STOP to opt out and HELP for help."
      },
      {
        title: "Privacy and terms",
        body:
          "Nex Realty's Privacy Policy states that mobile numbers and SMS consent are not sold, rented, or shared with third parties or affiliates for their marketing or promotional purposes. Terms & Conditions and Privacy Policy links are shown with the form."
      }
    ]
  },
  "sms-notice": {
    eyebrow: "Nex Central SMS Notice",
    title: "Nex Central SMS Notification Consent",
    updated: "Last updated: June 2026",
    intro:
      "This public notice documents how Nex Realty agents and staff opt in to internal operational text notifications from Nex Central so SMS campaign reviewers can verify the call to action without logging in.",
    sections: [
      {
        title: "Program name and purpose",
        body:
          "Nex Central SMS Notifications is an internal operational notification program for active Nex Realty agents and staff. Messages include new lead alerts, agent website lead alerts, lead follow-up reminders, transaction and task deadline reminders, admin support alerts, account-related platform notifications, and security-related account alerts."
      },
      {
        title: "Who receives messages",
        body:
          "Messages are sent only to Nex Realty agents and staff who have a private Nex Central account, provide or confirm their mobile phone number, and opt in to the SMS categories they want to receive. This internal campaign is not used for public consumer marketing."
      },
      {
        title: "How agents and staff opt in",
        body:
          "Users opt in after logging in to Nex Central. From Communication Center or profile notification preferences, the user enters or confirms their mobile phone number, enables SMS notification categories such as lead alerts, task reminders, transaction reminders, admin announcements, account notifications, or security alerts, and agrees to the SMS disclosure shown with the preferences."
      },
      {
        title: "Opt-in disclosure shown in Nex Central",
        body:
          "I agree to receive SMS/text notifications from Nex Realty and Nex Central at the mobile number provided. Messages may include lead alerts, task reminders, transaction reminders, admin/account notifications, and security-related account alerts. Message frequency varies. Message and data rates may apply. Reply STOP to opt out or HELP for help."
      },
      {
        title: "Opt-out, help, terms, and privacy",
        body:
          "Recipients can reply STOP to opt out of eligible text messages and HELP for help. Users can also disable SMS notification categories inside Nex Central or contact Nex Realty at info@mynexrealty.com or 772-403-1259. Terms & Conditions and Privacy Policy links are public, and the Privacy Policy states that mobile numbers and SMS consent are not sold, rented, or shared with third parties or affiliates for their marketing or promotional purposes."
      }
    ]
  },
  "nex-central-sms-consent": {
    eyebrow: "Nex Central SMS Consent",
    title: "Nex Central SMS Notification Consent",
    updated: "Last updated: June 2026",
    intro:
      "This public notice documents how Nex Realty agents and staff opt in to internal operational text notifications from Nex Central so SMS campaign reviewers can verify the call to action without logging in.",
    sections: [
      {
        title: "Program name and purpose",
        body:
          "Nex Central SMS Notifications is an internal operational notification program for active Nex Realty agents and staff. Messages include new lead alerts, agent website lead alerts, lead follow-up reminders, transaction and task deadline reminders, admin support alerts, account-related platform notifications, and security-related account alerts."
      },
      {
        title: "Who receives messages",
        body:
          "Messages are sent only to Nex Realty agents and staff who have a private Nex Central account, provide or confirm their mobile phone number, and opt in to the SMS categories they want to receive. This internal campaign is not used for public consumer marketing."
      },
      {
        title: "How agents and staff opt in",
        body:
          "Users opt in after logging in to Nex Central. From Communication Center or profile notification preferences, the user enters or confirms their mobile phone number, enables SMS notification categories such as lead alerts, task reminders, transaction reminders, admin announcements, account notifications, or security alerts, and agrees to the SMS disclosure shown with the preferences."
      },
      {
        title: "Opt-in disclosure shown in Nex Central",
        body:
          "I agree to receive SMS/text notifications from Nex Realty and Nex Central at the mobile number provided. Messages may include lead alerts, task reminders, transaction reminders, admin/account notifications, and security-related account alerts. Message frequency varies. Message and data rates may apply. Reply STOP to opt out or HELP for help."
      },
      {
        title: "Opt-out, help, terms, and privacy",
        body:
          "Recipients can reply STOP to opt out of eligible text messages and HELP for help. Users can also disable SMS notification categories inside Nex Central or contact Nex Realty at info@mynexrealty.com or 772-403-1259. Terms & Conditions and Privacy Policy links are public, and the Privacy Policy states that mobile numbers and SMS consent are not sold, rented, or shared with third parties or affiliates for their marketing or promotional purposes."
      }
    ]
  }
};

const floridaHeroPhotos = [
  {
    label: "Florida coastline",
    url: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=1800&q=82"
  },
  {
    label: "Florida palm-lined neighborhood",
    url: "https://images.unsplash.com/photo-1570082676341-5aa5b699c7c9?auto=format&fit=crop&w=1800&q=82"
  },
  {
    label: "Miami waterfront high-rise real estate",
    url: "https://images.pexels.com/photos/9768488/pexels-photo-9768488.jpeg?auto=compress&cs=tinysrgb&w=1800"
  },
  {
    label: "Florida luxury home lifestyle",
    url: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=1800&q=82"
  },
  {
    label: "Florida waterfront homes",
    url: "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=1800&q=82"
  },
  {
    label: "Florida bright modern living",
    url: "https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?auto=format&fit=crop&w=1800&q=82"
  }
];

function normalizePublicWebsitePath(pathname) {
  const cleanPath = String(pathname || "").split(/[?#]/)[0].replace(/\/+$/, "") || "/";
  if (cleanPath === PUBLIC_SITE_BASE || cleanPath.startsWith(`${PUBLIC_SITE_BASE}/`)) return cleanPath;
  if (cleanPath.startsWith("/agent/")) return cleanPath;
  return publicSiteAliases[cleanPath] || "";
}

function getPublicPropertyViewCount() {
  try {
    return Math.max(0, Number(window.localStorage.getItem(PUBLIC_PROPERTY_GATE_COUNT_KEY)) || 0);
  } catch (error) {
    return 0;
  }
}

function isPublicPropertyGateRegistered() {
  try {
    return window.localStorage.getItem(PUBLIC_PROPERTY_GATE_REGISTERED_KEY) === "true";
  } catch (error) {
    return false;
  }
}

function rememberPublicPropertyGateRegistration(form = {}) {
  try {
    window.localStorage.setItem(PUBLIC_PROPERTY_GATE_REGISTERED_KEY, "true");
    window.localStorage.setItem(
      "nex-public-property-search-lead",
      JSON.stringify({
        name: form.name || "",
        email: form.email || "",
        phone: form.phone || "",
        registeredAt: new Date().toISOString()
      })
    );
  } catch (error) {
    // Browsers can block storage; the CRM submission still succeeds without it.
  }
}

function rememberPublicPropertyView() {
  const nextCount = getPublicPropertyViewCount() + 1;
  try {
    window.localStorage.setItem(PUBLIC_PROPERTY_GATE_COUNT_KEY, String(nextCount));
  } catch (error) {
    // Keep browsing usable if storage is unavailable.
  }
  return nextCount;
}

function rememberPublicListingSourceAgent(sourceAgentSlug = "") {
  try {
    if (sourceAgentSlug) window.sessionStorage.setItem(PUBLIC_LISTING_SOURCE_AGENT_KEY, sourceAgentSlug);
    else window.sessionStorage.removeItem(PUBLIC_LISTING_SOURCE_AGENT_KEY);
  } catch (error) {
    // Session storage is a convenience for attribution, not a blocker.
  }
}

function getRememberedPublicListingSourceAgent() {
  try {
    return window.sessionStorage.getItem(PUBLIC_LISTING_SOURCE_AGENT_KEY) || "";
  } catch (error) {
    return "";
  }
}

function isPublicWebsitePath(pathname) {
  return Boolean(normalizePublicWebsitePath(pathname));
}

function isBrokeragePublicWebsiteHost() {
  const host = window.location.hostname.toLowerCase();
  return PUBLIC_BROKERAGE_WEBSITE_HOSTS.includes(host);
}

function getPublicAgentSlugFromHost() {
  const host = window.location.hostname.toLowerCase();
  if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".onrender.com")) return "";
  const labels = host.split(".").filter(Boolean);
  if (labels.length < 3) return "";
  const [subdomain] = labels;
  const reserved = new Set(["", "www", "admin", "api", "app", "site", "login", "support", "privacy", "terms", "mail", "email", "idx", "search", "propertysearch", "blog"]);
  return reserved.has(subdomain) ? "" : subdomain.replace(/[^a-z0-9-]/g, "");
}

function publicPathParts(pathname) {
  const normalized = normalizePublicWebsitePath(pathname);
  if (normalized.startsWith("/agent/")) return normalized.replace(/^\/agent\/?/, "agent/").split("/").filter(Boolean);
  return normalized.replace(/^\/site\/?/, "").split("/").filter(Boolean);
}

function readPublicConsumerSession() {
  try {
    const parsed = JSON.parse(window.localStorage.getItem(PUBLIC_CONSUMER_SESSION_KEY) || "null");
    if (!parsed?.consumerId || !parsed?.sessionToken) return null;
    return parsed;
  } catch (error) {
    return null;
  }
}

function rememberPublicConsumerSession(session) {
  if (!session?.consumerId || !session?.sessionToken) return null;
  try {
    window.localStorage.setItem(PUBLIC_CONSUMER_SESSION_KEY, JSON.stringify(session));
  } catch (error) {
    // Local storage may be unavailable in private browsing.
  }
  return session;
}

function publicConsumerSessionPayload() {
  const session = readPublicConsumerSession();
  return session ? { consumerId: session.consumerId, consumerSessionToken: session.sessionToken } : {};
}

async function recordPublicConsumerActivity(activity = {}) {
  const session = readPublicConsumerSession();
  if (!session?.consumerId || !session?.sessionToken) return null;
  try {
    const payload = await API.request("/api/public/consumer-activity", {
      method: "POST",
      retries: 0,
      body: JSON.stringify({
        consumerId: session.consumerId,
        consumerSessionToken: session.sessionToken,
        ...activity
      })
    });
    if (payload.consumerSession) rememberPublicConsumerSession(payload.consumerSession);
    return payload;
  } catch (error) {
    return null;
  }
}

function propertyPriceLabel(listing) {
  if (!listing) return "";
  const price = formatCurrency(listing.price || 0);
  return /rent/i.test(listing.status || "") ? `${price}/mo` : price;
}

function publicInitials(name = "Nex Agent") {
  return String(name)
    .split(/\s+/)
    .filter(Boolean)
    .map((part) => part[0])
    .join("")
    .slice(0, 2)
    .toUpperCase();
}

function firstNameFromName(name = "") {
  return String(name || "").trim().split(/\s+/).filter(Boolean)[0] || "there";
}

const PUBLIC_LEAD_CONSENT_TEXT = "I agree that Nex Realty LLC and its agents, representatives, and trusted service providers may contact me about my inquiry by phone, text message, email, or automated technology. Consent is not required to purchase goods or services. Message and data rates may apply. I can opt out at any time.";
const PUBLIC_BLOCKED_EMAILS = new Set(["test@test.com", "fake@fake.com"]);
const PUBLIC_BLOCKED_NAMES = new Set(["test", "asdf"]);
const PUBLIC_BLOCKED_PHONES = new Set(["1234567890", "0000000000", "1111111111"]);

function publicNormalizePhoneDigits(value = "") {
  const digits = String(value || "").replace(/\D/g, "");
  if (digits.length === 11 && digits.startsWith("1")) return digits.slice(1);
  return digits;
}

function publicIsValidEmail(value = "") {
  return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i.test(String(value || "").trim());
}

function validatePublicLeadCapture({ name = "", email = "", phone = "", intent = "", consent = false }, options = {}) {
  const errors = [];
  const cleanName = String(name || "").trim();
  const emailValue = String(email || "").trim().toLowerCase();
  const phoneDigits = publicNormalizePhoneDigits(phone);
  const realNameCharacters = cleanName.replace(/[^a-z]/gi, "");
  const requireIntent = options.requireIntent !== false;

  if (realNameCharacters.length < 2) errors.push("Enter your real name.");
  if (PUBLIC_BLOCKED_NAMES.has(cleanName.toLowerCase())) errors.push("Please enter your real name, not placeholder text.");
  if (!publicIsValidEmail(emailValue)) errors.push("Enter a valid email address.");
  if (PUBLIC_BLOCKED_EMAILS.has(emailValue)) errors.push("Please enter a real email address.");
  if (phoneDigits.length !== 10) errors.push("Enter a valid 10-digit phone number.");
  if (PUBLIC_BLOCKED_PHONES.has(phoneDigits)) errors.push("Please enter a real phone number.");
  if (requireIntent && !String(intent || "").trim()) errors.push("Choose what you need help with.");
  if (!consent) errors.push("Please check the consent box so Nex Realty can contact you about this inquiry.");

  return {
    ok: errors.length === 0,
    errors,
    message: errors.join(" "),
    phoneDigits
  };
}

function publicListingsFromPayload(payload) {
  if (Array.isArray(payload)) return payload;
  if (Array.isArray(payload?.items)) return payload.items;
  if (Array.isArray(payload?.listings)) return payload.listings;
  if (Array.isArray(payload?.featuredListings)) return payload.featuredListings;
  return [];
}

function publicWebsiteSyncStats(data = {}) {
  const sync = data.websiteSync || {};
  return {
    sourceOfTruth: sync.sourceOfTruth || "Nex Central",
    publishedAgentCount: Number(sync.publishedAgentCount || (data.agents || []).length || 0),
    featuredListingCount: Number(sync.featuredListingCount || (data.featuredListings || []).length || 0),
    marketCount: Number(sync.marketCount || (data.markets || []).length || 0),
    crmName: sync.crmName || "Nex CRM",
    chatName: sync.chatName || "Nex Chat",
    updatedAt: sync.updatedAt || ""
  };
}

function NexPublicWebsite({ brand, currentPath, setCurrentPath, agentSlugFromHost = "" }) {
  const [siteData, setSiteData] = useState({ agents: [], featuredListings: [], markets: [], websiteSync: {}, brandSettings: brand });
  const [loading, setLoading] = useState(true);
  const [toast, setToast] = useState("");
  const [conciergeOpen, setConciergeOpen] = useState(false);
  const [conciergeContext, setConciergeContext] = useState({});
  const [consumerSession, setConsumerSession] = useState(() => readPublicConsumerSession());
  const [valuationOpen, setValuationOpen] = useState(false);
  const [propertyLeadGate, setPropertyLeadGate] = useState(() => ({
    open: false,
    pendingListing: null,
    pendingIntent: "",
    sourceAgentSlug: agentSlugFromHost,
    registered: isPublicPropertyGateRegistered(),
    viewCount: getPublicPropertyViewCount()
  }));

  useEffect(() => {
    let mounted = true;
    API.request("/api/public/website")
      .then((payload) => {
        if (!mounted) return;
        setSiteData({ ...payload, brandSettings: { ...brand, ...(payload.brandSettings || {}) } });
      })
      .catch(() => setToast("Public website data could not load."))
      .finally(() => mounted && setLoading(false));
    return () => {
      mounted = false;
    };
  }, []);

  useEffect(() => {
    if (!toast) return;
    const timer = setTimeout(() => setToast(""), 2800);
    return () => clearTimeout(timer);
  }, [toast]);

  useEffect(() => {
    const stored = readPublicConsumerSession();
    if (!stored?.consumerId || !stored?.sessionToken) return;
    let cancelled = false;
    const params = new URLSearchParams({
      consumerId: stored.consumerId,
      sessionToken: stored.sessionToken,
      sourcePage: currentPath || window.location.pathname
    });
    API.request(`/api/public/consumer-session?${params.toString()}`)
      .then((payload) => {
        if (cancelled) return;
        if (payload.recognized && payload.consumerSession) {
          rememberPublicConsumerSession(payload.consumerSession);
          setConsumerSession(payload.consumerSession);
        }
      })
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, []);

  function navigate(path) {
    window.history.pushState({}, "", path);
    setCurrentPath(path);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  function openPublicConcierge(context = {}) {
    setConciergeContext(context || {});
    setConciergeOpen(true);
  }

  function openListingWithLeadGate(listing, nextSourceAgentSlug = agentSlugFromHost, intent = "") {
    if (!listing?.id) return;
    rememberPublicListingSourceAgent(nextSourceAgentSlug || "");
    recordPublicConsumerActivity({
      activityType: "viewed_listing",
      message: `Viewed listing ${listing.mlsNumber || listing.providerListingId || listing.id}.`,
      intent: intent || "viewed_listing",
      leadId: consumerSession?.latestLeadId || "",
      mlsId: listing.mlsNumber || listing.providerListingId || "",
      criteria: { listingId: listing.id, city: listing.city, price: listing.price },
      websiteSlug: nextSourceAgentSlug || ""
    });
    const intentQuery = intent ? `?intent=${encodeURIComponent(intent)}` : "";
    if (isPublicPropertyGateRegistered()) {
      navigate(`/site/listings/${listing.id}${intentQuery}`);
      return;
    }

    const viewCount = getPublicPropertyViewCount();
    if (viewCount >= PUBLIC_PROPERTY_GATE_LIMIT) {
      setPropertyLeadGate((current) => ({
        ...current,
        open: true,
        pendingListing: listing,
        pendingIntent: intent || "",
        sourceAgentSlug: nextSourceAgentSlug || "",
        registered: false,
        viewCount
      }));
      return;
    }

    const nextCount = rememberPublicPropertyView();
    setPropertyLeadGate((current) => ({ ...current, viewCount: nextCount }));
    navigate(`/site/listings/${listing.id}${intentQuery}`);
  }

  function closePropertyLeadGate() {
    setPropertyLeadGate((current) => ({ ...current, open: false, pendingListing: null, pendingIntent: "" }));
    navigate("/site/search");
  }

  async function submitPropertyLeadGate(form) {
    const listing = propertyLeadGate.pendingListing || {};
    const sourceAgentSlug = propertyLeadGate.sourceAgentSlug || agentSlugFromHost || "";
    const leadType = /rent/i.test(listing.status || "") ? "renter" : "buyer";
    const listingLabel = [listing.address, listing.city, listing.county].filter(Boolean).join(", ");
    const payload = await API.request("/api/public/leads", {
      method: "POST",
      body: JSON.stringify({
        ...publicConsumerSessionPayload(),
        ...form,
        type: leadType,
        city: form.city || listing.city || "",
        county: form.county || listing.county || "",
        zip: form.zip || listing.zip || "",
        priceRange: form.priceRange || propertyPriceLabel(listing),
        timeline: form.timeline || "Actively searching",
        notes: [form.notes, listingLabel ? `Registered after viewing property search results for ${listingLabel}.` : "Registered after viewing property search results."].filter(Boolean).join("\n\n"),
        sourcePage: listing.mlsNumber ? `Lead Gate ${listing.mlsNumber}` : "Property Search Lead Gate",
        listingId: listing.id || "",
        mlsNumber: listing.mlsNumber || listing.stellarListingId || listing.providerListingId || "",
        propertyAddress: listing.address || "",
        preferredArea: [form.city || listing.city, form.county || listing.county, form.zip || listing.zip].filter(Boolean).join(", "),
        sourceAgentSlug,
        leadSource: sourceAgentSlug ? "Agent Property Search Signup" : "Property Search Signup",
        idxProvider: listing.idxSourceProvider || "Nex Realty Property Search",
        idxIntent: `Forced registration after ${PUBLIC_PROPERTY_GATE_LIMIT} property views`,
        sourceSystem: "Nex Website Lead Gate",
        formName: "Property Search Signup",
        consent: form.consent
      })
    });
    if (payload.consumerSession) {
      const remembered = rememberPublicConsumerSession(payload.consumerSession);
      if (remembered) setConsumerSession(remembered);
    }
    rememberPublicPropertyGateRegistration(form);
    setPropertyLeadGate((current) => ({
      ...current,
      open: false,
      pendingListing: null,
      pendingIntent: "",
      registered: true,
      viewCount: getPublicPropertyViewCount()
    }));
    setToast(payload.message || "Search access created. A Nex agent will follow up.");
    if (listing.id) {
      const intentQuery = propertyLeadGate.pendingIntent ? `?intent=${encodeURIComponent(propertyLeadGate.pendingIntent)}` : "";
      navigate(`/site/listings/${listing.id}${intentQuery}`);
    }
  }

  const normalizedCurrentPath = normalizePublicWebsitePath(currentPath) || currentPath;
  const routeParts = publicPathParts(normalizedCurrentPath);
  const route = routeParts[0] || "home";
  const routeId = routeParts[1] || "";
  const querySourceAgentSlug = new URLSearchParams(window.location.search).get("agent") || "";
  const pathSourceAgentSlug = route === "agent" ? routeId : "";
  const activeSourceAgentSlug = agentSlugFromHost || pathSourceAgentSlug || querySourceAgentSlug;
  const activeSourceAgent = activeSourceAgentSlug
    ? (siteData.agents || []).find((agent) => [agent.websiteSlug, agent.subdomainSlug, agent.publicSlug].filter(Boolean).includes(activeSourceAgentSlug))
    : null;
  const commonProps = {
    data: siteData,
    navigate,
    setToast,
    brand: siteData.brandSettings || brand,
    sourceAgentSlug: activeSourceAgentSlug,
    onViewListing: openListingWithLeadGate,
    onTalkAgent: openPublicConcierge,
    onHomeValue: () => setValuationOpen(true)
  };

  let page;
  if (agentSlugFromHost) {
    page = <PublicAgentProfile {...commonProps} slug={agentSlugFromHost} hostedSubdomain />;
  } else if (route === "agent" && routeId) {
    page = <PublicAgentProfile {...commonProps} slug={routeId} hostedSubdomain />;
  } else if (route === "search" || route === "idx") {
    page = <PublicPropertySearchV2 {...commonProps} />;
  } else if (route === "listings" && routeId) {
    page = <PublicListingDetail {...commonProps} listingId={routeId} />;
  } else if (route === "agents" && routeId) {
    page = <PublicAgentProfile {...commonProps} slug={routeId} />;
  } else if (route === "agents") {
    page = <PublicAgentDirectory {...commonProps} />;
  } else if (route === "join") {
    page = <PublicJoinNex {...commonProps} />;
  } else if (route === "recruiting" && routeId) {
    page = <PublicRecruitingSeoPage {...commonProps} slug={routeId} />;
  } else if (route === "brokerage" && routeId) {
    page = <PublicBrokerageSeoPage {...commonProps} topic={routeId} />;
  } else if (route === "markets" && routeId) {
    page = <PublicMarketPage {...commonProps} marketId={routeId} />;
  } else if (route === "homes" && routeId) {
    page = <PublicSearchSeoPage {...commonProps} pageId={routeId} />;
  } else if (route === "sms-consent") {
    page = <PublicSmsConsentPage {...commonProps} />;
  } else if (publicLegalPages[route]) {
    page = <PublicLegalPage {...commonProps} pageId={route} />;
  } else if (["buy", "sell", "rent", "about", "contact", "finance", "resources"].includes(route)) {
    page = <PublicInfoPage {...commonProps} page={route} />;
  } else {
    page = <PublicHomeExperience {...commonProps} />;
  }

  return (
    <main className="public-site">
      <PublicHeader
        brand={siteData.brandSettings || brand}
        navigate={navigate}
        currentPath={normalizedCurrentPath}
        hostedAgentSlug={activeSourceAgentSlug}
        onTalkAgent={openPublicConcierge}
      />
      {loading ? <PublicSkeleton /> : page}
      <PublicFooter brand={siteData.brandSettings || brand} navigate={navigate} idx={siteData.idx} />
      {!conciergeOpen && !valuationOpen && !propertyLeadGate.open && (
        <PublicNiaFloatingLauncher
          consumerSession={consumerSession}
          onOpen={() => openPublicConcierge({ sourcePage: normalizedCurrentPath, message: "I need help with the Nex Realty website." })}
        />
      )}
      {conciergeOpen && (
        <PublicNiaConciergeModal
          sourceAgentSlug={activeSourceAgentSlug}
          sourceAgentName={conciergeContext.sourceAgentName || activeSourceAgent?.name || ""}
          consumerSession={consumerSession}
          onConsumerSessionUpdate={(session) => {
            const remembered = rememberPublicConsumerSession(session);
            if (remembered) setConsumerSession(remembered);
          }}
          context={conciergeContext}
          setToast={setToast}
          onClose={() => {
            setConciergeOpen(false);
            setConciergeContext({});
          }}
          navigate={navigate}
        />
      )}
      {valuationOpen && (
        <PublicHomeValueModal
          sourceAgentSlug={activeSourceAgentSlug}
          onConsumerSessionUpdate={(session) => {
            const remembered = rememberPublicConsumerSession(session);
            if (remembered) setConsumerSession(remembered);
          }}
          setToast={setToast}
          onClose={() => setValuationOpen(false)}
        />
      )}
      {propertyLeadGate.open && (
        <PublicPropertyLeadGateModal
          listing={propertyLeadGate.pendingListing}
          sourceAgentSlug={propertyLeadGate.sourceAgentSlug}
          onBack={closePropertyLeadGate}
          onSubmit={submitPropertyLeadGate}
        />
      )}
      <Toast message={toast} />
    </main>
  );
}

function PublicNiaFloatingLauncher({ consumerSession = null, onOpen }) {
  const firstName = consumerSession?.contactCaptured ? consumerSession.firstName : "";
  return (
    <button className="public-nia-floating-launcher" type="button" onClick={onOpen} aria-label="Open NIA concierge">
      <span><Icon name="Sparkles" /></span>
      <strong>{firstName ? `Welcome back, ${firstName}` : "Ask NIA"}</strong>
      <small>{firstName ? "Continue your search" : "Search, value, tours, questions"}</small>
    </button>
  );
}

function PublicHeader({ brand, navigate, currentPath, hostedAgentSlug, onTalkAgent }) {
  return (
    <header className="public-header-wrap">
      <MarketPulseTicker endpoint="/api/public/market-pulse" variant="public" />
      <div className="public-topbar">
        <a href="tel:7724031259">772-403-1259</a>
        <button onClick={() => onTalkAgent ? onTalkAgent() : navigate("/site/contact")} type="button">Talk to Nex</button>
        <button onClick={() => navigate("/site/search")} type="button">Search Homes</button>
        <button onClick={() => { window.location.href = NEX_AGENT_PORTAL_URL; }} type="button">Agent Login</button>
      </div>
      <div className="public-header">
        <button className="public-brand" onClick={() => navigate("/site")} type="button">
          <Wordmark brand={brand} variant="light" className="public-logo" />
          <span>Welcome to your New Era eXperience</span>
        </button>
        {!hostedAgentSlug && (
          <nav className="public-nav">
            {publicSiteNav.map(([label, path]) => (
              <button key={path} className={currentPath === path || (path !== "/site" && currentPath.startsWith(path)) ? "active" : ""} onClick={() => navigate(path)} type="button">
                {label}
              </button>
            ))}
          </nav>
        )}
        <div className="public-header-actions">
          <button className="btn secondary" onClick={() => navigate("/site/search")} type="button">Search Homes</button>
          <button className="btn primary" onClick={() => navigate("/site/join")} type="button">Join Nex</button>
        </div>
      </div>
    </header>
  );
}

function PublicHomeExperience({ data, navigate, setToast, sourceAgentSlug = "", onViewListing, brand, onTalkAgent, onHomeValue }) {
  const liveIdxEnabled = Boolean(data.idx?.apiConfigured && data.idx?.apiFetchEnabled);
  const [featured, setFeatured] = useState(() => liveIdxEnabled ? [] : publicListingsFromPayload({ featuredListings: data.featuredListings || [] }));

  useEffect(() => {
    let mounted = true;
    API.request(`/api/public/listings?limit=6&homepage=1&ts=${Date.now()}`)
      .then((payload) => {
        if (!mounted) return;
        const listings = publicListingsFromPayload(payload);
        if (listings.length) setFeatured(listings);
        else if (liveIdxEnabled) setFeatured([]);
      })
      .catch(() => {
        if (mounted) setFeatured(liveIdxEnabled ? [] : publicListingsFromPayload({ featuredListings: data.featuredListings || [] }));
      });
    return () => {
      mounted = false;
    };
  }, [data.featuredListings, liveIdxEnabled]);

  return (
    <>
      <section className="public-site-main-hero">
        <div className="public-hero-photo-cycle" aria-hidden="true">
          {floridaHeroPhotos.map((photo, index) => (
            <span
              key={photo.label}
              style={{
                backgroundImage: `url("${photo.url}")`,
                animationDelay: `${index * 8}s`,
                animationDuration: `${floridaHeroPhotos.length * 8}s`
              }}
            />
          ))}
        </div>
        <div className="public-site-main-hero-content">
          <Wordmark brand={brand} variant="light" className="public-main-hero-logo" />
          <div className="public-hero-heading">
            <p className="eyebrow">Florida home search</p>
            <h1>Find Your Next Florida Home</h1>
            <p>Search Florida homes, save favorites, request showings, and connect with a local Nex Realty agent when you are ready.</p>
          </div>
          <PublicHeroSearchBox navigate={navigate} onTalkAgent={onTalkAgent} onHomeValue={onHomeValue} seedListings={featured.length ? featured : data.featuredListings || []} sourceAgentSlug={sourceAgentSlug} />
        </div>
      </section>

      <PublicCountySearchCarousels
        navigate={navigate}
        sourceAgentSlug={sourceAgentSlug}
        onViewListing={onViewListing}
        fallbackListings={featured.length ? featured : data.featuredListings || []}
      />

      <PublicConsumerPaths navigate={navigate} onTalkAgent={onTalkAgent} onHomeValue={onHomeValue} />

      <PublicRecruitingSoftCta navigate={navigate} />

      <PublicIdxComplianceNotice idx={data.idx} compact />
    </>
  );
}

const PUBLIC_COUNTY_SEARCH_CAROUSELS = [
  { region: "Tampa Bay", county: "Hillsborough County", title: "Hillsborough County homes", description: "Tampa, Brandon, Riverview, Plant City, and nearby communities." },
  { region: "Tampa Bay", county: "Pinellas County", title: "Pinellas County homes", description: "St. Petersburg, Clearwater, Largo, beaches, condos, and waterfront options." },
  { region: "Orlando Area", county: "Orange County", title: "Orange County homes", description: "Orlando, Winter Park, Lake Nona, Dr. Phillips, and surrounding areas." },
  { region: "Orlando Area", county: "Seminole County", title: "Seminole County homes", description: "Lake Mary, Sanford, Altamonte Springs, Oviedo, and north Orlando communities." },
  { region: "South Florida", county: "Miami-Dade County", title: "Miami-Dade County homes", description: "Miami, Miami Beach, Doral, Coral Gables, Aventura, and nearby markets." },
  { region: "South Florida", county: "Broward County", title: "Broward County homes", description: "Fort Lauderdale, Hollywood, Pembroke Pines, Weston, and coastal searches." }
];

function PublicCountySearchCarousels({ navigate, sourceAgentSlug = "", onViewListing, fallbackListings = [] }) {
  const [countyListings, setCountyListings] = useState({});
  const [loadingCounties, setLoadingCounties] = useState(true);

  useEffect(() => {
    let mounted = true;
    setLoadingCounties(true);
    Promise.all(PUBLIC_COUNTY_SEARCH_CAROUSELS.map(async (countySearch) => {
      const params = new URLSearchParams({
        county: countySearch.county,
        status: "Active",
        limit: "15",
        page: "1",
        sort: "newest"
      });
      try {
        const payload = await API.request(`/api/site/listings/search?${params.toString()}`, { retries: 0 });
        return [countySearch.county, publicListingsFromPayload(payload).slice(0, 15)];
      } catch (_) {
        return [countySearch.county, []];
      }
    }))
      .then((entries) => {
        if (!mounted) return;
        setCountyListings(Object.fromEntries(entries));
      })
      .finally(() => {
        if (mounted) setLoadingCounties(false);
      });
    return () => {
      mounted = false;
    };
  }, []);

  function countySearchUrl(county) {
    const params = new URLSearchParams({ county, status: "Active", sort: "newest" });
    if (sourceAgentSlug) params.set("agent", sourceAgentSlug);
    return `/site/search?${params.toString()}`;
  }

  function listingFallbackForCounty(county) {
    return (Array.isArray(fallbackListings) ? fallbackListings : [])
      .filter((listing) => String(listing.county || "").toLowerCase().includes(String(county || "").replace(/\s+county$/i, "").toLowerCase()))
      .slice(0, 4);
  }

  return (
    <section className="public-section public-county-carousel-section">
      <div className="public-county-carousel-intro">
        <div>
          <p className="eyebrow">County home search</p>
          <h2>Start searching. Let Nex guide the way.</h2>
          <small>Browse for your Nex home with us.</small>
        </div>
        <button className="btn secondary" type="button" onClick={() => navigate("/site/search")}>Search All Properties</button>
      </div>

      <div className="public-county-carousel-stack">
        {PUBLIC_COUNTY_SEARCH_CAROUSELS.map((countySearch, index) => {
          const listings = countyListings[countySearch.county] || listingFallbackForCounty(countySearch.county);
          return (
            <PublicCountyCarouselRow
              key={countySearch.county}
              index={index}
              countySearch={countySearch}
              listings={listings}
              loading={loadingCounties}
              navigate={navigate}
              countySearchUrl={countySearchUrl}
              onViewListing={onViewListing}
              sourceAgentSlug={sourceAgentSlug}
            />
          );
        })}
      </div>
    </section>
  );
}

function PublicCountyCarouselRow({ index = 0, countySearch, listings = [], loading = false, navigate, countySearchUrl, onViewListing, sourceAgentSlug = "" }) {
  const visibleListings = Array.isArray(listings) ? listings.slice(0, 15) : [];
  const loopListings = visibleListings.length > 1 ? [...visibleListings, ...visibleListings] : visibleListings;
  const cycleDuration = `${Math.max(50, visibleListings.length * 6)}s`;
  return (
    <article className="public-county-carousel-row">
      <div className="public-county-carousel-heading">
        <div>
          <span>{countySearch.region} - newest listings</span>
          <h3>{countySearch.title}</h3>
          <p>{countySearch.description}</p>
        </div>
        <div className="public-county-carousel-actions">
          <button className="public-county-carousel-link" type="button" onClick={() => navigate(countySearchUrl(countySearch.county))}>
            See all properties
            <Icon name="ArrowRight" size={16} />
          </button>
        </div>
      </div>
      <div
        className={classNames("public-county-carousel-track", visibleListings.length < 2 && "no-cycle")}
        style={{ "--county-carousel-duration": cycleDuration, "--county-carousel-delay": `${index * -5}s` }}
        aria-label={`${countySearch.county} newest listings`}
      >
        {loopListings.length > 0 && (
          <div className="public-county-carousel-strip">
            {loopListings.map((listing, listingIndex) => (
              <div key={`${listing.id}-${listingIndex}`} className="public-county-carousel-card">
                <PublicListingCard listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />
              </div>
            ))}
          </div>
        )}
        {!visibleListings.length && (
          <div className="public-county-carousel-empty">
            <Icon name="Home" />
            <strong>{loading ? "Loading newest homes" : "Open the full county search"}</strong>
            <span>{loading ? "We are pulling the latest listings for this county." : "See all available properties and refine by price, beds, baths, or map view."}</span>
            <button type="button" onClick={() => navigate(countySearchUrl(countySearch.county))}>View county search</button>
          </div>
        )}
      </div>
    </article>
  );
}

function publicSearchParamsFromFilters(filters = {}) {
  const params = new URLSearchParams();
  Object.entries(publicSearchNormalizeFiltersForIntent(filters) || {}).forEach(([key, value]) => {
    const text = String(value || "").trim();
    if (text) params.set(key, text);
  });
  return params;
}

function publicSearchSuggestionDetail(parts = []) {
  return parts.filter(Boolean).map((part) => String(part).trim()).filter(Boolean).join(" - ");
}

function publicSearchSuggestionTypeLabel(type) {
  if (type === "zip") return "ZIP";
  if (type === "address") return "Address";
  if (type === "city") return "City";
  if (type === "county") return "County";
  if (type === "mls") return "MLS";
  if (type === "propertyType") return "Type";
  if (type === "quick") return "Search";
  return type || "Search";
}

const PUBLIC_SEARCH_MARKET_SUGGESTIONS = [
  { type: "city", label: "Tampa", detail: "Hillsborough County, FL", queryPatch: { city: "Tampa", search: "Tampa" }, icon: "MapPin", aliases: ["tampa bay"] },
  { type: "city", label: "St. Petersburg", detail: "Pinellas County, FL", queryPatch: { city: "St. Petersburg", search: "St. Petersburg" }, icon: "MapPin", aliases: ["st pete", "st petersburg", "saint petersburg", "st petersberg", "st petersburgh"] },
  { type: "city", label: "Clearwater", detail: "Pinellas County, FL", queryPatch: { city: "Clearwater", search: "Clearwater" }, icon: "MapPin" },
  { type: "city", label: "Orlando", detail: "Orange County, FL", queryPatch: { city: "Orlando", search: "Orlando" }, icon: "MapPin" },
  { type: "city", label: "Miami", detail: "Miami-Dade County, FL", queryPatch: { city: "Miami", search: "Miami" }, icon: "MapPin", aliases: ["miami fl", "miamj", "miami dade"] },
  { type: "city", label: "Miami Beach", detail: "Miami-Dade County, FL", queryPatch: { city: "Miami Beach", search: "Miami Beach" }, icon: "MapPin", aliases: ["south beach", "miami-beach"] },
  { type: "city", label: "Coral Gables", detail: "Miami-Dade County, FL", queryPatch: { city: "Coral Gables", search: "Coral Gables" }, icon: "MapPin" },
  { type: "city", label: "Doral", detail: "Miami-Dade County, FL", queryPatch: { city: "Doral", search: "Doral" }, icon: "MapPin" },
  { type: "city", label: "Aventura", detail: "Miami-Dade County, FL", queryPatch: { city: "Aventura", search: "Aventura" }, icon: "MapPin" },
  { type: "city", label: "Hialeah", detail: "Miami-Dade County, FL", queryPatch: { city: "Hialeah", search: "Hialeah" }, icon: "MapPin" },
  { type: "city", label: "Homestead", detail: "Miami-Dade County, FL", queryPatch: { city: "Homestead", search: "Homestead" }, icon: "MapPin" },
  { type: "city", label: "Fort Lauderdale", detail: "Broward County, FL", queryPatch: { city: "Fort Lauderdale", search: "Fort Lauderdale" }, icon: "MapPin", aliases: ["ft lauderdale"] },
  { type: "city", label: "Hollywood", detail: "Broward County, FL", queryPatch: { city: "Hollywood", search: "Hollywood" }, icon: "MapPin" },
  { type: "city", label: "Boca Raton", detail: "Palm Beach County, FL", queryPatch: { city: "Boca Raton", search: "Boca Raton" }, icon: "MapPin" },
  { type: "city", label: "West Palm Beach", detail: "Palm Beach County, FL", queryPatch: { city: "West Palm Beach", search: "West Palm Beach" }, icon: "MapPin" },
  { type: "city", label: "Sarasota", detail: "Sarasota County, FL", queryPatch: { city: "Sarasota", search: "Sarasota" }, icon: "MapPin" },
  { type: "city", label: "Bradenton", detail: "Manatee County, FL", queryPatch: { city: "Bradenton", search: "Bradenton" }, icon: "MapPin" },
  { type: "city", label: "Naples", detail: "Collier County, FL", queryPatch: { city: "Naples", search: "Naples" }, icon: "MapPin" },
  { type: "city", label: "Fort Myers", detail: "Lee County, FL", queryPatch: { city: "Fort Myers", search: "Fort Myers" }, icon: "MapPin", aliases: ["ft myers"] },
  { type: "city", label: "Lakeland", detail: "Polk County, FL", queryPatch: { city: "Lakeland", search: "Lakeland" }, icon: "MapPin" },
  { type: "city", label: "Winter Haven", detail: "Polk County, FL", queryPatch: { city: "Winter Haven", search: "Winter Haven" }, icon: "MapPin" },
  { type: "city", label: "Kissimmee", detail: "Osceola County, FL", queryPatch: { city: "Kissimmee", search: "Kissimmee" }, icon: "MapPin" },
  { type: "city", label: "Davenport", detail: "Polk County, FL", queryPatch: { city: "Davenport", search: "Davenport" }, icon: "MapPin" },
  { type: "county", label: "Miami-Dade County", detail: "South Florida", queryPatch: { county: "Miami-Dade County", search: "Miami-Dade County" }, icon: "Map", aliases: ["miami dade", "dade county"] },
  { type: "county", label: "Broward County", detail: "South Florida", queryPatch: { county: "Broward County", search: "Broward County" }, icon: "Map" },
  { type: "county", label: "Hillsborough County", detail: "Tampa Bay", queryPatch: { county: "Hillsborough County", search: "Hillsborough County" }, icon: "Map" },
  { type: "county", label: "Pinellas County", detail: "Tampa Bay", queryPatch: { county: "Pinellas County", search: "Pinellas County" }, icon: "Map" },
  { type: "county", label: "Orange County", detail: "Orlando area", queryPatch: { county: "Orange County", search: "Orange County" }, icon: "Map" },
  { type: "county", label: "Seminole County", detail: "Orlando area", queryPatch: { county: "Seminole County", search: "Seminole County" }, icon: "Map" },
  { type: "county", label: "Palm Beach County", detail: "South Florida", queryPatch: { county: "Palm Beach County", search: "Palm Beach County" }, icon: "Map" }
];

function publicSearchComparableText(value = "") {
  return String(value || "")
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/&/g, " and ")
    .replace(/\bsaint\b/g, "st")
    .replace(/[^a-z0-9]+/g, "");
}

function publicSearchWords(value = "") {
  return String(value || "")
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, " ")
    .trim()
    .split(/\s+/)
    .filter(Boolean);
}

function publicSearchEditDistance(a = "", b = "") {
  const left = publicSearchComparableText(a);
  const right = publicSearchComparableText(b);
  if (!left) return right.length;
  if (!right) return left.length;
  if (Math.abs(left.length - right.length) > 3) return 99;
  const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
  for (let i = 1; i <= left.length; i += 1) {
    let diagonal = previous[0];
    previous[0] = i;
    for (let j = 1; j <= right.length; j += 1) {
      const above = previous[j];
      const cost = left[i - 1] === right[j - 1] ? 0 : 1;
      previous[j] = Math.min(previous[j] + 1, previous[j - 1] + 1, diagonal + cost);
      diagonal = above;
    }
  }
  return previous[right.length];
}

function publicSearchSuggestionTypePriority(type = "") {
  return { city: 0, county: 1, zip: 2, mls: 3, address: 4, propertyType: 5, quick: 6 }[type] ?? 9;
}

function publicSearchSuggestionScore(type, label, detail, termText, aliases = []) {
  if (!termText) return 50;
  const rawTerm = String(termText || "").trim().toLowerCase();
  const compactTerm = publicSearchComparableText(rawTerm);
  const labelText = String(label || "").trim().toLowerCase();
  const digits = rawTerm.replace(/\D/g, "");
  if (type === "zip") {
    if (digits.length === 5 && labelText === digits) return 0;
    if (digits.length >= 3 && labelText.startsWith(digits)) return 3;
  }
  if (type === "quick") return 42;
  if (type === "mls" && labelText === rawTerm) return 2;
  let best = 80;
  [label, detail, ...(Array.isArray(aliases) ? aliases : [])].filter(Boolean).forEach((value) => {
    const compact = publicSearchComparableText(value);
    if (!compact || !compactTerm) return;
    if (compact === compactTerm) best = Math.min(best, 0);
    else if (compact.startsWith(compactTerm)) best = Math.min(best, type === "city" || type === "county" ? 4 : 8);
    else if (compact.includes(compactTerm)) best = Math.min(best, type === "address" ? 18 : 12);
    else if (compactTerm.length >= 4) {
      const distance = publicSearchEditDistance(compactTerm, compact);
      const ratio = distance / Math.max(compactTerm.length, compact.length);
      if (distance <= 1) best = Math.min(best, 16);
      else if (distance <= 2 && ratio <= 0.34) best = Math.min(best, 24);
      else if (distance <= 3 && ratio <= 0.24) best = Math.min(best, 30);
    }
    if (publicSearchWords(value).some((word) => word.startsWith(rawTerm))) best = Math.min(best, 8);
  });
  return best;
}

function publicSearchSuggestionMatchesTerm(suggestion = {}, term = "") {
  const rawTerm = String(term || "").trim();
  if (!rawTerm) return true;
  if (suggestion.type === "quick") return rawTerm.length >= 2;
  const score = typeof suggestion.score === "number"
    ? suggestion.score
    : publicSearchSuggestionScore(suggestion.type, suggestion.label, suggestion.detail, rawTerm, suggestion.aliases);
  const intent = publicSearchTermIntent(rawTerm);
  if (suggestion.type === "address" && !intent.looksLikeAddress) {
    return score <= 18;
  }
  if (suggestion.type === "propertyType") return score <= 24;
  return score <= 42;
}

function publicSearchTermIntent(term = "") {
  const raw = String(term || "").trim();
  const lower = raw.toLowerCase();
  const digits = raw.replace(/\D/g, "");
  const looksLikeZip = /^\d{3,5}$/.test(raw);
  const looksLikeMls = /^(mls\s*)?[a-z]{0,4}\d{5,}$/i.test(raw) && !looksLikeZip;
  const looksLikeAddress = /^\d+\s+/.test(raw) || /\b(street|st|avenue|ave|road|rd|drive|dr|lane|ln|court|ct|circle|cir|way|place|pl|boulevard|blvd|trail|trl|terrace|ter|highway|hwy|unit|apt|suite)\b/i.test(lower);
  return { raw, lower, digits, looksLikeZip, looksLikeMls, looksLikeAddress };
}

function publicSearchNormalizeFiltersForIntent(filters = {}) {
  const next = { ...(filters || {}) };
  const search = String(next.search || next.q || "").trim();
  const intent = publicSearchTermIntent(search);
  if (intent.looksLikeZip && intent.digits.length === 5 && !String(next.zip || "").trim()) {
    next.search = intent.digits;
    next.zip = intent.digits;
  } else if (intent.looksLikeMls) {
    next.search = intent.raw.replace(/^mls\s*/i, "");
  } else if (intent.looksLikeAddress) {
    next.search = intent.raw;
  }
  return next;
}

function publicSearchSuggestionOptions(listings = [], term = "", options = {}) {
  const requireMatch = Boolean(options.requireMatch);
  const limit = Math.max(1, Number(options.limit || 8) || 8);
  const termText = String(term || "").trim().toLowerCase();
  const intent = publicSearchTermIntent(term);
  const suggestions = [];
  const seen = new Set();

  function addSuggestion(type, label, detail, queryPatch, icon, scoreOverride, aliases = []) {
    const safeLabel = String(label || "").trim();
    if (!safeLabel) return;
    const safeDetail = String(detail || "").trim();
    const key = `${type}:${safeLabel.toLowerCase()}`;
    if (seen.has(key)) return;
    const score = typeof scoreOverride === "number" ? scoreOverride : publicSearchSuggestionScore(type, safeLabel, safeDetail, termText, aliases);
    const suggestion = {
      type,
      label: safeLabel,
      value: safeLabel,
      detail: safeDetail,
      icon,
      score,
      queryPatch: { search: safeLabel, ...(queryPatch || {}) }
    };
    if (requireMatch && termText && !publicSearchSuggestionMatchesTerm({ ...suggestion, aliases }, termText)) return;
    seen.add(key);
    suggestions.push(suggestion);
  }

  if (termText) {
    if (intent.looksLikeZip) {
      const zip = intent.digits.slice(0, 5);
      addSuggestion("zip", zip, "Search by ZIP code", { zip, search: zip }, "Hash", 0);
    } else if (intent.looksLikeMls) {
      addSuggestion("mls", intent.raw.replace(/^mls\s*/i, ""), "Search by MLS number", { search: intent.raw.replace(/^mls\s*/i, "") }, "Hash", 0);
    } else if (intent.looksLikeAddress) {
      addSuggestion("address", intent.raw, "Search by address", { search: intent.raw }, "Home", 0);
    } else if (termText.length >= 2) {
      addSuggestion("quick", intent.raw, "Search city, neighborhood, county, or keyword", { search: intent.raw }, "Search", 6);
    }
  }

  PUBLIC_SEARCH_MARKET_SUGGESTIONS.forEach((suggestion) => {
    addSuggestion(suggestion.type, suggestion.label, suggestion.detail, suggestion.queryPatch, suggestion.icon, undefined, suggestion.aliases);
  });

  (Array.isArray(listings) ? listings : []).forEach((listing = {}) => {
    const address = [listing.address, listing.city, listing.state || "FL"].filter(Boolean).join(", ");
    const price = propertyPriceLabel(listing);
    const mlsNumber = listing.mlsNumber || listing.stellarListingId || listing.providerListingId || "";
    addSuggestion("address", address, publicSearchSuggestionDetail([price, listing.propertyType, mlsNumber && `MLS ${mlsNumber}`]), { search: address }, "Home");
    addSuggestion("city", listing.city, publicSearchSuggestionDetail([listing.county, listing.state || "FL"]), { city: listing.city }, "MapPin");
    addSuggestion("county", listing.county, "County", { county: listing.county }, "Map");
    addSuggestion("zip", listing.zip, "ZIP code", { zip: listing.zip }, "Hash");
    addSuggestion("propertyType", listing.propertyType, "Property type", { propertyType: listing.propertyType }, "Building2");
    addSuggestion("mls", mlsNumber, publicSearchSuggestionDetail(["MLS number", listing.city]), { search: mlsNumber }, "Hash");
  });

  return suggestions
    .sort((a, b) => a.score - b.score || publicSearchSuggestionTypePriority(a.type) - publicSearchSuggestionTypePriority(b.type) || a.label.localeCompare(b.label))
    .slice(0, limit);
}

function publicSearchMergeSuggestionOptions(primary = [], secondary = [], term = "", limit = 8) {
  const seen = new Map();
  [...(Array.isArray(primary) ? primary : []), ...(Array.isArray(secondary) ? secondary : [])].forEach((option = {}) => {
    const label = String(option.label || option.value || "").trim();
    if (!label) return;
    const normalized = {
      ...option,
      label,
      value: option.value || label,
      detail: String(option.detail || "").trim(),
      queryPatch: { search: label, ...(option.queryPatch || {}) },
      score: typeof option.score === "number"
        ? option.score
        : publicSearchSuggestionScore(option.type, label, option.detail, term, option.aliases)
    };
    if (!publicSearchSuggestionMatchesTerm(normalized, term)) return;
    const key = `${normalized.type}:${label.toLowerCase()}`;
    const current = seen.get(key);
    if (!current || normalized.score < current.score) seen.set(key, normalized);
  });
  return Array.from(seen.values())
    .sort((a, b) => a.score - b.score || publicSearchSuggestionTypePriority(a.type) - publicSearchSuggestionTypePriority(b.type) || String(a.label || "").localeCompare(String(b.label || "")))
    .slice(0, Math.max(1, Number(limit || 8) || 8));
}

function filtersFromPublicSearchSuggestion(currentFilters = {}, suggestion = {}) {
  const next = {
    ...currentFilters,
    ...(suggestion.queryPatch || {})
  };
  if (suggestion.type === "zip") {
    next.zip = suggestion.queryPatch?.zip || suggestion.value || suggestion.label || "";
    next.city = "";
    next.county = "";
    next.search = next.zip;
    return next;
  }
  return {
    ...next,
    search: suggestion.queryPatch?.search || suggestion.value || suggestion.label || currentFilters.search || ""
  };
}

function PublicListingSearchAutocomplete({ value = "", onChange, onSelect, placeholder = "Search city, ZIP, address, or MLS #", seedListings = [] }) {
  const [open, setOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [options, setOptions] = useState(() => publicSearchSuggestionOptions(seedListings, value));
  const valueText = String(value || "");
  const seedListingSignature = useMemo(
    () => (Array.isArray(seedListings) ? seedListings.map((listing) => listing?.id || listing?.mlsNumber || listing?.address || "").join("|") : ""),
    [seedListings]
  );

  useEffect(() => {
    let cancelled = false;
    const term = valueText.trim();
    const seedOptions = publicSearchSuggestionOptions(seedListings, term, { requireMatch: Boolean(term), limit: 8 });
    setOptions(seedOptions.length ? seedOptions : publicSearchSuggestionOptions(seedListings, "", { limit: 8 }));
    if (term.length < 2) {
      setBusy(false);
      return () => {
        cancelled = true;
      };
    }

    setBusy(true);
    const timer = setTimeout(() => {
      const suggestionParams = new URLSearchParams({ term, limit: "8" });
      API.request(`/api/site/listings/suggest?${suggestionParams.toString()}`, { retries: 0 })
        .then((payload) => {
          if (cancelled) return;
          const remoteOptions = Array.isArray(payload?.suggestions) ? payload.suggestions : [];
          if (remoteOptions.length) {
            setOptions(publicSearchMergeSuggestionOptions(seedOptions, remoteOptions, term, 8));
            return;
          }
          const params = publicSearchParamsFromFilters({ search: term, limit: "10" });
          API.request(`/api/site/listings/search?${params.toString()}`, { retries: 0 })
            .then((searchPayload) => {
              if (cancelled) return;
              const listings = publicListingsFromPayload(searchPayload);
              const liveOptions = publicSearchSuggestionOptions(listings, term, { requireMatch: true, limit: 8 });
              setOptions(publicSearchMergeSuggestionOptions(seedOptions, liveOptions, term, 8));
            })
            .catch(() => {
              if (!cancelled) setOptions(seedOptions);
            });
        })
        .catch(() => {
          if (!cancelled) setOptions(seedOptions);
        })
        .finally(() => {
          if (!cancelled) setBusy(false);
        });
    }, 180);

    return () => {
      cancelled = true;
      clearTimeout(timer);
    };
  }, [valueText, seedListingSignature]);

  function chooseSuggestion(suggestion) {
    onChange?.(suggestion.value);
    onSelect?.(suggestion);
    setOpen(false);
  }

  const showOptions = open && options.length > 0;

  return (
    <div className="public-search-autocomplete">
      <input
        value={valueText}
        onChange={(event) => {
          onChange?.(event.target.value);
          setOpen(true);
        }}
        onFocus={() => setOpen(true)}
        onBlur={() => setTimeout(() => setOpen(false), 140)}
        placeholder={placeholder}
        autoComplete="off"
      />
      {showOptions && (
        <div className="public-search-autocomplete-menu" role="listbox">
          {options.map((option) => (
            <button
              key={`${option.type}-${option.label}`}
              type="button"
              className="public-search-suggestion"
              onMouseDown={(event) => {
                event.preventDefault();
                chooseSuggestion(option);
              }}
            >
              <span className="public-search-suggestion-icon"><Icon name={option.icon || "Search"} /></span>
              <span>
                <strong>{option.label}</strong>
                {option.detail && <small>{option.detail}</small>}
              </span>
              <em>{publicSearchSuggestionTypeLabel(option.type)}</em>
            </button>
          ))}
          {busy && <span className="public-search-autocomplete-status">Checking live matches...</span>}
        </div>
      )}
    </div>
  );
}

function PublicConsumerPaths({ navigate, onTalkAgent, onHomeValue }) {
  const paths = [
    {
      title: "Buying in Florida?",
      eyebrow: "For buyers",
      cta: "Get matched with a Nex agent",
      icon: "Home",
      body: "Search homes, save the ones you love, and ask a local Nex agent for showing help when you are ready.",
      action: () => onTalkAgent ? onTalkAgent() : navigate("/site/contact")
    },
    {
      title: "Thinking about selling?",
      eyebrow: "For sellers",
      cta: "Request a home value estimate",
      icon: "BadgeDollarSign",
      body: "Find out what your home may be worth, then request a real CMA from a Nex Realty agent.",
      action: () => onHomeValue ? onHomeValue() : navigate("/site/sell")
    }
  ];
  return (
    <section className="public-section public-consumer-paths">
      {paths.map((path) => (
        <article key={path.title}>
          <span><Icon name={path.icon} /> {path.eyebrow}</span>
          <h2>{path.title}</h2>
          <p>{path.body}</p>
          <button className="btn primary" type="button" onClick={path.action}>{path.cta}</button>
        </article>
      ))}
    </section>
  );
}

function PublicRecruitingSoftCta({ navigate }) {
  return (
    <section className="public-section public-agent-recruiting-cta">
      <div>
        <p className="eyebrow">For real estate agents</p>
        <h2>Agents: build with Nex Realty</h2>
        <p>Explore a modern Florida brokerage path with support, training, marketing, and tools for growing your business.</p>
      </div>
      <button className="btn secondary" type="button" onClick={() => navigate("/site/join")}>Join Nex Realty</button>
    </section>
  );
}

function PublicPathStrip({ navigate }) {
  return (
    <section className="public-path-strip" aria-label="Popular Nex Realty actions">
      {[
        ["Search Homes", "Find listings and request showings", "/site/search", "Search"],
        ["Home Value", "Start a quick seller estimate", "/site/sell", "BadgeDollarSign"],
        ["Find an Agent", "Search Nex professionals", "/site/agents", "ContactRound"],
        ["Join Nex", "Compare Nex Realty", "/site/join", "Rocket"]
      ].map(([title, body, path, icon]) => (
        <button key={title} type="button" onClick={() => navigate(path)}>
          <Icon name={icon} />
          <span>
            <strong>{title}</strong>
            <small>{body}</small>
          </span>
        </button>
      ))}
    </section>
  );
}

function PublicSyncProofPanel({ data = {}, navigate }) {
  const stats = publicWebsiteSyncStats(data);
  const cards = [
    ["Local agents", stats.publishedAgentCount || "Ready", "Published Nex agent profiles stay current"],
    ["Market footprint", stats.marketCount || "Florida", "Markets and service areas power search pages"],
    ["Quick follow-up", "Ready", "Inquiries keep the property, area, and source attached"],
    ["Live search", data.idx?.provider || "MLS", "MLS search support with clear listing details"]
  ];
  return (
    <section className="public-section public-sync-proof-panel">
      <div className="public-sync-proof-copy">
        <p className="eyebrow">Built for Florida search</p>
        <h2>A cleaner path from search to the right local help.</h2>
        <p>
          Published agent details, service areas, listing questions, and showing requests are designed to stay organized
          so buyers and sellers get a smoother experience from first search to next step.
        </p>
        <button className="btn secondary" type="button" onClick={() => navigate("/site/agents")}>Find an Agent</button>
      </div>
      <div className="public-sync-proof-grid">
        {cards.map(([label, value, body]) => (
          <article key={label}>
            <span>{label}</span>
            <strong>{value}</strong>
            <small>{body}</small>
          </article>
        ))}
      </div>
    </section>
  );
}

function PublicAgentSiteShowcase({ agents = [], navigate }) {
  const fallbackAgents = agents.length ? agents : [
    {
      id: "preview-agent-site",
      name: "Nex Realty Agent",
      title: "Modern Florida real estate advisor",
      market: "Florida",
      serviceAreas: ["Tampa Bay", "Orlando", "Miami"],
      specialties: ["Buyer Agent", "Listing Agent", "Luxury"],
      subdomainSlug: "agent-preview",
      websiteHeadline: "Your local Nex Realty advisor",
      websiteTagline: "Local search guidance, showing help, seller support, and Florida market insight.",
      websiteAccentColor: "#e30613"
    }
  ];

  return (
    <section className="public-section public-agent-site-showcase">
      <div className="public-section-head">
        <div>
          <p className="eyebrow">Meet local Nex agents</p>
          <h2>Connect with a Florida real estate professional.</h2>
          <small>Published agent profiles show current contact details, service areas, specialties, and market focus.</small>
        </div>
        <button className="btn secondary" onClick={() => navigate("/site/agents")} type="button">Find an Agent</button>
      </div>
      <div className="public-agent-site-grid">
        {fallbackAgents.map((agent) => (
          <button
            key={agent.id || agent.subdomainSlug}
            className="public-agent-site-card"
            onClick={() => navigate(`/site/agents/${agent.subdomainSlug}`)}
            type="button"
            style={{ "--agent-site-accent": agent.websiteAccentColor || "#e30613" }}
          >
            <span className="public-agent-site-status"><i /> Local Nex agent</span>
            <div className="public-agent-site-preview">
              <div className="public-agent-site-topbar">
                <span>{agent.subdomainSlug}.nexrealtygroup.com</span>
                <em>Nex Realty</em>
              </div>
              <div className="public-agent-site-body">
                <div className="public-avatar">{agent.headshot ? <img src={agent.headshot} alt={agent.name} /> : publicInitials(agent.name)}</div>
                <div>
                  <strong>{agent.websiteHeadline || agent.name}</strong>
                  <small>{agent.websiteTagline || agent.title}</small>
                </div>
              </div>
              <div className="public-agent-site-tags">
                {(agent.serviceAreas || []).slice(0, 3).map((area) => <span key={area}>{area}</span>)}
              </div>
            </div>
            <div className="public-agent-site-copy">
              <strong>{agent.name}</strong>
              <span>{agent.market || agent.title || "Nex Realty"}</span>
              <small>{(agent.specialties || []).slice(0, 3).join(" | ") || "Buying | Selling | Local guidance"}</small>
            </div>
          </button>
        ))}
      </div>
    </section>
  );
}

function PublicIdxMapSearchPanel({ idx = {}, listings = [], navigate }) {
  const feeds = Array.isArray(idx.feeds) && idx.feeds.length ? idx.feeds : [
    { id: "primary", name: idx.provider || "Home Search", provider: idx.provider || "MLS", region: "Florida search", status: idx.licenseStatus || "Ready", mode: "Search ready" }
  ];
  const previewPins = (listings || []).slice(0, 6).map((listing, index) => ({
    id: listing.id || `pin-${index}`,
    label: listing.city || listing.county || "Florida",
    price: propertyPriceLabel(listing),
    status: listing.status,
    left: [18, 34, 52, 69, 78, 43][index] || 50,
    top: [62, 44, 57, 38, 68, 30][index] || 50
  }));

  return (
    <section className="public-section public-idx-map-section">
      <div className="public-idx-map-shell">
        <div className="public-idx-map-copy">
          <p className="eyebrow">Florida home search</p>
          <h2>Search Florida homes and connect with a local Nex agent.</h2>
          <p>
            Browse available homes, ask questions, request showings, and save the searches that matter to your move.
          </p>
          <div className="public-feed-grid">
            {feeds.slice(0, 4).map((feed) => (
              <article key={feed.id || feed.name} className="public-feed-card">
                <span>{feed.status || "Ready"}</span>
                <strong>{feed.name || feed.provider}</strong>
                <small>{[feed.region, feed.mode].filter(Boolean).join(" - ") || "Home search"}</small>
              </article>
            ))}
          </div>
        </div>
        <div className="public-map-console">
          <div className="public-map-toolbar">
            <span><i /> Map search</span>
            <button className="btn primary" type="button" onClick={() => navigate("/site/search")}>
              <Icon name="MapPinned" />
              <span>Open Search</span>
            </button>
          </div>
          <div className="public-live-map">
            <div className="public-map-gridlines" />
            <div className="public-map-region tampa">Tampa Bay</div>
            <div className="public-map-region orlando">Orlando</div>
            <div className="public-map-region miami">Miami</div>
            {previewPins.map((pin) => (
              <button
                key={pin.id}
                className="public-map-pin"
                style={{ left: `${pin.left}%`, top: `${pin.top}%` }}
                type="button"
                onClick={() => navigate("/site/search")}
                title={`${pin.label} ${pin.price}`}
              >
                <Icon name="MapPin" size={18} />
                <span>{pin.price || pin.label}</span>
              </button>
            ))}
          </div>
          <div className="public-map-bottom">
            <PublicMarketTicker initialLocation="Florida" />
            <div className="public-map-feed-note">
              <Icon name="Layers3" />
              <span>{idx.multiFeedReady ? "Florida search details ready" : "MLS search details ready"}</span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function PublicHeroSearchBox({ navigate, onTalkAgent, onHomeValue, seedListings = [], sourceAgentSlug = "" }) {
  const [filters, setFilters] = useState({ search: "", city: "", county: "", zip: "", minPrice: "", maxPrice: "", beds: "", baths: "", propertyType: "" });

  function submit(event) {
    event.preventDefault();
    const params = publicSearchParamsFromFilters(filters);
    if (sourceAgentSlug) params.set("agent", sourceAgentSlug);
    recordPublicConsumerActivity({
      activityType: "searched",
      message: `Searched homes${filters.search ? ` in ${filters.search}` : ""}.`,
      intent: "property_search",
      criteria: filters,
      websiteSlug: sourceAgentSlug
    });
    navigate(`/site/search${params.toString() ? `?${params.toString()}` : ""}`);
  }

  function update(field, value) {
    setFilters((current) => field === "search"
      ? { ...current, search: value, city: "", county: "", zip: "" }
      : { ...current, [field]: value });
  }

  function quickSearch(value) {
    const params = new URLSearchParams();
    params.set("search", value);
    if (sourceAgentSlug) params.set("agent", sourceAgentSlug);
    recordPublicConsumerActivity({
      activityType: "searched",
      message: `Searched homes in ${value}.`,
      intent: "property_search",
      criteria: { search: value },
      websiteSlug: sourceAgentSlug
    });
    navigate(`/site/search?${params.toString()}`);
  }

  function chooseSearchSuggestion(suggestion) {
    const nextFilters = filtersFromPublicSearchSuggestion(filters, suggestion);
    setFilters(nextFilters);
    const params = publicSearchParamsFromFilters(nextFilters);
    if (sourceAgentSlug) params.set("agent", sourceAgentSlug);
    recordPublicConsumerActivity({
      activityType: "searched",
      message: `Searched homes${nextFilters.search ? ` in ${nextFilters.search}` : ""}.`,
      intent: "property_search",
      criteria: nextFilters,
      websiteSlug: sourceAgentSlug
    });
    navigate(`/site/search${params.toString() ? `?${params.toString()}` : ""}`);
  }

  return (
    <form className="public-hero-simple-search" onSubmit={submit}>
      <div className="public-hero-simple-search-row">
        <PublicListingSearchAutocomplete
          value={filters.search}
          onChange={(value) => update("search", value)}
          onSelect={chooseSearchSuggestion}
          placeholder="City, ZIP, neighborhood, address, or MLS #"
          seedListings={seedListings}
        />
        <button type="submit" aria-label="Search Florida homes">
          <Icon name="Search" />
          <span>Search</span>
        </button>
      </div>
      <div className="public-hero-filter-row">
        <select value={filters.minPrice} onChange={(event) => update("minPrice", event.target.value)} aria-label="Minimum price">
          <option value="">Min price</option>
          {PUBLIC_SEARCH_PRICE_OPTIONS.map((price) => <option key={`hero-min-${price}`} value={price}>{formatCurrency(price)}</option>)}
        </select>
        <select value={filters.maxPrice} onChange={(event) => update("maxPrice", event.target.value)} aria-label="Maximum price">
          <option value="">Max price</option>
          {PUBLIC_SEARCH_PRICE_OPTIONS.map((price) => <option key={`hero-max-${price}`} value={price}>{formatCurrency(price)}</option>)}
        </select>
        <select value={filters.beds} onChange={(event) => update("beds", event.target.value)} aria-label="Beds">
          <option value="">Beds</option>
          <option value="1">1+ beds</option>
          <option value="2">2+ beds</option>
          <option value="3">3+ beds</option>
          <option value="4">4+ beds</option>
          <option value="5">5+ beds</option>
        </select>
        <select value={filters.baths} onChange={(event) => update("baths", event.target.value)} aria-label="Baths">
          <option value="">Baths</option>
          <option value="1">1+ baths</option>
          <option value="2">2+ baths</option>
          <option value="3">3+ baths</option>
          <option value="4">4+ baths</option>
        </select>
        <select value={filters.propertyType} onChange={(event) => update("propertyType", event.target.value)} aria-label="Property type">
          <option value="">Property type</option>
          <option>Single Family Residence</option>
          <option>Condominium</option>
          <option>Townhouse</option>
          <option>Villa</option>
          <option>Multi-Family</option>
        </select>
        <button type="button" className="public-more-filter-button" onClick={() => navigate(sourceAgentSlug ? `/site/search?agent=${encodeURIComponent(sourceAgentSlug)}` : "/site/search")}>More</button>
      </div>
      <div className="public-hero-chip-row" aria-label="Quick searches">
        {["New Listings", "Waterfront", "Pool Homes", "Open Houses", "Condos", "Luxury", "Tampa Bay", "Orlando", "Miami"].map((chip) => (
          <button key={chip} type="button" onClick={() => quickSearch(chip)}>{chip}</button>
        ))}
      </div>
      <div className="public-hero-concierge-row">
        <button type="button" onClick={() => onTalkAgent ? onTalkAgent() : navigate("/site/contact")}>
          <Icon name="Sparkles" />
          <span>{sourceAgentSlug ? "Talk to Agent" : "Talk to a Nex Agent"}</span>
        </button>
        <button type="button" onClick={() => onHomeValue ? onHomeValue() : navigate("/site/sell")}>
          <Icon name="BadgeDollarSign" />
          <span>Get Home Value</span>
        </button>
      </div>
    </form>
  );
}

function niaPromptForIntent(intent, firstName, step = 0) {
  const buyer = [
    `Got it, ${firstName}. I can help narrow this down. What area are you looking in?`,
    "City, ZIP, or neighborhood?",
    "What budget range should I stay within?",
    "How many beds and baths would feel right?",
    "Any must-haves, like waterfront, pool, garage, or a shorter commute?",
    "What timeline are you working with?",
    "Are you paying cash, already pre-approved, or still exploring financing?"
  ];
  const seller = [
    `Got it, ${firstName}. I can help you get a better idea of your selling options. What is the property address?`,
    "How would you describe the current property condition?",
    "What timeline are you considering for selling?",
    "Have there been any meaningful upgrades?",
    "Is the property occupied or vacant?",
    "Do you want a quick home value direction or a full CMA from a Nex listing advisor?"
  ];
  const showing = [
    `Got it, ${firstName}. Are you asking about this specific property or looking for similar homes?`,
    "What day and time would work best?",
    "Are you cash, pre-approved, or still working on financing?",
    "Are there any other homes you want to include?",
    "What area should the advisor focus on if that property is not available?"
  ];
  const question = [
    `Got it, ${firstName}. Ask me your question and I'll help point you in the right direction.`,
    "Tell me a little more so I can guide you better.",
    "Would you like me to connect you with a live Nex agent for this?"
  ];
  const recruiting = [
    `Got it, ${firstName}. I can help with Nex Realty agent opportunities. Are you already licensed in Florida?`,
    "What brokerage are you with now?",
    "What are you trying to improve: commission plan, support, technology, leads, or training?",
    "Would you like a Nex team member to reach out?"
  ];
  const flows = { buyer, seller, showing, general: question, home_value: seller, recruiting };
  const flow = flows[intent] || question;
  return flow[Math.min(step, flow.length - 1)];
}

function niaIntentToLeadType(intent) {
  if (intent === "seller" || intent === "home_value") return "seller";
  if (intent === "recruiting") return "recruiting";
  if (intent === "showing") return "buyer";
  return intent || "general";
}

function updateNiaMemoryFromText(memory, text) {
  const next = { ...memory };
  const value = String(text || "").trim();
  const lower = value.toLowerCase();
  const zip = value.match(/\b\d{5}\b/)?.[0] || "";
  const budget = value.match(/\$?\s?\d{2,4}(?:,\d{3})*(?:\s?k)?/i)?.[0] || "";
  if (zip) next.area = zip;
  if (!next.area && /\b(in|near|around)\s+([a-z][a-z\s.-]{2,40})/i.test(value)) next.area = value.match(/\b(?:in|near|around)\s+([a-z][a-z\s.-]{2,40})/i)?.[1]?.trim() || next.area;
  if (!next.area && value.length <= 60 && !budget && /[a-z]/i.test(value)) next.area = value;
  if (budget || /\bunder|budget|max|up to\b/i.test(lower)) next.budget = value;
  if (/\b\d+\s*(bed|br|bedroom)/i.test(lower)) next.bedsBaths = value;
  if (/\b(pool|waterfront|garage|fenced|view|school|commute|acre|condo|hoa|new construction)\b/i.test(lower)) next.mustHaves = [next.mustHaves, value].filter(Boolean).join("; ");
  if (/\b(now|asap|month|days|weeks|spring|summer|fall|winter|year|soon|timeline)\b/i.test(lower)) next.timeline = value;
  if (/\b(cash|pre.?approved|loan|financing|mortgage|lender)\b/i.test(lower)) next.financing = value;
  if (/\b(address|street|ave|avenue|road|rd|drive|dr|lane|ln|circle|ct|court)\b/i.test(lower)) next.propertyAddress = value;
  return next;
}

function niaSearchUrl(memory = {}, sourceAgentSlug = "") {
  const params = new URLSearchParams();
  if (memory.area) params.set("search", memory.area);
  if (memory.budget) {
    const numeric = Number(String(memory.budget).replace(/[^0-9]/g, ""));
    if (numeric) params.set("maxPrice", numeric < 10000 ? String(numeric * 1000) : String(numeric));
  }
  if (sourceAgentSlug) params.set("agent", sourceAgentSlug);
  return `/site/search${params.toString() ? `?${params.toString()}` : ""}`;
}

function PublicNiaConciergeModal({ sourceAgentSlug = "", sourceAgentName = "", consumerSession = null, onConsumerSessionUpdate, context = {}, setToast, onClose, navigate }) {
  const initialConsumerSession = consumerSession || readPublicConsumerSession();
  const intentOptions = [
    { id: "buyer", label: "Buy a home", prompt: "I want to buy a home." },
    { id: "seller", label: "Sell a home", prompt: "I want to sell a home." },
    { id: "showing", label: "See a property", prompt: "I want to see a property." },
    { id: "general", label: "Ask a question", prompt: "I have a real estate question." },
    { id: "home_value", label: "Get home value", prompt: "I want to know what my home may be worth." },
    { id: "recruiting", label: "Join Nex Realty", prompt: "I am interested in joining Nex Realty." }
  ];
  const [intent, setIntent] = useState(context.intent || "");
  const [draftMessage, setDraftMessage] = useState(context.message || "");
  const [contact, setContact] = useState({ name: "", phone: "", email: "" });
  const [consent, setConsent] = useState(false);
  const [contactCaptured, setContactCaptured] = useState(Boolean(initialConsumerSession?.contactCaptured));
  const [session, setSession] = useState(initialConsumerSession || null);
  const [leadId, setLeadId] = useState(initialConsumerSession?.latestLeadId || "");
  const [flowStep, setFlowStep] = useState(0);
  const [memory, setMemory] = useState({
    intent: context.intent || "",
    area: "",
    budget: "",
    bedsBaths: "",
    mustHaves: "",
    timeline: "",
    financing: "",
    propertyAddress: "",
    sourcePage: context.sourcePage || "Public NIA Concierge",
    propertyId: context.propertyId || "",
    liveAgentRequested: false
  });
  const [messages, setMessages] = useState(() => {
    if (initialConsumerSession?.contactCaptured) {
      return [
        {
          id: "welcome-back",
          role: "assistant",
          text: `Welcome back, ${initialConsumerSession.firstName || "there"}. Are you continuing your search or looking for something new?`
        }
      ];
    }
    return [
      {
        id: "welcome",
        role: "assistant",
        text: sourceAgentName
          ? `You're connecting with ${sourceAgentName} at Nex Realty. What can I help you with today?`
          : "What can I help you with today?"
      }
    ];
  });
  const [error, setError] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const selected = intentOptions.find((option) => option.id === intent);
  const firstName = contactCaptured ? (session?.firstName || firstNameFromName(contact.name)) : firstNameFromName(contact.name);

  useEffect(() => {
    if (!consumerSession?.contactCaptured) return;
    setSession(consumerSession);
    setContactCaptured(true);
    setLeadId(consumerSession.latestLeadId || "");
  }, [consumerSession?.consumerId]);

  function pushMessage(role, text, extra = {}) {
    const item = { id: `${Date.now()}-${Math.random().toString(16).slice(2)}`, role, text, ...extra };
    setMessages((current) => [...current, item]);
    return item;
  }

  function choose(option) {
    setIntent(option.id);
    setMemory((current) => ({ ...current, intent: option.id }));
    pushMessage("user", option.label);
    if (contactCaptured) {
      const nextPrompt = niaPromptForIntent(option.id, firstName, 0);
      setFlowStep(1);
      pushMessage("assistant", nextPrompt);
      appendConversation({ message: option.label, intent: option.id, activityType: "nia_intent_selected" });
    } else {
      setDraftMessage(option.prompt);
    }
    setError("");
  }

  function updateContact(field, value) {
    setContact((current) => ({ ...current, [field]: value }));
    if (error) setError("");
  }

  async function captureContact(event) {
    event.preventDefault();
    const nextIntent = intent || detectPublicIntent(draftMessage);
    if (!nextIntent && !draftMessage.trim()) {
      setError("Choose an option or tell NIA what you need.");
      return;
    }
    if (!contact.name.trim() || !contact.phone.trim() || !contact.email.trim()) {
      setError("Please add your name, phone, and email so NIA can connect you with the right Nex contact.");
      return;
    }
    const validation = validatePublicLeadCapture({ ...contact, intent: nextIntent, consent });
    if (!validation.ok) {
      setError(validation.message);
      return;
    }
    setSubmitting(true);
    setError("");
    try {
      const endpoint = nextIntent === "recruiting" ? "/api/public/recruiting-inquiries" : "/api/public/site-assistant";
      const payload = await API.request(endpoint, {
        method: "POST",
        retries: 0,
        body: JSON.stringify({
          ...publicConsumerSessionPayload(),
          ...contact,
          type: niaIntentToLeadType(nextIntent),
          intent: nextIntent,
          message: draftMessage || selected?.prompt || "Consumer requested help from NIA.",
          sourceAgentSlug,
          sourcePage: context.sourcePage || "Public NIA Concierge",
          leadSource: sourceAgentSlug ? "Agent Website NIA Concierge" : nextIntent === "recruiting" ? "Nex Realty Agent Interest" : "Nex Realty NIA Concierge",
          leadIntent: nextIntent,
          formName: "Public NIA Concierge",
          consent
        })
      });
      if (payload.consumerSession) {
        const remembered = rememberPublicConsumerSession(payload.consumerSession);
        setSession(remembered || payload.consumerSession);
        onConsumerSessionUpdate?.(payload.consumerSession);
      }
      setLeadId(payload.lead?.id || payload.consumerSession?.latestLeadId || "");
      setContactCaptured(true);
      setIntent(nextIntent);
      setMemory((current) => updateNiaMemoryFromText({ ...current, intent: nextIntent }, draftMessage));
      pushMessage("user", draftMessage || selected?.label || "I need help.");
      pushMessage("assistant", niaPromptForIntent(nextIntent, firstNameFromName(contact.name), 0));
      setFlowStep(1);
      setToast("Thanks. NIA saved your info and will keep helping here.");
    } catch (submitError) {
      setError(submitError.message || "NIA could not capture this request. Please try again.");
    } finally {
      setSubmitting(false);
    }
  }

  async function appendConversation(extra = {}) {
    const activeSession = session || readPublicConsumerSession();
    if (!activeSession?.consumerId || !activeSession?.sessionToken) return null;
    try {
      const payload = await API.request("/api/public/consumer-activity", {
        method: "POST",
        retries: 0,
        body: JSON.stringify({
          consumerId: activeSession.consumerId,
          consumerSessionToken: activeSession.sessionToken,
          leadId: leadId || activeSession.latestLeadId || "",
          sourcePage: context.sourcePage || memory.sourcePage || "Public NIA Concierge",
          websiteSlug: sourceAgentSlug,
          intent: intent || memory.intent || "general",
          criteria: memory,
          ...extra
        })
      });
      if (payload.consumerSession) {
        const remembered = rememberPublicConsumerSession(payload.consumerSession);
        setSession(remembered || payload.consumerSession);
        onConsumerSessionUpdate?.(payload.consumerSession);
      }
      return payload;
    } catch (activityError) {
      return null;
    }
  }

  async function sendChat(event) {
    event.preventDefault();
    const text = draftMessage.trim();
    if (!text) return;
    if (!contactCaptured) {
      const detected = intent || detectPublicIntent(text);
      setIntent(detected);
      setMemory((current) => ({ ...current, intent: detected }));
      setError("Please add your contact info so NIA can keep helping and route your request correctly.");
      return;
    }
    setDraftMessage("");
    pushMessage("user", text);
    const nextMemory = updateNiaMemoryFromText(memory, text);
    setMemory(nextMemory);
    await appendConversation({ message: text, intent: intent || nextMemory.intent || detectPublicIntent(text), criteria: nextMemory, activityType: "nia_question" });
    const nextPrompt = niaPromptForIntent(intent || nextMemory.intent || "general", firstName, flowStep);
    setFlowStep((current) => current + 1);
    pushMessage("assistant", nextPrompt);
  }

  async function requestLiveAgent() {
    setMemory((current) => ({ ...current, liveAgentRequested: true }));
    await appendConversation({
      message: "Connect me with a live Nex agent",
      intent: "live_agent_requested",
      activityType: "live_agent_requested",
      liveAgentRequested: true
    });
    pushMessage("user", "Connect me with a live Nex agent");
    pushMessage("assistant", "Perfect. We'll have someone from Nex Realty reach out shortly. If this is about a specific area, we'll route it to someone familiar with that market.");
  }

  async function saveSearchActivity(label = "Save this search") {
    await appendConversation({
      message: label,
      intent: "saved_search",
      activityType: "saved_search",
      criteria: memory
    });
    pushMessage("assistant", "Done. I saved this search direction to your Nex profile and a Nex advisor can follow up with matching homes.");
  }

  const showSearchActions = contactCaptured && ["buyer", "showing", "general"].includes(intent || memory.intent || "general");
  const searchUrl = niaSearchUrl(memory, sourceAgentSlug);
  return (
    <div className="public-modal-backdrop" role="presentation">
      <section className="public-nia-modal" role="dialog" aria-modal="true" aria-label="NIA Nex Realty concierge">
        <button className="public-modal-close" type="button" onClick={onClose} aria-label="Close NIA concierge"><Icon name="X" /></button>
        <div className="public-nia-modal-head">
          <span><i /> NIA concierge</span>
          <h2>What can I help you with today?</h2>
          <p>{contactCaptured ? "Your contact info is saved for this session. Keep chatting here." : sourceAgentName ? `You're connecting with ${sourceAgentName} at Nex Realty.` : "NIA can point you in the right direction, then connect you with Nex Realty once your contact info is captured."}</p>
        </div>
        <div className="public-nia-chat-log">
          {messages.map((item) => (
            <div key={item.id} className={`public-nia-bubble ${item.role}`}>
              <p>{item.text}</p>
            </div>
          ))}
        </div>

        {!contactCaptured && (
          <form onSubmit={captureContact} className="public-nia-flow">
            <div className="public-nia-options">
              {intentOptions.map((option) => (
                <button
                  key={`${option.id}-${option.label}`}
                  className={intent === option.id ? "active" : ""}
                  type="button"
                  onClick={() => choose(option)}
                >
                  {option.label}
                </button>
              ))}
            </div>
            <textarea
              value={draftMessage}
              onChange={(event) => {
                setDraftMessage(event.target.value);
                if (!intent) setIntent(detectPublicIntent(event.target.value));
              }}
              placeholder="Or type what you need help with..."
              rows={3}
            />
            <div className="public-nia-contact-gate">
              <strong>Contact info required to continue</strong>
              <span>NIA will not continue the conversation until Nex can identify where to send the request.</span>
              <input value={contact.name} onChange={(event) => updateContact("name", event.target.value)} placeholder="Full name" required />
              <input value={contact.phone} onChange={(event) => updateContact("phone", event.target.value)} placeholder="Phone" required />
              <input type="email" value={contact.email} onChange={(event) => updateContact("email", event.target.value)} placeholder="Email" required />
            </div>
            <label className="public-consent">
              <input required type="checkbox" checked={consent} onChange={(event) => setConsent(event.target.checked)} />
              <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
            </label>
            {error && <div className="login-error public-form-error">{error}</div>}
            <button className="btn primary" type="submit" disabled={submitting}>
              <Icon name={submitting ? "LoaderCircle" : "Sparkles"} className={submitting ? "spin" : ""} />
              <span>{submitting ? "Connecting" : "Continue with NIA"}</span>
            </button>
          </form>
        )}

        {contactCaptured && (
          <div className="public-nia-chat-controls">
            <div className="public-nia-action-row">
              <button className="btn secondary" type="button" onClick={requestLiveAgent}>Connect me with a live Nex agent</button>
              {showSearchActions && <button className="btn secondary" type="button" onClick={() => navigate(searchUrl)}>Search Homes</button>}
              {showSearchActions && <button className="btn secondary" type="button" onClick={() => saveSearchActivity("Save this search")}>Save this search</button>}
              {showSearchActions && <button className="btn secondary" type="button" onClick={() => saveSearchActivity("Get new listing alerts")}>Get new listing alerts</button>}
            </div>
            <form className="public-nia-message-form" onSubmit={sendChat}>
              <input value={draftMessage} onChange={(event) => setDraftMessage(event.target.value)} placeholder="Type a follow-up..." />
              <button className="btn primary" type="submit"><Icon name="Send" /><span>Send</span></button>
            </form>
          </div>
        )}
      </section>
    </div>
  );
}

function detectPublicIntent(text = "") {
  const lower = String(text || "").toLowerCase();
  if (/sell|value|worth|cma|home value/.test(lower)) return "seller";
  if (/rent|lease/.test(lower)) return "renter";
  if (/join|agent|brokerage|commission|career/.test(lower)) return "recruiting";
  if (/question|help|ask/.test(lower)) return "general";
  return "buyer";
}

function PublicHomeValueModal({ sourceAgentSlug = "", onConsumerSessionUpdate, setToast, onClose }) {
  const [step, setStep] = useState("address");
  const [form, setForm] = useState({
    address: "",
    city: "",
    county: "",
    sqft: "",
    propertyType: "",
    name: "",
    phone: "",
    email: "",
    consent: false
  });
  const [result, setResult] = useState(null);
  const [error, setError] = useState("");
  const [submitting, setSubmitting] = useState(false);

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
    if (error) setError("");
  }

  function continueToContact(event) {
    event.preventDefault();
    if (!form.address.trim()) {
      setError("Enter the property address first.");
      return;
    }
    setError("");
    setStep("contact");
  }

  async function requestEstimate(event) {
    event.preventDefault();
    if (!form.name.trim() || !form.phone.trim() || !form.email.trim()) {
      setError("Please add your name, phone, and email before viewing the estimate.");
      return;
    }
    const validation = validatePublicLeadCapture({ name: form.name, phone: form.phone, email: form.email, intent: "seller", consent: form.consent });
    if (!validation.ok) {
      setError(validation.message);
      return;
    }
    setSubmitting(true);
    setError("");
    try {
      const payload = await API.request("/api/public/cma-estimate", {
        method: "POST",
        retries: 0,
        body: JSON.stringify({
          ...publicConsumerSessionPayload(),
          ...form,
          propertyAddress: form.address,
          sellerPropertyAddress: form.address,
          sourceAgentSlug,
          sourcePage: "Public Home Value Modal",
          leadSource: "Nex Realty Home Value",
          leadIntent: "Home Value",
          notes: "Consumer requested an instant rough home value range.",
          consent: form.consent
        })
      });
      if (payload.consumerSession) {
        const remembered = rememberPublicConsumerSession(payload.consumerSession);
        onConsumerSessionUpdate?.(remembered || payload.consumerSession);
      }
      setResult(payload.cma);
      setStep("result");
      setToast(payload.message || "Home value request captured.");
    } catch (estimateError) {
      setError(estimateError.message || "Could not create the estimate. Please try again.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <div className="public-modal-backdrop" role="presentation">
      <section className="public-home-value-modal" role="dialog" aria-modal="true" aria-label="Nex Realty home value estimate">
        <button className="public-modal-close" type="button" onClick={onClose} aria-label="Close home value"><Icon name="X" /></button>
        <div className="public-home-value-head">
          <span><i /> Home value</span>
          <h2>Get a quick estimated range.</h2>
          <p>Start with an instant planning estimate. This is not an appraisal; a Nex agent can prepare a more accurate CMA.</p>
        </div>
        {step === "address" && (
          <form className="public-home-value-flow" onSubmit={continueToContact}>
            <input value={form.address} onChange={(event) => update("address", event.target.value)} placeholder="Property address" required />
            <div className="public-form-row">
              <input value={form.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
              <input value={form.county} onChange={(event) => update("county", event.target.value)} placeholder="County" />
            </div>
            <div className="public-form-row">
              <input value={form.sqft} onChange={(event) => update("sqft", event.target.value)} placeholder="Approx. square feet" />
              <input value={form.propertyType} onChange={(event) => update("propertyType", event.target.value)} placeholder="Property type" />
            </div>
            {error && <div className="login-error public-form-error">{error}</div>}
            <button className="btn primary" type="submit">Continue</button>
          </form>
        )}
        {step === "contact" && (
          <form className="public-home-value-flow" onSubmit={requestEstimate}>
            <div className="public-contact-required-card">
              <strong>Where should Nex send the CMA follow-up?</strong>
              <span>Add contact info to view the instant estimate and request a local review.</span>
            </div>
            <input value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Full name" required />
            <input value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" required />
            <input type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" required />
            <label className="public-consent">
              <input required type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
              <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
            </label>
            {error && <div className="login-error public-form-error">{error}</div>}
            <button className="btn primary" type="submit" disabled={submitting}>
              <Icon name={submitting ? "LoaderCircle" : "BadgeDollarSign"} className={submitting ? "spin" : ""} />
              <span>{submitting ? "Estimating" : "Show Estimated Range"}</span>
            </button>
          </form>
        )}
        {step === "result" && result && (
          <div className="public-home-value-result">
            <span>Estimated range</span>
            <strong>{formatCurrency(result.low)} - {formatCurrency(result.high)}</strong>
            <small>Confidence: {result.confidence || "Early estimate"}</small>
            {result.confidenceExplanation && <p>{result.confidenceExplanation}</p>}
            <div className="public-home-value-facts">
              {result.averagePricePerSqft ? <em>{formatCurrency(result.averagePricePerSqft)} avg / sqft</em> : null}
              {result.compsUsed?.length ? <em>{result.compsUsed.length} comps reviewed</em> : <em>Limited comparable data available</em>}
              {result.updatedAt ? <em>Updated {new Date(result.updatedAt).toLocaleString()}</em> : null}
            </div>
            {Array.isArray(result.compsUsed) && result.compsUsed.length > 0 && (
              <div className="public-home-value-comps">
                <strong>Comparable data used</strong>
                {result.compsUsed.slice(0, 4).map((comp) => (
                  <article key={comp.id || comp.mlsNumber || comp.address}>
                    <span>{comp.address || [comp.city, comp.county].filter(Boolean).join(", ") || "Comparable property"}</span>
                    <small>{formatCurrency(comp.price)} | {comp.beds || "-"} bd / {comp.baths || "-"} ba | {comp.sqft ? `${Number(comp.sqft).toLocaleString()} sqft` : "Sqft unavailable"}</small>
                    <em>Source: {comp.sourceLabel || result.dataSource || "Available listing data"}{comp.dataLastUpdated ? `, data updated ${new Date(comp.dataLastUpdated).toLocaleDateString()}` : ""}</em>
                  </article>
                ))}
              </div>
            )}
            <p>{result.disclaimer || "This is not an appraisal. A Nex agent can prepare a more accurate CMA using verified comparable sales and property details."}</p>
            <div>
              <button className="btn primary" type="button" onClick={onClose}>Have a Nex agent review this estimate</button>
              <button className="btn secondary" type="button" onClick={() => setStep("address")}>Edit property</button>
            </div>
          </div>
        )}
      </section>
    </div>
  );
}

function PublicHome({ data, navigate, setToast, sourceAgentSlug = "", onViewListing }) {
  const featured = data.featuredListings || [];
  const heroListing = featured[0] || {};
  return (
    <>
      <section className="public-hero">
        <div className="public-hero-copy">
          <p className="eyebrow">Nex Realty Florida</p>
          <h1>Search Florida homes with local Nex Realty guidance.</h1>
          <p>
            Search homes, compare market activity, request showings, estimate your home value, and connect with the
            right Nex agent when you are ready.
          </p>
          <PublicHomeSearchBox navigate={navigate} />
          <div className="public-status-row">
            {["Search guidance", "Saved searches", "Local agent help", "Showing requests"].map((item) => (
              <span key={item}><i />{item}</span>
            ))}
          </div>
        </div>
        <div className="public-hero-panel">
          <div className="public-side-cta-stack">
            <button className="public-feature-cta finance" onClick={() => navigate("/site/finance")} type="button">
              <Icon name="Landmark" />
              <strong>Get Financing</strong>
              <span>Start your pre-approval with Matthew Wolk at Wolk Mortgage.</span>
            </button>
            <button className="public-feature-cta value" onClick={() => navigate("/site/sell")} type="button">
              <Icon name="BadgeDollarSign" />
              <strong>What’s My Home Worth?</strong>
              <span>Request a local valuation strategy from a Nex Realty agent.</span>
            </button>
            <PublicLeadForm title="Quick Contact" compact sourcePage="Public Home" leadType="buyer" setToast={setToast} />
          </div>
        </div>
      </section>

      <section className="public-section public-card-grid">
        {[
          ["Buy With Nex", "Find homes, request showings, save searches, and get connected to a local Nex agent.", "/site/buy", "Home"],
          ["Sell With Nex", "Request a home value strategy and launch with premium Nex marketing.", "/site/sell", "TrendingUp"],
          ["Rent With Nex", "Ask about rental options, availability, and next steps.", "/site/rent", "KeyRound"],
          ["Join Nex Realty", "Explore the cloud brokerage model, NexU, support, and agent technology.", "/site/join", "Rocket"]
        ].map(([title, body, path, icon]) => (
          <button key={title} className="public-action-card" onClick={() => navigate(path)} type="button">
            <Icon name={icon} />
            <strong>{title}</strong>
            <span>{body}</span>
          </button>
        ))}
      </section>

      <section className="public-section">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Live home search</p>
            <h2>Search Florida properties with Nex Realty</h2>
          </div>
          <button className="btn secondary" onClick={() => navigate("/site/search")} type="button">Search Homes</button>
        </div>
        <div className="public-listing-grid">
          {featured.map((listing) => <PublicListingCard key={listing.id} listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />)}
        </div>
      </section>

      <section className="public-section">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Areas We Cover</p>
            <h2>Explore popular Florida markets</h2>
          </div>
        </div>
        <div className="public-areas-grid">
          {publicCoveredAreas.map((area) => (
            <button key={area} type="button" onClick={() => navigate(`/site/markets/${area.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`)}>
              {area}
            </button>
          ))}
        </div>
      </section>

      <section className="public-split-section">
        <div>
          <p className="eyebrow">Helpful follow-up</p>
          <h2>Every request keeps the right details attached.</h2>
          <p>
            Buyer, seller, renter, and agent inquiries preserve the market, message, source page, and contact details
            so the right Nex Realty team member can respond with context.
          </p>
        </div>
        <div className="public-mini-grid">
          {["Local market context", "Property details", "Showing requests", "Clear follow-up"].map((item) => (
            <span key={item}><Icon name="CheckCircle2" /> {item}</span>
          ))}
        </div>
      </section>
    </>
  );
}

function PublicHomeSearchBox({ navigate }) {
  const [search, setSearch] = useState("");
  const [type, setType] = useState("");
  const [beds, setBeds] = useState("");
  const [baths, setBaths] = useState("");
  const [minPrice, setMinPrice] = useState("");
  const [maxPrice, setMaxPrice] = useState("");

  function submit(event) {
    event.preventDefault();
    const params = new URLSearchParams();
    if (search) params.set("search", search);
    if (type) params.set("propertyType", type);
    if (beds) params.set("beds", beds);
    if (baths) params.set("baths", baths);
    if (minPrice) params.set("minPrice", minPrice);
    if (maxPrice) params.set("maxPrice", maxPrice);
    navigate(`/site/search${params.toString() ? `?${params.toString()}` : ""}`);
  }

  return (
    <form className="public-home-search" onSubmit={submit}>
      <div className="public-search-main-field">
        <Icon name="Search" />
        <input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="Search by city, ZIP, county, neighborhood, or address" />
      </div>
      <div className="public-home-search-row">
        <select value={type} onChange={(event) => setType(event.target.value)}>
          <option value="">Type</option>
          <option>Single Family</option>
          <option>Condo</option>
          <option>Townhome</option>
          <option>Land</option>
          <option>Commercial</option>
          <option>Rental</option>
        </select>
        <select value={minPrice} onChange={(event) => setMinPrice(event.target.value)}>
          <option value="">Min Price</option>
          {[100000, 200000, 300000, 400000, 500000, 750000, 1000000, 1500000].map((value) => <option key={value} value={value}>{formatCurrency(value)}</option>)}
        </select>
        <select value={maxPrice} onChange={(event) => setMaxPrice(event.target.value)}>
          <option value="">Max Price</option>
          {[300000, 400000, 500000, 750000, 1000000, 1500000, 2000000, 5000000].map((value) => <option key={value} value={value}>{formatCurrency(value)}</option>)}
        </select>
        <select value={beds} onChange={(event) => setBeds(event.target.value)}>
          <option value="">Beds</option>
          {[1, 2, 3, 4, 5, 6].map((value) => <option key={value} value={value}>{value}+</option>)}
        </select>
        <select value={baths} onChange={(event) => setBaths(event.target.value)}>
          <option value="">Baths</option>
          {[1, 1.5, 2, 2.5, 3, 4, 5].map((value) => <option key={value} value={value}>{value}+</option>)}
        </select>
        <button className="btn primary" type="submit">
          <Icon name="Search" />
          <span>Search</span>
        </button>
      </div>
      <button className="public-more-options" type="button" onClick={() => navigate("/site/search")}>More Options</button>
    </form>
  );
}

function PublicMarketTicker({ initialLocation = "" }) {
  const [snapshot, setSnapshot] = useState(null);

  useEffect(() => {
    let mounted = true;
    let timer;
    async function loadSnapshot() {
      const params = new URLSearchParams();
      if (initialLocation) params.set("search", initialLocation);
      try {
        const payload = await API.request(`/api/public/market-snapshot${params.toString() ? `?${params.toString()}` : ""}`, { retries: 0 });
        if (mounted) setSnapshot(payload);
      } catch (error) {
        if (mounted) setSnapshot({ error: true });
      }
    }
    loadSnapshot();
    timer = setInterval(loadSnapshot, 5 * 60 * 1000);
    return () => {
      mounted = false;
      clearInterval(timer);
    };
  }, [initialLocation]);

  const mortgageRate = snapshot?.mortgageRate;
  const inventory = snapshot?.inventory;
  const averagePrice = Number(inventory?.averagePrice || 0);

  return (
    <article className="public-market-ticker">
      <div className="public-ticker-head">
        <span><i /> Live market pulse</span>
        <small>{inventory?.location || initialLocation || "Florida"}</small>
      </div>
      <div className="public-ticker-track">
        <span>30yr avg: <strong>{mortgageRate?.rate ? `${mortgageRate.rate}%` : "checking"}</strong></span>
        <span>Active: <strong>{inventory?.active ?? "--"}</strong></span>
        <span>Pending: <strong>{inventory?.pending ?? "--"}</strong></span>
        <span>Sold: <strong>{inventory?.sold ?? "--"}</strong></span>
        <span>Rentals: <strong>{inventory?.rentals ?? "--"}</strong></span>
        <span>Avg list price: <strong>{averagePrice ? formatCurrency(averagePrice) : "--"}</strong></span>
      </div>
      <small className="public-ticker-note">
        {mortgageRate?.source || "Market data updates automatically. Live IDX counts display as available."}
      </small>
    </article>
  );
}

function PublicAiAssistant({ setToast, sourceAgentSlug = "" }) {
  const [form, setForm] = useState({
    message: "I want to buy in Tampa under $550,000.",
    name: "",
    email: "",
    phone: "",
    city: "",
    county: "",
    zip: "",
    timeline: "",
    priceRange: "",
    consent: false
  });
  const [reply, setReply] = useState(null);
  const [submitting, setSubmitting] = useState(false);

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
  }

  function usePrompt(prompt) {
    update("message", prompt);
  }

  async function submit(event) {
    event.preventDefault();
    const hasContact = form.name.trim() || form.email.trim() || form.phone.trim();
    if (hasContact) {
      const validation = validatePublicLeadCapture({ name: form.name, email: form.email, phone: form.phone, intent: detectPublicIntent(form.message), consent: form.consent });
      if (!validation.ok) {
        setToast(validation.message);
        return;
      }
    }
    setSubmitting(true);
    try {
      const payload = await API.request("/api/public/site-assistant", {
        method: "POST",
        retries: 0,
        body: JSON.stringify({
          ...publicConsumerSessionPayload(),
          ...form,
          sourceAgentSlug,
          sourcePage: "Public AI property guide"
        })
      });
      if (payload.consumerSession) rememberPublicConsumerSession(payload.consumerSession);
      setReply(payload);
      if (payload.lead) setToast("Thanks. A Nex Realty professional can follow up with you.");
    } catch (error) {
      setToast(error.message || "The AI property guide could not respond.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <article className="public-ai-assistant">
      <div className="public-widget-head">
        <span className="public-live-chip"><i /> AI Guide</span>
        <h2>Ask Nex to help you search.</h2>
        <p>Describe your move and the guide can detect your market, suggest next steps, and route you to the right Nex contact when you share your info.</p>
      </div>
      <form onSubmit={submit}>
        <textarea value={form.message} onChange={(event) => update("message", event.target.value)} rows={4} placeholder="Example: I want a 3 bedroom home in Tampa under $550,000." required />
        <div className="public-form-row three">
          <input value={form.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
          <input value={form.county} onChange={(event) => update("county", event.target.value)} placeholder="County" />
          <input value={form.priceRange} onChange={(event) => update("priceRange", event.target.value)} placeholder="Budget" />
        </div>
        <div className="public-form-row three">
          <input value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Name" />
          <input type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" />
          <input value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" />
        </div>
        <label className="public-consent">
          <input type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
          <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
        </label>
        <div className="public-prompt-row">
          {[
            "Find homes near Orlando under $600,000",
            "What is my Tampa home worth?",
            "I need a rental in Miami",
            "I am an agent researching Nex Realty"
          ].map((prompt) => (
            <button key={prompt} type="button" onClick={() => usePrompt(prompt)}>{prompt}</button>
          ))}
        </div>
        <button className="btn primary" type="submit" disabled={submitting}>
          <Icon name={submitting ? "LoaderCircle" : "Sparkles"} className={submitting ? "spin" : ""} />
          <span>{submitting ? "Thinking" : "Ask Nex"}</span>
        </button>
      </form>
      {reply && (
        <div className="public-ai-reply">
          <strong>Nex guide</strong>
          <p>{reply.reply}</p>
          <div className="public-ai-facts">
            <span>Intent: {reply.intent}</span>
            <span>Area: {[reply.location?.city, reply.location?.county, reply.location?.zip].filter(Boolean).join(", ") || reply.snapshot?.location || "Needs location"}</span>
            {reply.lead?.assignedAgentName && <span>Routed to: {reply.lead.assignedAgentName}</span>}
          </div>
        </div>
      )}
    </article>
  );
}

function PublicCmaCard({ setToast, sourceAgentSlug = "", requireContact = false, headline = "Estimate your value range.", sourcePage = "Public quick CMA" }) {
  const [form, setForm] = useState({
    address: "",
    city: "",
    county: "",
    sqft: "",
    beds: "",
    baths: "",
    name: "",
    email: "",
    phone: "",
    consent: false
  });
  const [result, setResult] = useState(null);
  const [submitting, setSubmitting] = useState(false);

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
  }

  async function submit(event) {
    event.preventDefault();
    if (requireContact || form.name || form.email || form.phone) {
      const validation = validatePublicLeadCapture({ name: form.name, email: form.email, phone: form.phone, intent: "seller", consent: form.consent });
      if (!validation.ok) {
        setToast(validation.message);
        return;
      }
    }
    setSubmitting(true);
    try {
      const payload = await API.request("/api/public/cma-estimate", {
        method: "POST",
        retries: 0,
        body: JSON.stringify({
          ...publicConsumerSessionPayload(),
          ...form,
          sourceAgentSlug,
          sourcePage
        })
      });
      if (payload.consumerSession) rememberPublicConsumerSession(payload.consumerSession);
      setResult(payload);
      if (payload.lead) setToast("Thanks. A Nex Realty professional can follow up with your home value request.");
    } catch (error) {
      setToast(error.message || "Could not create a quick value estimate.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <article className="public-cma-card">
      <div className="public-widget-head">
        <span className="public-live-chip red"><i /> Quick CMA</span>
        <h2>{headline}</h2>
        <p>A fast planning estimate uses nearby listing data where available, then a Nex agent can verify condition, upgrades, timing, and pricing strategy.</p>
      </div>
      <form onSubmit={submit}>
        <input value={form.address} onChange={(event) => update("address", event.target.value)} placeholder="Property address" />
        <div className="public-form-row three">
          <input value={form.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
          <input value={form.county} onChange={(event) => update("county", event.target.value)} placeholder="County" />
          <input type="number" min="0" value={form.sqft} onChange={(event) => update("sqft", event.target.value)} placeholder="Square feet" />
        </div>
        <div className="public-form-row three">
          <input value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Name" />
          <input type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" />
          <input value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" />
        </div>
        <label className="public-consent">
          <input type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
          <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
        </label>
        <button className="btn secondary" type="submit" disabled={submitting}>
          <Icon name={submitting ? "LoaderCircle" : "Calculator"} className={submitting ? "spin" : ""} />
          <span>{submitting ? "Calculating" : "Get Value Range"}</span>
        </button>
      </form>
      {result?.cma && (
        <div className="public-cma-result">
          <span>Preview range</span>
          <strong>{formatCurrency(result.cma.low)} - {formatCurrency(result.cma.high)}</strong>
          <div className="public-cma-result-facts">
            <em>{result.cma.compsUsed?.length || 0} comps reviewed</em>
            {result.cma.averagePricePerSqft ? <em>{formatCurrency(result.cma.averagePricePerSqft)} avg / sqft</em> : null}
            {result.cma.confidence ? <em>{result.cma.confidence}</em> : null}
          </div>
          {result.cma.confidenceExplanation && <small>{result.cma.confidenceExplanation}</small>}
          {Array.isArray(result.cma.compsUsed) && result.cma.compsUsed.length > 0 && (
            <div className="public-cma-comps">
              {result.cma.compsUsed.slice(0, 3).map((comp) => (
                <article key={comp.id || comp.mlsNumber || comp.address}>
                  <strong>{comp.address || [comp.city, comp.county].filter(Boolean).join(", ") || "Comparable property"}</strong>
                  <span>{formatCurrency(comp.price)} | {comp.sqft ? `${Number(comp.sqft).toLocaleString()} sqft` : "Sqft unavailable"} | {comp.pricePerSqft ? `${formatCurrency(comp.pricePerSqft)}/sqft` : "PPSF unavailable"}</span>
                  <small>Source: {comp.sourceLabel || result.cma.dataSource || "Available listing data"}</small>
                </article>
              ))}
            </div>
          )}
          <small>{result.cma.disclaimer}</small>
        </div>
      )}
    </article>
  );
}

function buildIdxSearchUrl(idx, filters = {}) {
  const base = filters.agentIdxUrl || idx?.searchUrl || idx?.stagingUrl || idx?.liveUrl || "https://nexrealtygroup.osiidxdev.com";
  try {
    const url = new URL(base);
    const location = filters.search || filters.city || filters.county || "";
    if (location) url.searchParams.set("q", location);
    if (filters.minPrice) url.searchParams.set("min_price", filters.minPrice);
    if (filters.maxPrice) url.searchParams.set("max_price", filters.maxPrice);
    if (filters.beds) url.searchParams.set("beds", filters.beds);
    if (filters.baths) url.searchParams.set("baths", filters.baths);
    return url.toString();
  } catch (error) {
    return base;
  }
}

function isIdxDomainApprovedForCurrentHost(idx) {
  const host = window.location.hostname.toLowerCase();
  if (["localhost", "127.0.0.1"].includes(host) || host.endsWith(".onrender.com")) return true;
  const approved = (idx?.approvedUrls || [idx?.approvedDomain, idx?.stagingUrl, idx?.liveUrl])
    .filter(Boolean)
    .map((value) => {
      try {
        return new URL(value).hostname.toLowerCase();
      } catch (error) {
        return "";
      }
    })
    .filter(Boolean);
  return approved.includes(host) || approved.some((domain) => host.endsWith(`.${domain}`));
}

function idxComplianceFrom(idx = {}, listing = null) {
  const compliance = listing?.idxCompliance || idx?.compliance || {};
  const sourceName = listing?.idxSourceName || compliance.sourceName || idx?.sourceMlsName || "MLS";
  const lowerSourceName = String(sourceName || "").toLowerCase();
  const isSefMlsSource = Boolean(compliance.isSefMlsSource) || /sefmls|miami|miamire|miami realtors|southeast florida/.test(lowerSourceName);
  const displaySourceName = listing?.idxDataSourceLabel || compliance.dataSourceLabel || compliance.displaySourceName || (isSefMlsSource ? "SEFMLS / MIAMI REALTORS" : sourceName);
  return {
    ...compliance,
    sourceName,
    displaySourceName,
    dataSourceLabel: displaySourceName,
    isSefMlsSource,
    brokerageName:
      compliance.brokerageName ||
      idx?.brokerage ||
      "Nex Realty LLC",
    brokerageLicenseText:
      compliance.brokerageLicenseText ||
      idx?.brokerageLicenseText ||
      "Florida licensed real estate brokerage",
    brokeragePhone:
      compliance.brokeragePhone ||
      idx?.brokeragePhone ||
      "[Brokerage phone/email]",
    brokerageEmail:
      compliance.brokerageEmail ||
      idx?.brokerageEmail ||
      "",
    brokerageStatement:
      compliance.brokerageStatement ||
      `${idx?.brokerage || "Nex Realty LLC"} is a ${idx?.brokerageLicenseText || "Florida licensed real estate brokerage"}.`,
    attributionText:
      listing?.idxAttribution ||
      compliance.attributionText ||
      "IDX information is provided exclusively for consumers' personal, non-commercial use and may not be used for any purpose other than to identify prospective properties consumers may be interested in purchasing.",
    disclaimerText:
      listing?.idxDisclaimer ||
      compliance.disclaimerText ||
      "Information is deemed reliable but not guaranteed. Listing information should be independently verified.",
    sourceDisclaimerText:
      listing?.idxSourceDisclaimerText ||
      compliance.sourceDisclaimerText ||
      (isSefMlsSource ? "Information is provided by MIAMI REALTORS / Southeast Florida MLS. Information is deemed reliable but is not guaranteed accurate by Nex Realty LLC or SEFMLS." : ""),
    dataUpdateText:
      listing?.idxDataUpdateText ||
      compliance.dataUpdateText ||
      `Based on information submitted to ${displaySourceName} as of [DATE/TIME]. Listing information is updated at least every 12 hours.`,
    dataAccuracyText:
      listing?.idxDataAccuracyText ||
      compliance.dataAccuracyText ||
      "Consumers should verify listing details with a licensed professional.",
    brokerageDisplayText:
      compliance.brokerageDisplayText ||
      "Nex Realty LLC is a Florida licensed real estate brokerage.",
    excludedListingsText:
      compliance.excludedListingsText ||
      "Some IDX listings may have been excluded from this website.",
    fullDisclaimerText:
      compliance.fullDisclaimerText ||
      "",
    automatedValuationDisabledText:
      compliance.automatedValuationDisabledText ||
      "Automated estimates and third-party commentary are not displayed with IDX listings on this website.",
    consumerCommentDisabledText:
      compliance.consumerCommentDisabledText ||
      "Consumer comments and reviews are not displayed with IDX listings on this website.",
    fairHousingText:
      listing?.idxFairHousingText ||
      compliance.fairHousingText ||
      "Nex Realty supports Equal Housing Opportunity and the Fair Housing Act."
  };
}

function PublicComplianceLogos({ compliance = {} }) {
  const logos = [
    { key: "eho", url: compliance.equalHousingLogoUrl, alt: "Equal Housing Opportunity" },
    { key: "provider", url: compliance.providerLogoUrl, alt: "IDX provider logo" },
    { key: "mls", url: compliance.mlsLogoUrl, alt: "MLS logo" }
  ].filter((logo) => logo.url);

  return (
    <div className="public-compliance-logos">
      {logos.map((logo) => (
        <img key={logo.key} src={logo.url} alt={logo.alt} className="public-compliance-logo" loading="lazy" />
      ))}
      {!logos.length && <span className="public-eho-badge">Equal Housing Opportunity</span>}
    </div>
  );
}

function PublicIdxListingAttribution({ listing = {}, compact = false }) {
  const compliance = idxComplianceFrom({}, listing);
  const status = listing.idxListingStatus || listing.status || "[Status]";
  const sourceName = listing.idxDataSourceLabel || compliance.dataSourceLabel || listing.idxSourceName || compliance.sourceName || "MLS";
  const mlsId = listing.stellarListingId || listing.mlsNumber || listing.providerListingId || "[MLS ID]";
  const rawBrokerageName = listing.listingBrokerageName || listing.listingOffice || "";
  const brokerageName = /\[listing brokerage name\]/i.test(rawBrokerageName) ? "" : rawBrokerageName;
  const sold = /sold|closed/i.test(status);
  const cooperatingLine = sold && listing.cooperatingBrokerageName ? `Cooperating brokerage: ${listing.cooperatingBrokerageName}` : "";
  const soldDisclosure = sold && !listing.cooperatingBrokerageName
    ? listing.idxSoldDisclosure || "Properties displayed may be listed or sold by various participants in the MLS."
    : "";

  return (
    <div className={`public-listing-attribution ${compact ? "compact" : ""}`}>
      {brokerageName && <span>Listing courtesy of {brokerageName}</span>}
      <span>Data source: {sourceName}</span>
      <span>MLS ID: {mlsId}</span>
      <span>Status: {status}</span>
      {cooperatingLine && <span>{cooperatingLine}</span>}
      {soldDisclosure && <small>{soldDisclosure}</small>}
    </div>
  );
}

function PublicIdxComplianceNotice({ idx = {}, listing = null, compact = false }) {
  const compliance = idxComplianceFrom(idx, listing);
  const showAvmNotice = listing && listing.idxAutomatedValuationAllowed === false;
  const showCommentNotice = listing && listing.idxConsumerCommentAllowed === false;
  const contactLine = [compliance.brokeragePhone, compliance.brokerageEmail].filter(Boolean).join(" | ");
  return (
    <aside className={`public-compliance-card ${compact ? "compact" : ""}`}>
      <PublicComplianceLogos compliance={compliance} />
      <div className="public-compliance-text">
        {!compact && <strong>IDX / MLS compliance notice</strong>}
        <p>{compliance.brokerageStatement}</p>
        <p>{compliance.attributionText}</p>
        <p>{compliance.disclaimerText}</p>
        {compliance.sourceDisclaimerText && <p>{compliance.sourceDisclaimerText}</p>}
        <p>
          {compliance.dataUpdateText}
          {compliance.displayCriteriaLimited !== false && ` ${compliance.excludedListingsText}`}
        </p>
        {!compact && <p>{compliance.dataAccuracyText}</p>}
        {!compact && contactLine && <small>{contactLine}</small>}
        <small>{compliance.fairHousingText}</small>
        {showAvmNotice && <small>{compliance.automatedValuationDisabledText}</small>}
        {showCommentNotice && <small>{compliance.consumerCommentDisabledText}</small>}
        {compliance.needsProviderReview && (
          <em>Provider-approved MLS wording is still pending before live IDX display should be enabled.</em>
        )}
      </div>
    </aside>
  );
}

function IDXSearchEmbed({ idx = {}, filters = {}, sourceAgentSlug = "", agent = null, setToast }) {
  const searchUrl = buildIdxSearchUrl(idx, { ...filters, agentIdxUrl: agent?.idxSearchUrl });
  const canEmbed = idx.embedMode === "iframe" && idx.embedUrl;
  const domainApproved = isIdxDomainApprovedForCurrentHost(idx);
  const liveApiMode = Boolean(idx.apiConfigured && idx.apiFetchEnabled);
  const providerLabel = liveApiMode ? "Live MLS Search" : idx.provider || "Property Search";

  return (
    <section className="idx-search-card">
      <div className="idx-search-head">
        <div>
          <p className="eyebrow">Home search source</p>
          <h2>{providerLabel}</h2>
          <p>
            {liveApiMode
              ? "Live MLS listings are available on this site with saved search, showing request, and property question options."
              : "Use the available property search option or tell us what you are looking for and a Nex agent can help."}
          </p>
        </div>
        <span className="idx-provider-badge">{idx.licenseStatus || "Active"}</span>
      </div>

      {!domainApproved && (
        <div className="idx-domain-warning">
          <Icon name="TriangleAlert" />
          <span>{idx.domainWarning || "This domain may need IDX provider approval before live IDX display."}</span>
        </div>
      )}

      <div className="idx-search-frame-wrap">
        {canEmbed ? (
          <iframe title="OSI IDX Property Search" src={idx.embedUrl} loading="lazy" />
        ) : liveApiMode ? (
          <div className="idx-hosted-panel">
            <Icon name="Satellite" />
            <strong>Live MLS search is active on this website.</strong>
            <span>Listings are loading directly into the search results below. You can ask questions, request showings, and save search preferences.</span>
            <button className="btn primary" type="button" onClick={() => document.querySelector(".public-listing-grid")?.scrollIntoView({ behavior: "smooth", block: "start" })}>
              <Icon name="ArrowDown" />
              <span>View Live Results</span>
            </button>
          </div>
        ) : (
          <div className="idx-hosted-panel">
            <Icon name="Search" />
            <strong>Property search is available through the approved search page.</strong>
            <span>{agent?.idxSearchUrl ? `This opens ${agent.name}'s property search page.` : "Open the search page or submit the form below and Nex Realty can help you find matching homes."}</span>
            <a className="btn primary" href={searchUrl} target="_blank" rel="noreferrer">
              <Icon name="ExternalLink" />
              <span>Open Property Search</span>
            </a>
          </div>
        )}
      </div>

      <PublicIdxComplianceNotice idx={idx} compact />

      <div className="idx-lead-grid">
        <PublicLeadForm
          title="Request property help"
          leadType="buyer"
          sourcePage={liveApiMode ? "Nex Realty MLS Search" : "Property Search"}
          sourceAgentSlug={sourceAgentSlug}
          leadSource="IDX Search"
          idxProvider={providerLabel}
          idxIntent="Property Inquiry"
          idxSearchUrl={searchUrl}
          setToast={setToast}
          compact
        />
        <article className="idx-sync-card">
          <strong>Need help with a property?</strong>
          <span>{liveApiMode ? "Send a question, showing request, saved search, or favorite property and a Nex Realty professional can follow up." : "Tell us what you are looking for and a Nex Realty professional can help with search options."}</span>
          <div>
            {(idx.leadSources || ["Property Inquiry", "Saved Search", "Showing Request", "Home Search"]).slice(0, 5).map((source) => (
              <em key={source}>{source}</em>
            ))}
          </div>
        </article>
      </div>
    </section>
  );
}

const PUBLIC_SEARCH_SORT_OPTIONS = [
  ["recommended", "Recommended first"],
  ["newest", "Newest listings"],
  ["price-desc", "Price high to low"],
  ["price-asc", "Price low to high"],
  ["beds-desc", "Most bedrooms"],
  ["baths-desc", "Most bathrooms"],
  ["sqft-desc", "Largest square footage"]
];

const PUBLIC_SEARCH_PAGE_SIZE = 16;
const PUBLIC_SEARCH_PROPERTY_TYPES = ["", "Single Family", "Condo", "Townhouse", "Villa", "Multi-Family", "Land", "Manufactured Home"];
const PUBLIC_SEARCH_PRICE_OPTIONS = Array.from({ length: 100 }, (_, index) => String((index + 1) * 50000));
const PUBLIC_SEARCH_FLORIDA_COUNTIES = [
  "Alachua County", "Baker County", "Bay County", "Bradford County", "Brevard County", "Broward County", "Calhoun County", "Charlotte County",
  "Citrus County", "Clay County", "Collier County", "Columbia County", "DeSoto County", "Dixie County", "Duval County", "Escambia County",
  "Flagler County", "Franklin County", "Gadsden County", "Gilchrist County", "Glades County", "Gulf County", "Hamilton County", "Hardee County",
  "Hendry County", "Hernando County", "Highlands County", "Hillsborough County", "Holmes County", "Indian River County", "Jackson County",
  "Jefferson County", "Lafayette County", "Lake County", "Lee County", "Leon County", "Levy County", "Liberty County", "Madison County",
  "Manatee County", "Marion County", "Martin County", "Miami-Dade County", "Monroe County", "Nassau County", "Okaloosa County", "Okeechobee County",
  "Orange County", "Osceola County", "Palm Beach County", "Pasco County", "Pinellas County", "Polk County", "Putnam County", "Santa Rosa County",
  "Sarasota County", "Seminole County", "St. Johns County", "St. Lucie County", "Sumter County", "Suwannee County", "Taylor County", "Union County",
  "Volusia County", "Wakulla County", "Walton County", "Washington County"
];

function publicSearchDefaultFilters() {
  return {
    search: "",
    city: "",
    county: "",
    zip: "",
    status: "Active",
    minPrice: "",
    maxPrice: "",
    beds: "",
    baths: "",
    propertyType: ""
  };
}

function publicSearchInitialFilters() {
  const params = new URLSearchParams(window.location.search);
  return {
    ...publicSearchDefaultFilters(),
    search: params.get("search") || params.get("q") || "",
    city: params.get("city") || "",
    county: params.get("county") || "",
    zip: params.get("zip") || "",
    status: params.get("status") || "Active",
    minPrice: params.get("minPrice") || "",
    maxPrice: params.get("maxPrice") || "",
    beds: params.get("beds") || "",
    baths: params.get("baths") || "",
    propertyType: params.get("propertyType") || ""
  };
}

function publicSearchQueryParams(filters = {}, sort = "recommended", page = 1, limit = PUBLIC_SEARCH_PAGE_SIZE) {
  const params = publicSearchParamsFromFilters({ ...filters, sort, page, limit });
  return params;
}

function publicSearchActiveChips(filters = {}) {
  const chips = [];
  const location = [filters.search, filters.city, filters.county, filters.zip].filter(Boolean).join(", ");
  if (location) chips.push({ id: "location", label: location, keys: ["search", "city", "county", "zip"] });
  if (filters.minPrice || filters.maxPrice) {
    const min = filters.minPrice ? formatCurrency(filters.minPrice) : "Any";
    const max = filters.maxPrice ? formatCurrency(filters.maxPrice) : "Any";
    chips.push({ id: "price", label: `${min} to ${max}`, keys: ["minPrice", "maxPrice"] });
  }
  if (filters.beds || filters.baths) chips.push({ id: "beds-baths", label: `${filters.beds || "Any"}+ beds / ${filters.baths || "Any"}+ baths`, keys: ["beds", "baths"] });
  if (filters.propertyType) chips.push({ id: "property-type", label: filters.propertyType, keys: ["propertyType"] });
  if (filters.status && filters.status !== "Active") chips.push({ id: "status", label: filters.status, keys: ["status"] });
  return chips;
}

function PublicSearchFilterChips({ filters, onClear, onClearAll }) {
  const chips = publicSearchActiveChips(filters);
  if (!chips.length) return null;
  return (
    <div className="public-active-filter-chips" aria-label="Active search filters">
      {chips.map((chip) => (
        <button key={chip.id} type="button" onClick={() => onClear(chip.keys)}>
          <span>{chip.label}</span>
          <Icon name="X" size={14} />
        </button>
      ))}
      <button className="clear-all" type="button" onClick={onClearAll}>Clear all</button>
    </div>
  );
}

const publicMapAssetPromises = {};

function loadPublicExternalScript(src) {
  if (typeof document === "undefined") return Promise.reject(new Error("Document is unavailable."));
  if (publicMapAssetPromises[src]) return publicMapAssetPromises[src];
  const existing = Array.from(document.scripts || []).find((script) => script.src === src);
  if (existing) {
    publicMapAssetPromises[src] = Promise.resolve();
    return publicMapAssetPromises[src];
  }
  publicMapAssetPromises[src] = new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = src;
    script.async = true;
    script.defer = true;
    script.onload = resolve;
    script.onerror = () => reject(new Error(`Could not load ${src}`));
    document.head.appendChild(script);
  });
  return publicMapAssetPromises[src];
}

function loadPublicExternalStyle(href) {
  if (typeof document === "undefined") return Promise.reject(new Error("Document is unavailable."));
  if (publicMapAssetPromises[href]) return publicMapAssetPromises[href];
  const existing = Array.from(document.querySelectorAll("link[rel='stylesheet']")).find((link) => link.href === href);
  if (existing) {
    publicMapAssetPromises[href] = Promise.resolve();
    return publicMapAssetPromises[href];
  }
  publicMapAssetPromises[href] = new Promise((resolve, reject) => {
    const link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = href;
    link.onload = resolve;
    link.onerror = () => reject(new Error(`Could not load ${href}`));
    document.head.appendChild(link);
  });
  return publicMapAssetPromises[href];
}

function publicMapEscapeHtml(value) {
  return String(value ?? "").replace(/[&<>"']/g, (char) => ({
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    "\"": "&quot;",
    "'": "&#39;"
  }[char] || char));
}

function publicMapMarkerSignature(markers = []) {
  return markers
    .map((marker) => [marker.id, marker.price, marker.latitude, marker.longitude].join(":"))
    .join("|");
}

function publicMapProviderLabel(map = {}) {
  if (map.provider === "google" && map.googleMapsApiKey) return "Google Maps";
  if (map.provider === "mapbox" && map.mapboxToken) return "Mapbox";
  return "Map being connected";
}

function PublicInteractiveListingMap({ markers = [], listings = [], map = {}, activeListingId = "", onActivate, onOpenListing, sourceAgentSlug = "" }) {
  const containerRef = useRef(null);
  const mapInstanceRef = useRef(null);
  const markerRefs = useRef([]);
  const callbackRef = useRef({ onActivate, onOpenListing });
  const [loadError, setLoadError] = useState("");
  const markerSignature = useMemo(() => publicMapMarkerSignature(markers), [markers]);
  const resolvedProvider = map.provider === "google" && map.googleMapsApiKey
    ? "google"
    : map.provider === "mapbox" && map.mapboxToken
      ? "mapbox"
      : "";

  useEffect(() => {
    callbackRef.current = { onActivate, onOpenListing };
  }, [onActivate, onOpenListing]);

  useEffect(() => {
    if (!containerRef.current) return;
    const activeId = String(activeListingId || "");
    containerRef.current.querySelectorAll("[data-map-marker-id]").forEach((element) => {
      element.classList.toggle("active", element.getAttribute("data-map-marker-id") === activeId);
    });
  }, [activeListingId]);

  useEffect(() => {
    let cancelled = false;
    let googleAuthCheckTimer = null;
    let previousGoogleAuthFailure = null;
    const showMapLoadError = () => {
      if (!cancelled) setLoadError("Map view is temporarily unavailable. The full listing results are still available in list view.");
    };
    const cleanupMap = () => {
      if (googleAuthCheckTimer) {
        try {
          window.clearTimeout(googleAuthCheckTimer);
        } catch (_) {}
        googleAuthCheckTimer = null;
      }
      markerRefs.current.forEach((marker) => {
        try {
          if (typeof marker.setMap === "function") {
            marker.setMap(null);
          } else {
            marker.remove?.();
          }
        } catch (_) {}
      });
      markerRefs.current = [];
      if (mapInstanceRef.current) {
        try {
          mapInstanceRef.current.remove?.();
        } catch (_) {}
      }
      mapInstanceRef.current = null;
    };

    const openListingFromMarker = (marker) => {
      const listing = listings.find((item) => item.id === marker.id) || marker;
      callbackRef.current.onOpenListing?.(listing, sourceAgentSlug);
    };

    async function renderMap() {
      cleanupMap();
      setLoadError("");
      if (!containerRef.current || !markers.length) return;
      if (resolvedProvider === "google") {
        if (typeof window !== "undefined") {
          previousGoogleAuthFailure = window.gm_authFailure;
          window.gm_authFailure = () => {
            try {
              if (typeof previousGoogleAuthFailure === "function") previousGoogleAuthFailure();
            } catch (_) {}
            showMapLoadError();
          };
        }
        await loadPublicExternalScript(`https://maps.googleapis.com/maps/api/js?key=${encodeURIComponent(map.googleMapsApiKey)}&v=weekly`);
        if (cancelled || !containerRef.current || !window.google?.maps) return;
        const google = window.google.maps;
        const first = markers[0];
        const googleMap = new google.Map(containerRef.current, {
          center: { lat: first.latitude, lng: first.longitude },
          zoom: markers.length > 1 ? 10 : 12,
          mapTypeControl: false,
          fullscreenControl: true,
          streetViewControl: false,
          clickableIcons: false
        });
        mapInstanceRef.current = googleMap;
        const bounds = new google.LatLngBounds();
        markers.forEach((marker) => {
          class PriceOverlay extends google.OverlayView {
            onAdd() {
              this.button = document.createElement("button");
              this.button.type = "button";
              this.button.className = classNames("public-google-price-marker", activeListingId === marker.id && "active");
              this.button.setAttribute("data-map-marker-id", String(marker.id || ""));
              this.button.setAttribute("aria-label", `Open ${marker.address || "listing"} on map`);
              this.button.innerHTML = `<span>${publicMapEscapeHtml(formatCurrency(marker.price || 0))}</span>`;
              this.button.addEventListener("mouseenter", () => callbackRef.current.onActivate?.(marker.id));
              this.button.addEventListener("focus", () => callbackRef.current.onActivate?.(marker.id));
              this.button.addEventListener("click", () => openListingFromMarker(marker));
              this.getPanes().overlayMouseTarget.appendChild(this.button);
            }
            draw() {
              const projection = this.getProjection();
              const point = projection?.fromLatLngToDivPixel(new google.LatLng(marker.latitude, marker.longitude));
              if (!point || !this.button) return;
              this.button.style.left = `${point.x}px`;
              this.button.style.top = `${point.y}px`;
            }
            onRemove() {
              if (this.button?.parentNode) this.button.parentNode.removeChild(this.button);
              this.button = null;
            }
          }
          const overlay = new PriceOverlay();
          overlay.setMap(googleMap);
          markerRefs.current.push(overlay);
          bounds.extend({ lat: marker.latitude, lng: marker.longitude });
        });
        if (markers.length > 1) {
          googleMap.fitBounds(bounds, 46);
        } else {
          googleMap.setCenter({ lat: first.latitude, lng: first.longitude });
          googleMap.setZoom(12);
        }
        googleAuthCheckTimer = window.setTimeout(() => {
          const mapText = containerRef.current?.textContent || "";
          if (/Oops!\s*Something went wrong|didn.?t load Google Maps correctly/i.test(mapText)) {
            showMapLoadError();
          }
        }, 1600);
        return;
      }
      if (resolvedProvider === "mapbox") {
        await Promise.all([
          loadPublicExternalStyle("https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.css"),
          loadPublicExternalScript("https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.js")
        ]);
        if (cancelled || !containerRef.current || !window.mapboxgl) return;
        window.mapboxgl.accessToken = map.mapboxToken;
        const first = markers[0];
        const mapboxMap = new window.mapboxgl.Map({
          container: containerRef.current,
          style: map.mapboxStyle || "mapbox://styles/mapbox/streets-v12",
          center: [first.longitude, first.latitude],
          zoom: markers.length > 1 ? 10 : 12,
          attributionControl: true
        });
        mapInstanceRef.current = mapboxMap;
        mapboxMap.addControl(new window.mapboxgl.NavigationControl({ showCompass: false }), "top-right");
        const bounds = new window.mapboxgl.LngLatBounds();
        markers.forEach((marker) => {
          const button = document.createElement("button");
          button.type = "button";
          button.className = classNames("public-mapbox-price-marker", activeListingId === marker.id && "active");
          button.setAttribute("data-map-marker-id", String(marker.id || ""));
          button.setAttribute("aria-label", `Open ${marker.address || "listing"} on map`);
          button.innerHTML = `<span>${publicMapEscapeHtml(formatCurrency(marker.price || 0))}</span>`;
          button.addEventListener("mouseenter", () => callbackRef.current.onActivate?.(marker.id));
          button.addEventListener("focus", () => callbackRef.current.onActivate?.(marker.id));
          button.addEventListener("click", () => openListingFromMarker(marker));
          const mapboxMarker = new window.mapboxgl.Marker({ element: button, anchor: "bottom" })
            .setLngLat([marker.longitude, marker.latitude])
            .addTo(mapboxMap);
          markerRefs.current.push(mapboxMarker);
          bounds.extend([marker.longitude, marker.latitude]);
        });
        mapboxMap.once("load", () => {
          if (cancelled) return;
          if (markers.length > 1) {
            mapboxMap.fitBounds(bounds, { padding: 48, maxZoom: 14, duration: 0 });
          } else {
            mapboxMap.setZoom(12);
          }
        });
        return;
      }
    }

    renderMap().catch(() => {
      if (!cancelled) setLoadError("The map could not load, but the listing results are still available.");
    });

    return () => {
      cancelled = true;
      cleanupMap();
      if (resolvedProvider === "google" && typeof window !== "undefined") {
        try {
          if (typeof previousGoogleAuthFailure === "function") {
            window.gm_authFailure = previousGoogleAuthFailure;
          } else {
            delete window.gm_authFailure;
          }
        } catch (_) {
          window.gm_authFailure = previousGoogleAuthFailure || undefined;
        }
      }
    };
  }, [markerSignature, resolvedProvider, map.googleMapsApiKey, map.mapboxToken, map.mapboxStyle, sourceAgentSlug]);

  return (
    <>
      <div ref={containerRef} className="public-list-map-interactive" />
      {loadError && (
        <div className="public-list-map-load-error">
          <Icon name="MapPinned" />
          <strong>Map temporarily unavailable</strong>
          <span>{loadError}</span>
        </div>
      )}
    </>
  );
}

function PublicListingMapPreview({ listings = [], map = {}, activeListingId = "", onActivate, onOpenListing, sourceAgentSlug = "", locationLabel = "current search" }) {
  const mapConfigured = Boolean(map.providerConfigured && map.provider !== "none" && map.provider !== "native-preview");
  const markers = listings
    .map((listing) => ({
      id: listing.id,
      price: listing.price,
      address: listing.address,
      city: listing.city,
      latitude: Number(listing.latitude || listing.lat || 0),
      longitude: Number(listing.longitude || listing.lng || listing.lon || 0)
    }))
    .filter((marker) => Number.isFinite(marker.latitude) && Number.isFinite(marker.longitude) && marker.latitude && marker.longitude);
  const skippedCount = Math.max(0, listings.length - markers.length);

  return (
    <article className={classNames("public-list-map-card", !mapConfigured && "not-configured")}>
      <div className="public-list-map-toolbar">
        <span><Icon name="MapPinned" /> Map search</span>
        <small>{mapConfigured && markers.length ? `${markers.length} mapped in ${locationLabel}` : mapConfigured ? publicMapProviderLabel(map) : "Map provider needed"}</small>
      </div>
      {!mapConfigured ? (
        <div className="public-list-map-config-needed">
          <Icon name="MapPinned" />
          <strong>Map search is almost ready.</strong>
          <p>The listings are filtered for {locationLabel}. Map view is being connected now, and the full listing results are still available below.</p>
          <span>{listings.length ? `${listings.length} homes are still available in this search page.` : "Search results will continue to load in list view."}</span>
        </div>
      ) : (
        <div className="public-list-map-stage interactive" role="application" aria-label="Interactive listing map">
          {markers.length ? (
            <PublicInteractiveListingMap
              markers={markers}
              listings={listings}
              map={map}
              activeListingId={activeListingId}
              onActivate={onActivate}
              onOpenListing={onOpenListing}
              sourceAgentSlug={sourceAgentSlug}
            />
          ) : (
            <div className="public-list-map-empty">
              <Icon name="MapPinned" />
              <strong>Map locations unavailable</strong>
              <span>{map.message || "These listings can still be browsed in the list."}</span>
            </div>
          )}
          {markers.length ? (
            <div className="public-list-map-provider-badge">
              <Icon name="MapPin" size={14} />
              <span>{publicMapProviderLabel(map)}</span>
            </div>
          ) : null}
        </div>
      )}
      {(map.message || skippedCount) && (
        <p className="public-list-map-message">
          {mapConfigured ? (map.message || `Showing mapped homes from ${locationLabel}.`) : "Map provider is not configured yet."}
          {skippedCount ? ` ${skippedCount} listing${skippedCount === 1 ? "" : "s"} did not include coordinates and stayed in list view.` : ""}
        </p>
      )}
    </article>
  );
}

function PublicSearchPagination({ pagination = {}, loading = false, onPage }) {
  const currentPage = Math.max(1, Number(pagination.page || 1) || 1);
  const totalPages = Math.max(1, Number(pagination.totalPages || 1) || 1);
  if (totalPages <= 1) return null;
  const windowStart = Math.max(1, Math.min(currentPage - 2, totalPages - 4));
  const pages = Array.from({ length: Math.min(5, totalPages) }, (_, index) => windowStart + index).filter((page) => page <= totalPages);
  return (
    <nav className="public-pagination" aria-label="Search result pages">
      <button type="button" disabled={loading || currentPage <= 1} onClick={() => onPage(currentPage - 1)}>
        <Icon name="ChevronLeft" size={16} />
        <span>Previous</span>
      </button>
      {pages[0] > 1 && (
        <>
          <button type="button" disabled={loading} onClick={() => onPage(1)}>1</button>
          {pages[0] > 2 && <em>...</em>}
        </>
      )}
      {pages.map((page) => (
        <button key={page} type="button" className={page === currentPage ? "active" : ""} disabled={loading || page === currentPage} onClick={() => onPage(page)}>
          {page}
        </button>
      ))}
      {pages[pages.length - 1] < totalPages && (
        <>
          {pages[pages.length - 1] < totalPages - 1 && <em>...</em>}
          <button type="button" disabled={loading} onClick={() => onPage(totalPages)}>{totalPages}</button>
        </>
      )}
      <button type="button" disabled={loading || currentPage >= totalPages} onClick={() => onPage(currentPage + 1)}>
        <span>Next</span>
        <Icon name="ChevronRight" size={16} />
      </button>
    </nav>
  );
}

function PublicPropertySearchV2({ data, navigate, setToast, sourceAgentSlug = "", onViewListing, onTalkAgent, onHomeValue }) {
  const initialSearchFilters = useMemo(() => publicSearchInitialFilters(), []);
  const [filters, setFilters] = useState(initialSearchFilters);
  const [draftFilters, setDraftFilters] = useState(initialSearchFilters);
  const [sort, setSort] = useState(() => new URLSearchParams(window.location.search).get("sort") || "recommended");
  const [results, setResults] = useState({ items: [], pagination: { total: 0, page: 1, limit: PUBLIC_SEARCH_PAGE_SIZE, totalPages: 1, hasMore: false }, idx: {}, map: {} });
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [viewMode, setViewMode] = useState("list");
  const [filtersOpen, setFiltersOpen] = useState(false);
  const [activeListingId, setActiveListingId] = useState("");
  const requestRef = useRef(0);
  const listings = results.items || [];
  const pagination = results.pagination || {};
  const liveIdxEnabled = Boolean(data.idx?.apiConfigured && data.idx?.apiFetchEnabled);
  const resultCountLabel = pagination.total
    ? `${Number(pagination.total).toLocaleString()} homes found`
    : loading
      ? "Loading homes"
      : "No matching homes yet";
  const currentPage = Math.max(1, Number(pagination.page || 1) || 1);
  const resultStart = pagination.total ? ((currentPage - 1) * Number(pagination.limit || PUBLIC_SEARCH_PAGE_SIZE)) + 1 : 0;
  const resultEnd = pagination.total ? Math.min(Number(pagination.total), resultStart + listings.length - 1) : listings.length;
  const sourceLabel = results.idx?.source === "live-idx-api" ? "Live MLS results" : liveIdxEnabled ? "Live search" : "Preview search";
  const locationLabel = [filters.search, filters.city, filters.county, filters.zip].filter(Boolean).join(", ") || "current search";

  async function loadListings(nextFilters = filters, options = {}) {
    const nextPage = Math.max(1, Number(options.page || 1) || 1);
    const requestedSort = options.sort || sort;
    const requestId = requestRef.current + 1;
    requestRef.current = requestId;
    setError("");
    setLoading(true);
    const params = publicSearchQueryParams(nextFilters, requestedSort, nextPage, PUBLIC_SEARCH_PAGE_SIZE);
    try {
      const payload = await API.request(`/api/site/listings/search?${params.toString()}`, { retries: 0 });
      if (requestRef.current !== requestId) return;
      const nextItems = publicListingsFromPayload(payload);
      setResults({
        ...payload,
        items: nextItems,
        listings: nextItems,
        pagination: payload.pagination || { total: nextItems.length, page: nextPage, limit: PUBLIC_SEARCH_PAGE_SIZE, totalPages: 1, hasMore: false },
        idx: payload.idx || {},
        map: payload.map || {}
      });
      console.info("[site-listings-render-count]", { rendered: nextItems.length, page: nextPage, total: payload.pagination?.total || nextItems.length });
      const urlParams = publicSearchQueryParams(nextFilters, requestedSort, nextPage, PUBLIC_SEARCH_PAGE_SIZE);
      window.history.replaceState({}, "", `/site/search?${urlParams.toString()}`);
    } catch (loadError) {
      if (requestRef.current !== requestId) return;
      setError(loadError.message || "Listings are loading. Try searching a city, ZIP, or neighborhood.");
      setResults({ items: [], pagination: { total: 0, page: 1, limit: PUBLIC_SEARCH_PAGE_SIZE, totalPages: 1, hasMore: false }, idx: {}, map: {} });
    } finally {
      if (requestRef.current === requestId) {
        setLoading(false);
      }
    }
  }

  useEffect(() => {
    loadListings(filters, { page: Math.max(1, Number(new URLSearchParams(window.location.search).get("page") || 1) || 1) });
  }, []);

  function update(field, value) {
    setDraftFilters((current) => field === "search"
      ? { ...current, search: value, city: "", county: "", zip: "" }
      : { ...current, [field]: value });
  }

  function applyFilters(nextFilters = draftFilters, options = {}) {
    const appliedFilters = { ...publicSearchDefaultFilters(), ...(nextFilters || {}) };
    setFilters(appliedFilters);
    setDraftFilters(appliedFilters);
    if (options.closeFilters !== false) setFiltersOpen(false);
    loadListings(appliedFilters, { page: 1, sort: options.sort || sort });
  }

  function submitSearch(event) {
    event.preventDefault();
    applyFilters(draftFilters);
  }

  function clearChip(keys) {
    const next = { ...filters };
    keys.forEach((key) => {
      next[key] = key === "status" ? "Active" : "";
    });
    setFilters(next);
    setDraftFilters(next);
    loadListings(next, { page: 1 });
  }

  function clearAll() {
    const reset = publicSearchDefaultFilters();
    setFilters(reset);
    setDraftFilters(reset);
    setSort("recommended");
    loadListings(reset, { page: 1, sort: "recommended" });
  }

  function applyQuickFilter(quick) {
    const next = { ...filters, search: quick, city: "", county: "", zip: "" };
    if (/waterfront|pool|open house|price reduced|luxury/i.test(quick)) next.search = quick;
    setFilters(next);
    setDraftFilters(next);
    loadListings(next, { page: 1 });
  }

  function goToPage(page) {
    window.scrollTo({ top: 0, behavior: "smooth" });
    loadListings(filters, { page });
  }

  function changeSort(value) {
    setSort(value);
    loadListings(filters, { page: 1, sort: value });
  }

  function chooseSearchSuggestion(suggestion) {
    const nextFilters = filtersFromPublicSearchSuggestion(draftFilters, suggestion);
    setFilters(nextFilters);
    setDraftFilters(nextFilters);
    loadListings(nextFilters, { page: 1 });
  }

  const searchCriteria = Object.entries(filters)
    .filter(([, value]) => String(value || "").trim())
    .map(([key, value]) => `${key}: ${value}`)
    .join(", ");

  return (
    <section className="public-page public-property-search-v2">
      <div className="public-search-v2-hero">
        <div>
          <p className="eyebrow">Home search</p>
          <h1>Search Florida homes with Nex Realty.</h1>
          <p>Search by city, ZIP, neighborhood, address, or MLS number. Browse first, then save a search, request a showing, or ask Nex for help when you are ready.</p>
        </div>
        <form className="public-search-v2-box" onSubmit={submitSearch}>
          <PublicListingSearchAutocomplete
            value={draftFilters.search}
            onChange={(value) => update("search", value)}
            onSelect={chooseSearchSuggestion}
            placeholder="City, ZIP, neighborhood, address, or MLS number"
            seedListings={listings.length ? listings : data.featuredListings || []}
          />
          <button className="btn primary" type="submit">
            <Icon name="Search" />
            <span>Search Homes</span>
          </button>
        </form>
      </div>

      <div className="public-search-command public-search-v2-command">
        <div className="public-search-v2-mobile-row">
          <button className="btn secondary" type="button" onClick={() => setFiltersOpen((current) => !current)}>
            <Icon name="SlidersHorizontal" />
            <span>{filtersOpen ? "Hide Filters" : "Filters"}</span>
          </button>
          <div className="public-view-toggle" role="group" aria-label="Mobile listing view">
            <button className={viewMode === "list" ? "active" : ""} type="button" onClick={() => setViewMode("list")}><Icon name="List" /> List</button>
            <button className={viewMode === "map" ? "active" : ""} type="button" onClick={() => setViewMode("map")}><Icon name="Map" /> Map</button>
          </div>
        </div>
        <div className={classNames("public-search-panel public-search-v2-filters", filtersOpen && "open")}>
          <input value={draftFilters.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
          <input value={draftFilters.zip} onChange={(event) => update("zip", event.target.value)} placeholder="ZIP" />
          <select value={draftFilters.county} onChange={(event) => update("county", event.target.value)} aria-label="County">
            <option value="">County</option>
            {PUBLIC_SEARCH_FLORIDA_COUNTIES.map((county) => <option key={county} value={county}>{county}</option>)}
          </select>
          <select value={draftFilters.status} onChange={(event) => update("status", event.target.value)}>
            <option value="Active">Active listings</option>
            <option value="For Rent">For rent</option>
            <option value="Pending">Pending</option>
            <option value="Closed">Sold/closed</option>
          </select>
          <select value={draftFilters.minPrice} onChange={(event) => update("minPrice", event.target.value)} aria-label="Minimum price">
            <option value="">Min price</option>
            {PUBLIC_SEARCH_PRICE_OPTIONS.map((price) => <option key={`min-${price}`} value={price}>{formatCurrency(price)}</option>)}
          </select>
          <select value={draftFilters.maxPrice} onChange={(event) => update("maxPrice", event.target.value)} aria-label="Maximum price">
            <option value="">Max price</option>
            {PUBLIC_SEARCH_PRICE_OPTIONS.map((price) => <option key={`max-${price}`} value={price}>{formatCurrency(price)}</option>)}
          </select>
          <select value={draftFilters.beds} onChange={(event) => update("beds", event.target.value)} aria-label="Beds">
            <option value="">Beds</option>
            {[1, 2, 3, 4, 5, 6].map((count) => <option key={count} value={count}>{count}+ beds</option>)}
          </select>
          <select value={draftFilters.baths} onChange={(event) => update("baths", event.target.value)} aria-label="Baths">
            <option value="">Baths</option>
            {[1, 2, 3, 4, 5, 6].map((count) => <option key={count} value={count}>{count}+ baths</option>)}
          </select>
          <select value={draftFilters.propertyType} onChange={(event) => update("propertyType", event.target.value)}>
            {PUBLIC_SEARCH_PROPERTY_TYPES.map((type) => <option key={type || "any"} value={type}>{type || "Property type"}</option>)}
          </select>
          <div className="public-search-filter-actions">
            <button className="btn primary" type="button" onClick={() => applyFilters(draftFilters)}>
              <Icon name="SlidersHorizontal" />
              <span>Apply Filters</span>
            </button>
            <button className="btn secondary" type="button" onClick={clearAll}>Clear All</button>
          </div>
        </div>
        <PublicSearchFilterChips filters={filters} onClear={clearChip} onClearAll={clearAll} />
        <div className="public-search-quick-row">
          {["Tampa", "St. Petersburg", "Clearwater", "Orlando", "Waterfront", "Pool Homes", "Open Houses", "Condos"].map((quick) => (
            <button key={quick} type="button" onClick={() => applyQuickFilter(quick)}>{quick}</button>
          ))}
        </div>
      </div>

      <div className="public-results-head public-search-v2-results-head">
        <div>
          <p className="eyebrow">{sourceLabel}</p>
          <h2>{resultCountLabel}</h2>
          <small>{error || (pagination.total ? `Showing ${resultStart.toLocaleString()}-${resultEnd.toLocaleString()} of ${Number(pagination.total).toLocaleString()} matching listings.` : "Listings are loading. Try searching a city, ZIP, or neighborhood.")}</small>
        </div>
        <div className="public-results-actions">
          <label className="public-sort-control">
            <span>Sort</span>
            <select value={sort} onChange={(event) => changeSort(event.target.value)} disabled={loading}>
              {PUBLIC_SEARCH_SORT_OPTIONS.map(([value, label]) => <option key={value} value={value}>{label}</option>)}
            </select>
          </label>
          <div className="public-view-toggle public-view-toggle-desktop" role="group" aria-label="Listing view">
            <button className={viewMode === "list" ? "active" : ""} type="button" onClick={() => setViewMode("list")}><Icon name="List" /> List</button>
            <button className={viewMode === "map" ? "active" : ""} type="button" onClick={() => setViewMode("map")}><Icon name="Map" /> Map</button>
          </div>
          <button className="btn secondary" type="button" onClick={() => onTalkAgent ? onTalkAgent({ intent: "buyer", initialMessage: "I want help with my home search." }) : navigate("/site/contact")}>
            <Icon name="MessageSquare" />
            <span>Ask a Question</span>
          </button>
          <button className="btn secondary" type="button" onClick={() => onHomeValue ? onHomeValue() : navigate("/site/sell")}>
            <Icon name="BadgeDollarSign" />
            <span>Home Value</span>
          </button>
        </div>
      </div>

      {loading && !listings.length ? (
        <PublicSkeleton />
      ) : (
        <div className={classNames("public-list-map-shell", viewMode === "map" ? "map-active" : "list-active")}>
          <div className="public-search-results-list">
            {listings.map((listing) => (
              <div key={listing.id} onMouseEnter={() => setActiveListingId(listing.id)} onFocus={() => setActiveListingId(listing.id)}>
                <PublicListingCard listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />
              </div>
            ))}
            {!listings.length && (
              <EmptyState icon="SearchX" title="No homes matched that search" body="Listings are loading. Try searching a city, ZIP, or neighborhood." />
            )}
          </div>
          <PublicListingMapPreview
            listings={listings}
            map={results.map}
            activeListingId={activeListingId}
            onActivate={setActiveListingId}
            onOpenListing={onViewListing}
            sourceAgentSlug={sourceAgentSlug}
            locationLabel={locationLabel}
          />
        </div>
      )}
      <PublicSearchPagination pagination={pagination} loading={loading} onPage={goToPage} />

      <section className="public-search-support public-search-v2-lead-paths">
        <PublicLeadForm
          title="Get new listing alerts"
          leadType="buyer"
          sourcePage="Nex Realty Property Search"
          sourceAgentSlug={sourceAgentSlug}
          leadSource="IDX Search"
          idxProvider={liveIdxEnabled ? "MLS IDX" : data.idx?.provider || "IDX Search"}
          idxIntent="Saved Search"
          idxSearchUrl={window.location.href}
          searchCriteria={searchCriteria}
          defaultPreferredArea={[filters.search, filters.city, filters.county, filters.zip].filter(Boolean).join(", ")}
          setToast={setToast}
          compact
          ctaLabel="Save This Search"
        />
        <article className="public-live-idx-card">
          <span><i /> Search help</span>
          <strong>Need a faster path to the right home?</strong>
          <p>Save a search, request a showing from any listing card, or ask NIA to narrow options by area, budget, timeline, and must-haves.</p>
          <div>{["Save search", "Request showing", "Ask NIA"].map((item) => <em key={item}>{item}</em>)}</div>
        </article>
      </section>
      <PublicIdxComplianceNotice idx={data.idx} compact />
    </section>
  );
}

function PublicPropertySearch({ data, navigate, setToast, sourceAgentSlug = "", onViewListing, onTalkAgent, onHomeValue }) {
  const [filters, setFilters] = useState(() => {
    const params = new URLSearchParams(window.location.search);
    return {
      search: params.get("search") || "",
      city: params.get("city") || "",
      county: params.get("county") || "",
      zip: params.get("zip") || "",
      status: params.get("status") || "",
      minPrice: params.get("minPrice") || "",
      maxPrice: params.get("maxPrice") || "",
      beds: params.get("beds") || "",
      baths: params.get("baths") || "",
      propertyType: params.get("propertyType") || "",
      lifestyle: params.get("lifestyle") || ""
    };
  });
  const [listings, setListings] = useState([]);
  const [loading, setLoading] = useState(true);
  const [viewMode, setViewMode] = useState("grid");

  async function loadListings(nextFilters = filters) {
    setLoading(true);
    const queryFilters = { ...nextFilters };
    if (queryFilters.lifestyle) {
      queryFilters.search = [queryFilters.search, queryFilters.lifestyle].filter(Boolean).join(" ");
      delete queryFilters.lifestyle;
    }
    const params = new URLSearchParams(Object.entries(queryFilters).filter(([, value]) => value !== ""));
    try {
      const payload = await API.request(`/api/public/listings?${params.toString()}`);
      setListings(publicListingsFromPayload(payload));
    } catch (error) {
      setToast("Listing search could not load.");
      setListings([]);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadListings();
  }, []);

  function update(field, value) {
    setFilters((current) => field === "search"
      ? { ...current, search: value, city: "", county: "", zip: "" }
      : { ...current, [field]: value });
  }

  function applyQuickFilter(quick) {
    const nextFilters = { ...filters };
    if (quick === "For Sale" || quick === "For Rent") nextFilters.status = quick;
    else nextFilters.search = quick;
    setFilters(nextFilters);
    loadListings(nextFilters);
  }

  function chooseSearchSuggestion(suggestion) {
    const nextFilters = filtersFromPublicSearchSuggestion(filters, suggestion);
    setFilters(nextFilters);
    loadListings(nextFilters);
  }

  const liveIdxEnabled = Boolean(data.idx?.apiConfigured && data.idx?.apiFetchEnabled);
  const hasLiveIdxListings = listings.some((listing) => listing.dataMode === "live-idx-api" || /^bridge-/i.test(String(listing.id || "")));
  const listingModeLabel = hasLiveIdxListings ? "Live Listings" : liveIdxEnabled ? "Live Home Search" : "Search Results";
  const resultSummary = listings.length
    ? `${listings.length} ${hasLiveIdxListings ? "live MLS matches" : liveIdxEnabled ? "home matches" : "search matches"}`
    : liveIdxEnabled
      ? "Listings are loading"
      : "No matching homes found yet";
  const searchCriteria = Object.entries(filters)
    .filter(([, value]) => String(value || "").trim())
    .map(([key, value]) => `${key}: ${value}`)
    .join(", ");

  return (
    <section className={`public-page ${liveIdxEnabled ? "live-idx-page" : ""}`}>
      <div className="public-page-head public-search-hero-head">
        <div>
          <p className="eyebrow">Live home search</p>
          <h1>Search Florida homes with Nex Realty.</h1>
          <p>
            {liveIdxEnabled
              ? "Browse active MLS listings, save search preferences, and ask a local Nex agent for the next step."
              : "Tell us where you want to search and a local Nex agent can help you find matching Florida homes."}
          </p>
        </div>
        <div className="public-search-launch-card">
          <span><i /> {liveIdxEnabled ? "Live MLS search" : "Search help"}</span>
          <strong>{liveIdxEnabled ? "MLS listings are available." : "A Nex agent can help you search."}</strong>
          <small>{liveIdxEnabled ? "Ask questions, request tours, and save searches directly from the property results." : "Share your area, budget, and timing so we can point you in the right direction."}</small>
        </div>
      </div>
      <div className="public-search-command">
        <div className="public-search-command-main">
          <Icon name="Search" />
          <PublicListingSearchAutocomplete
            value={filters.search}
            onChange={(value) => update("search", value)}
            onSelect={chooseSearchSuggestion}
            placeholder="Search address, neighborhood, city, county, or ZIP"
            seedListings={listings.length ? listings : data.featuredListings || []}
          />
          <button className="btn primary" onClick={() => loadListings()} type="button">Search</button>
        </div>
        <div className="public-search-panel">
          <input value={filters.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
          <input value={filters.county} onChange={(event) => update("county", event.target.value)} placeholder="County" />
          <select value={filters.status} onChange={(event) => update("status", event.target.value)}>
            <option value="">Sale or rent</option>
            <option>For Sale</option>
            <option>For Rent</option>
          </select>
          <input type="number" min="0" value={filters.minPrice} onChange={(event) => update("minPrice", event.target.value)} placeholder="Min price" />
          <input type="number" min="0" value={filters.maxPrice} onChange={(event) => update("maxPrice", event.target.value)} placeholder="Max price" />
          <input type="number" min="0" value={filters.beds} onChange={(event) => update("beds", event.target.value)} placeholder="Beds" />
          <input type="number" min="0" value={filters.baths} onChange={(event) => update("baths", event.target.value)} placeholder="Baths" />
          <input value={filters.propertyType} onChange={(event) => update("propertyType", event.target.value)} placeholder="Property type" />
          <select value={filters.lifestyle} onChange={(event) => update("lifestyle", event.target.value)}>
            <option value="">Lifestyle</option>
            <option>Waterfront</option>
            <option>Pool Homes</option>
            <option>Condos</option>
            <option>New Listings</option>
            <option>Open Houses</option>
            <option>Price Reduced</option>
            <option>Luxury</option>
          </select>
        </div>
        <div className="public-search-quick-row">
          {["Tampa Bay", "St. Petersburg", "Clearwater", "Orlando", "Miami", "Waterfront", "Pool Homes", "Open Houses", "Price Reduced"].map((quick) => (
            <button
              key={quick}
              type="button"
              onClick={() => applyQuickFilter(quick)}
            >
              {quick}
            </button>
          ))}
        </div>
      </div>
      <PublicMarketTicker initialLocation={filters.search || filters.city || filters.county || filters.zip} />
      {loading ? (
        <PublicSkeleton />
      ) : (
        <>
          <div className="public-results-head">
            <div>
              <p className="eyebrow">{listingModeLabel}</p>
              <h2>{resultSummary}</h2>
              <small>{hasLiveIdxListings ? "Live MLS results are available for your search." : liveIdxEnabled ? "Try searching a city, ZIP, or neighborhood." : "Try a broader city, county, price range, or ask Nex for help finding similar homes."}</small>
            </div>
            <div className="public-results-actions">
              <div className="public-view-toggle" role="group" aria-label="Listing view">
                {["grid", "list"].map((mode) => (
                  <button key={mode} className={viewMode === mode ? "active" : ""} type="button" onClick={() => setViewMode(mode)}>
                    <Icon name={mode === "grid" ? "LayoutGrid" : "List"} />
                    <span>{mode === "grid" ? "Grid" : "List"}</span>
                  </button>
                ))}
              </div>
              <button className="btn secondary" type="button" onClick={() => onTalkAgent ? onTalkAgent() : navigate("/site/contact")}>
                <Icon name="MessageSquare" />
                <span>Ask a Question</span>
              </button>
              <button className="btn secondary" type="button" onClick={() => onHomeValue ? onHomeValue() : navigate("/site/sell")}>
                <Icon name="BadgeDollarSign" />
                <span>Get Home Value</span>
              </button>
              <button className="btn primary" type="button" onClick={() => document.querySelector(".public-search-support")?.scrollIntoView({ behavior: "smooth", block: "start" })}>
                <Icon name="Bell" />
                <span>Send Me Homes Like This</span>
              </button>
            </div>
          </div>
          <div className={classNames("public-listing-grid", viewMode === "list" && "list-view")}>
            {listings.map((listing) => <PublicListingCard key={listing.id} listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />)}
          </div>
          <article className="public-map-fallback-card">
            <Icon name="MapPinned" />
            <div>
              <strong>Map details unavailable</strong>
              <span>Use the filters and listing cards, or ask a Nex agent to help narrow the best area for you.</span>
            </div>
          </article>
        </>
      )}
      <section className="public-search-support">
        <PublicLeadForm
          title={liveIdxEnabled ? "Send me homes like this" : "Request property help"}
          leadType="buyer"
          sourcePage={liveIdxEnabled ? "Nex Realty MLS Search" : "Nex Realty Property Search"}
          sourceAgentSlug={sourceAgentSlug}
          leadSource="IDX Search"
          idxProvider={liveIdxEnabled ? "MLS IDX" : data.idx?.provider || "IDX Search"}
          idxIntent="Saved Search"
          idxSearchUrl={window.location.href}
          searchCriteria={searchCriteria}
          defaultPreferredArea={[filters.search, filters.city, filters.county].filter(Boolean).join(", ")}
          setToast={setToast}
          compact
          ctaLabel="Save Search Request"
        />
        <article className="public-live-idx-card">
          <span><i /> {liveIdxEnabled ? "Live MLS connected" : "Search help"}</span>
          <strong>{liveIdxEnabled ? "Need help narrowing the search?" : "Tell us what you want to find."}</strong>
          <p>{liveIdxEnabled ? "Share your target area, price range, timeline, and must-haves. A local Nex agent can help you find the right next move." : "Tell us what you are looking for and we will connect you with the right Nex Realty resource."}</p>
          <div>
            {(liveIdxEnabled ? ["Tour requests", "Questions", "Saved searches"] : ["Buying", "Selling", "Renting"]).map((item) => <em key={item}>{item}</em>)}
          </div>
        </article>
      </section>
      <PublicIdxComplianceNotice idx={data.idx} compact={liveIdxEnabled} />
      {!liveIdxEnabled && (
        <>
          <div className="public-search-platform-strip">
            {[
              ["Search help", "Tell us what you are looking for and a local Nex agent can help narrow the options.", "Sparkles"],
              ["Saved searches", "Share your target area, budget, timeline, and must-haves for follow-up.", "Bell"],
              ["Area guidance", "Ask Nex for help comparing locations, commute needs, showing logistics, and search options.", "MapPin"],
              ["MLS disclosures", "Listing source, status, brokerage attribution, and update language stay visible.", "ShieldCheck"]
            ].map(([title, body, icon]) => (
              <article key={title}>
                <Icon name={icon} />
                <strong>{title}</strong>
                <span>{body}</span>
              </article>
            ))}
          </div>
          <div className="public-search-portal-grid">
            <div className="public-search-map-card">
              <div className="public-search-map-toolbar">
              <span><i /> Map search</span>
                <button type="button" onClick={() => navigate("/site/contact")}>Request Search Help</button>
              </div>
              <div className="public-search-map-stage">
                <div className="public-search-map-radar" />
                {(listings.length ? listings : data.featuredListings || []).slice(0, 5).map((listing, index) => (
                  <button
                    key={listing.id || index}
                    className="public-search-map-pin"
                    style={{
                      left: `${[22, 42, 58, 70, 33][index] || 50}%`,
                      top: `${[62, 44, 54, 34, 28][index] || 50}%`
                    }}
                    onClick={() => onViewListing ? onViewListing(listing, sourceAgentSlug) : navigate(`/site/listings/${listing.id}`)}
                    type="button"
                  >
                    <Icon name="MapPin" size={16} />
                    <span>{propertyPriceLabel(listing)}</span>
                  </button>
                ))}
              </div>
            </div>
            <div className="public-search-readiness-panel">
              <p className="eyebrow">Search support</p>
              <h2>Tell us what you want and we will help you find it.</h2>
              <div className="public-search-ready-list">
                {[
                  "Save search preferences",
                  "Ask a question about a listing",
                  "Request a showing",
                  "Get property updates",
                  "Talk with a local Nex agent"
                ].map((item) => <span key={item}><Icon name="CheckCircle2" /> {item}</span>)}
              </div>
            </div>
          </div>
          <section className="public-search-journey">
            <div>
              <p className="eyebrow">How Search Connects</p>
              <h2>From search to showing, Nex keeps the next step simple.</h2>
              <p>
                Search by area, save what you like, request more information, and connect with a Nex Realty professional
                when you are ready to tour, write an offer, or plan your sale.
              </p>
            </div>
            <div className="public-workflow-timeline">
              {[
                ["Search", "Consumer searches by market, budget, beds, or property type."],
                ["Capture", "Showing requests and saved searches create trackable leads."],
                ["Connect", "A local Nex agent can help with questions, showings, and next steps."],
                ["Move forward", "Buyers and sellers get clearer guidance from search through closing."]
              ].map(([title, body], index) => (
                <article key={title}>
                  <em>{String(index + 1).padStart(2, "0")}</em>
                  <strong>{title}</strong>
                  <span>{body}</span>
                </article>
              ))}
            </div>
          </section>
          <IDXSearchEmbed idx={data.idx} filters={filters} sourceAgentSlug={sourceAgentSlug} setToast={setToast} />
          <PublicIdxComplianceNotice idx={data.idx} />
        </>
      )}
    </section>
  );
}

function publicListingPhotoCandidates(listing = {}, preferredSrc = "") {
  const values = [];
  const addValue = (value) => {
    const text = String(value || "").trim();
    if (!text || text === "/assets/nex-logo-black.png" || values.includes(text)) return;
    values.push(text);
  };
  const addMediaItem = (item) => {
    if (!item) return;
    if (typeof item === "string") {
      addValue(item);
      return;
    }
    addValue(
      item.MediaURL ||
        item.MediaUrl ||
        item.MediaURLLarge ||
        item.MediaUrlLarge ||
        item.MediaObjectURL ||
        item.MediaURLSecure ||
        item.HighResolutionMediaURL ||
        item.ThumbnailURL ||
        item.ImageUrl ||
        item.imageUrl ||
        item.Url ||
        item.URL ||
        item.uri ||
        item.url ||
        ""
    );
  };

  [
    preferredSrc,
    listing.primaryPhoto,
    listing.photo,
    listing.imageUrl,
    listing.thumbnail,
    listing.heroImage,
    listing.coverImage
  ].forEach(addValue);
  if (Array.isArray(listing.photos)) listing.photos.forEach(addMediaItem);
  if (Array.isArray(listing.images)) listing.images.forEach(addMediaItem);
  if (Array.isArray(listing.media)) listing.media.forEach(addMediaItem);
  if (Array.isArray(listing.Media)) listing.Media.forEach(addMediaItem);
  return values;
}

function publicListingImageAlt(listing = {}) {
  return [listing.address, listing.city, listing.state || "Florida"].filter(Boolean).join(", ") || "Nex Realty property photo";
}

function PublicPropertyImage({ listing = {}, src = "", alt = "", className = "", loading = "lazy" }) {
  const candidates = publicListingPhotoCandidates(listing, src);
  const [photoIndex, setPhotoIndex] = useState(0);

  useEffect(() => {
    setPhotoIndex(0);
  }, [listing?.id, src]);

  const activeSrc = candidates[photoIndex] || "";
  if (!activeSrc) {
    return (
      <div className={classNames("public-property-placeholder", className)} role="img" aria-label={alt || "Property photo unavailable"}>
        <span>NEX REALTY</span>
        <strong>Photo coming soon</strong>
        <small>Property image unavailable</small>
      </div>
    );
  }

  return (
    <img
      className={className || undefined}
      src={activeSrc}
      alt={alt || publicListingImageAlt(listing)}
      loading={loading}
      referrerPolicy="no-referrer"
      onError={() => setPhotoIndex((current) => current + 1)}
    />
  );
}

function PublicListingCard({ listing, navigate, onViewListing, sourceAgentSlug = "" }) {
  function openListing() {
    if (onViewListing) {
      onViewListing(listing, sourceAgentSlug);
      return;
    }
    navigate(`/site/listings/${listing.id}`);
  }

  function openListingIntent(intent) {
    if (onViewListing) {
      onViewListing(listing, sourceAgentSlug, intent);
      return;
    }
    navigate(`/site/listings/${listing.id}?intent=${encodeURIComponent(intent)}`);
  }

  return (
    <article className="public-listing-card">
      <button className="public-listing-photo" onClick={openListing} type="button">
        <PublicPropertyImage listing={listing} alt={publicListingImageAlt(listing)} />
        <span>{listing.status}</span>
      </button>
      <div className="public-listing-body">
        <strong>{propertyPriceLabel(listing)}</strong>
        <h3>{listing.address}</h3>
        <p>{listing.city}, {listing.county} {listing.zip}</p>
        <div className="public-listing-stats">
          <span>{listing.beds} beds</span>
          <span>{listing.baths} baths</span>
          <span>{Number(listing.sqft || 0).toLocaleString()} sqft</span>
        </div>
        <div className="public-listing-card-actions">
          <button className="btn secondary" onClick={() => openListingIntent("Save property")} type="button">
            <Icon name="Heart" />
            <span>Save</span>
          </button>
          <button className="btn primary" onClick={() => openListingIntent("Tour this home")} type="button">
            <Icon name="CalendarCheck" />
            <span>Tour</span>
          </button>
          <button className="btn secondary" onClick={() => openListingIntent("Ask a question")} type="button">
            <Icon name="MessageSquare" />
            <span>Ask</span>
          </button>
        </div>
        <button className="btn ghost full-width" onClick={openListing} type="button">View Details</button>
        <PublicIdxListingAttribution listing={listing} compact />
      </div>
    </article>
  );
}

function PublicListingDetail({ listingId, navigate, setToast, sourceAgentSlug = "" }) {
  const [listing, setListing] = useState(null);
  const [loading, setLoading] = useState(true);
  const [detailIntent, setDetailIntent] = useState(() => new URLSearchParams(window.location.search).get("intent") || "Tour this home");
  const detailSourceAgentSlug = sourceAgentSlug || getRememberedPublicListingSourceAgent();

  useEffect(() => {
    let mounted = true;
    API.request(`/api/public/listings/${encodeURIComponent(listingId)}`)
      .then((payload) => mounted && setListing(payload))
      .catch(() => setToast("Listing not found."))
      .finally(() => mounted && setLoading(false));
    return () => {
      mounted = false;
    };
  }, [listingId]);

  if (loading) return <PublicSkeleton />;
  if (!listing) return <EmptyState icon="Home" title="Listing not found" body="Try another property search." />;
  const photos = publicListingPhotoCandidates(listing);
  const heroPhoto = photos[0] || "";
  const areaLabel = listing.addressWithheld || listing.idxAddressDisplayAllowed === false
    ? [listing.city, listing.county].filter(Boolean).join(", ") || "Location available on request"
    : [listing.city, listing.county].filter(Boolean).join(", ");
  const mlsLabel = listing.mlsNumber || listing.stellarListingId || listing.providerListingId || listing.id || "";
  const estimatedPayment = listing.price ? Math.round(Number(listing.price) * 0.0064) : 0;

  function focusLeadForm(intent) {
    setDetailIntent(intent);
    window.setTimeout(() => {
      document.querySelector(".public-detail-lead-form")?.scrollIntoView({ behavior: "smooth", block: "start" });
    }, 0);
  }

  return (
    <section className="public-detail-page">
      <button className="public-back" onClick={() => navigate("/site/search")} type="button"><Icon name="ArrowLeft" /> Back to search</button>
      <div className="public-detail-hero">
        <div className="public-detail-gallery">
          <PublicPropertyImage listing={listing} src={heroPhoto} alt={publicListingImageAlt(listing)} className="public-detail-main-photo" loading="eager" />
          {photos.length > 1 && (
            <div>
              {photos.slice(1, 5).map((photo, index) => (
                <PublicPropertyImage
                  key={`${photo}-${index}`}
                  listing={listing}
                  src={photo}
                  alt={`${publicListingImageAlt(listing)} preview ${index + 2}`}
                  className="public-detail-thumb-photo"
                />
              ))}
            </div>
          )}
        </div>
        <div>
          <span className="public-badge">{listing.status}</span>
          <h1>{listing.address}</h1>
          <p>{listing.city}, {listing.county} {listing.zip}</p>
          <strong>{propertyPriceLabel(listing)}</strong>
          <div className="public-listing-stats large">
            <span>{listing.beds} beds</span>
            <span>{listing.baths} baths</span>
            <span>{Number(listing.sqft || 0).toLocaleString()} sqft</span>
            <span>{listing.propertyType}</span>
          </div>
          <PublicIdxListingAttribution listing={listing} />
          <div className="public-detail-actions">
            <button className="btn primary" type="button" onClick={() => focusLeadForm("Tour this home")}>
              <Icon name="CalendarCheck" />
              <span>Tour this home</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => focusLeadForm("Ask a question")}>
              <Icon name="MessageSquare" />
              <span>Ask a question</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => focusLeadForm("Save property")}>
              <Icon name="Heart" />
              <span>Save home</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => focusLeadForm("Send me homes like this")}>
              <Icon name="Bell" />
              <span>Similar homes</span>
            </button>
          </div>
        </div>
      </div>
      <div className="public-detail-grid">
        <article className="public-detail-copy">
          <h2>Property overview</h2>
          <div className="public-detail-facts">
            {[
              ["Price", propertyPriceLabel(listing)],
              ["Property type", listing.propertyType],
              ["Living area", `${Number(listing.sqft || 0).toLocaleString()} sqft`],
              ["Location", areaLabel],
              ["MLS ID", mlsLabel],
              ["Status", listing.idxListingStatus || listing.status]
            ].map(([label, value]) => (
              <span key={label}>
                <small>{label}</small>
                <strong>{value || "Available on request"}</strong>
              </span>
            ))}
          </div>
          <p>{listing.description}</p>
          <div className="public-feature-list">
            {(listing.features || []).map((feature) => <span key={feature}><Icon name="CheckCircle2" /> {feature}</span>)}
          </div>
          <div className="public-detail-support-grid">
            <article>
              <Icon name="MapPinned" />
              <strong>Location</strong>
              <span>{listing.addressWithheld || listing.idxAddressDisplayAllowed === false ? "Address withheld by seller" : areaLabel || "Florida"}</span>
              <small>{listing.addressWithheld || listing.idxAddressDisplayAllowed === false ? "Exact address and map location are not displayed because the seller or listing participant has withheld internet address display." : "Ask a Nex agent for area guidance, showing logistics, and property-specific context."}</small>
            </article>
            <article>
              <Icon name="Calculator" />
              <strong>Payment estimate</strong>
              <span>{estimatedPayment ? `About $${estimatedPayment.toLocaleString()}/mo` : "Available on request"}</span>
              <small>Estimate only. Actual payment, taxes, insurance, HOA, rates, APR, and eligibility vary.</small>
            </article>
          </div>
          <section className="public-similar-homes-panel">
            <div>
              <p className="eyebrow">Similar homes</p>
              <h3>Want more options like this?</h3>
              <p>Search nearby listings or ask Nex to send homes that match this price range, area, and property style.</p>
            </div>
            <div>
              <button className="btn secondary" type="button" onClick={() => navigate(`/site/search?search=${encodeURIComponent(listing.city || listing.county || "")}`)}>
                <Icon name="Search" />
                <span>Search Nearby</span>
              </button>
              <button className="btn primary" type="button" onClick={() => focusLeadForm("Send me homes like this")}>
                <Icon name="Bell" />
                <span>Send similar homes</span>
              </button>
            </div>
          </section>
          <PublicIdxComplianceNotice listing={listing} />
        </article>
        <div className="public-detail-lead-form">
          <PublicLeadForm
            key={detailIntent}
            title={detailIntent}
            leadType={/rent/i.test(listing.status) ? "renter" : "buyer"}
            sourcePage={mlsLabel ? `Listing ${mlsLabel}` : "Listing Detail"}
            listingId={listing.id}
            mlsNumber={mlsLabel}
            propertyAddress={listing.address}
            defaultCity={listing.city}
            defaultCounty={listing.county}
            defaultPreferredArea={areaLabel}
            defaultPriceRange={propertyPriceLabel(listing)}
            sourceAgentSlug={detailSourceAgentSlug}
            leadSource="Property Inquiry"
            idxProvider={listing.idxSourceName || listing.idxSourceProvider || "MLS IDX"}
            idxIntent={detailIntent}
            inquiryPurpose={detailIntent}
            ctaLabel={detailIntent === "Save property" ? "Save Home" : detailIntent === "Ask a question" ? "Ask Question" : detailIntent === "Send me homes like this" ? "Send Similar Homes" : "Request Showing"}
            setToast={setToast}
          />
        </div>
      </div>
      <div className="public-detail-sticky-cta">
        <button type="button" onClick={() => focusLeadForm("Tour this home")}><Icon name="CalendarCheck" /> Tour</button>
        <button type="button" onClick={() => focusLeadForm("Ask a question")}><Icon name="MessageSquare" /> Ask</button>
        <button type="button" onClick={() => focusLeadForm("Save property")}><Icon name="Heart" /> Save</button>
      </div>
    </section>
  );
}

function PublicPropertyLeadGateModal({ listing, sourceAgentSlug = "", onBack, onSubmit }) {
  const [form, setForm] = useState({
    name: "",
    email: "",
    phone: "",
    city: listing?.city || "",
    county: listing?.county || "",
    zip: listing?.zip || "",
    priceRange: propertyPriceLabel(listing),
    timeline: "Actively searching",
    notes: "",
    consent: false
  });
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState("");

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
  }

  async function submit(event) {
    event.preventDefault();
    setError("");
    if (!form.consent) {
      setError("Please agree to be contacted so a Nex agent can help with your search.");
      return;
    }
    const validation = validatePublicLeadCapture({ name: form.name, email: form.email, phone: form.phone, intent: "buyer", consent: form.consent });
    if (!validation.ok) {
      setError(validation.message);
      return;
    }
    setSubmitting(true);
    try {
      await onSubmit(form);
    } catch (submitError) {
      setError(submitError.message || "Could not create search access. Please try again.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <div className="public-lead-gate-backdrop" role="dialog" aria-modal="true" aria-labelledby="property-lead-gate-title">
      <form className="public-lead-gate-modal" onSubmit={submit}>
        <div className="public-lead-gate-lock">
          <Icon name="LockKeyhole" />
          <span>{sourceAgentSlug ? "Agent search access" : "Nex property search access"}</span>
        </div>
        <div className="public-lead-gate-copy">
          <p className="eyebrow">Free Nex Search Access</p>
          <h2 id="property-lead-gate-title">Create your search access to keep viewing homes.</h2>
          <p>
            You can preview two properties before registration. Tell us where to send the details and a Nex agent can
            help with showings, saved searches, and local market questions.
          </p>
        </div>
        {listing?.id && (
          <div className="lead-gate-listing">
            <div>
              <strong>{listing.address || "Property details"}</strong>
              <span>{[listing.city, listing.county, listing.zip].filter(Boolean).join(", ")}</span>
            </div>
            <em>{propertyPriceLabel(listing) || listing.status}</em>
          </div>
        )}
        <div className="lead-gate-form-grid">
          <input required value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Full name" />
          <input required type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" />
          <input required value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" />
          <input value={form.timeline} onChange={(event) => update("timeline", event.target.value)} placeholder="Timeline" />
          <input value={form.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
          <input value={form.priceRange} onChange={(event) => update("priceRange", event.target.value)} placeholder="Price range" />
        </div>
        <textarea value={form.notes} onChange={(event) => update("notes", event.target.value)} placeholder="Anything specific you're looking for?" rows={3} />
        <label className="public-consent">
          <input type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
          <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
        </label>
        <PublicLegalInlineLinks />
        {error && <div className="login-error lead-gate-error">{error}</div>}
        <div className="lead-gate-actions">
          <button className="btn secondary" onClick={onBack} type="button">Back to Search</button>
          <button className="btn primary" disabled={submitting} type="submit">
            <Icon name={submitting ? "LoaderCircle" : "ArrowRight"} className={submitting ? "spin" : ""} />
            <span>{submitting ? "Creating Access" : "Continue to Property"}</span>
          </button>
        </div>
      </form>
    </div>
  );
}

function PublicAgentDirectory({ navigate, setToast }) {
  const [filters, setFilters] = useState({ search: "", market: "", specialty: "" });
  const [agents, setAgents] = useState([]);
  const visibleMarkets = Array.from(new Set(agents.map((agent) => agent.market).filter(Boolean))).slice(0, 8);

  async function loadAgents(nextFilters = filters) {
    const params = new URLSearchParams(Object.entries(nextFilters).filter(([, value]) => value));
    try {
      setAgents(await API.request(`/api/public/agents?${params.toString()}`));
    } catch (error) {
      setToast("Agent directory could not load.");
    }
  }

  useEffect(() => {
    loadAgents();
  }, []);

  function update(field, value) {
    const next = { ...filters, [field]: value };
    setFilters(next);
    loadAgents(next);
  }

  return (
    <section className="public-page">
      <div className="public-page-head public-agent-directory-head">
        <div>
          <p className="eyebrow">Agent Directory</p>
          <h1>Find a local Nex Realty agent.</h1>
          <p>Search Nex Realty professionals by market, city, language, specialty, and service area.</p>
        </div>
        <div className="public-directory-sync-card">
          <span><i /> Local guidance</span>
          <strong>{agents.length || "Published"} agents</strong>
          <small>Connect with a Nex professional for buying, selling, renting, investing, or local market questions.</small>
        </div>
      </div>
      <div className="public-directory-command-row">
        {[
          ["Local markets", "Find agents by service area, city, and region.", "MapPin"],
          ["Direct contact", "Call, email, or request help from an agent profile.", "ContactRound"],
          ["Property search", "Agents can help you search, tour, and compare homes.", "Home"]
        ].map(([title, body, icon]) => (
          <article key={title}>
            <Icon name={icon} />
            <strong>{title}</strong>
            <span>{body}</span>
          </article>
        ))}
      </div>
      <div className="public-agent-filters">
        <input value={filters.search} onChange={(event) => update("search", event.target.value)} placeholder="Name, city, county, language" />
        <select value={filters.market} onChange={(event) => update("market", event.target.value)}>
          <option value="">All markets</option>
          <option>Tampa Bay</option>
          <option>Orlando</option>
          <option>Miami</option>
        </select>
        <select value={filters.specialty} onChange={(event) => update("specialty", event.target.value)}>
          <option value="">All specialties</option>
          <option>Buyer Agent</option>
          <option>Listing Agent</option>
          <option>Rental Agent</option>
          <option>Luxury</option>
          <option>Investor Friendly</option>
          <option>New Construction</option>
        </select>
      </div>
      {!!visibleMarkets.length && (
        <div className="public-directory-market-row">
          {visibleMarkets.map((market) => (
            <button key={market} type="button" onClick={() => update("market", market)}>{market}</button>
          ))}
        </div>
      )}
      <div className="public-agent-grid">
        {agents.map((agent) => <PublicAgentCard key={agent.id} agent={agent} navigate={navigate} />)}
      </div>
      {!agents.length && <EmptyState icon="ContactRound" title="No published agents match this search" body="Try another market, specialty, name, or service area." />}
    </section>
  );
}

function PublicAgentCard({ agent, navigate }) {
  const sitePath = agent.publicProfilePath || `/site/agents/${agent.subdomainSlug}`;
  return (
    <article className="public-agent-card enhanced">
      <div className="public-agent-card-top">
        <div className="public-avatar">{agent.headshot ? <img src={agent.headshot} alt={agent.name} /> : publicInitials(agent.name)}</div>
        <span><i /> Nex Realty agent</span>
      </div>
      <h3>{agent.name}</h3>
      <p>{agent.title}</p>
      <div className="public-agent-market-row">
        <span>{agent.market || "Florida"}</span>
        <small>{agent.leadRotationEligible === false ? "Contact directly" : "Available for inquiries"}</small>
      </div>
      <small>{(agent.serviceAreas || []).slice(0, 4).join(" | ")}</small>
      <div className="public-agent-contact-mini">
        {agent.phone && <a href={`tel:${agent.phone}`}><Icon name="Phone" size={14} /> {agent.phone}</a>}
        {agent.email && <a href={`mailto:${agent.email}`}><Icon name="Mail" size={14} /> {agent.email}</a>}
      </div>
      <div className="public-agent-skill-row">
        {[...(agent.languages || []).slice(0, 2), ...(agent.specialties || []).slice(0, 2)].filter(Boolean).map((item) => <em key={item}>{item}</em>)}
      </div>
      <div className="public-agent-site-url">
        <Icon name="Globe2" size={15} />
        <span>{agent.agentSubdomainUrl ? agent.agentSubdomainUrl.replace(/^https?:\/\//, "") : sitePath}</span>
      </div>
      <div className="public-agent-actions">
        <button className="btn secondary" onClick={() => navigate(`/site/agents/${agent.subdomainSlug}`)} type="button">View Profile</button>
        {agent.email ? <a className="btn primary" href={`mailto:${agent.email}`}>Email</a> : <button className="btn primary" onClick={() => navigate(`/site/agents/${agent.subdomainSlug}`)} type="button">Contact</button>}
      </div>
    </article>
  );
}

function PublicAgentProfile({ slug, data, navigate, setToast, hostedSubdomain = false, onViewListing, onTalkAgent, onHomeValue }) {
  const [profile, setProfile] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let mounted = true;
    API.request(`/api/public/agents/${encodeURIComponent(slug)}`)
      .then((payload) => mounted && setProfile(payload))
      .catch(() => setToast("Agent profile could not load."))
      .finally(() => mounted && setLoading(false));
    return () => {
      mounted = false;
    };
  }, [slug]);

  if (loading) return <PublicSkeleton />;
  if (!profile?.agent) return <EmptyState icon="ContactRound" title="Agent profile not found" body="Return to the agent directory." />;
  const agent = profile.agent;
  const agentAccent = agent.websiteAccentColor || "#e30613";
  const firstName = agent.firstName || String(agent.name || "your agent").split(" ")[0] || "your agent";
  const agentHeadline = agent.websiteHeadline || `Search Florida homes with ${agent.name}`;
  const agentTagline = agent.websiteTagline || agent.bio || `Work with ${agent.name} at Nex Realty LLC for Florida home search, showing requests, seller questions, and local next steps.`;
  const agentCtaLabel = agent.websiteCtaLabel || `Ask ${firstName} a question`;
  const agentSiteHost = (agent.websiteUrl || agent.agentWebsiteUrl || agent.agentSubdomainUrl || `/agent/${agent.subdomainSlug}`).replace(/^https?:\/\//, "").replace(/\/$/, "");
  const featuredListings = (profile.listings?.length ? profile.listings : data.featuredListings || []).slice(0, 6);
  const compliance = idxComplianceFrom(profile.idx || data?.idx);
  const sourceSlug = agent.websiteSlug || agent.subdomainSlug || slug;

  function openAgentNia(intent = "general", message = "") {
    if (onTalkAgent) {
      onTalkAgent({
        intent,
        message: message || `I want to connect with ${agent.name} at Nex Realty.`,
        sourceAgentName: agent.name
      });
    }
  }

  function searchCategory(search) {
    const params = new URLSearchParams({ agent: sourceSlug, search });
    navigate(`/site/search?${params.toString()}`);
  }

  return (
    <section className="public-agent-profile">
      {!hostedSubdomain && <button className="public-back" onClick={() => navigate("/site/agents")} type="button"><Icon name="ArrowLeft" /> Back to agents</button>}
      <div
        className={classNames("public-agent-hero", "custom-agent-hero", `theme-${agent.websiteBackgroundStyle || "light"}`)}
        style={{
          "--agent-site-accent": agentAccent,
          backgroundImage: agent.websiteHeroImageUrl ? `linear-gradient(120deg, rgba(255,255,255,.94), rgba(255,255,255,.72)), url(${agent.websiteHeroImageUrl})` : ""
        }}
      >
        <div>
          <p className="eyebrow">Nex Realty LLC agent website</p>
          <h1>{agentHeadline}</h1>
          <p>{agentTagline}</p>
          <PublicHeroSearchBox
            navigate={navigate}
            onTalkAgent={() => openAgentNia("general", `I want to connect with ${agent.name} at Nex Realty.`)}
            onHomeValue={onHomeValue}
            seedListings={featuredListings}
            sourceAgentSlug={sourceSlug}
          />
          <div className="public-profile-actions">
            <button className="btn primary" type="button" onClick={() => openAgentNia("general", `I have a question for ${agent.name}.`)}>{agentCtaLabel}</button>
            {agent.phone ? <a className="btn secondary" href={`tel:${agent.phone}`}>Call {firstName}</a> : <a className="btn secondary" href={`mailto:${agent.email}`}>Email {firstName}</a>}
          </div>
        </div>
        <aside className="public-agent-intro-card">
          <div className="public-avatar xl">{agent.headshot ? <img src={agent.headshot} alt={agent.name} /> : publicInitials(agent.name)}</div>
          <strong>{agent.name}</strong>
          <span>{agent.title || "Nex Realty Agent"}</span>
          <a href={agent.phone ? `tel:${agent.phone}` : `mailto:${agent.email}`}><Icon name="Phone" /> {agent.phone || "Contact through Nex"}</a>
          <a href={`mailto:${agent.email}`}><Icon name="Mail" /> {agent.email}</a>
          <small><Icon name="MapPin" /> {(agent.serviceAreas || []).slice(0, 4).join(", ") || agent.market || "Florida"}</small>
        </aside>
      </div>

      <section className="public-agent-site-strip">
        <span><Icon name="Globe2" /> {agentSiteHost}</span>
        <span><Icon name="ShieldCheck" /> Branded under Nex Realty LLC</span>
        <span><Icon name="SearchCheck" /> Brokerage IDX search connected</span>
      </section>

      <section className="public-section public-agent-service-section">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Agent intro</p>
            <h2>Work with {agent.name}</h2>
          </div>
          <button className="btn primary" type="button" onClick={() => openAgentNia("general", `I want to talk with ${agent.name}.`)}>Ask {firstName} a question</button>
        </div>
        <div className="public-detail-copy">
          <div className="public-feature-list">
            {(agent.serviceAreas || []).map((area) => <span key={area}><Icon name="MapPin" /> {area}</span>)}
            {(agent.languages || []).map((language) => <span key={language}><Icon name="Languages" /> {language}</span>)}
            {(agent.specialties || []).map((specialty) => <span key={specialty}><Icon name="Sparkles" /> {specialty}</span>)}
          </div>
          <p>{agent.bio || `${agent.name} helps Florida buyers and sellers search confidently, ask better questions, and move with Nex Realty support.`}</p>
        </div>
      </section>

      <section className="public-section public-agent-search-section">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">IDX search</p>
            <h2>Search by city, ZIP, neighborhood, address, or MLS number.</h2>
          </div>
        </div>
        <IDXSearchEmbed idx={profile.idx || data?.idx} filters={{}} sourceAgentSlug={sourceSlug} agent={agent} setToast={setToast} />
      </section>

      <section className="public-section">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Featured listings</p>
            <h2>Browse homes from the Nex Realty IDX search.</h2>
          </div>
        </div>
        <div className="public-hero-chip-row public-agent-category-row">
          {["New Listings", "Waterfront", "Pool Homes", "Condos", "Luxury", agent.market || "Florida"].filter(Boolean).map((chip) => (
            <button key={chip} type="button" onClick={() => searchCategory(chip)}>{chip}</button>
          ))}
        </div>
        <div className="public-listing-grid compact">
          {featuredListings.map((listing) => (
            <PublicListingCard
              key={listing.id}
              listing={listing}
              navigate={navigate}
              onViewListing={onViewListing}
              sourceAgentSlug={sourceSlug}
            />
          ))}
        </div>
        {!featuredListings.length && <EmptyState icon="Search" title="Listings are loading" body="Try searching a city, ZIP, or neighborhood." />}
      </section>

      <section className="public-section public-agent-cta-grid">
        <article>
          <Icon name="Home" />
          <h2>Need help finding the right home?</h2>
          <p>Tell NIA what you are looking for and your request will route to {agent.name}.</p>
          <button className="btn primary" type="button" onClick={() => openAgentNia("buyer", `I need help finding the right home with ${agent.name}.`)}>Talk to agent</button>
        </article>
        <article>
          <Icon name="BadgeDollarSign" />
          <h2>Want to know what your home may be worth?</h2>
          <p>Start a seller request and Nex will route the follow-up to this agent website.</p>
          <button className="btn secondary" type="button" onClick={() => onHomeValue ? onHomeValue() : openAgentNia("seller", "I want to know what my home may be worth.")}>Home value</button>
        </article>
        <article>
          <Icon name="MessageSquare" />
          <h2>Ask {agent.name} a question</h2>
          <p>NIA will capture your question and connect it to this Nex Realty agent.</p>
          <button className="btn primary" type="button" onClick={() => openAgentNia("general", `I have a question for ${agent.name}.`)}>Ask a question</button>
        </article>
      </section>

      <section className="public-agent-idx-footer">
        <strong>{compliance.brokerageStatement}</strong>
        <p>{compliance.attributionText}</p>
        <p>{compliance.disclaimerText} {compliance.dataUpdateText}</p>
      </section>
    </section>
  );
}

function PublicRecruitingSeoPage({ slug, navigate, setToast }) {
  const [payload, setPayload] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    API.request(`/api/public/recruiting-pages/${encodeURIComponent(slug)}`)
      .then((response) => {
        if (!cancelled) setPayload(response);
      })
      .catch((error) => {
        setToast(error.message || "Could not load this recruiting page.");
        if (!cancelled) setPayload(null);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [slug, setToast]);

  if (loading) return <PublicSkeleton />;
  if (!payload?.page) {
    return (
      <section className="public-page">
        <EmptyState icon="SearchX" title="Recruiting page not found" body="This page is not published yet. Explore the main Nex Realty agent platform instead." />
        <button className="btn primary" type="button" onClick={() => navigate("/site/join")}>Open Agent Platform</button>
      </section>
    );
  }

  const { page, plans = [], faqs = [], markets = [], competitors = [], relatedBlogPosts = [], relatedPages = [] } = payload;
  const comparisonPage = page.category === "Comparison";
  const planPage = /commission|100 percent|100%/i.test(`${page.category} ${page.slug}`);
  const cityPage = page.category === "City Page";

  return (
    <section className="public-page public-recruiting-seo-page">
      <div className="public-recruiting-hero">
        <div>
          <p className="eyebrow">{page.category || "Join Nex Realty"}</p>
          <h1>{page.h1 || page.title}</h1>
          <p>{page.subheadline}</p>
          <div className="public-recruiting-cta-row">
            <button className="btn primary" type="button" onClick={() => document.querySelector(".public-recruiting-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" })}>
              <Icon name="CalendarCheck" />
              <span>{page.heroCtaPrimary || "Book a Discovery Call"}</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => document.querySelector(".public-recruiting-calculator")?.scrollIntoView({ behavior: "smooth", block: "start" })}>
              <Icon name="Calculator" />
              <span>{page.heroCtaSecondary || "Compare Commission Plans"}</span>
            </button>
          </div>
          <div className="public-seo-intent-row">
            <span><Icon name="SearchCheck" /> {page.searchIntent || "Florida agent brokerage search"}</span>
            <span><Icon name="MapPin" /> Florida agents</span>
            <span><Icon name="ShieldCheck" /> Editable SEO engine</span>
          </div>
        </div>
        <div className="public-recruiting-score-card">
          <span>Nex Recruiting Engine</span>
          <strong>Built to rank and convert</strong>
          <div>
            {["Low-fee plans", "Nex Central", "NexU", "Support", "Florida growth"].map((item) => <em key={item}>{item}</em>)}
          </div>
        </div>
      </div>

      <section className="public-section public-recruiting-platform-grid">
        {[
          ["Nex Central", "CRM, marketing, transactions, documents, chat, activity, calculators, PowerShare tracking, and agent tools."],
          ["NexU Training", "Onboarding, weekly education, practical resources, and agent learning content."],
          ["Florida Focus", "Built around Tampa Bay, Orlando, South Florida, Treasure Coast, and statewide expansion."],
          ["Growth Paths", "Level, Elite, and Premium plan options for different agent business models."]
        ].map(([title, body]) => (
          <article key={title}>
            <Icon name="Sparkles" />
            <strong>{title}</strong>
            <span>{body}</span>
          </article>
        ))}
      </section>

      {planPage && <RecruitingCommissionCalculator setToast={setToast} />}

      <section className="public-section public-recruiting-plans">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Three Clear Commission Paths</p>
            <h2>Pick the brokerage model that fits the way you produce.</h2>
          </div>
        </div>
        <div className="public-recruiting-plan-grid">
          {plans.map((plan) => <RecruitingPlanCard key={plan.id} plan={plan} />)}
        </div>
      </section>

      {(page.sections || []).filter((section) => section.type !== "plans").map((section) => (
        <section className="public-section public-recruiting-content-band" key={section.id}>
          <div>
            <p className="eyebrow">{section.eyebrow}</p>
            <h2>{section.title}</h2>
            <p>{section.body}</p>
          </div>
          {Array.isArray(section.items) && (
            <div className="public-benefit-grid compact">
              {section.items.map((item) => <article key={item}><Icon name="CircleCheck" /><strong>{item}</strong></article>)}
            </div>
          )}
        </section>
      ))}

      {comparisonPage && (
        <section className="public-section public-comparison-disclaimer">
          <p className="eyebrow">Fair comparison note</p>
          <h2>Compare brokerage fit, not rumors.</h2>
          <p>Brokerage fees and programs can change. This comparison is for general informational purposes only and should be verified directly with each brokerage. Admin can update competitor fields and notes as accurate data is confirmed.</p>
          <div className="public-mini-grid">
            {["Commission model", "Monthly fees", "Transaction fees", "Cap structure", "Training", "Broker support", "Technology", "Best fit"].map((item) => <span key={item}><Icon name="CheckCircle2" /> {item}</span>)}
          </div>
        </section>
      )}

      <section className="public-section public-recruiting-lead-split">
        <div>
          <p className="eyebrow">See If Nex Is a Fit</p>
          <h2>Get a side-by-side plan review based on your actual business.</h2>
          <p>Tell Nex where you are now, what market you serve, and what you want from your next brokerage. The form routes into Nex CRM with source page, intent, score, and follow-up status.</p>
          <div className="public-recruiting-market-cloud">
            {markets.slice(0, 12).map((market) => <span key={market.id}>{market.city || market.region}</span>)}
          </div>
        </div>
        <PublicRecruitingLeadForm page={page} setToast={setToast} />
      </section>

      <section className="public-section public-recruiting-faqs">
        <div className="public-section-head">
          <div>
            <p className="eyebrow">Agent Questions</p>
            <h2>What Florida agents ask before joining Nex.</h2>
          </div>
        </div>
        <div className="public-faq-grid">
          {faqs.slice(0, 10).map((faq) => (
            <article key={faq.id}>
              <strong>{faq.question}</strong>
              <p>{faq.answer}</p>
            </article>
          ))}
        </div>
      </section>

      <section className="public-section public-internal-link-band">
        <div>
          <p className="eyebrow">Keep researching</p>
          <h2>Related Nex Realty recruiting pages</h2>
        </div>
        <div className="public-recruiting-link-grid">
          {(relatedPages.length ? relatedPages : [
            { label: "Join Nex Realty", path: "/join-nex-realty" },
            { label: "Commission Plans", path: "/real-estate-brokerage-commission-plans-florida" },
            { label: "100% Commission", path: "/100-percent-commission-real-estate-brokerage-florida" },
            { label: "Training & Support", path: "/real-estate-brokerage-with-training-florida" },
            { label: "Team Leaders", path: "/real-estate-team-brokerage-florida" },
            { label: "Best Florida Brokerage Options", path: "/best-florida-brokerage" }
          ]).map(({ label, path }) => (
            <button key={path} type="button" onClick={() => navigate(path)}>
              <span>{label}</span>
              <Icon name="ArrowRight" />
            </button>
          ))}
          {cityPage && competitors.slice(0, 2).map((competitor) => (
            <button key={competitor.id} type="button" onClick={() => navigate(`/nex-realty-vs-${String(competitor.id)}`)}>
              <span>Nex vs {competitor.name}</span>
              <Icon name="ArrowRight" />
            </button>
          ))}
          {relatedBlogPosts.map((post) => (
            <button key={post.id} type="button" onClick={() => navigate(`/site/resources/${post.slug}`)}>
              <span>{post.title}</span>
              <Icon name="ArrowRight" />
            </button>
          ))}
        </div>
      </section>
    </section>
  );
}

function RecruitingPlanCard({ plan }) {
  const capLabel = plan.cap ? `${formatCurrency(plan.cap)} annual cap` : "No annual cap";
  return (
    <article className="public-recruiting-plan-card">
      <span>{plan.name}</span>
      <h3>{plan.subtitle}</h3>
      <strong>{plan.split} Split | {capLabel}</strong>
      <ul>
        <li>{formatCurrency(plan.monthlyFee)} monthly fee</li>
        <li>{plan.joinFee ? `${formatCurrency(plan.joinFee)} one-time join fee` : "No upfront fee"}</li>
        <li>{formatCurrency(plan.transactionFee)} transaction fee</li>
        <li>{plan.postCap}</li>
        <li>{plan.npsEligible ? "Nex PowerShare eligible" : "Nex commission plan not eligible for NPS"}</li>
      </ul>
      <p>{plan.bestFor}</p>
    </article>
  );
}

function RecruitingCommissionCalculator({ setToast }) {
  const [draft, setDraft] = useState({
    averageSalePrice: "450000",
    dealsPerYear: "8",
    averageCommissionPercentage: "3",
    currentSplit: "80",
    currentCap: "20000",
    monthlyFee: "0",
    transactionFee: "295"
  });
  const [result, setResult] = useState(null);
  const [submitting, setSubmitting] = useState(false);

  function update(field, value) {
    setDraft((current) => ({ ...current, [field]: value }));
  }

  async function calculate(event) {
    event.preventDefault();
    setSubmitting(true);
    try {
      const payload = await API.request("/api/public/recruiting-commission-calculator", {
        method: "POST",
        body: JSON.stringify(draft)
      });
      setResult(payload);
    } catch (error) {
      setToast(error.message || "Could not run the commission comparison.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <section className="public-section public-recruiting-calculator">
      <div className="public-section-head">
        <div>
          <p className="eyebrow">Commission comparison</p>
          <h2>Estimate your annual brokerage cost.</h2>
        </div>
      </div>
      <div className="public-calculator-grid">
        <form onSubmit={calculate} className="public-calculator-form">
          <div className="public-form-row">
            <input value={draft.averageSalePrice} onChange={(event) => update("averageSalePrice", event.target.value)} placeholder="Average sale price" />
            <input value={draft.dealsPerYear} onChange={(event) => update("dealsPerYear", event.target.value)} placeholder="Deals per year" />
          </div>
          <div className="public-form-row">
            <input value={draft.averageCommissionPercentage} onChange={(event) => update("averageCommissionPercentage", event.target.value)} placeholder="Avg commission %" />
            <input value={draft.currentSplit} onChange={(event) => update("currentSplit", event.target.value)} placeholder="Current agent split %" />
          </div>
          <div className="public-form-row">
            <input value={draft.currentCap} onChange={(event) => update("currentCap", event.target.value)} placeholder="Current cap" />
            <input value={draft.monthlyFee} onChange={(event) => update("monthlyFee", event.target.value)} placeholder="Current monthly fee" />
          </div>
          <input value={draft.transactionFee} onChange={(event) => update("transactionFee", event.target.value)} placeholder="Current transaction fee" />
          <button className="btn primary" type="submit" disabled={submitting}>
            <Icon name={submitting ? "LoaderCircle" : "Calculator"} className={submitting ? "spin" : ""} />
            <span>{submitting ? "Calculating" : "Compare Plans"}</span>
          </button>
          <small>This calculator is an estimate and does not include every possible fee, split, tax, referral, or team agreement.</small>
        </form>
        <div className="public-calculator-results">
          {result ? (
            <>
              <div className="public-current-cost-card">
                <span>Current estimated brokerage cost</span>
                <strong>{formatCurrency(result.inputs.currentBrokerageCost)}</strong>
                <small>Estimated current take-home: {formatCurrency(result.inputs.currentTakeHome)}</small>
              </div>
              <div className="public-plan-result-list">
                {result.plans.map((plan) => (
                  <article key={plan.planId} className={result.suggestedPlan?.planId === plan.planId ? "suggested" : ""}>
                    <div>
                      <strong>{plan.name}</strong>
                      <span>{plan.subtitle}</span>
                    </div>
                    <em>{formatCurrency(plan.estimatedTakeHome)} est. take-home</em>
                    <small>{plan.differenceFromCurrent >= 0 ? "+" : ""}{formatCurrency(plan.differenceFromCurrent)} vs current</small>
                  </article>
                ))}
              </div>
            </>
          ) : (
            <EmptyState icon="Calculator" title="Run your numbers" body="Enter your current brokerage costs to compare Nex Level, Nex Elite, and Nex Premium." />
          )}
        </div>
      </div>
    </section>
  );
}

function PublicRecruitingLeadForm({ page, setToast }) {
  const [form, setForm] = useState({
    name: "",
    email: "",
    phone: "",
    licenseStatus: "",
    currentBrokerage: "",
    countyMarket: "",
    averageTransactionsPerYear: "",
    interestedPlan: "",
    mainReason: "",
    preferredContactMethod: "",
    consent: false,
    website: ""
  });
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState("");

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
    if (error) setError("");
  }

  async function submit(event) {
    event.preventDefault();
    setError("");
    const validation = validatePublicLeadCapture({ name: form.name, email: form.email, phone: form.phone, intent: "Join Nex", consent: form.consent });
    if (!validation.ok) {
      setError(validation.message);
      return;
    }
    setSubmitting(true);
    try {
      const payload = await API.request("/api/site/agent-interest", {
        method: "POST",
        body: JSON.stringify({
          ...form,
          preferredContactTime: form.preferredContactMethod,
          sourceSlug: page.slug,
          sourcePage: page.path || `/${page.slug}`,
          sourceCategory: page.category,
          searchIntent: page.searchIntent,
          formName: `Recruiting SEO - ${page.slug}`,
          referrer: document.referrer || ""
        })
      });
      setToast(payload.message || "Recruiting request submitted.");
      setForm({
        name: "",
        email: "",
        phone: "",
        licenseStatus: "",
        currentBrokerage: "",
        countyMarket: "",
        averageTransactionsPerYear: "",
        interestedPlan: "",
        mainReason: "",
        preferredContactMethod: "",
        consent: false,
        website: ""
      });
    } catch (error) {
      setToast(error.message || "Could not submit recruiting request.");
      setError(error.message || "Could not submit recruiting request.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <form className="public-recruiting-lead-form" onSubmit={submit}>
      <h3>Talk to Nex recruiting</h3>
      <p>Send the basics and the Nex team can follow up. No long application required.</p>
      <input required value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Full name" />
      <div className="public-form-row">
        <input required type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" />
        <input required value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" />
      </div>
      <div className="public-form-row">
        <select value={form.licenseStatus} onChange={(event) => update("licenseStatus", event.target.value)}>
          <option value="">License status</option>
          <option>Active Florida license</option>
          <option>Licensed in another state</option>
          <option>In licensing school</option>
          <option>Exploring real estate</option>
        </select>
        <input value={form.countyMarket} onChange={(event) => update("countyMarket", event.target.value)} placeholder="Market / city" />
      </div>
      <select value={form.preferredContactMethod} onChange={(event) => update("preferredContactMethod", event.target.value)}>
        <option value="">Preferred contact</option>
        <option>Call</option>
        <option>Text</option>
        <option>Email</option>
      </select>
      <label className="public-consent">
        <input required type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
        <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
      </label>
      <PublicLegalInlineLinks />
      {error && <div className="login-error public-form-error">{error}</div>}
      <button className="btn primary" disabled={submitting} type="submit">
        <Icon name={submitting ? "LoaderCircle" : "Send"} className={submitting ? "spin" : ""} />
        <span>{submitting ? "Sending" : "Send My Info"}</span>
      </button>
      <input className="public-honeypot" tabIndex="-1" autoComplete="off" value={form.website} onChange={(event) => update("website", event.target.value)} placeholder="Website" />
    </form>
  );
}

function PublicJoinNex({ navigate, setToast }) {
  const platformModules = [
    ["Nex Central", "The operating hub for agents, support, training, marketing, transactions, chat, and brokerage systems.", "MonitorSmartphone"],
    ["Nex CRM", "A daily follow-up command center for leads, tasks, pipeline status, and accountability.", "ContactRound"],
    ["Nex Chat", "Company channels, market chats, direct messages, mentions, and faster internal communication.", "MessagesSquare"],
    ["NexU", "Training, onboarding, weekly education, and resources built around real Florida agent workflows.", "GraduationCap"],
    ["Marketing Studio", "AI-assisted Nex-branded flyers, posts, business cards, rental assets, recruiting posts, and listing packages.", "Palette"],
    ["Lead Routing", "Brokerage leads, agent website leads, recruiting inquiries, and market-based routing logic.", "Route"],
    ["Transactions", "File guidance, checklist structure, deadline visibility, and future document workflow expansion.", "ClipboardCheck"],
    ["Agent Intelligence", "Admin analytics for production, engagement, lead performance, cap status, and activity signals.", "BarChart3"]
  ];
  const workflow = [
    ["Lead comes in", "Website, IDX, agent profile, SEO page, or campaign form captures the source."],
    ["Nex Central classifies it", "Brokerage-generated, agent-generated, recruiting, or review-required routing stays clear."],
    ["Agent gets notified", "Nex Chat, dashboard notifications, email, and SMS-ready alerts keep the response fast."],
    ["Nex CRM tracks follow-up", "The assigned agent sees tasks, status, notes, and next follow-up without losing context."],
    ["Transaction moves forward", "Commission, checklist, and support workflows can connect back to the original source."]
  ];
  return (
    <section className="public-page public-join-page">
      <div className="public-platform-hero">
        <div>
          <p className="eyebrow">Agent Platform</p>
          <h1>Nex Central is the brokerage operating system behind Nex Realty.</h1>
          <p>
            A modern Florida brokerage should give agents more than a place to hang a license. Nex Realty is building
            the tools, support, CRM, chat, training, marketing, lead routing, and production visibility agents need to
            build, produce, and grow.
          </p>
          <div className="public-brokerage-hero-actions">
            <button className="btn primary" type="button" onClick={() => document.querySelector(".public-join-page .public-recruiting-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" })}>
              <Icon name="CalendarCheck" />
              <span>Talk to Nex</span>
            </button>
            <button className="btn secondary" type="button" onClick={() => navigate("/site/search")}>
              <Icon name="Search" />
              <span>See IDX-ready search</span>
            </button>
            <a className="btn secondary public-agent-platform-link" href="https://www.mynexrealty.com" target="_blank" rel="noreferrer">
              <Icon name="ExternalLink" />
              <span>Open Agent Site</span>
            </a>
          </div>
        </div>
        <div className="public-platform-device">
          <div className="public-platform-device-top">
            <span><i /> Nex Central</span>
            <small>Agent command center</small>
          </div>
          <div className="public-platform-device-metrics">
            {["Leads", "CRM", "Chat", "NexU"].map((item, index) => (
              <article key={item}>
                <strong>{["24", "8", "3", "92%"][index]}</strong>
                <span>{item}</span>
              </article>
            ))}
          </div>
          <div className="public-platform-device-flow">
            {["New IDX lead", "Market routed", "Agent notified", "Follow-up task"].map((item, index) => (
              <span key={item}><em>{index + 1}</em>{item}</span>
            ))}
          </div>
        </div>
      </div>

      <section className="public-section public-platform-module-grid">
        {platformModules.map(([title, body, icon]) => (
          <article key={title}>
            <Icon name={icon} />
            <strong>{title}</strong>
            <span>{body}</span>
          </article>
        ))}
      </section>

      <section className="public-platform-workflow">
        <div>
          <p className="eyebrow">Agent Workflow</p>
          <h2>Lead to close, built around one connected Nex system.</h2>
          <p>
            The recruiting story is simple: Nex gives agents a more organized place to work. Website lead capture,
            CRM follow-up, chat, training, transaction support, production tracking, and future IDX data are designed
            to speak to each other.
          </p>
        </div>
        <div className="public-workflow-timeline">
          {workflow.map(([title, body], index) => (
            <article key={title}>
              <em>{String(index + 1).padStart(2, "0")}</em>
              <strong>{title}</strong>
              <span>{body}</span>
            </article>
          ))}
        </div>
      </section>

      <section className="public-split-section public-platform-support-band">
        <div>
          <p className="eyebrow">Modern Florida Brokerage</p>
          <h2>Cloud-based support with real systems behind it.</h2>
          <p>
            Agents can research Nex for commission options, technology, training, support, lead opportunities, and a
            brokerage culture built around accountability without the old-school operational drag.
          </p>
          <div className="public-seo-intent-row">
            {["Nex CRM", "Nex Chat", "NexU", "Marketing Studio", "Commission tracking"].map((item) => (
              <span key={item}><Icon name="CheckCircle2" /> {item}</span>
            ))}
          </div>
        </div>
        <PublicRecruitingLeadForm page={{ slug: "join-nex-realty", path: "/site/join", category: "Join Nex", searchIntent: "Join Nex Realty" }} setToast={setToast} />
      </section>
    </section>
  );
}

function PublicInlineSearchBand({ page = "buy", navigate }) {
  const [form, setForm] = useState({ search: "", maxPrice: "", beds: "", propertyType: "" });
  const isRental = page === "rent";
  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
  }
  function submit(event) {
    event.preventDefault();
    const params = new URLSearchParams();
    params.set("status", isRental ? "For Rent" : "Active");
    Object.entries(form).forEach(([key, value]) => {
      if (String(value || "").trim()) params.set(key, value);
    });
    navigate(`/site/search?${params.toString()}`);
  }
  return (
    <section className="public-inline-search-band">
      <div>
        <p className="eyebrow">{isRental ? "Rental search" : "Live home search"}</p>
        <h2>{isRental ? "Search rental options without filling out a long form first." : "Start with the area, then refine from live MLS results."}</h2>
        <p>{isRental ? "Enter a city, ZIP, neighborhood, address, or MLS number and continue into the full search experience." : "The full search page supports map/list view, filters, sort, saved search requests, and showing questions."}</p>
      </div>
      <form onSubmit={submit}>
        <PublicListingSearchAutocomplete
          value={form.search}
          onChange={(value) => update("search", value)}
          onSelect={(suggestion) => update("search", suggestion.value || suggestion.label || "")}
          placeholder="City, ZIP, neighborhood, address, or MLS number"
          seedListings={[]}
        />
        <input type="number" min="0" value={form.maxPrice} onChange={(event) => update("maxPrice", event.target.value)} placeholder={isRental ? "Max rent" : "Max price"} />
        <input type="number" min="0" value={form.beds} onChange={(event) => update("beds", event.target.value)} placeholder="Beds" />
        <select value={form.propertyType} onChange={(event) => update("propertyType", event.target.value)}>
          <option value="">Property type</option>
          {PUBLIC_SEARCH_PROPERTY_TYPES.filter(Boolean).map((type) => <option key={type} value={type}>{type}</option>)}
        </select>
        <button className="btn primary" type="submit">
          <Icon name="Search" />
          <span>{isRental ? "Search Rentals" : "Search Homes"}</span>
        </button>
      </form>
    </section>
  );
}

function PublicReturningConsumerPanel({ navigate, onTalkAgent }) {
  const session = readPublicConsumerSession();
  const firstName = session?.firstName || firstNameFromName(session?.name || "");
  if (!session) {
    return (
      <section className="public-returning-consumer-panel">
        <Icon name="UserRoundCheck" />
        <div>
          <p className="eyebrow">Returning visitors</p>
          <h2>No separate consumer password is needed right now.</h2>
          <p>After you submit a valid inquiry on this browser, Nex Central remembers the session so NIA and saved-search requests can continue without making you re-enter the same contact info.</p>
        </div>
        <button className="btn secondary" type="button" onClick={() => navigate("/site/search")}>Continue to Search</button>
      </section>
    );
  }
  return (
    <section className="public-returning-consumer-panel recognized">
      <Icon name="UserRoundCheck" />
      <div>
        <p className="eyebrow">Welcome back</p>
        <h2>{firstName ? `Welcome back, ${firstName}.` : "Welcome back."}</h2>
        <p>Your search session is recognized on this browser. You can continue searching, ask NIA a question, save homes, or request help without creating a duplicate lead.</p>
      </div>
      <div className="public-returning-actions">
        <button className="btn primary" type="button" onClick={() => navigate("/site/search")}>Continue Search</button>
        <button className="btn secondary" type="button" onClick={() => onTalkAgent ? onTalkAgent({ intent: "question", initialMessage: "I am returning to continue my Nex Realty search." }) : navigate("/site/contact")}>Ask NIA</button>
      </div>
    </section>
  );
}

function PublicAboutTechGrid() {
  const systems = [
    ["Nex Central", "Agent dashboard, leads, CRM, communication, training, marketing, and transaction visibility in one operating hub.", "MonitorSmartphone"],
    ["IDX Agent Websites", "Approved brokerage IDX feed powers public search and agent-branded websites with lead routing attached.", "Home"],
    ["NIA Concierge", "Consumer and agent conversations capture intent, preserve context, and help route follow-up more cleanly.", "Sparkles"],
    ["Marketing Studio", "Nex-branded listing, recruiting, social, and agent materials keep the brand consistent without slowing agents down.", "Palette"],
    ["LaunchPad + NexU", "Structured onboarding and training help agents learn the Nex systems, scripts, compliance habits, and daily workflows.", "GraduationCap"],
    ["Support Forward", "The brokerage model is built around fast answers, practical tools, documented processes, and clearer next steps.", "Headphones"]
  ];
  return (
    <section className="public-about-tech-grid">
      {systems.map(([title, body, icon]) => (
        <article key={title}>
          <Icon name={icon} />
          <strong>{title}</strong>
          <span>{body}</span>
        </article>
      ))}
    </section>
  );
}

function pulseNumericValue(value) {
  if (value === null || typeof value === "undefined" || value === "") return null;
  const numeric = Number(value);
  return Number.isFinite(numeric) ? numeric : null;
}

function pulseLooksLikeZeroDisplay(value) {
  const text = String(value || "").trim().toLowerCase();
  if (!text) return false;
  return /^[-+]?0(?:\.0+)?\s*(%|pts?|bps)$/.test(text) || /^[-+]?0\s*basis\s*points?$/.test(text);
}

function pulseLooksLikePlainZeroDisplay(value) {
  return /^[-+]?0(?:\.0+)?$/.test(String(value || "").trim().toLowerCase());
}

function pulseUsesRateUnit(item) {
  const suffix = String(item?.suffix || "").toLowerCase();
  const identity = `${item?.id || ""} ${item?.label || ""}`.toLowerCase();
  return suffix.includes("%")
    || suffix.includes("pt")
    || suffix.includes("bp")
    || /mortgage|rate|treasury|spread|funds|cpi|unemployment|arm|fha|va|usda|jumbo|refi|bond|mbs/.test(identity);
}

function pulseShouldSuppressZero(item) {
  const numeric = pulseNumericValue(item?.value);
  const quality = String(item?.dataQuality || "").toLowerCase();
  const live = Boolean(item?.live);
  const looksZero = pulseLooksLikeZeroDisplay(item?.displayValue)
    || (pulseLooksLikePlainZeroDisplay(item?.displayValue) && pulseUsesRateUnit(item))
    || (numeric === 0 && pulseUsesRateUnit(item));
  if (!looksZero) return false;
  if (live && numeric === 0) return false;
  return numeric === null || !live || ["fallback", "pending", "proxy", "source-offline", "estimate"].includes(quality);
}

function pulseDisplayValue(item, fallback = "Unavailable") {
  if (pulseShouldSuppressZero(item)) {
    if (item?.dataQuality === "pending" || item?.dataQuality === "proxy") return "Pending data";
    if (item?.dataQuality === "source-offline") return "Pending data";
    return fallback;
  }
  if (item?.displayValue && !pulseLooksLikeZeroDisplay(item.displayValue)) return item.displayValue;
  const numeric = pulseNumericValue(item?.value);
  if (numeric !== null) return item?.suffix ? `${numeric.toFixed(2)}${item.suffix}` : numeric.toFixed(2);
  if (item?.dataQuality === "pending") return "Pending data";
  if (item?.dataQuality === "source-offline") return "Pending data";
  if (item?.dataQuality === "proxy") return "Pending data";
  return fallback;
}

function pulseLooksUnavailable(value) {
  const text = String(value || "").trim().toLowerCase();
  return !text
    || text === "--"
    || text === "n/a"
    || text === "na"
    || text === "unavailable"
    || text === "pending"
    || text === "pending data"
    || text === "source offline"
    || text === "source unavailable";
}

function pulseShouldShowInTicker(item) {
  if (!item) return false;
  const display = pulseDisplayValue(item, "");
  if (pulseLooksUnavailable(display)) return false;
  if (pulseShouldSuppressZero(item)) return false;
  return true;
}

function pulseTickerStatusLabel(item) {
  const raw = String(item?.statusLabel || (item?.live ? "live" : "")).trim();
  const normalized = raw.toLowerCase();
  if (!raw || ["offline", "source-offline", "pending"].includes(normalized)) return "";
  return raw;
}

function pulseStatusClass(label, item) {
  return String(item?.dataQuality || label || "")
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9-]+/g, "-");
}

function pulseTooltip(item) {
  return [item?.note, item?.source, item?.sourceLastUpdated || item?.date ? `Source date ${item.sourceLastUpdated || item.date}` : ""]
    .filter(Boolean)
    .join(" | ");
}

function MarketPulseTicker({ endpoint = "/api/public/market-pulse", variant = "public", refreshToken = 0 }) {
  const [pulse, setPulse] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let mounted = true;
    let timer;
    function scheduleNext(payload) {
      const minutes = Math.max(1, Number(payload?.autoRefreshMinutes || payload?.refreshMinutes || 5) || 5);
      timer = window.setTimeout(loadPulse, minutes * 60 * 1000);
    }
    async function loadPulse() {
      if (timer) window.clearTimeout(timer);
      let nextPayload = null;
      setLoading((current) => current || !pulse);
      try {
        const separator = endpoint.includes("?") ? "&" : "?";
        const payload = await API.request(`${endpoint}${separator}ts=${Date.now()}`, { retries: 0 });
        nextPayload = payload;
        if (mounted) setPulse(payload);
      } catch (error) {
        nextPayload = { autoRefreshMinutes: 5 };
        if (mounted) setPulse({ error: true, items: [], housing: [], disclaimer: "Market Pulse is temporarily unavailable. Please try again shortly." });
      } finally {
        if (mounted) {
          setLoading(false);
          scheduleNext(nextPayload);
        }
      }
    }
    loadPulse();
    return () => {
      mounted = false;
      if (timer) window.clearTimeout(timer);
    };
  }, [endpoint, refreshToken]);

  const items = [
    ...(pulse?.items || []),
    ...(pulse?.housing || [])
  ].filter(Boolean);
  const tickerReadyItems = items.filter(pulseShouldShowInTicker);
  const visibleItems = tickerReadyItems.length ? tickerReadyItems : [
    { id: "loading-30y", label: "30Y Conv", displayValue: loading ? "Checking" : "Unavailable" },
    { id: "loading-treasury", label: "10Y Treasury", displayValue: loading ? "Checking" : "Unavailable" },
    { id: "loading-inventory", label: "Active Preview", displayValue: loading ? "Checking" : "Unavailable" }
  ];
  const tickerItems = Array.from({ length: 4 }).flatMap(() => visibleItems);

  return (
    <section className={classNames("market-pulse-ticker", `market-pulse-${variant}`, pulse?.error && "has-error")} aria-label="Nex Market Pulse">
      <div className="market-pulse-label">
        <Icon name="Activity" />
        <span>{pulse?.title || "Nex Market Pulse"}</span>
        <em>{pulse?.location || "Florida"}</em>
      </div>
      <div className="market-pulse-marquee">
        <div>
          {tickerItems.map((item, index) => {
            const status = pulseTickerStatusLabel(item);
            return (
              <span key={`${item.id || item.label}-${index}`} title={pulseTooltip(item)}>
                <strong>{item.label}</strong>
                <b>{pulseDisplayValue(item)}</b>
                {item.indicator && <i className={classNames("pulse-trend", item.trend)}>{item.indicator}</i>}
                {status && <i className={classNames("pulse-status", pulseStatusClass(status, item))}>{status}</i>}
              </span>
            );
          })}
        </div>
      </div>
      <small>{pulse?.updatedAt ? `Updated ${new Date(pulse.updatedAt).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}` : "Rates checking"}</small>
    </section>
  );
}

function PublicBrokerageSeoPage({ topic, navigate, setToast }) {
  const pageMap = {
    "best-florida-brokerage": {
      eyebrow: "Florida Real Estate Brokerage",
      title: "A modern Florida brokerage built for agents who want tech, support, and opportunity.",
      body: "Nex Realty is designed for Florida agents comparing brokerage models, technology, training, support, commission plans, and long-term growth. Explore Nex Central, NexU, marketing tools, CRM, transactions, PowerShare, and a cloud-forward brokerage platform.",
      intent: "Best Florida brokerage",
      bullets: ["Modern agent technology", "Florida brokerage support", "Nex Central tools", "NexU training", "Commission plan options", "PowerShare eligibility where applicable"]
    },
    "new-agent-friendly-real-estate-brokerage": {
      eyebrow: "New Agent Friendly Brokerage",
      title: "A cleaner launchpad for new Florida real estate agents.",
      body: "New agents need training, structure, answers, templates, transaction guidance, marketing, CRM follow-up, and a place to ask questions without feeling lost. Nex Realty is building that experience directly inside Nex Central.",
      intent: "New agent friendly real estate brokerage",
      bullets: ["Onboarding support", "NexU training library", "Marketing templates", "Transaction checklist guidance", "Agent chat and support", "Brokerage resources in one hub"]
    },
    "exp-realty-alternative": {
      eyebrow: "Brokerage Comparison",
      title: "Looking at eXp Realty? Compare a Florida-first Nex Realty model.",
      body: "Agents researching eXp Realty are often looking for cloud brokerage technology, revenue opportunities, training, and scalability. Nex Realty offers a Florida-focused alternative with Nex Central, local brokerage support, and modern systems built around our agents.",
      intent: "eXp Realty alternative Florida",
      bullets: ["Florida-first brokerage", "Cloud-friendly operations", "Nex PowerShare", "Internal CRM and tools", "Local support structure", "Modern marketing and transaction workflows"]
    },
    "keller-williams-alternative": {
      eyebrow: "Brokerage Comparison",
      title: "Considering Keller Williams? See Nex Realty's modern Florida brokerage platform.",
      body: "Agents comparing Keller Williams, traditional offices, and cloud brokerage options should understand how Nex Realty is building a more streamlined Florida agent platform with technology, training, support, and flexible growth paths.",
      intent: "Keller Williams alternative Florida",
      bullets: ["Less old-school friction", "Modern Nex Central platform", "Training and support", "Marketing and CRM tools", "Florida agent focus", "Scalable brokerage technology"]
    }
  };
  const config = pageMap[topic] || pageMap["best-florida-brokerage"];
  return (
    <section className="public-page public-brokerage-seo-page">
      <div className="public-page-head">
        <p className="eyebrow">{config.eyebrow}</p>
        <h1>{config.title}</h1>
        <p>{config.body}</p>
        <div className="public-brokerage-hero-actions">
          <button className="btn primary" type="button" onClick={() => document.querySelector(".public-brokerage-seo-page .public-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" })}>
            <Icon name="CalendarCheck" />
            <span>Talk to Nex Recruiting</span>
          </button>
          <a className="btn secondary" href="https://www.mynexrealty.com" target="_blank" rel="noreferrer">
            <Icon name="ExternalLink" />
            <span>View Agent Platform</span>
          </a>
        </div>
        <div className="public-seo-intent-row">
          <span><Icon name="SearchCheck" /> Built for: {config.intent}</span>
          <span><Icon name="MapPin" /> Florida agents</span>
          <span><Icon name="ShieldCheck" /> Nex Realty brokerage model</span>
        </div>
        <div className="public-recruiting-highlight-row">
          {[
            ["Nex Central", "CRM, marketing, transactions, chat, documents, activity, and agent tools."],
            ["Florida Focus", "Built around real Florida agents, markets, training, and support."],
            ["Growth Model", "Commission plans, PowerShare where eligible, and better production visibility."]
          ].map(([title, body]) => (
            <article key={title}>
              <Icon name="Sparkles" />
              <strong>{title}</strong>
              <span>{body}</span>
            </article>
          ))}
        </div>
      </div>
      <div className="public-split-section">
        <div>
          <p className="eyebrow">Why Agents Compare Nex</p>
          <h2>Technology, training, support, and growth in one brokerage ecosystem.</h2>
          <p>
            Nex Realty is not trying to look like every legacy brokerage. The platform is being built around what agents
            actually need each day: lead follow-up, marketing, transaction support, education, collaboration, commission
            visibility, and a clear path for production.
          </p>
          <div className="public-seo-link-row">
            <button className="btn primary" type="button" onClick={() => navigate("/site/join")}>Explore Nex Careers</button>
            <a className="btn secondary" href="https://www.mynexrealty.com" target="_blank" rel="noreferrer">Visit Agent Site</a>
          </div>
        </div>
        <div className="public-benefit-grid compact">
          {config.bullets.map((item) => (
            <article key={item}><Icon name="CircleCheck" /><strong>{item}</strong></article>
          ))}
        </div>
      </div>
      <section className="public-section public-card-grid">
        {[
          ["Nex Central", "CRM, marketing, transactions, documents, chat, activity, calculators, and agent tools."],
          ["NexU", "Training, onboarding, brokerage resources, and learning content inside the agent portal."],
          ["Nex PowerShare", "A professional revenue-share rewards tracker and genealogy-ready foundation."],
          ["Modern Marketing", "Direct-edit marketing studio, business cards, flyers, social assets, and campaigns."]
        ].map(([title, body]) => (
          <article key={title} className="public-action-card static">
            <Icon name="Sparkles" />
            <strong>{title}</strong>
            <span>{body}</span>
          </article>
        ))}
      </section>
      <PublicLeadForm title="Talk to Nex recruiting" leadType="recruiting" sourcePage={`SEO Brokerage ${topic}`} setToast={setToast} recruiting />
    </section>
  );
}

function PublicInfoPage({ page, data, navigate, setToast, sourceAgentSlug = "", onTalkAgent }) {
  const defaultWorkflow = [
    ["Share", "Tell us what you need, where you are looking, and your timing."],
    ["Connect", "A Nex Realty professional can help with the right local next step."],
    ["Move forward", "Get guidance for search, showings, valuation, or selling strategy."]
  ];
  const pageMap = {
    buy: {
      eyebrow: "Buy With Nex",
      title: "Search smarter, tour faster, and move with a Nex Realty agent.",
      body: "Nex gives buyers a cleaner path from search to showing to offer. Tell us what you want, then a local Nex agent can help with saved searches, tours, buyer agreement questions, financing steps, offer strategy, and next moves.",
      type: "buyer",
      action: "Start a buyer search",
      proof: ["Live home search", "Saved search requests", "Showing requests", "Local agent help"],
      metrics: [["Search", "Live"], ["Guidance", "Local"], ["Next step", "Clear"]],
      systemTitle: "A buyer experience designed for speed and clarity.",
      systemBody: "Search homes, ask questions, request tours, and get connected with a local Nex agent who can help you compare options.",
      systemCards: [
        ["Simple search", "Search by city, budget, beds, baths, neighborhood, or property type."],
        ["Agent matching", "Buyer requests can connect with the right Nex professional for the area."],
        ["Showing path", "Property inquiries preserve listing context so agents do not start cold."],
        ["Next-step guidance", "Get help with tours, financing questions, offer timing, and local market context."]
      ],
      workflow: [
        ["Search homes", "Buyer searches by city, price, beds, market, or property type."],
        ["Request help", "Showing and search requests capture city, budget, timeline, and source."],
        ["Connect with Nex", "The right agent or team can respond with context."],
        ["Next step", "Get help with follow-up, showings, and offer preparation."]
      ]
    },
    sell: {
      eyebrow: "Sell With Nex",
      title: "Start with a quick home value, then build the right selling plan.",
      body: "Nex Realty helps sellers move from curiosity to market-ready with nearby comparable data, pricing strategy, listing prep, Nex-branded marketing, buyer follow-up, and clear seller communication.",
      type: "seller",
      action: "Get home value",
      proof: ["Smart pricing strategy", "Marketing Studio rollout", "Seller pipeline tracking", "Offer strategy support"],
      metrics: [["CMA", "Fast start"], ["Marketing", "Nex branded"], ["Pipeline", "Tracked"]],
      systemTitle: "A premium seller process from pricing to offers.",
      systemBody: "Start with a home value request, then get help with pricing, listing prep, marketing launch, showing feedback, and offer strategy.",
      systemCards: [
        ["Smart pricing strategy", "Start with value range, local comps, timing, and positioning questions."],
        ["Listing prep checklist", "Help sellers understand photos, repairs, access, disclosures, and launch timing."],
        ["Marketing rollout", "Nex-branded flyers, social posts, QR assets, and listing promotion can connect to Marketing Studio."],
        ["Offer and reporting rhythm", "Keep sellers informed on interest, follow-up, showings, offers, and next decisions."]
      ],
      workflow: [
        ["Value request", "Seller submits address, city, timeline, and goals."],
        ["Market match", "Nex can connect the request with local market guidance."],
        ["Listing plan", "Agent prepares pricing, prep, marketing, and launch strategy."],
        ["Follow-up", "Seller updates, offer strategy, and next steps stay organized."]
      ]
    },
    rent: {
      eyebrow: "Rent With Nex",
      title: "Find rental options with a cleaner, more organized search path.",
      body: "Share your desired city, budget, move date, and property needs. Nex can keep your search details together and make the next step simple where rental support is available.",
      type: "renter",
      action: "Request rental help",
      proof: ["Rental search help", "Availability questions", "Move-date details", "Direct agent help"],
      metrics: [["Rental", "Search"], ["Details", "Clear"], ["Follow-up", "Simple"]],
      systemTitle: "Rental inquiries should feel organized, not random.",
      systemBody: "The rental page captures the details an agent needs first so the conversation can start with your area, timing, and budget.",
      systemCards: [
        ["Budget and timing", "Capture monthly rent, move date, city, and urgency before follow-up."],
        ["Property context", "Listing and search URLs can stay connected to the inquiry."],
        ["Agent connection", "Requests can connect with a Nex professional for the right market."],
        ["Next step", "The assigned agent can help with availability, showing, application, and follow-up."]
      ],
      workflow: [
        ["Search rentals", "Consumer searches by area and budget."],
        ["Share needs", "Form captures move date, city, price range, and notes."],
        ["Connect", "A Nex professional can respond with the right context."],
        ["Follow up", "Agent handles availability, showing, and application questions."]
      ]
    },
    finance: {
      eyebrow: "Finance",
      title: "Get pre-approved before you tour.",
      body: "Connect with Matthew Wolk at Wolk Mortgage, understand your estimated payment, and start shopping with a stronger plan.",
      type: "buyer",
      action: "Start pre-approval",
      proof: ["Pre-approval link", "Buyer readiness", "Payment planning", "Search confidence"],
      metrics: [["Partner", "Matt Wolk"], ["Buyer", "Prepared"], ["Search", "Stronger"]],
      systemTitle: "Financing readiness makes the search cleaner.",
      systemBody: "A stronger buyer profile helps the agent and lender align early so showings, offers, and timelines are less reactive.",
      systemCards: [
        ["Pre-approval first", "Buyers can prepare before touring seriously."],
        ["Payment clarity", "Set expectations around price range, payment, and comfort level."],
        ["Offer readiness", "Agents can write stronger offers when financing is already moving."],
        ["Search handoff", "Nex can connect search help after financing context is started."]
      ],
      workflow: defaultWorkflow
    },
    resources: {
      eyebrow: "Resources",
      title: "Florida real estate resources for buyers, sellers, and homeowners.",
      body: "Explore buyer guides, seller strategy, market updates, financing tools, home valuation content, and local Florida real estate resources.",
      type: "general",
      action: "Ask Nex a question",
      proof: ["Market guides", "Buyer resources", "Seller resources", "Florida relocation"],
      metrics: [["Guides", "Helpful"], ["Markets", "Florida"], ["Next step", "Simple"]],
      systemTitle: "Useful resources should make the next step easier.",
      systemBody: "Read, compare options, and reach out when you want local guidance from Nex Realty.",
      systemCards: [
        ["Buyer education", "Search, showings, buyer agreements, financing, and offer preparation."],
        ["Seller strategy", "Pricing, preparation, marketing, reporting, offers, and closing timelines."],
        ["Market pages", "Local search content can help buyers and sellers understand their area."],
        ["Agent content", "Agent-focused resources can help real estate professionals learn about Nex."]
      ],
      workflow: defaultWorkflow
    },
    about: {
      eyebrow: "About Nex Realty",
      title: "A tech-forward Florida brokerage built around support, systems, and clearer real estate moves.",
      body: "Nex Realty combines consumer search, IDX-enabled agent websites, NIA guidance, Nex Central, Marketing Studio, LaunchPad training, and practical Florida brokerage support so agents and customers are not left guessing.",
      type: "general",
      action: "Talk to Nex",
      proof: ["Nex Central", "IDX search", "NIA concierge", "Agent training"],
      metrics: [["Platform", "Nex Central"], ["Search", "IDX"], ["Support", "Built in"]],
      systemTitle: "Nex is building the operating layer agents and customers need.",
      systemBody: "The public website, agent support, marketing, training, consumer lead flow, and real estate tools are designed to work together instead of living in disconnected places.",
      systemCards: [
        ["Consumer search", "A cleaner public experience for buying, selling, renting, and contacting Nex."],
        ["Agent technology", "Nex Central gives agents a practical daily system for leads, CRM, training, marketing, and support."],
        ["Florida growth", "A cloud-forward brokerage model built around Florida markets, service areas, and real support."],
        ["Operational clarity", "Cleaner follow-up, training, marketing, communication, and transaction visibility."]
      ],
      workflow: defaultWorkflow
    },
    contact: {
      eyebrow: "Contact Nex Realty",
      title: "Tell us what you need and we will connect you with the right Nex resource.",
      body: "Choose the reason you are reaching out, share the basics, and a Nex Realty professional can help with the right next step.",
      type: "general",
      action: "Send message",
      proof: ["Buyer help", "Seller help", "Rental help", "Recruiting and support"],
      metrics: [["Inquiry", "Clear"], ["Market", "Shared"], ["Follow-up", "Helpful"]],
      systemTitle: "The right question should reach the right person.",
      systemBody: "Buying, selling, renting, agent recruiting, partnerships, support, and general questions deserve clear next steps.",
      systemCards: [
        ["Inquiry type", "The form captures why someone is reaching out before follow-up."],
        ["Market context", "City and county fields help connect local consumer inquiries."],
        ["Recruiting path", "Agent or brokerage questions go to the right Nex team."],
        ["Clear follow-up", "Your message includes the details needed for a helpful response."]
      ],
      workflow: [
        ["Choose path", "Visitor selects buying, selling, renting, recruiting, support, or general."],
        ["Share details", "Form captures contact, market, timeline, and message."],
        ["Connect", "Your request reaches the right Nex resource."],
        ["Follow up", "The right Nex team or agent responds with context."]
      ]
    }
  };
  const config = pageMap[page] || pageMap.contact;
  const contactRoutes = [
    ["Buying", "Search homes, showings, saved searches, buyer questions.", "Home"],
    ["Selling", "Home value, pricing, marketing, listing strategy.", "BadgeDollarSign"],
    ["Renting", "Rental search, availability, move date, application questions.", "KeyRound"],
    ["Join Nex", "Brokerage model, commission plans, training, and support.", "Rocket"],
    ["Agent support", "Existing agent support or platform questions.", "Headphones"],
    ["Partnerships", "Vendor, lender, event, or community partnerships.", "Handshake"]
  ];
  function scrollToPrimaryAction() {
    const selector = page === "sell" ? ".public-info-sell .public-cma-card" : ".public-info-page .public-lead-form";
    document.querySelector(selector)?.scrollIntoView({ behavior: "smooth", block: "center" });
  }
  return (
    <section className={classNames("public-page", "public-info-page", `public-info-${page}`)}>
      <div className="public-inner-tech-hero">
        <div className="public-inner-hero-copy">
          <p className="eyebrow">{config.eyebrow}</p>
          <h1>{config.title}</h1>
          <p>{config.body}</p>
          <div className="public-brokerage-hero-actions">
            <button className="btn primary" type="button" onClick={scrollToPrimaryAction}>
              <Icon name="ArrowRight" />
              <span>{config.action}</span>
            </button>
            {page !== "sell" && <button className="btn secondary" type="button" onClick={() => navigate("/site/search")}>Search Homes</button>}
            {page === "sell" && <button className="btn secondary" type="button" onClick={() => navigate("/site/agents")}>Find a Listing Agent</button>}
          </div>
          <div className="public-seo-intent-row">
            {(config.proof || []).map((item) => <span key={item}><Icon name="CheckCircle2" /> {item}</span>)}
          </div>
        </div>
        <div className="public-inner-command-panel">
          <div className="public-inner-command-top">
            <span><i /> Nex Realty guidance</span>
            <small>{config.eyebrow}</small>
          </div>
          <div className="public-inner-command-metrics">
            {(config.metrics || []).map(([label, value]) => (
              <article key={label}>
                <strong>{value}</strong>
                <span>{label}</span>
              </article>
            ))}
          </div>
          <div className="public-inner-command-list">
            {(config.proof || []).slice(0, 4).map((item) => <span key={item}><Icon name="CheckCircle2" /> {item}</span>)}
          </div>
        </div>
      </div>

      {page === "contact" && (
        <>
          <PublicReturningConsumerPanel navigate={navigate} onTalkAgent={onTalkAgent} />
          <section className="public-contact-route-grid">
            {contactRoutes.map(([title, body, icon]) => (
              <button
                key={title}
                type="button"
                onClick={() => {
                  if (title === "Join Nex") navigate("/site/join");
                  else document.querySelector(".public-info-page .public-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" });
                }}
              >
                <Icon name={icon} />
                <strong>{title}</strong>
                <span>{body}</span>
              </button>
            ))}
          </section>
        </>
      )}

      {["buy", "rent"].includes(page) && (
        <PublicInlineSearchBand page={page} navigate={navigate} />
      )}

      {page === "sell" && (
        <section className="public-seller-value-panel">
          <div>
            <p className="eyebrow">Quick Home Value</p>
            <h2>Get a practical value range from nearby comparable data.</h2>
            <p>Enter the address, city, size, and your contact info. Nex will generate a planning range from available market data, save the request, and keep the next step attached to your seller profile.</p>
            <div className="public-seo-intent-row">
              {["Comparable listings", "Price per sqft review", "Seller follow-up", "No appraisal claim"].map((item) => <span key={item}><Icon name="CheckCircle2" /> {item}</span>)}
            </div>
          </div>
          <PublicCmaCard
            setToast={setToast}
            sourceAgentSlug={sourceAgentSlug}
            requireContact
            headline="Get my quick value range."
            sourcePage="Public sell page quick value"
          />
        </section>
      )}

      {page === "about" && (
        <PublicAboutTechGrid />
      )}

      <section className="public-split-section public-info-system-band">
        <div>
          <p className="eyebrow">How Nex Helps</p>
          <h2>{config.systemTitle}</h2>
          <p>{config.systemBody}</p>
        </div>
        <div className="public-benefit-grid">
          {(config.systemCards || []).map(([title, body]) => (
            <article key={title}>
              <Icon name="CircleCheck" />
              <strong>{title}</strong>
              <span>{body}</span>
            </article>
          ))}
        </div>
      </section>

      <section className="public-workflow-band">
        <div>
          <p className="eyebrow">Clear Next Steps</p>
          <h2>From first click to helpful follow-up.</h2>
        </div>
        <div className="public-workflow-timeline">
          {(config.workflow || defaultWorkflow).map(([title, body], index) => (
            <article key={title}>
              <em>{String(index + 1).padStart(2, "0")}</em>
              <strong>{title}</strong>
              <span>{body}</span>
            </article>
          ))}
        </div>
      </section>

      <div className="public-split-section public-info-form-band">
        <div className="public-info-form-copy">
          <p className="eyebrow">Helpful Follow-Up</p>
          <h2>Send the request once. Keep the context attached.</h2>
          <p>
            Public forms capture your inquiry type, market, message, and contact preference so Nex can respond with
            less guesswork.
          </p>
          {page === "finance" && (
            <a className="public-preapproval-link" href={WOLK_MORTGAGE_PARTNER.preapprovalUrl} target="_blank" rel="noreferrer">
              <Icon name="ExternalLink" />
              <span>Start with Matthew Wolk</span>
            </a>
          )}
        </div>
        <PublicLeadForm
          title={config.eyebrow}
          leadType={config.type}
          sourcePage={`Public ${page}`}
          sourceAgentSlug={sourceAgentSlug}
          setToast={setToast}
          inquiryPurpose={config.eyebrow}
          compact={page === "sell"}
          ctaLabel={page === "sell" ? "Ask About Selling" : "Submit"}
        />
      </div>
    </section>
  );
}

function PublicSmsConsentPage({ navigate, setToast }) {
  const config = publicLegalPages["sms-consent"];
  return (
    <section className="public-page public-sms-consent-page">
      <div className="public-page-head">
        <p className="eyebrow">{config.eyebrow}</p>
        <h1>{config.title}</h1>
        <p>{config.intro}</p>
        <span className="public-legal-updated">{config.updated}</span>
      </div>

      <div className="public-legal-grid">
        <article className="public-legal-summary">
          <Icon name="MousePointerClick" />
          <strong>Active opt-in</strong>
          <span>The SMS checkbox starts unchecked and must be selected before the form can be submitted.</span>
        </article>
        <article className="public-legal-summary">
          <Icon name="ShieldCheck" />
          <strong>Required disclosures</strong>
          <span>Consent-not-required, message/data rates, STOP/HELP, terms, privacy, and frequency language are visible.</span>
        </article>
        <article className="public-legal-summary">
          <Icon name="ExternalLink" />
          <strong>Public review URL</strong>
          <span>This page is publicly available at /sms-consent and /site/sms-consent without login.</span>
        </article>
      </div>

      <div className="public-sms-proof-band">
        <div className="public-sms-proof-copy">
          <p className="eyebrow">What reviewers can verify</p>
          <h2>Website opt-in path</h2>
          <ol>
            <li>Visitor opens a public Nex Realty page.</li>
            <li>Visitor enters name, email, and mobile phone number.</li>
            <li>Visitor selects or describes their real estate inquiry.</li>
            <li>Visitor checks the required consent box shown beside the full SMS disclosure.</li>
            <li>Nex Realty stores the inquiry and may follow up by phone, text, or email.</li>
          </ol>
          <div className="public-sms-consent-copy">
            <strong>Consent language shown on the form</strong>
            <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
          </div>
          <div className="public-legal-actions">
            <button className="btn secondary" onClick={() => navigate("/site/privacy-policy")} type="button">Privacy Policy</button>
            <button className="btn secondary" onClick={() => navigate("/site/terms-and-conditions")} type="button">Terms & Conditions</button>
          </div>
        </div>
        <PublicLeadForm
          title="Text me about my Nex Realty inquiry"
          leadType="general"
          sourcePage="SMS consent opt-in page"
          leadSource="Nex SMS consent page"
          inquiryPurpose="Ask a question"
          ctaLabel="Submit request"
          setToast={setToast}
        />
      </div>

      <div className="public-legal-content">
        {config.sections.map((section) => (
          <article key={section.title}>
            <h2>{section.title}</h2>
            <p>{section.body}</p>
          </article>
        ))}
      </div>
    </section>
  );
}

function PublicLegalPage({ pageId, navigate }) {
  const config = publicLegalPages[pageId] || publicLegalPages["privacy-policy"];
  const relatedPath = pageId === "privacy-policy" ? "/site/terms-and-conditions" : "/site/privacy-policy";
  const relatedLabel = pageId === "privacy-policy" ? "Terms & Conditions" : "Privacy Policy";
  const internalSmsNotice = ["sms-notice", "nex-central-sms-consent"].includes(pageId);
  return (
    <section className="public-page public-legal-page">
      <div className="public-page-head">
        <p className="eyebrow">{config.eyebrow}</p>
        <h1>{config.title}</h1>
        <p>{config.intro}</p>
        <span className="public-legal-updated">{config.updated}</span>
      </div>
      <div className="public-legal-grid">
        <article className="public-legal-summary">
          <Icon name="ShieldCheck" />
          <strong>SMS compliance ready</strong>
          <span>Includes opt-in, STOP/HELP, message/data rates, consent-not-required, and mobile data sharing language for Twilio/A2P review.</span>
        </article>
        <article className="public-legal-summary">
          <Icon name="Home" />
          <strong>Real estate specific</strong>
          <span>Addresses IDX/MLS data, lead routing, property estimates, agent pages, and verification of listing information.</span>
        </article>
        <article className="public-legal-summary">
          <Icon name="Phone" />
          <strong>Contact included</strong>
          <span>Nex Realty contact details are included for privacy, terms, opt-out, and support requests.</span>
        </article>
      </div>
      {internalSmsNotice && (
        <div className="public-sms-proof-band">
          <div className="public-sms-proof-copy">
            <p className="eyebrow">Internal SMS CTA</p>
            <h2>What agents and staff see inside Nex Central</h2>
            <ol>
              <li>User signs in to their private Nex Central account.</li>
              <li>User opens Communication Center or profile notification preferences.</li>
              <li>User confirms their mobile phone number.</li>
              <li>User chooses operational SMS categories such as lead alerts, task reminders, transaction reminders, admin announcements, and account/security alerts.</li>
              <li>User checks the required SMS consent box before SMS preferences are enabled.</li>
            </ol>
            <div className="public-sms-consent-copy">
              <strong>Consent language shown beside the checkbox</strong>
              <span>I agree to receive SMS/text notifications from Nex Realty and Nex Central at the mobile number provided. Messages may include lead alerts, task reminders, transaction reminders, admin/account notifications, and security-related account alerts. Message frequency varies. Message and data rates may apply. Reply STOP to opt out or HELP for help.</span>
            </div>
          </div>
          <div className="public-lead-form public-sms-preference-preview" aria-label="Example Nex Central SMS preference screen">
            <h3>Nex Central SMS Preferences</h3>
            <Field label="Mobile phone" value="772-403-1259" onChange={() => {}} type="tel" />
            <label className="toggle-row"><input type="checkbox" checked readOnly /> SMS lead alerts</label>
            <label className="toggle-row"><input type="checkbox" checked readOnly /> SMS task reminders</label>
            <label className="toggle-row"><input type="checkbox" checked readOnly /> SMS deadline reminders</label>
            <label className="toggle-row"><input type="checkbox" checked readOnly /> SMS admin/account alerts</label>
            <label className="consent-line"><input type="checkbox" readOnly /> <span>Consent checkbox starts unchecked and must be selected before SMS preferences are saved.</span></label>
            <div className="public-legal-actions">
              <button className="btn secondary" onClick={() => navigate("/site/privacy-policy")} type="button">Privacy Policy</button>
              <button className="btn secondary" onClick={() => navigate("/site/terms-and-conditions")} type="button">Terms & Conditions</button>
            </div>
          </div>
        </div>
      )}
      <div className="public-legal-content">
        {config.sections.map((section) => (
          <article key={section.title}>
            <h2>{section.title}</h2>
            <p>{section.body}</p>
          </article>
        ))}
      </div>
      <div className="public-legal-actions">
        <button className="btn primary" onClick={() => navigate("/site/contact")} type="button">Contact Nex Realty</button>
        <button className="btn secondary" onClick={() => navigate(relatedPath)} type="button">View {relatedLabel}</button>
      </div>
    </section>
  );
}

function PublicSearchSeoPage({ pageId, data, navigate, setToast, sourceAgentSlug = "", onViewListing }) {
  const config = publicConsumerSearchSeoPageMap[pageId] || publicConsumerSearchSeoPageMap["florida-homes-for-sale"];
  const [filters, setFilters] = useState(() => ({
    search: config.filters?.search || "",
    city: config.filters?.city || "",
    county: config.filters?.county || "",
    zip: config.filters?.zip || "",
    status: config.filters?.status || "",
    minPrice: config.filters?.minPrice || "",
    maxPrice: config.filters?.maxPrice || "",
    beds: config.filters?.beds || "",
    baths: config.filters?.baths || "",
    propertyType: config.filters?.propertyType || "",
    lifestyle: config.lifestyle || ""
  }));
  const [listings, setListings] = useState([]);
  const [loading, setLoading] = useState(true);

  function listingQuery(nextFilters = filters) {
    const query = { ...nextFilters };
    if (query.lifestyle) {
      query.search = [query.search, query.lifestyle].filter(Boolean).join(" ");
      delete query.lifestyle;
    }
    return query;
  }

  async function loadListings(nextFilters = filters) {
    setLoading(true);
    const params = new URLSearchParams(Object.entries(listingQuery(nextFilters)).filter(([, value]) => String(value || "").trim()));
    try {
      const payload = await API.request(`/api/public/listings?${params.toString()}`);
      setListings(publicListingsFromPayload(payload));
    } catch (error) {
      setToast("Listings could not load for this search.");
      setListings([]);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadListings();
  }, [pageId]);

  function update(field, value) {
    setFilters((current) => field === "search"
      ? { ...current, search: value, city: "", county: "", zip: "" }
      : { ...current, [field]: value });
  }

  function submit(event) {
    event.preventDefault();
    loadListings();
  }

  function chooseSearchSuggestion(suggestion) {
    const nextFilters = filtersFromPublicSearchSuggestion(filters, suggestion);
    setFilters(nextFilters);
    loadListings(nextFilters);
  }

  const relatedPages = (config.related || [])
    .map((slug) => publicConsumerSearchSeoPageMap[slug])
    .filter(Boolean);
  const searchCriteria = Object.entries(listingQuery(filters))
    .filter(([, value]) => String(value || "").trim())
    .map(([key, value]) => `${key}: ${value}`)
    .join(", ");
  const preferredArea = [filters.search, filters.city, filters.county].filter(Boolean).join(", ") || config.h1;
  const fallbackListings = listings.length ? listings : (data.featuredListings || []).slice(0, 6);

  return (
    <section className="public-page public-search-seo-page">
      <div className="public-page-head public-seo-search-hero">
        <div>
          <p className="eyebrow">Nex Realty home search</p>
          <h1>{config.h1}</h1>
          <p>{config.intro}</p>
          <div className="public-seo-intent-row">
            {["Save your favorite homes", "Get new listing alerts", "Request a showing", "Ask a local Nex agent"].map((item) => (
              <span key={item}><Icon name="CheckCircle2" /> {item}</span>
            ))}
          </div>
        </div>
        <PublicLeadForm
          title={config.leadTitle}
          leadType={config.leadType}
          sourcePage={config.title}
          sourceAgentSlug={sourceAgentSlug}
          leadSource="Consumer Search SEO Page"
          idxProvider={data.idx?.provider || "Stellar MLS"}
          idxIntent={config.leadIntent}
          searchCriteria={searchCriteria || config.h1}
          defaultPreferredArea={preferredArea}
          inquiryPurpose={config.leadIntent}
          compact
          ctaLabel={config.cta}
          setToast={setToast}
        />
      </div>

      <form className="public-seo-filter-bar" onSubmit={submit}>
        <PublicListingSearchAutocomplete
          value={filters.search}
          onChange={(value) => update("search", value)}
          onSelect={chooseSearchSuggestion}
          placeholder="City, ZIP, neighborhood, address, or MLS number"
          seedListings={listings.length ? listings : data.featuredListings || []}
        />
        <input type="number" min="0" value={filters.maxPrice} onChange={(event) => update("maxPrice", event.target.value)} placeholder="Max price" />
        <input type="number" min="0" value={filters.beds} onChange={(event) => update("beds", event.target.value)} placeholder="Beds" />
        <input type="number" min="0" value={filters.baths} onChange={(event) => update("baths", event.target.value)} placeholder="Baths" />
        <select value={filters.propertyType} onChange={(event) => update("propertyType", event.target.value)}>
          <option value="">Property type</option>
          <option>Single Family Residence</option>
          <option>Condominium</option>
          <option>Townhouse</option>
          <option>Villa</option>
          <option>Multi-Family</option>
        </select>
        <select value={filters.lifestyle} onChange={(event) => update("lifestyle", event.target.value)}>
          <option value="">Lifestyle</option>
          <option>Waterfront</option>
          <option>Pool</option>
          <option>Open House</option>
          <option>Price Reduced</option>
          <option>Luxury</option>
          <option>New Listing</option>
        </select>
        <button className="btn primary" type="submit">Update Search</button>
      </form>

      <div className="public-results-head">
        <div>
          <p className="eyebrow">{loading ? "Loading listings" : listings.length ? "Matching listings" : "Search help available"}</p>
          <h2>{loading ? "Finding homes..." : listings.length ? `${listings.length} homes found` : "Listings are loading for this search"}</h2>
          <small>
            {listings.length
              ? "Save a search, ask about a property, or request a showing from the listing cards below."
              : "If live matches are limited, send us your criteria and a Nex agent can help you find similar homes."}
          </small>
        </div>
        <div className="public-results-actions">
          <button className="btn secondary" type="button" onClick={() => document.querySelector(".public-search-seo-page .public-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" })}>
            <Icon name="Bell" />
            <span>Save Search</span>
          </button>
          <button className="btn secondary" type="button" onClick={() => navigate("/site/contact")}>
            <Icon name="MessageSquare" />
            <span>Ask Nex</span>
          </button>
          <button className="btn primary" type="button" onClick={() => navigate("/site/search")}>
            <Icon name="Search" />
            <span>Open Full Search</span>
          </button>
        </div>
      </div>

      {loading ? (
        <PublicSkeleton />
      ) : (
        <>
          <div className="public-listing-grid">
            {fallbackListings.map((listing) => (
              <PublicListingCard key={listing.id} listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />
            ))}
          </div>
          {!listings.length && (
            <div className="public-seo-fallback-panel">
              <Icon name="Bell" />
              <div>
                <strong>Want alerts for {config.h1.toLowerCase()}?</strong>
                <span>Tell us your desired area, timing, and must-haves. A local Nex agent can help you track the right homes as new options hit the market.</span>
              </div>
              <button className="btn primary" type="button" onClick={() => document.querySelector(".public-search-seo-page .public-lead-form")?.scrollIntoView({ behavior: "smooth", block: "center" })}>
                {config.cta}
              </button>
            </div>
          )}
        </>
      )}

      {!!relatedPages.length && (
        <section className="public-related-searches">
          <div>
            <p className="eyebrow">Related searches</p>
            <h2>Explore nearby and similar Florida searches</h2>
          </div>
          <div>
            {relatedPages.map((page) => (
              <button key={page.slug} type="button" onClick={() => navigate(`/site/homes/${page.slug}`)}>{page.title}</button>
            ))}
          </div>
        </section>
      )}

      <PublicIdxComplianceNotice idx={data.idx} compact />
    </section>
  );
}

function PublicMarketPage({ marketId, data, navigate, setToast, sourceAgentSlug = "", onViewListing }) {
  const marketName = decodeURIComponent(marketId).replace(/-/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
  const listings = (data.featuredListings || []).filter((listing) =>
    [listing.city, listing.county].join(" ").toLowerCase().includes(marketName.toLowerCase())
  );
  return (
    <section className="public-page">
      <div className="public-page-head">
        <p className="eyebrow">Florida market search</p>
        <h1>{marketName} real estate with Nex Realty</h1>
        <p>Search homes, ask questions, request showings, and connect with a local Nex Realty agent who understands this area.</p>
      </div>
      <div className="public-listing-grid">
        {(listings.length ? listings : data.featuredListings || []).slice(0, 3).map((listing) => (
          <PublicListingCard key={listing.id} listing={listing} navigate={navigate} onViewListing={onViewListing} sourceAgentSlug={sourceAgentSlug} />
        ))}
      </div>
      <PublicLeadForm title={`Ask about ${marketName}`} leadType="buyer" sourcePage={`Market ${marketName}`} setToast={setToast} />
    </section>
  );
}

function PublicLegalInlineLinks() {
  return (
    <small className="public-form-legal-links">
      By submitting, you agree to the <a href="/terms-and-conditions">Terms & Conditions</a> and acknowledge the <a href="/privacy-policy">Privacy Policy</a>.
    </small>
  );
}

function PublicLeadForm({
  title,
  leadType = "general",
  sourcePage,
  listingId = "",
  mlsNumber = "",
  propertyAddress = "",
  sourceAgentSlug = "",
  defaultCity = "",
  defaultCounty = "",
  defaultPreferredArea = "",
  defaultPriceRange = "",
  leadSource = "",
  idxProvider = "",
  idxIntent = "",
  idxSearchUrl = "",
  searchCriteria = "",
  setToast,
  compact = false,
  recruiting = false,
  inquiryPurpose = "",
  ctaLabel = "Submit"
}) {
  const [form, setForm] = useState({
    name: "",
    email: "",
    phone: "",
    inquiryPurpose: inquiryPurpose || (recruiting ? "Join Nex" : leadType === "seller" ? "Selling" : leadType === "renter" ? "Renting" : leadType === "buyer" ? "Buying" : "General question"),
    city: defaultCity,
    county: defaultCounty,
    preferredArea: defaultPreferredArea || [defaultCity, defaultCounty].filter(Boolean).join(", "),
    zip: "",
    priceRange: defaultPriceRange,
    timeline: "",
    notes: "",
    currentBrokerage: "",
    licenseStatus: "",
    productionLevel: "",
    interestedPlan: "",
    preferredContactTime: "",
    consent: false
  });
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState("");

  function update(field, value) {
    setForm((current) => ({ ...current, [field]: value }));
    if (error) setError("");
  }

  async function submit(event) {
    event.preventDefault();
    setError("");
    if (!form.consent) {
      setError("Please agree to be contacted so Nex Realty can respond to your request.");
      return;
    }
    const validation = validatePublicLeadCapture({ name: form.name, email: form.email, phone: form.phone, intent: form.inquiryPurpose || leadType, consent: form.consent });
    if (!validation.ok) {
      setError(validation.message);
      return;
    }
    setSubmitting(true);
    try {
      const endpoint = recruiting || leadType === "recruiting" ? "/api/public/recruiting-inquiries" : "/api/public/leads";
      const payload = await API.request(endpoint, {
        method: "POST",
        body: JSON.stringify({
          ...publicConsumerSessionPayload(),
          ...form,
          type: leadType,
          sourcePage,
          listingId,
          mlsNumber,
          propertyAddress,
          city: form.city || form.preferredArea,
          sourceAgentSlug,
          leadSource: leadSource || (recruiting ? "Nex recruiting website" : "Nex Website"),
          leadIntent: form.inquiryPurpose || idxIntent || leadType,
          idxProvider,
          idxIntent,
          idxSearchUrl,
          buyerSearchCriteria: searchCriteria || form.preferredArea,
          preferredArea: form.preferredArea,
          message: form.notes,
          submittedAt: new Date().toISOString(),
          sourceSystem: idxProvider ? "Nex Website IDX Capture" : "Nex Website",
          inquiryType: form.inquiryPurpose,
          formName: title
        })
      });
      if (payload.consumerSession) rememberPublicConsumerSession(payload.consumerSession);
      setToast(payload.message || "Lead submitted.");
      setForm((current) => ({ ...current, name: "", email: "", phone: "", notes: "", consent: false }));
    } catch (error) {
      setToast(error.message || "Could not submit this form.");
      setError(error.message || "Could not submit this form.");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <form className={classNames("public-lead-form", compact && "compact")} onSubmit={submit}>
      <h3>{title}</h3>
      <input required value={form.name} onChange={(event) => update("name", event.target.value)} placeholder="Full name" />
      <input required type="email" value={form.email} onChange={(event) => update("email", event.target.value)} placeholder="Email" />
      <input required value={form.phone} onChange={(event) => update("phone", event.target.value)} placeholder="Phone" />
      <select value={form.inquiryPurpose} onChange={(event) => update("inquiryPurpose", event.target.value)}>
        <option>Buying</option>
        <option>Selling</option>
        <option>Renting</option>
        <option>Tour this home</option>
        <option>Save property</option>
        <option>Ask a question</option>
        <option>Send me homes like this</option>
        <option>Get property updates</option>
        <option>Get new listing alerts</option>
        <option>Schedule buyer consultation</option>
        <option>Request home value estimate</option>
        <option>Talk to listing agent</option>
        <option>Get seller net sheet</option>
        <option>Ask about selling timeline</option>
        <option>Get local market report</option>
        <option>Contact agent</option>
        <option>Join Nex</option>
        <option>Talk to broker</option>
        <option>See Nex technology</option>
        <option>See training and LaunchPad</option>
        <option>See lead and support systems</option>
        <option>Agent support</option>
        <option>Partnerships</option>
        <option>General question</option>
      </select>
      <input value={form.preferredArea} onChange={(event) => update("preferredArea", event.target.value)} placeholder="Preferred area" />
      <input value={form.timeline} onChange={(event) => update("timeline", event.target.value)} placeholder="Timeline" />
      {!compact && (
        <>
          <div className="public-form-row">
            <input value={form.city} onChange={(event) => update("city", event.target.value)} placeholder="City" />
            <input value={form.county} onChange={(event) => update("county", event.target.value)} placeholder="County" />
          </div>
          <input value={form.priceRange} onChange={(event) => update("priceRange", event.target.value)} placeholder="Price range / budget" />
          {recruiting && (
            <>
              <input value={form.currentBrokerage} onChange={(event) => update("currentBrokerage", event.target.value)} placeholder="Current brokerage" />
              <input value={form.licenseStatus} onChange={(event) => update("licenseStatus", event.target.value)} placeholder="License status" />
              <input value={form.productionLevel} onChange={(event) => update("productionLevel", event.target.value)} placeholder="Production level" />
              <input value={form.interestedPlan} onChange={(event) => update("interestedPlan", event.target.value)} placeholder="Interested plan" />
              <input value={form.preferredContactTime} onChange={(event) => update("preferredContactTime", event.target.value)} placeholder="Preferred contact time" />
            </>
          )}
        </>
      )}
      <textarea value={form.notes} onChange={(event) => update("notes", event.target.value)} placeholder="Message" rows={compact ? 3 : 4} />
      {listingId && <small className="public-form-context">Listing ID: {mlsNumber || listingId}</small>}
      <label className="public-consent">
        <input required type="checkbox" checked={form.consent} onChange={(event) => update("consent", event.target.checked)} />
        <span>{PUBLIC_LEAD_CONSENT_TEXT}</span>
      </label>
      <PublicLegalInlineLinks />
      {error && <div className="login-error public-form-error">{error}</div>}
      <button className="btn primary" disabled={submitting} type="submit">
        <Icon name={submitting ? "LoaderCircle" : "Send"} className={submitting ? "spin" : ""} />
        <span>{submitting ? "Sending" : ctaLabel}</span>
      </button>
    </form>
  );
}

function PublicFooter({ brand, navigate, idx }) {
  const compliance = idxComplianceFrom(idx);
  const contactLine = [compliance.brokeragePhone, compliance.brokerageEmail].filter(Boolean).join(" | ");
  return (
    <footer className="public-footer">
      <div>
        <Wordmark brand={brand} variant="light" className="public-footer-logo" />
        <p>Nex Realty | Florida home search, local real estate guidance, seller support, and agent connection.</p>
        <small>{compliance.brokerageStatement} {contactLine}</small>
      </div>
      <div className="public-footer-links">
        {publicSiteNav.slice(0, 6).map(([label, path]) => (
          <button key={path} onClick={() => navigate(path)} type="button">{label}</button>
        ))}
        <button onClick={() => navigate("/site/privacy-policy")} type="button">Privacy Policy</button>
        <button onClick={() => navigate("/site/terms-and-conditions")} type="button">Terms & Conditions</button>
        <button onClick={() => navigate("/site/sms-consent")} type="button">SMS Consent</button>
        <button onClick={() => navigate("/site/sms-notice")} type="button">SMS Notice</button>
      </div>
      <PublicComplianceLogos compliance={compliance} />
      <small>
        {compliance.disclaimerText} {compliance.dataUpdateText} {compliance.excludedListingsText} {compliance.fairHousingText}
      </small>
    </footer>
  );
}

function PublicSkeleton() {
  return (
    <section className="public-skeleton">
      <div />
      <div />
      <div />
    </section>
  );
}

function LoginScreen({ onLogin, onVerifyTwoFactor, onForgotPassword, onResetPassword, brand, resetToken = "" }) {
  const [mode, setMode] = useState(resetToken ? "reset" : "login");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [twoFactorChallenge, setTwoFactorChallenge] = useState(null);
  const [twoFactorCode, setTwoFactorCode] = useState("");
  const [error, setError] = useState("");
  const [message, setMessage] = useState(resetToken ? "Enter a new password for your Nex Central account." : "");
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    if (resetToken) {
      setMode("reset");
      setMessage("Enter a new password for your Nex Central account.");
    }
  }, [resetToken]);

  async function submit(event) {
    event.preventDefault();
    setError("");
    setMessage("");
    setIsSubmitting(true);
    try {
      if (twoFactorChallenge) {
        await onVerifyTwoFactor({ email: twoFactorChallenge.email || email, challengeId: twoFactorChallenge.challengeId, code: twoFactorCode });
        setTwoFactorChallenge(null);
        setTwoFactorCode("");
      } else if (mode === "forgot") {
        const response = await onForgotPassword(email);
        setMessage(response?.message || "If that email is registered, a reset link has been sent.");
      } else if (mode === "reset") {
        const response = await onResetPassword({ token: resetToken, password, confirmPassword });
        setMessage(response?.message || "Password updated. You can sign in now.");
        setPassword("");
        setConfirmPassword("");
        window.history.replaceState({}, document.title, window.location.pathname);
        setMode("login");
      } else {
        const response = await onLogin({ email, password });
        if (response?.requiresTwoFactor) {
          setTwoFactorChallenge(response);
          setPassword("");
          setMessage(response.message || "Enter the verification code sent to your phone.");
          if (response.debugCode) setMessage(`${response.message || "Enter the verification code sent to your phone."} Dev code: ${response.debugCode}`);
        }
      }
    } catch (loginError) {
      setError(friendlyNetworkError(loginError, "Could not sign in."));
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <main className="login-screen">
      <section className="login-panel">
        <div className="login-brand">
          <Wordmark brand={brand} variant="light" className="login-logo" />
          <div>
            <p className="eyebrow">Secure agent access</p>
            <h1>{APP_NAME}</h1>
          </div>
        </div>
        <p>
          Sign in with your Nex Central email and password. Admins can create accounts, reset passwords, and manage user
          access.
        </p>
        <form onSubmit={submit} className="login-form">
          {mode !== "reset" && <Field label="Email" value={email} onChange={setEmail} type="email" placeholder="agent@nexrealty.com" disabled={Boolean(twoFactorChallenge)} />}
          {mode === "login" && !twoFactorChallenge && <Field label="Password" value={password} onChange={setPassword} type="password" placeholder="Enter your password" />}
          {twoFactorChallenge && <Field label="Verification code" value={twoFactorCode} onChange={setTwoFactorCode} placeholder="6-digit code" />}
          {mode === "reset" && (
            <>
              <Field label="New password" value={password} onChange={setPassword} type="password" placeholder="At least 8 characters" />
              <Field label="Confirm new password" value={confirmPassword} onChange={setConfirmPassword} type="password" placeholder="Re-enter password" />
            </>
          )}
          {message && <div className="login-message">{message}</div>}
          {error && (
            <div className="login-error">
              {error}
              <small>If it still fails, contact Nex admin for access help.</small>
            </div>
          )}
          <button className="btn primary" type="submit" disabled={isSubmitting}>
            <Icon name={isSubmitting ? "LoaderCircle" : "LockKeyhole"} className={isSubmitting ? "spin" : ""} />
            <span>
              {isSubmitting
                ? "Working"
                : mode === "forgot"
                  ? "Send Reset Link"
                  : mode === "reset"
                    ? "Reset Password"
                    : twoFactorChallenge
                      ? "Verify Code"
                      : "Sign In"}
            </span>
          </button>
          <div className="auth-links">
            {twoFactorChallenge ? (
              <button type="button" onClick={() => { setTwoFactorChallenge(null); setTwoFactorCode(""); setError(""); setMessage(""); }}>
                Back to sign in
              </button>
            ) : mode === "login" ? (
              <button type="button" onClick={() => { setMode("forgot"); setError(""); setMessage(""); }}>
                Forgot password?
              </button>
            ) : (
              <button type="button" onClick={() => { setMode("login"); setError(""); setMessage(""); }}>
                Back to sign in
              </button>
            )}
          </div>
        </form>
      </section>
    </main>
  );
}

function ForcePasswordChangeScreen({ user, brand, onChangePassword, onLogout }) {
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [error, setError] = useState("");
  const [message, setMessage] = useState("");
  const [isSubmitting, setIsSubmitting] = useState(false);

  async function submit(event) {
    event.preventDefault();
    setError("");
    setMessage("");
    setIsSubmitting(true);
    try {
      await onChangePassword({ password, confirmPassword });
      setMessage("Password updated. Welcome to Nex Central.");
    } catch (changeError) {
      setError(friendlyNetworkError(changeError, "Could not update password."));
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <main className="login-screen">
      <section className="login-panel">
        <div className="login-brand">
          <Wordmark brand={brand} variant="light" className="login-logo" />
          <div>
            <p className="eyebrow">Account setup</p>
            <h1>Set your password</h1>
          </div>
        </div>
        <p>Hi {user?.name || user?.email}. Create a private password before entering Nex Central.</p>
        <form onSubmit={submit} className="login-form">
          <Field label="New password" value={password} onChange={setPassword} type="password" placeholder="At least 8 characters" />
          <Field label="Confirm password" value={confirmPassword} onChange={setConfirmPassword} type="password" placeholder="Re-enter password" />
          {message && <div className="login-message">{message}</div>}
          {error && <div className="login-error">{error}</div>}
          <button className="btn primary" type="submit" disabled={isSubmitting}>
            <Icon name={isSubmitting ? "LoaderCircle" : "KeyRound"} className={isSubmitting ? "spin" : ""} />
            <span>{isSubmitting ? "Saving" : "Save Password"}</span>
          </button>
          <button className="btn secondary" type="button" onClick={onLogout}>Sign out</button>
        </form>
      </section>
    </main>
  );
}

function Toast({ message }) {
  if (!message) return null;
  return <div className="toast">{message}</div>;
}

function AppRecoveryBanner({ state, onRefresh, onDismiss }) {
  if (!state?.visible) return null;
  const isUpdate = state.type === "update";
  return (
    <div className={classNames("app-recovery-banner", isUpdate ? "update" : "reconnect")} role="status" aria-live="polite">
      <div className="app-recovery-copy">
        <Icon name={isUpdate ? "RefreshCcw" : "WifiOff"} />
        <div>
          <strong>{isUpdate ? "Nex Central was updated" : "Nex Central is reconnecting"}</strong>
          <p>
            {isUpdate
              ? "A newer version is ready. Finish anything you are typing, then refresh before starting any new work so Nex Central loads the latest tools and fixes."
              : "A request did not finish. If buttons stop responding, refresh the page to reconnect cleanly."}
          </p>
        </div>
      </div>
      <div className="app-recovery-actions">
        {!isUpdate && <button type="button" className="btn ghost" onClick={onDismiss}>Keep working</button>}
        <button type="button" className="btn primary" onClick={onRefresh}>
          <Icon name="RotateCw" />
          <span>Refresh now</span>
        </button>
      </div>
    </div>
  );
}

function App() {
  const [activePage, setActivePage] = useState("Dashboard");
  const [publicPath, setPublicPath] = useState(() => window.location.pathname);
  const [authChecked, setAuthChecked] = useState(false);
  const [currentUser, setCurrentUser] = useState(null);
  const [resetToken, setResetToken] = useState(() => new URLSearchParams(window.location.search).get("resetToken") || "");
  const [brand, setBrand] = useState(localDefaultBrand);
  const [templates, setTemplates] = useState([]);
  const [projects, setProjects] = useState([]);
  const [allowedUsers, setAllowedUsers] = useState([]);
  const [agentDirectory, setAgentDirectory] = useState([]);
  const [announcements, setAnnouncements] = useState([]);
  const [quickLinks, setQuickLinks] = useState([]);
  const [trainingResources, setTrainingResources] = useState([]);
  const [documents, setDocuments] = useState([]);
  const [transactionGuides, setTransactionGuides] = useState([]);
  const [supportTickets, setSupportTickets] = useState([]);
  const [buyerNotifications, setBuyerNotifications] = useState([]);
  const [chatUnreadTotal, setChatUnreadTotal] = useState(0);
  const [latestChat, setLatestChat] = useState(null);
  const [buyerTrackerStartView, setBuyerTrackerStartView] = useState("");
  const [fields, setFields] = useState(defaultFields);
  const [prompt, setPrompt] = useState("");
  const [output, setOutput] = useState(null);
  const [messages, setMessages] = useState([
    {
      id: "welcome",
      type: "assistant",
      text:
        "Tell me what you need. I can create listing posts, flyer copy, open house promotions, rental ads, recruiting copy, emails, SMS scripts, and agent marketing content."
    }
  ]);
  const [propertyPhotos, setPropertyPhotos] = useState([]);
  const [agentHeadshot, setAgentHeadshot] = useState(null);
  const [selectedTemplateId, setSelectedTemplateId] = useState("just-listed");
  const [isGenerating, setIsGenerating] = useState(false);
  const [projectTitle, setProjectTitle] = useState("Untitled Nex marketing project");
  const [saveStatus, setSaveStatus] = useState("Ready");
  const [toast, setToast] = useState("");
  const [canInstall, setCanInstall] = useState(Boolean(window.__nexInstallPrompt));
  const [recoveryNotice, setRecoveryNotice] = useState({ visible: false, type: "", detail: null });
  const [flyerCopy, setFlyerCopy] = useState(defaultFlyerCopy);
  const [businessCardCopy, setBusinessCardCopy] = useState(defaultBusinessCardCopy);
  const flyerRef = useRef(null);
  const businessCardFrontRef = useRef(null);
  const businessCardBackRef = useRef(null);
  const role = currentUser?.role || "Agent";

  useEffect(() => {
    function handlePublicNavigation() {
      setPublicPath(window.location.pathname);
    }
    window.addEventListener("popstate", handlePublicNavigation);
    return () => window.removeEventListener("popstate", handlePublicNavigation);
  }, []);

  async function checkAppVersion(reason = "manual") {
    try {
      const response = await fetch(`/api/app-version?reason=${encodeURIComponent(reason)}&ts=${Date.now()}`, {
        credentials: "same-origin",
        cache: "no-store"
      });
      if (!response.ok) return;
      const payload = await response.json();
      rememberAppVersion(payload.version);
    } catch (_) {
      setRecoveryNotice((current) => current.visible ? current : { visible: true, type: "reconnect", detail: { reason } });
    }
  }

  async function refreshNexCentral() {
    setToast("Refreshing Nex Central...");
    try {
      const controller = navigator.serviceWorker?.controller;
      if (controller) {
        controller.postMessage({ type: "CLEAR_NEX_CACHES" });
        controller.postMessage({ type: "SKIP_WAITING" });
      }
      const registrations = navigator.serviceWorker?.getRegistrations ? await navigator.serviceWorker.getRegistrations() : [];
      await Promise.all((registrations || []).map(async (registration) => {
        try {
          registration.waiting?.postMessage({ type: "SKIP_WAITING" });
          await registration.update();
        } catch (_) {}
      }));
    } catch (_) {}
    try {
      if (window.caches?.keys) {
        const keys = await window.caches.keys();
        await Promise.all(keys.filter((key) => key.startsWith("nex-central")).map((key) => window.caches.delete(key)));
      }
    } catch (_) {}
    const nextUrl = new URL(window.location.href);
    nextUrl.searchParams.set("appRefresh", String(Date.now()));
    window.location.replace(nextUrl.toString());
  }

  function isPublicWebsiteExperience() {
    const normalized = normalizePublicWebsitePath(window.location.pathname);
    return Boolean(normalized || getPublicAgentSlugFromHost() || isBrokeragePublicWebsiteHost());
  }

  useEffect(() => {
    function showUpdateNotice(event) {
      if (isPublicWebsiteExperience()) {
        const reason = event?.detail?.reason || "public-update";
        const guardKey = `nex-public-update-refresh:${reason}`;
        const lastRefresh = Number(sessionStorage.getItem(guardKey) || 0);
        if (Date.now() - lastRefresh > 30000) {
          sessionStorage.setItem(guardKey, String(Date.now()));
          window.setTimeout(() => refreshNexCentral(), 250);
        }
        return;
      }
      setRecoveryNotice({ visible: true, type: "update", detail: event?.detail || null });
    }
    function showReconnectNotice(event) {
      setRecoveryNotice((current) => current.visible ? current : { visible: true, type: "reconnect", detail: event?.detail || null });
    }
    function checkWhenVisible() {
      if (document.visibilityState === "visible") checkAppVersion("visible");
    }

    window.addEventListener(APP_VERSION_EVENT, showUpdateNotice);
    window.addEventListener("nex-app-update-ready", showUpdateNotice);
    window.addEventListener(API_RECONNECT_EVENT, showReconnectNotice);
    document.addEventListener("visibilitychange", checkWhenVisible);
    checkAppVersion("startup");
    const timer = setInterval(() => checkAppVersion("interval"), 60000);
    return () => {
      window.removeEventListener(APP_VERSION_EVENT, showUpdateNotice);
      window.removeEventListener("nex-app-update-ready", showUpdateNotice);
      window.removeEventListener(API_RECONNECT_EVENT, showReconnectNotice);
      document.removeEventListener("visibilitychange", checkWhenVisible);
      clearInterval(timer);
    };
  }, []);

  async function loadAppData(user) {
    const [brandSettings, templateList, savedProjects, accessList, npsBootstrap, directoryList, announcementList, linkList, trainingList, documentList, guideList, ticketList, notificationList, chatBootstrap] = await Promise.all([
      API.request("/api/brand-settings").catch(() => localDefaultBrand),
      API.request("/api/templates").catch(() => []),
      API.request("/api/projects").catch(() => []),
      isAdminRole(user?.role) ? API.request("/api/users").catch(() => []) : Promise.resolve([]),
      API.request("/api/nps/bootstrap").catch(() => ({ users: [] })),
      API.request("/api/agent-directory").catch(() => []),
      API.request("/api/announcements").catch(() => []),
      API.request("/api/quick-links").catch(() => []),
      API.request("/api/training-resources").catch(() => []),
      API.request("/api/documents").catch(() => []),
      API.request("/api/transaction-guides").catch(() => []),
      API.request("/api/support-tickets").catch(() => []),
      API.request("/api/notifications").catch(() => []),
      API.request("/api/chat/bootstrap").catch(() => ({ unreadCounts: {} }))
    ]);
    const mergedTemplates = mergeTemplates(templateList);
    const nextBrand = { ...localDefaultBrand, ...brandSettings };
    setBrand(nextBrand);
    setTemplates(mergedTemplates);
    setProjects(savedProjects);
    const accessUsers = Array.isArray(accessList?.items) ? accessList.items : Array.isArray(accessList) ? accessList : [];
    const npsUsers = Array.isArray(npsBootstrap?.users) ? npsBootstrap.users : [];
    const directoryUsers = Array.isArray(directoryList?.items) ? directoryList.items : Array.isArray(directoryList) ? directoryList : [];
    const knownUsers = uniqueSortedUsers(accessUsers.length ? accessUsers : npsUsers);
    setAllowedUsers(knownUsers);
    setAgentDirectory(uniqueSortedUsers(directoryUsers.length ? directoryUsers : knownUsers));
    setAnnouncements(announcementList);
    setQuickLinks(linkList);
    setTrainingResources(trainingList);
    setDocuments(documentList);
    setTransactionGuides(guideList);
    setSupportTickets(ticketList);
    setBuyerNotifications(notificationList);
    setChatUnreadTotal(Object.values(chatBootstrap.unreadCounts || {}).reduce((sum, value) => sum + Number(value || 0), 0));
    setLatestChat((chatBootstrap.messages || []).slice(-1)[0] || null);
    setFlyerCopy((current) => ({ ...current, footer: nextBrand.defaultDisclaimer }));
    if (mergedTemplates[0] && !mergedTemplates.find((template) => template.id === selectedTemplateId)) {
      setSelectedTemplateId(mergedTemplates[0].id);
    }
  }

  useEffect(() => {
    let mounted = true;
    API.request("/api/auth/me")
      .then(async (auth) => {
        if (!mounted) return;
        setCurrentUser(auth.user || null);
        setAuthChecked(true);
        if (auth.authenticated && auth.user) {
          await loadAppData(auth.user);
        }
      })
      .catch(() => {
        if (!mounted) return;
        setCurrentUser(null);
        setAuthChecked(true);
      });
    return () => {
      mounted = false;
    };
  }, []);

  useEffect(() => {
    if (!toast) return;
    const timer = setTimeout(() => setToast(""), 2600);
    return () => clearTimeout(timer);
  }, [toast]);

  useEffect(() => {
    if (!currentUser) return;
    setFields((current) => ({
      ...current,
      agentName: current.agentName || currentUser.name || "",
      agentEmail: current.agentEmail || currentUser.email || ""
    }));
  }, [currentUser]);

  useEffect(() => {
    if (!currentUser) return;
    setSaveStatus("Autosaving");
    const timer = setTimeout(() => {
      const draft = {
        projectTitle,
        fields,
        flyerCopy,
        businessCardCopy,
        selectedTemplateId,
        propertyPhotos,
        agentHeadshot,
        updatedAt: new Date().toISOString()
      };
      localStorage.setItem(`nex-marketing-draft-${currentUser.email}`, JSON.stringify(draft));
      setSaveStatus("Autosaved");
    }, 700);
    return () => clearTimeout(timer);
  }, [currentUser, projectTitle, fields, flyerCopy, businessCardCopy, selectedTemplateId, propertyPhotos, agentHeadshot]);

  useEffect(() => {
    function handleInstallReady() {
      setCanInstall(true);
    }
    function handleInstalled() {
      setCanInstall(false);
      setToast("Nex Central installed.");
    }
    window.addEventListener("nex-install-ready", handleInstallReady);
    window.addEventListener("nex-installed", handleInstalled);
    return () => {
      window.removeEventListener("nex-install-ready", handleInstallReady);
      window.removeEventListener("nex-installed", handleInstalled);
    };
  }, []);

  useEffect(() => {
    const matchingTemplate =
      templates.find((template) => template.name.toLowerCase() === fields.marketingType.toLowerCase()) ||
      templates.find((template) => fields.marketingType.toLowerCase().includes(template.name.toLowerCase().replace(" / production recognition", "")));
    if (matchingTemplate) {
      setSelectedTemplateId(matchingTemplate.id);
      setFlyerCopy((current) => ({
        ...current,
        headline: matchingTemplate.headline || current.headline,
        badge: matchingTemplate.badge || current.badge,
        layout: matchingTemplate.style || current.layout
      }));
    }
  }, [fields.marketingType, templates]);

  const selectedTemplate = useMemo(
    () => templates.find((template) => template.id === selectedTemplateId) || templates[0],
    [templates, selectedTemplateId]
  );

  async function generateContent(customPrompt) {
    const requestPrompt = customPrompt || prompt || `Create ${fields.marketingType} marketing for Nex Realty.`;
    setIsGenerating(true);
    const userMessage = {
      id: `user-${Date.now()}`,
      type: "user",
      text: requestPrompt
    };
    setMessages((current) => [...current, userMessage]);

    try {
      const generated = await API.request("/api/generate", {
        method: "POST",
        body: JSON.stringify({ prompt: requestPrompt, fields, brandSettings: brand })
      });
      applyGeneratedContent(generated);
      setMessages((current) => [
        ...current,
        { id: `assistant-${Date.now()}`, type: "assistant", output: generated }
      ]);
      setPrompt("");
      return generated;
    } catch (error) {
      const generated = fallbackGenerate({ fields, brandSettings: brand, prompt: requestPrompt });
      applyGeneratedContent(generated);
      setMessages((current) => [
        ...current,
        { id: `assistant-${Date.now()}`, type: "assistant", output: generated }
      ]);
      setToast("Generated with local fallback.");
      return generated;
    } finally {
      setIsGenerating(false);
    }
  }

  function applyGeneratedContent(generated) {
    setOutput(generated);
    setFlyerCopy((current) => ({
      ...current,
      headline: generated.suggestedHeadline || current.headline,
      badge: selectedTemplate ? selectedTemplate.badge : current.badge,
      body: generated.flyerReadyCopy || generated.primary || current.body,
      cta: generated.suggestedCTA || current.cta,
      footer: generated.footerDisclaimer || brand.defaultDisclaimer
    }));
  }

  async function onChatSubmit(event) {
    event.preventDefault();
    if (!prompt.trim()) return;
    await generateContent(prompt.trim());
  }

  async function saveBrand() {
    try {
      const saved = await API.request("/api/brand-settings", {
        method: "PUT",
        body: JSON.stringify(brand)
      });
      setBrand(saved);
      setFlyerCopy((current) => ({ ...current, footer: saved.defaultDisclaimer }));
      setToast("Brand settings saved.");
    } catch (error) {
      setToast("Could not save brand settings.");
    }
  }

  async function saveProject() {
    const title = projectTitle && projectTitle !== "Untitled Nex marketing project"
      ? projectTitle
      : `${fields.marketingType || "Marketing"} - ${fields.propertyAddress || fields.agentName || "Nex Realty"}`;
    const project = {
      title,
      projectType: fields.marketingType || "Marketing",
      thumbnail: {
        headline: flyerCopy.headline,
        badge: flyerCopy.badge,
        accent: flyerCopy.accentColor || selectedTemplate?.accent || brand.primaryColor,
        format: flyerCopy.canvasFormat
      },
      fields,
      output,
      flyerCopy,
      businessCardCopy,
      selectedTemplateId,
      propertyPhotos,
      agentHeadshot
    };
    try {
      const saved = await API.request("/api/projects", {
        method: "POST",
        body: JSON.stringify(project)
      });
      setProjects((current) => [saved, ...current]);
      setProjectTitle(saved.title || title);
      setSaveStatus("Saved");
      setToast("Project saved.");
    } catch (error) {
      const saved = { ...project, id: String(Date.now()), createdAt: new Date().toISOString() };
      setProjects((current) => [saved, ...current]);
      localStorage.setItem("nex-projects", JSON.stringify([saved, ...projects]));
      setSaveStatus("Saved locally");
      setToast("Project saved in this browser.");
    }
  }

  function loadProject(project) {
    setProjectTitle(project.title || "Untitled Nex marketing project");
    if (project.fields) setFields(project.fields);
    if (project.output) setOutput(project.output);
    if (project.flyerCopy) setFlyerCopy({ ...defaultFlyerCopy, ...project.flyerCopy });
    if (project.businessCardCopy) setBusinessCardCopy({ ...defaultBusinessCardCopy, ...project.businessCardCopy });
    if (project.selectedTemplateId) setSelectedTemplateId(project.selectedTemplateId);
    setPropertyPhotos(project.propertyPhotos || []);
    setAgentHeadshot(project.agentHeadshot || null);
    setActivePage("Marketing Studio");
    setToast("Project loaded.");
  }

  async function duplicateProject(project = null) {
    const source = project || {
      title: projectTitle,
      fields,
      output,
      flyerCopy,
      businessCardCopy,
      selectedTemplateId,
      propertyPhotos,
      agentHeadshot
    };
    const duplicate = {
      ...source,
      title: `${source.title || projectTitle || "Nex marketing project"} Copy`,
      createdAt: undefined,
      updatedAt: undefined
    };
    try {
      const saved = await API.request("/api/projects", {
        method: "POST",
        body: JSON.stringify(duplicate)
      });
      setProjects((current) => [saved, ...current]);
      setToast("Project duplicated.");
      return saved;
    } catch (error) {
      const saved = { ...duplicate, id: String(Date.now()), createdAt: new Date().toISOString() };
      setProjects((current) => [saved, ...current]);
      setToast("Project duplicated locally.");
      return saved;
    }
  }

  async function deleteProject(projectId) {
    try {
      await API.request(`/api/projects/${encodeURIComponent(projectId)}`, { method: "DELETE" });
      setProjects((current) => current.filter((project) => project.id !== projectId));
      setToast("Project deleted.");
    } catch (error) {
      setProjects((current) => current.filter((project) => project.id !== projectId));
      setToast(error.message || "Project removed locally.");
    }
  }

  async function saveAsTemplate() {
    const template = {
      name: projectTitle || flyerCopy.headline || "Nex Template",
      category: fields.marketingType || "Custom",
      headline: flyerCopy.headline,
      badge: flyerCopy.badge,
      accent: flyerCopy.accentColor || selectedTemplate?.accent || brand.primaryColor,
      style: flyerCopy.layout || "classic"
    };
    try {
      const saved = await API.request("/api/templates", {
        method: "POST",
        body: JSON.stringify(template)
      });
      setTemplates((current) => [saved, ...current]);
      setToast("Template saved.");
    } catch (error) {
      setToast(error.message || "Admin access is required to save global templates.");
    }
  }

  async function waitForMarketingExportAssets(element) {
    if (document.fonts?.ready) {
      try {
        await document.fonts.ready;
      } catch (_) {
        // Font loading failures should not block an export.
      }
    }
    const images = Array.from(element.querySelectorAll("img"));
    await Promise.all(images.map((image) => {
      if (image.complete && image.naturalWidth !== 0) return Promise.resolve();
      return new Promise((resolve) => {
        const timeout = window.setTimeout(resolve, 2500);
        const done = () => {
          window.clearTimeout(timeout);
          resolve();
        };
        image.addEventListener("load", done, { once: true });
        image.addEventListener("error", done, { once: true });
      });
    }));
  }

  async function captureElement(element, format, fileBase) {
    if (!element) {
      setToast("No active design canvas found. Open a template first, then export.");
      return;
    }
    if (!window.html2canvas) {
      setToast("Export library did not load. Refresh Nex Central and try again.");
      return;
    }
    setToast(`Preparing ${format.toUpperCase()}...`);
    try {
      if (document.activeElement && document.activeElement.blur) {
        document.activeElement.blur();
        await new Promise((resolve) => setTimeout(resolve, 120));
      }
      await waitForMarketingExportAssets(element);
      const previousZoom = element.style.zoom;
      const previousTransform = element.style.transform;
      let canvas;
      try {
        element.classList.add("is-exporting");
        element.style.zoom = "1";
        element.style.transform = "none";
        await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
        const exportBounds = element.getBoundingClientRect();
        const exportWidth = Math.ceil(exportBounds.width || element.offsetWidth || element.scrollWidth);
        const exportHeight = Math.ceil(exportBounds.height || element.offsetHeight || element.scrollHeight);
        canvas = await html2canvas(element, {
          scale: 3,
          backgroundColor: "#ffffff",
          useCORS: true,
          allowTaint: false,
          width: exportWidth,
          height: exportHeight,
          windowWidth: Math.max(document.documentElement.clientWidth, exportWidth),
          windowHeight: Math.max(document.documentElement.clientHeight, exportHeight),
          imageTimeout: 15000,
          logging: false,
          ignoreElements: (node) => {
            if (!node?.classList) return false;
            return [
              "resize-handles",
              "canvas-image-toolbar",
              "canvas-headshot-button",
              "agent-headshot-replace"
            ].some((className) => node.classList.contains(className));
          }
        });
      } finally {
        element.style.zoom = previousZoom;
        element.style.transform = previousTransform;
        element.classList.remove("is-exporting");
      }
      const image = canvas.toDataURL("image/png", 1);
      const fileName = fileBase.toLowerCase().replace(/[^a-z0-9]+/g, "-");

      if (format === "png" || format === "jpg") {
        const link = document.createElement("a");
        link.download = `${fileName}.${format}`;
        link.href = format === "jpg" ? canvas.toDataURL("image/jpeg", 0.92) : image;
        document.body.appendChild(link);
        link.click();
        link.remove();
        setToast(`${format.toUpperCase()} downloaded.`);
        return;
      }

      const { jsPDF } = window.jspdf || {};
      if (!jsPDF) throw new Error("PDF export library did not load. Refresh Nex Central and try again.");
      const pdf = new jsPDF({
        orientation: canvas.width > canvas.height ? "landscape" : "portrait",
        unit: "px",
        format: [canvas.width, canvas.height]
      });
      pdf.addImage(image, "PNG", 0, 0, canvas.width, canvas.height);
      pdf.save(`${fileName}.pdf`);
      setToast("PDF downloaded.");
    } catch (error) {
      console.error("Nex Central export failed", error);
      setToast(error.message || "Could not export this design. Try removing external images or refresh and export again.");
    }
  }

  function captureFlyer(format) {
    const selectedFormat = getCreativeFormat(flyerCopy.canvasFormat);
    return captureElement(flyerRef.current, format, `nex-realty-${fields.marketingType || "flyer"}-${selectedFormat.id}`);
  }

  function captureBusinessCard(format, side) {
    const ref = side === "back" ? businessCardBackRef : businessCardFrontRef;
    return captureElement(ref.current, format, `nex-realty-business-card-${side}-${businessCardCopy.displayName || fields.agentName || "agent"}`);
  }

  function addStockPhoto(photo) {
    const image = makeStudioMediaItem({
      ...photo,
      name: `${photo.title || "Stock image"}.${String(photo.dataUrl || "").startsWith("data:image/svg") ? "svg" : "jpg"}`,
      type: String(photo.dataUrl || "").startsWith("data:image/svg") ? "image/svg+xml" : "image/jpeg",
      source: photo.source || "Nex Studio Stock"
    }, photo.source || "Nex Studio Stock");
    if (!image) return;
    setPropertyPhotos((current) => mergeStudioMedia([image], current, 8));
    setToast(`${image.title || image.name} added to photos.`);
  }

  async function downloadQuickVideo(orientation = flyerCopy.videoOrientation || "vertical") {
    setToast("Rendering quick video...");
    try {
      const blob = await createQuickMarketingVideo({ brand, fields, flyerCopy, propertyPhotos, orientation });
      const spec = getVideoOrientation(orientation);
      downloadBlob(blob, `nex-realty-${spec.id}-video-${fields.marketingType || "marketing"}.webm`.toLowerCase().replace(/[^a-z0-9.]+/g, "-"));
      setFlyerCopy((current) => ({ ...current, videoOrientation: orientation }));
      setToast(`${spec.name} downloaded as WEBM.`);
    } catch (error) {
      setToast(error.message || "Could not render quick video.");
    }
  }

  function openQuickLink(link) {
    if (!link) return;
    if (link.id === "nexu" || link.title === "NexU") {
      setActivePage("NexU / Training Center");
      return;
    }
    const url = String(link.url || "").trim();
    if (!url || url === "#") {
      setToast(`${link.title} link has not been added yet.`);
      return;
    }
    if (url.startsWith("app:")) {
      setActivePage(url.replace("app:", ""));
      return;
    }
    window.open(url, "_blank", "noopener,noreferrer");
  }

  function getMarketingShareText() {
    const locationLine = [fields.propertyAddress, fields.city, fields.state].filter(Boolean).join(", ");
    const hashtags = Array.isArray(output?.hashtags) ? output.hashtags.join(" ") : "#NexRealty #RealEstate";
    return [
      flyerCopy.headline || output?.suggestedHeadline || fields.marketingType || "Nex Realty",
      output?.primary || flyerCopy.body,
      locationLine,
      flyerCopy.cta || fields.cta,
      hashtags
    ]
      .filter(Boolean)
      .join("\n\n");
  }

  function getMarketingShareUrl() {
    return flyerCopy.qrUrl || flyerCopy.agentWebsite || window.location.origin;
  }

  async function shareMarketingDesign(platform = "native") {
    const text = getMarketingShareText();
    const url = getMarketingShareUrl();
    const title = projectTitle || flyerCopy.headline || "Nex Realty marketing asset";

    if (platform === "native" && navigator.share) {
      try {
        await navigator.share({ title, text, url });
        setToast("Share sheet opened.");
        return;
      } catch (error) {
        if (error?.name === "AbortError") return;
      }
    }

    try {
      await navigator.clipboard.writeText(text);
    } catch (error) {
      // Sharing still works even if the browser blocks clipboard access.
    }

    const encodedText = encodeURIComponent(text);
    const encodedUrl = encodeURIComponent(url);
    const shareTargets = {
      facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
      x: `https://twitter.com/intent/tweet?text=${encodedText}`,
      linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
      instagram: "https://www.instagram.com/"
    };

    const target = shareTargets[platform];
    if (target) {
      window.open(target, "_blank", "noopener,noreferrer");
      setToast(platform === "instagram" ? "Caption copied. Download the asset and upload it to Instagram." : "Caption copied and share page opened.");
      return;
    }

    setToast("Caption copied. Download the design before posting.");
  }

  function openVistaPrint() {
    const formatId = flyerCopy.canvasFormat || "letter-flyer";
    const printUrl = formatId === "business-card"
      ? "https://www.vistaprint.com/business-cards"
      : formatId === "postcard"
        ? "https://www.vistaprint.com/postcards"
        : "https://www.vistaprint.com/marketing-materials";
    window.open(printUrl, "_blank", "noopener,noreferrer");
    setToast("Opening VistaPrint. Upload the exported PDF, PNG, or JPG there.");
  }

  async function installApp() {
    if (window.nexPromptInstall) {
      const result = await window.nexPromptInstall();
      setCanInstall(false);
      if (result?.outcome === "accepted") setToast("Nex Central installed.");
      else if (result?.outcome === "unavailable") setToast("Use your browser menu to add Nex Central to your home screen.");
      return;
    }
    setToast("Use your browser menu to add Nex Central to your home screen.");
  }

  async function login(credentials) {
    const auth = await API.request("/api/auth/login", {
      method: "POST",
      body: JSON.stringify(credentials),
      retries: 2,
      retryDelay: 700
    });
    if (auth.consumerSession) {
      const remembered = rememberPublicConsumerSession(auth.consumerSession);
      if (remembered) setConsumerSession(remembered);
    }
    if (auth.requiresTwoFactor) return auth;
    setCurrentUser(auth.user);
    try {
      await loadAppData(auth.user);
      setToast("Signed in.");
    } catch (error) {
      console.error("Post-login data load failed", error);
      setToast("Signed in. Refresh if dashboard data looks incomplete.");
    }
    return auth;
  }

  async function verifyTwoFactorLogin(payload) {
    const auth = await API.request("/api/auth/2fa/verify-login", {
      method: "POST",
      body: JSON.stringify(payload),
      retries: 1
    });
    setCurrentUser(auth.user);
    try {
      await loadAppData(auth.user);
      setToast("Signed in securely.");
    } catch (error) {
      console.error("Post-login data load failed", error);
      setToast("Signed in. Refresh if dashboard data looks incomplete.");
    }
    return auth;
  }

  async function requestPasswordReset(email) {
    return API.request("/api/auth/forgot-password", {
      method: "POST",
      body: JSON.stringify({ email }),
      retries: 1
    });
  }

  async function resetPassword(payload) {
    const response = await API.request("/api/auth/reset-password", {
      method: "POST",
      body: JSON.stringify(payload),
      retries: 1
    });
    setResetToken("");
    return response;
  }

  async function changeOwnPassword(payload) {
    const response = await API.request("/api/auth/change-password", {
      method: "POST",
      body: JSON.stringify(payload),
      retries: 1
    });
    if (response.user) setCurrentUser(response.user);
    setToast(response.message || "Password updated.");
    return response;
  }

  async function logout() {
    await API.request("/api/auth/logout", { method: "POST" }).catch(() => {});
    setCurrentUser(null);
    setAllowedUsers([]);
    setAgentDirectory([]);
    setProjects([]);
    setAnnouncements([]);
    setQuickLinks([]);
    setTrainingResources([]);
    setDocuments([]);
    setTransactionGuides([]);
    setSupportTickets([]);
    setBuyerNotifications([]);
    setChatUnreadTotal(0);
    setLatestChat(null);
    setBuyerTrackerStartView("");
    setActivePage("Dashboard");
    setToast("");
  }

  function renderMain() {
    if (activePage === "Dashboard") {
      return (
        <Dashboard
          projects={projects}
          templates={templates}
          announcements={announcements}
          quickLinks={quickLinks}
          trainingResources={trainingResources}
          tickets={supportTickets}
          latestChat={latestChat}
          chatUnreadTotal={chatUnreadTotal}
          buyerNotifications={buyerNotifications}
          documents={documents}
          currentUser={currentUser}
          users={allowedUsers}
          setActivePage={setActivePage}
          setBuyerTrackerStartView={setBuyerTrackerStartView}
          setSelectedTemplateId={setSelectedTemplateId}
          setFields={setFields}
          brand={brand}
          openQuickLink={openQuickLink}
        />
      );
    }
    if (activePage === "Activity") {
      return <PlatformActivity currentUser={currentUser} role={role} setToast={setToast} />;
    }
    if (activePage === "Agent Intelligence") {
      return isAdminRole(role) ? (
        <AgentIntelligence role={role} setToast={setToast} setActivePage={setActivePage} />
      ) : (
        <EmptyState icon="ShieldAlert" title="Admin-only page" body="Agent Intelligence is only available to Nex admins and super admins." />
      );
    }
    if (activePage === "Communication Center") {
      return <CommunicationCenter currentUser={currentUser} role={role} setToast={setToast} setCurrentUser={setCurrentUser} />;
    }
    if (activePage === "Marketing Studio") {
      return (
        <MarketingStudioHub
          currentUser={currentUser}
          setActivePage={setActivePage}
          templates={templates}
          brand={brand}
          selectedTemplateId={selectedTemplateId}
          setSelectedTemplateId={setSelectedTemplateId}
          fields={fields}
          setFields={setFields}
          flyerCopy={flyerCopy}
          setFlyerCopy={setFlyerCopy}
          propertyPhotos={propertyPhotos}
          setPropertyPhotos={setPropertyPhotos}
          agentHeadshot={agentHeadshot}
          setAgentHeadshot={setAgentHeadshot}
          flyerRef={flyerRef}
          output={output}
          setOutput={setOutput}
          prompt={prompt}
          setPrompt={setPrompt}
          isGenerating={isGenerating}
          onGenerate={generateContent}
          onQuickAction={generateContent}
          onSaveProject={saveProject}
          onDuplicateProject={() => duplicateProject()}
          onDownloadPdf={() => captureFlyer("pdf")}
          onDownloadPng={() => captureFlyer("png")}
          onDownloadJpg={() => captureFlyer("jpg")}
          onPrint={openVistaPrint}
          onSharePlatform={shareMarketingDesign}
          onSaveAsTemplate={saveAsTemplate}
          projects={projects}
          loadProject={loadProject}
          setToast={setToast}
          projectTitle={projectTitle}
          setProjectTitle={setProjectTitle}
          saveStatus={saveStatus}
        />
      );
    }
    if (activePage === "Bulletin Board") {
      return <BulletinBoard announcements={announcements} role={role} setAnnouncements={setAnnouncements} setToast={setToast} />;
    }
    if (activePage === "Quick Links") {
      return <QuickLinksCenter quickLinks={quickLinks} role={role} setQuickLinks={setQuickLinks} setToast={setToast} openQuickLink={openQuickLink} />;
    }
    if (activePage === "Directory" || activePage === "Agent Directory") {
      return <AgentDirectory agents={agentDirectory} currentUser={currentUser} setToast={setToast} setActivePage={setActivePage} />;
    }
    if (activePage === "My Website") {
      return <AgentWebsiteManager currentUser={currentUser} setCurrentUser={setCurrentUser} brand={brand} setToast={setToast} setActivePage={setActivePage} />;
    }
    if (activePage === "Nex Intelligent Assistant" || activePage === "Nex Agent Assist") {
      return <NexAgentAssist currentUser={currentUser} role={role} setToast={setToast} />;
    }
    if (activePage === "Nex Chat") {
      return <NexChat currentUser={currentUser} role={role} setToast={setToast} onUnreadTotalChange={setChatUnreadTotal} onLatestMessageChange={setLatestChat} />;
    }
    if (activePage === legacyCrmPageName || activePage === "Nex CRM") {
      return <NexCrm currentUser={currentUser} role={role} setToast={setToast} />;
    }
    if (activePage === "Nex Leads") {
      return <NexLeads currentUser={currentUser} role={role} setToast={setToast} setActivePage={setActivePage} />;
    }
    if (activePage === "Production Tracker" || activePage === "Agent Production Calculator") {
      return <AgentProductionCalculator currentUser={currentUser} setToast={setToast} />;
    }
    if (activePage === "Calculators") {
      return <NexCalculators currentUser={currentUser} setToast={setToast} />;
    }
    if (activePage === "Commission Tracker") {
      return <CommissionCapTracker currentUser={currentUser} role={role} users={allowedUsers} setToast={setToast} />;
    }
    if (activePage === "Nex PowerShare" || activePage === ["Revenue", "Share"].join(" ")) {
      return <NexPowerShareRewards currentUser={currentUser} role={role} users={allowedUsers} setUsers={setAllowedUsers} setToast={setToast} />;
    }
    if (activePage === "Transactions") {
      return <NexTransactions currentUser={currentUser} role={role} setToast={setToast} />;
    }
    if (activePage === "Buyer Contract Tracker") {
      return (
        <BuyerContractTrackerPage
          currentUser={currentUser}
          role={role}
          setToast={setToast}
          notifications={buyerNotifications}
          setNotifications={setBuyerNotifications}
          initialView={buyerTrackerStartView}
          onInitialViewConsumed={() => setBuyerTrackerStartView("")}
        />
      );
    }
    if (activePage === "NexU / Training Center") {
      return <TrainingCenter resources={trainingResources} role={role} setTrainingResources={setTrainingResources} setToast={setToast} />;
    }
    if (activePage === "Documents") {
      return <DocumentsLibrary documents={documents} setDocuments={setDocuments} role={role} setToast={setToast} />;
    }
    if (activePage === "Nex LaunchPad") {
      return <NexLaunchPad currentUser={currentUser} role={role} setToast={setToast} />;
    }
    if (activePage === "Transaction Help Center") {
      return (
        <TransactionHelpCenter
          guides={transactionGuides}
          role={role}
          setTransactionGuides={setTransactionGuides}
          setActivePage={setActivePage}
          setToast={setToast}
        />
      );
    }
    if (activePage === "Support Desk") {
      return <SupportDesk currentUser={currentUser} role={role} tickets={supportTickets} setSupportTickets={setSupportTickets} setToast={setToast} />;
    }
    if (activePage === "Admin Panel") {
      return (
        <AdminPanel
          role={role}
          announcements={announcements}
          quickLinks={quickLinks}
          trainingResources={trainingResources}
          documents={documents}
          transactionGuides={transactionGuides}
          supportTickets={supportTickets}
          allowedUsers={allowedUsers}
          setActivePage={setActivePage}
        />
      );
    }
    if (activePage === "Website Leads / IDX") {
      return <WebsiteLeadCenter role={role} setActivePage={setActivePage} setToast={setToast} />;
    }
    if (activePage === "Recruiting SEO") {
      return <RecruitingSeoCenter role={role} setToast={setToast} />;
    }
    if (activePage === "Flyer Builder") {
      return (
        <FlyerBuilder
          brand={brand}
          fields={fields}
          setFields={setFields}
          templates={templates}
          selectedTemplateId={selectedTemplateId}
          setSelectedTemplateId={setSelectedTemplateId}
          flyerCopy={flyerCopy}
          setFlyerCopy={setFlyerCopy}
          propertyPhotos={propertyPhotos}
          agentHeadshot={agentHeadshot}
          flyerRef={flyerRef}
          onDownloadPdf={() => captureFlyer("pdf")}
          onDownloadPng={() => captureFlyer("png")}
          onDownloadVideo={downloadQuickVideo}
          onGenerate={() => generateContent(`Regenerate flyer copy for ${fields.marketingType}.`)}
          onAddStockPhoto={addStockPhoto}
        />
      );
    }
    if (activePage === "Quick Video Builder") {
      return (
        <QuickVideoBuilder
          brand={brand}
          fields={fields}
          flyerCopy={flyerCopy}
          setFlyerCopy={setFlyerCopy}
          propertyPhotos={propertyPhotos}
          onAddStockPhoto={addStockPhoto}
          onGenerate={() => generateContent(`Create a short ${flyerCopy.videoOrientation === "horizontal" ? "horizontal video" : "vertical reel"} script for ${fields.marketingType}.`)}
          onDownloadVideo={downloadQuickVideo}
        />
      );
    }
    if (activePage === "Business Card Builder") {
      return (
        <BusinessCardBuilder
          brand={brand}
          fields={fields}
          agentHeadshot={agentHeadshot}
          setAgentHeadshot={setAgentHeadshot}
          businessCardCopy={businessCardCopy}
          setBusinessCardCopy={setBusinessCardCopy}
          businessCardFrontRef={businessCardFrontRef}
          businessCardBackRef={businessCardBackRef}
          onDownloadFrontPdf={() => captureBusinessCard("pdf", "front")}
          onDownloadBackPdf={() => captureBusinessCard("pdf", "back")}
          onDownloadFrontPng={() => captureBusinessCard("png", "front")}
          onDownloadBackPng={() => captureBusinessCard("png", "back")}
          onPrint={openVistaPrint}
        />
      );
    }
    if (activePage === "Social Media Generator") {
      return <SocialGenerator output={output} setToast={setToast} />;
    }
    if (activePage === "Email/SMS Generator") {
      return <EmailSmsGenerator output={output} setToast={setToast} />;
    }
    if (activePage === "Saved Projects") {
      return <SavedProjects projects={projects} loadProject={loadProject} duplicateProject={duplicateProject} deleteProject={deleteProject} brand={brand} />;
    }
    if (activePage === "Brand Settings / Admin") {
      return (
        <BrandSettings
          brand={brand}
          setBrand={setBrand}
          saveBrand={saveBrand}
          role={role}
          allowedUsers={allowedUsers}
          setAllowedUsers={setAllowedUsers}
          setAgentDirectory={setAgentDirectory}
          setToast={setToast}
        />
      );
    }
    if (activePage === "Template Library") {
      return <TemplateLibrary templates={templates} setTemplates={setTemplates} brand={brand} role={role} setSelectedTemplateId={setSelectedTemplateId} setFields={setFields} setActivePage={setActivePage} setToast={setToast} />;
    }
    return (
      <ChatWorkspace
        messages={messages}
        prompt={prompt}
        setPrompt={setPrompt}
        onSubmit={onChatSubmit}
        isGenerating={isGenerating}
        output={output}
        setToast={setToast}
        onQuickAction={generateContent}
      />
    );
  }

  const publicAgentSlug = getPublicAgentSlugFromHost();
  const brokeragePublicHost = isBrokeragePublicWebsiteHost();
  const normalizedPublicPath = normalizePublicWebsitePath(publicPath);
  if (normalizedPublicPath || publicAgentSlug || brokeragePublicHost) {
    return (
      <>
        <NexPublicWebsite
          brand={brand}
          currentPath={normalizedPublicPath || (brokeragePublicHost ? "/site" : publicPath)}
          setCurrentPath={setPublicPath}
          agentSlugFromHost={publicAgentSlug}
        />
      </>
    );
  }

  if (!authChecked) {
    return (
      <main className="login-screen">
        <section className="login-panel">
          <div className="login-brand">
            <Wordmark brand={brand} variant="light" className="login-logo" />
            <div>
              <p className="eyebrow">Loading</p>
              <h1>{APP_NAME}</h1>
            </div>
          </div>
        </section>
      </main>
    );
  }

  if (!currentUser) {
    return <LoginScreen onLogin={login} onVerifyTwoFactor={verifyTwoFactorLogin} onForgotPassword={requestPasswordReset} onResetPassword={resetPassword} brand={brand} resetToken={resetToken} />;
  }

  if (currentUser.forcePasswordChange) {
    return <ForcePasswordChangeScreen user={currentUser} brand={brand} onChangePassword={changeOwnPassword} onLogout={logout} />;
  }

  const isMarketingPage = ["Marketing Studio", ...marketingStudioPages.map(([page]) => page)].includes(activePage);
  const showMarketingInputPanel = marketingStudioPages.map(([page]) => page).includes(activePage);
  const updateAvailable = recoveryNotice.visible && recoveryNotice.type === "update";

  return (
    <div className={classNames("app-shell", !showMarketingInputPanel && "portal-shell")}>
      <Sidebar activePage={activePage} setActivePage={setActivePage} currentUser={currentUser} onLogout={logout} brand={brand} chatUnreadTotal={chatUnreadTotal} />
      <main className="main-area">
        <Header
          activePage={activePage}
          onGenerate={() => generateContent()}
          onSaveProject={saveProject}
          isGenerating={isGenerating}
          isMarketingPage={isMarketingPage}
          canInstall={canInstall}
          onInstall={installApp}
          onRefreshApp={refreshNexCentral}
          updateAvailable={updateAvailable}
          notifications={buyerNotifications}
          onOpenNotifications={() => {
            setActivePage("Communication Center");
          }}
        />
        {renderMain()}
      </main>
      {showMarketingInputPanel && (
        <InputPanel
          fields={fields}
          setFields={setFields}
          agentHeadshot={agentHeadshot}
          setAgentHeadshot={setAgentHeadshot}
          propertyPhotos={propertyPhotos}
          setPropertyPhotos={setPropertyPhotos}
        />
      )}
      <AppRecoveryBanner
        state={recoveryNotice}
        onRefresh={refreshNexCentral}
        onDismiss={() => setRecoveryNotice({ visible: false, type: "", detail: null })}
      />
      <Toast message={toast} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
