const { useState, useEffect, useMemo, useRef } = React;

// ============================================
// Hero parcel preview card
// ============================================
function HeroParcelCard() {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = setInterval(() => setPhase(p => (p + 1) % 3), 2400);
    return () => clearInterval(t);
  }, []);

  const heroCardStyles = {
    wrap: { position: 'relative' },
    surveyMark: {
      position: 'absolute',
      top: -12,
      right: -12,
      fontFamily: 'JetBrains Mono, monospace',
      fontSize: 9,
      letterSpacing: '0.14em',
      color: '#5c594f',
      textTransform: 'uppercase',
      transform: 'rotate(8deg)',
      border: '1px solid rgba(255,255,255,0.14)',
      borderRadius: 4,
      padding: '6px 10px',
      background: '#0b0d10'
    }
  };

  // Mini parcel grid for hero preview
  const cells = useMemo(() => {
    const arr = [];
    for (let i = 0; i < 96; i++) {
      const r = Math.random();
      let kind;
      if (r < 0.55) kind = 'claimed';
      else if (r < 0.75) kind = 'available';
      else if (r < 0.85) kind = 'reserved';
      else kind = 'empty';
      arr.push(kind);
    }
    // Highlight one cell
    arr[42] = 'highlight';
    return arr;
  }, []);

  return (
    <div className="parcel-card" style={heroCardStyles.wrap}>
      <div className="parcel-card-header">
        <div>
          <div className="parcel-id">PARCEL · CHI-OAK-04</div>
          <div style={{ fontSize: 22, fontWeight: 500, letterSpacing: '-0.02em', marginTop: 4 }}>
            Oak Park, IL
          </div>
          <div style={{ fontSize: 12, color: '#8a8578', fontFamily: 'JetBrains Mono, monospace', marginTop: 4, letterSpacing: '0.06em' }}>
            ZIP 60301-60304 · PLUMBING
          </div>
        </div>
        <div className="parcel-stamp">{phase === 0 ? 'AVAILABLE' : phase === 1 ? 'INSPECTING' : 'OPEN'}</div>
      </div>

      {/* Mini grid */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(12, 1fr)',
        gap: 3,
        aspectRatio: '12 / 8',
        marginBottom: 24,
        padding: 14,
        background: '#0b0d10',
        borderRadius: 8,
        border: '1px solid rgba(255,255,255,0.06)'
      }}>
        {cells.map((kind, i) => {
          const styleByKind = {
            claimed: { background: '#4a4842' },
            available: { background: '#e8a04a' },
            reserved: { background: 'transparent', border: '1px dashed #6a6258' },
            empty: { background: 'rgba(255,255,255,0.02)' },
            highlight: {
              background: '#e8a04a',
              boxShadow: '0 0 0 2px #0b0d10, 0 0 0 3px #f6c886, 0 0 16px rgba(232,160,74,0.6)',
              animation: 'heroPulse 2s ease-in-out infinite'
            }
          };
          return <div key={i} style={{ borderRadius: 2, ...styleByKind[kind] }} />;
        })}
      </div>

      {/* Stats */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: '1fr 1fr',
        gap: 1,
        background: 'rgba(255,255,255,0.06)',
        border: '1px solid rgba(255,255,255,0.06)',
        borderRadius: 8,
        overflow: 'hidden'
      }}>
        {[
          { k: 'Trade', v: 'Plumbing' },
          { k: 'ZIP coverage', v: '60301–60304' },
        ].map((s, i) => (
          <div key={i} style={{ background: '#0f1216', padding: '14px 16px' }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.12em', color: '#8a8578', textTransform: 'uppercase', marginBottom: 6 }}>{s.k}</div>
            <div style={{ fontSize: 17, fontWeight: 500, letterSpacing: '-0.015em' }}>{s.v}</div>
          </div>
        ))}
      </div>

      <div style={heroCardStyles.surveyMark}>
        FILED · 04.{String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}.26
      </div>

      <style>{`
        @keyframes heroPulse {
          0%, 100% { transform: scale(1); }
          50% { transform: scale(1.15); }
        }
      `}</style>
    </div>
  );
}

// ============================================
// Territory Grid (interactive)
// ============================================
// Approximate positions on a 1000×560 US-map viewBox.
// x/y are the parcel's anchor point on the map.
const PARCELS = [
  // West coast
  { id: 'SEA-BEL-01', name: 'Bellevue',       region: 'Seattle metro · WA',     zips: '98004–98008', trade: 'Roofing',    status: 'available', monthly: 215, ticket: '$1,420', x: 178, y: 95  },
  { id: 'PDX-BVR-02', name: 'Beaverton',      region: 'Portland metro · OR',    zips: '97005–97008', trade: 'HVAC',       status: 'available', monthly: 230, ticket: '$640',   x: 168, y: 145 },
  { id: 'SFO-OAK-03', name: 'Oakland Hills',  region: 'Bay Area · CA',          zips: '94605–94619', trade: 'Plumbing',   status: 'available', monthly: 290, ticket: '$580',   x: 145, y: 255 },
  { id: 'SFO-SJC-04', name: 'Willow Glen',    region: 'San Jose · CA',          zips: '95125–95128', trade: 'Electrical', status: 'reserved',  monthly: 320, ticket: '$640',   x: 158, y: 275 },
  { id: 'LAX-PAS-09', name: 'Pasadena',       region: 'LA metro · CA',          zips: '91101–91107', trade: 'Electrical', status: 'available', monthly: 360, ticket: '$640',   x: 195, y: 340 },
  { id: 'LAX-LBC-10', name: 'Long Beach',     region: 'LA metro · CA',          zips: '90803–90815', trade: 'Plumbing',   status: 'available', monthly: 310, ticket: '$520',   x: 205, y: 358 },
  { id: 'SAN-DEL-11', name: 'Del Mar',        region: 'San Diego · CA',         zips: '92014, 92130', trade: 'Roofing',    status: 'available', monthly: 175, ticket: '$1,520', x: 220, y: 380 },

  // Mountain
  { id: 'PHX-MES-12', name: 'Mesa East',      region: 'Phoenix metro · AZ',     zips: '85207–85215', trade: 'HVAC',       status: 'available', monthly: 410, ticket: '$640',   x: 285, y: 370 },
  { id: 'TUC-ORV-13', name: 'Oro Valley',     region: 'Tucson · AZ',            zips: '85737–85755', trade: 'Plumbing',   status: 'available', monthly: 165, ticket: '$520',   x: 305, y: 405 },
  { id: 'LAS-HEN-14', name: 'Henderson',      region: 'Las Vegas metro · NV',   zips: '89011–89074', trade: 'HVAC',       status: 'available', monthly: 285, ticket: '$640',   x: 245, y: 305 },
  { id: 'SLC-SDY-15', name: 'Sandy',          region: 'Salt Lake metro · UT',   zips: '84070–84094', trade: 'Roofing',    status: 'available', monthly: 200, ticket: '$1,450', x: 305, y: 235 },
  { id: 'DEN-LIT-16', name: 'Littleton',      region: 'Denver metro · CO',      zips: '80120–80129', trade: 'Plumbing',   status: 'available', monthly: 240, ticket: '$520',   x: 395, y: 260 },
  { id: 'BOI-MER-17', name: 'Meridian',       region: 'Boise metro · ID',       zips: '83642–83646', trade: 'HVAC',       status: 'reserved',  monthly: 155, ticket: '$640',   x: 270, y: 175 },
  { id: 'ABQ-RIO-18', name: 'Rio Rancho',     region: 'Albuquerque · NM',       zips: '87124–87144', trade: 'Plumbing',   status: 'available', monthly: 170, ticket: '$520',   x: 380, y: 340 },

  // Texas
  { id: 'DAL-PLN-19', name: 'Plano',          region: 'Dallas metro · TX',      zips: '75023–75094', trade: 'HVAC',       status: 'available', monthly: 380, ticket: '$640',   x: 540, y: 380 },
  { id: 'HOU-SUG-20', name: 'Sugar Land',     region: 'Houston metro · TX',     zips: '77478–77498', trade: 'Plumbing',   status: 'available', monthly: 350, ticket: '$520',   x: 580, y: 430 },
  { id: 'AUS-RND-08', name: 'Round Rock',     region: 'Austin metro · TX',      zips: '78664–78681', trade: 'Roofing',    status: 'available', monthly: 195, ticket: '$1,750', x: 540, y: 415 },
  { id: 'SAT-NBR-21', name: 'New Braunfels',  region: 'San Antonio · TX',       zips: '78130–78132', trade: 'Electrical', status: 'reserved',  monthly: 165, ticket: '$640',   x: 530, y: 440 },

  // Midwest
  { id: 'CHI-OAK-04', name: 'Oak Park',       region: 'Chicago metro · IL',     zips: '60301–60304', trade: 'Plumbing',   status: 'available', monthly: 340, ticket: '$520',   x: 640, y: 230 },
  { id: 'CHI-EVN-22', name: 'Evanston North', region: 'Chicago metro · IL',     zips: '60201–60203', trade: 'HVAC',       status: 'available', monthly: 280, ticket: '$640',   x: 645, y: 220 },
  { id: 'MSP-EDN-23', name: 'Edina',          region: 'Twin Cities · MN',       zips: '55416–55439', trade: 'Roofing',    status: 'available', monthly: 220, ticket: '$1,520', x: 580, y: 175 },
  { id: 'STL-CHF-24', name: 'Chesterfield',   region: 'St. Louis metro · MO',   zips: '63005–63017', trade: 'HVAC',       status: 'available', monthly: 230, ticket: '$640',   x: 615, y: 295 },
  { id: 'KCY-OVL-25', name: 'Overland Park',  region: 'Kansas City · KS',       zips: '66204–66224', trade: 'Plumbing',   status: 'available', monthly: 245, ticket: '$520',   x: 565, y: 285 },
  { id: 'IND-CRM-26', name: 'Carmel',         region: 'Indianapolis · IN',      zips: '46032–46074', trade: 'Electrical', status: 'available', monthly: 215, ticket: '$640',   x: 670, y: 270 },
  { id: 'CLE-WLB-27', name: 'Westlake',       region: 'Cleveland metro · OH',   zips: '44145, 44116', trade: 'Roofing',    status: 'reserved',  monthly: 195, ticket: '$1,420', x: 730, y: 230 },
  { id: 'CIN-MAS-28', name: 'Mason',          region: 'Cincinnati metro · OH',  zips: '45040–45069', trade: 'HVAC',       status: 'available', monthly: 235, ticket: '$640',   x: 700, y: 280 },
  { id: 'DET-RYL-29', name: 'Royal Oak',      region: 'Detroit metro · MI',     zips: '48067–48073', trade: 'Plumbing',   status: 'available', monthly: 270, ticket: '$520',   x: 715, y: 215 },
  { id: 'MKE-WAW-30', name: 'Wauwatosa',      region: 'Milwaukee · WI',         zips: '53213–53226', trade: 'HVAC',       status: 'available', monthly: 200, ticket: '$640',   x: 635, y: 205 },

  // South
  { id: 'NSH-FRK-12', name: 'Franklin',       region: 'Nashville metro · TN',   zips: '37064, 37067', trade: 'Roofing',    status: 'available', monthly: 180, ticket: '$1,650', x: 685, y: 335 },
  { id: 'ATL-DEC-06', name: 'Decatur',        region: 'Atlanta metro · GA',     zips: '30030, 30033', trade: 'Plumbing',   status: 'reserved',  monthly: 265, ticket: '$520',   x: 720, y: 385 },
  { id: 'CHA-BLM-31', name: 'Ballantyne',     region: 'Charlotte · NC',         zips: '28277, 28270', trade: 'HVAC',       status: 'available', monthly: 250, ticket: '$640',   x: 770, y: 350 },
  { id: 'RDU-CRY-32', name: 'Cary',           region: 'Raleigh-Durham · NC',    zips: '27511–27519', trade: 'Electrical', status: 'available', monthly: 230, ticket: '$640',   x: 805, y: 335 },
  { id: 'JAX-MAN-33', name: 'Mandarin',       region: 'Jacksonville · FL',      zips: '32223–32258', trade: 'Plumbing',   status: 'available', monthly: 220, ticket: '$520',   x: 790, y: 435 },
  { id: 'TPA-CWT-34', name: 'Clearwater',     region: 'Tampa Bay · FL',         zips: '33755–33767', trade: 'Roofing',    status: 'available', monthly: 285, ticket: '$1,520', x: 790, y: 470 },
  { id: 'MIA-CRL-05', name: 'Coral Gables',   region: 'Miami metro · FL',       zips: '33134, 33146', trade: 'HVAC',       status: 'available', monthly: 305, ticket: '$640',   x: 830, y: 495 },
  { id: 'ORL-WIN-35', name: 'Winter Park',    region: 'Orlando · FL',           zips: '32789–32792', trade: 'HVAC',       status: 'reserved',  monthly: 270, ticket: '$640',   x: 815, y: 460 },
  { id: 'NOL-MET-36', name: 'Metairie',       region: 'New Orleans · LA',       zips: '70001–70006', trade: 'Plumbing',   status: 'available', monthly: 195, ticket: '$520',   x: 625, y: 460 },
  { id: 'BHM-HOO-37', name: 'Hoover',         region: 'Birmingham · AL',        zips: '35216–35244', trade: 'Roofing',    status: 'available', monthly: 175, ticket: '$1,420', x: 685, y: 405 },

  // Northeast
  { id: 'NYC-BKL-07', name: 'Brooklyn Hts.',  region: 'NYC · NY',               zips: '11201, 11231', trade: 'Electrical', status: 'reserved',  monthly: 220, ticket: '$640',   x: 870, y: 215 },
  { id: 'NYC-WCH-38', name: 'White Plains',   region: 'NYC metro · NY',         zips: '10601–10607', trade: 'Plumbing',   status: 'available', monthly: 285, ticket: '$580',   x: 870, y: 200 },
  { id: 'BOS-CMB-10', name: 'Cambridge',      region: 'Boston metro · MA',      zips: '02138–02142', trade: 'HVAC',       status: 'available', monthly: 245, ticket: '$640',   x: 895, y: 175 },
  { id: 'PHL-CHR-39', name: 'Cherry Hill',    region: 'Philadelphia metro · NJ', zips: '08002–08034', trade: 'Roofing',    status: 'available', monthly: 230, ticket: '$1,420', x: 855, y: 235 },
  { id: 'PIT-MTL-40', name: 'Mt. Lebanon',    region: 'Pittsburgh · PA',        zips: '15228, 15243', trade: 'Plumbing',   status: 'available', monthly: 195, ticket: '$520',   x: 790, y: 245 },
  { id: 'WAS-ARL-41', name: 'Arlington',      region: 'DC metro · VA',          zips: '22201–22209', trade: 'HVAC',       status: 'available', monthly: 295, ticket: '$640',   x: 830, y: 270 },
  { id: 'BAL-TWS-42', name: 'Towson',         region: 'Baltimore metro · MD',   zips: '21204, 21286', trade: 'Electrical', status: 'reserved',  monthly: 215, ticket: '$640',   x: 840, y: 255 },
  { id: 'HRT-WHF-43', name: 'West Hartford',  region: 'Hartford · CT',          zips: '06107, 06119', trade: 'HVAC',       status: 'available', monthly: 175, ticket: '$640',   x: 880, y: 200 },
];

// Held / claimed dots scattered across map — dense nationwide texture
const HELD_DOTS = [
  // Pacific Northwest
  { x: 165, y: 75 }, { x: 195, y: 105 }, { x: 175, y: 130 }, { x: 158, y: 155 }, { x: 185, y: 165 },
  { x: 215, y: 90 }, { x: 200, y: 120 }, { x: 150, y: 105 },
  // California / West
  { x: 138, y: 215 }, { x: 152, y: 235 }, { x: 165, y: 265 }, { x: 175, y: 290 }, { x: 188, y: 315 },
  { x: 195, y: 350 }, { x: 210, y: 365 }, { x: 215, y: 335 }, { x: 200, y: 305 }, { x: 178, y: 340 },
  { x: 230, y: 320 }, { x: 165, y: 195 }, { x: 148, y: 178 },
  // Mountain
  { x: 240, y: 145 }, { x: 265, y: 195 }, { x: 285, y: 215 }, { x: 250, y: 260 }, { x: 275, y: 285 },
  { x: 295, y: 245 }, { x: 320, y: 215 }, { x: 305, y: 270 }, { x: 335, y: 260 }, { x: 318, y: 320 },
  { x: 290, y: 330 }, { x: 270, y: 350 }, { x: 295, y: 380 }, { x: 340, y: 300 }, { x: 350, y: 240 },
  { x: 365, y: 195 }, { x: 380, y: 220 }, { x: 395, y: 245 }, { x: 410, y: 285 }, { x: 425, y: 260 },
  { x: 435, y: 295 }, { x: 360, y: 320 }, { x: 395, y: 355 }, { x: 420, y: 330 }, { x: 415, y: 380 },
  // Plains / Texas
  { x: 460, y: 215 }, { x: 480, y: 250 }, { x: 495, y: 285 }, { x: 470, y: 310 }, { x: 510, y: 270 },
  { x: 530, y: 300 }, { x: 550, y: 330 }, { x: 525, y: 360 }, { x: 495, y: 345 }, { x: 555, y: 395 },
  { x: 570, y: 365 }, { x: 595, y: 395 }, { x: 610, y: 420 }, { x: 565, y: 425 }, { x: 545, y: 455 },
  { x: 580, y: 460 }, { x: 510, y: 410 }, { x: 525, y: 440 }, { x: 460, y: 380 }, { x: 480, y: 360 },
  // Midwest
  { x: 555, y: 195 }, { x: 580, y: 220 }, { x: 605, y: 245 }, { x: 590, y: 270 }, { x: 565, y: 235 },
  { x: 615, y: 200 }, { x: 630, y: 250 }, { x: 655, y: 245 }, { x: 670, y: 215 }, { x: 685, y: 240 },
  { x: 660, y: 285 }, { x: 685, y: 310 }, { x: 700, y: 250 }, { x: 720, y: 270 }, { x: 695, y: 195 },
  { x: 540, y: 175 }, { x: 575, y: 155 }, { x: 615, y: 165 }, { x: 600, y: 145 },
  // South
  { x: 645, y: 320 }, { x: 670, y: 360 }, { x: 695, y: 370 }, { x: 720, y: 400 }, { x: 705, y: 420 },
  { x: 740, y: 380 }, { x: 755, y: 410 }, { x: 690, y: 440 }, { x: 660, y: 430 }, { x: 635, y: 430 },
  { x: 615, y: 460 }, { x: 645, y: 475 }, { x: 765, y: 360 }, { x: 745, y: 335 }, { x: 770, y: 395 },
  { x: 790, y: 405 }, { x: 800, y: 445 }, { x: 815, y: 470 }, { x: 835, y: 460 }, { x: 825, y: 480 },
  { x: 780, y: 425 }, { x: 800, y: 470 }, { x: 760, y: 445 },
  // Appalachia / Mid-Atlantic
  { x: 740, y: 290 }, { x: 760, y: 305 }, { x: 770, y: 280 }, { x: 785, y: 300 }, { x: 805, y: 285 },
  { x: 820, y: 305 }, { x: 745, y: 260 }, { x: 765, y: 250 }, { x: 805, y: 330 },
  // Northeast
  { x: 825, y: 235 }, { x: 845, y: 220 }, { x: 855, y: 245 }, { x: 875, y: 230 }, { x: 860, y: 260 },
  { x: 880, y: 250 }, { x: 845, y: 195 }, { x: 870, y: 165 }, { x: 885, y: 195 }, { x: 855, y: 175 },
  { x: 895, y: 205 }, { x: 905, y: 185 }, { x: 825, y: 200 }, { x: 810, y: 215 },
];

// Lower-48 US silhouette path on a 1000x560 viewBox.
// Hand-tuned approximation — recognizably USA: PNW corner, CA hook,
// Texas wedge, Florida peninsula, Maine notch, Great Lakes indent.
const US_PATH = "M138,90 L175,80 L215,75 L260,72 L320,72 L385,72 L450,75 L520,78 L595,82 L665,85 L735,90 L800,98 L835,108 L838,135 L848,158 L862,178 L880,165 L895,178 L905,200 L895,218 L878,225 L862,212 L848,225 L835,242 L818,245 L800,238 L800,260 L815,275 L805,295 L795,318 L788,340 L795,360 L808,380 L820,402 L835,435 L838,468 L825,492 L810,515 L795,520 L782,498 L775,475 L765,455 L750,440 L730,438 L712,445 L695,452 L678,456 L658,452 L640,460 L625,468 L605,470 L582,468 L562,462 L545,468 L525,470 L505,468 L485,460 L465,450 L445,442 L425,438 L405,438 L385,442 L365,448 L345,450 L325,448 L308,438 L292,425 L278,408 L265,388 L252,365 L240,340 L228,315 L218,288 L208,260 L195,232 L180,208 L165,188 L148,168 L138,148 L132,125 L130,108 Z";

// Latitude/longitude graticule reference dots for grid backdrop
const GRATICULE_DOTS = [];

function TerritoryMap() {
  const [selected, setSelected] = useState('CHI-OAK-04');
  const [hover, setHover] = useState(null);
  const [tipPos, setTipPos] = useState({ x: 0, y: 0 });
  const boardRef = useRef(null);

  const sel = PARCELS.find(p => p.id === selected) || PARCELS[0];

  function showTip(e, label, status) {
    setHover({ name: label, status });
    const rect = boardRef.current.getBoundingClientRect();
    const r = e.currentTarget.getBoundingClientRect();
    setTipPos({ x: r.left - rect.left + r.width / 2, y: r.top - rect.top });
  }

  return (
    <div className="territory-wrap">
      <div className="territory-board" ref={boardRef}>
        <div className="tboard-header">
          <div className="tboard-title">REGISTRY · UNITED STATES · 142 OPEN</div>
          <div className="legend">
            <div className="legend-item"><span className="legend-dot" style={{ background: '#e8a04a' }}></span>Available</div>
            <div className="legend-item"><span className="legend-dot" style={{ background: '#4a4842' }}></span>Held</div>
            <div className="legend-item"><span className="legend-dot" style={{ background: 'transparent', border: '1px dashed #6a6258' }}></span>Reserved</div>
          </div>
        </div>

        <div style={{ position: 'relative', background: '#0b0d10', borderRadius: 8, border: '1px solid rgba(255,255,255,0.06)', padding: 18, overflow: 'hidden' }}>
          {/* Latitude graticule */}
          <svg viewBox="0 0 1000 560" style={{ display: 'block', width: '100%', height: 'auto' }}>
            <defs>
              <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.03)" strokeWidth="1"/>
              </pattern>
              <radialGradient id="glowAvail" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#e8a04a" stopOpacity="0.45"/>
                <stop offset="100%" stopColor="#e8a04a" stopOpacity="0"/>
              </radialGradient>
            </defs>
            <rect width="1000" height="560" fill="url(#grid)"/>

            {/* US silhouette */}
            <path d={US_PATH}
              fill="rgba(255,255,255,0.025)"
              stroke="rgba(232,160,74,0.22)"
              strokeWidth="1"
              strokeDasharray="2 3"
            />
            <path d={US_PATH} fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>

            {/* Held parcels — small dim squares */}
            {HELD_DOTS.map((d, i) => (
              <rect key={i} x={d.x - 3} y={d.y - 3} width="6" height="6" fill="#4a4842" rx="1"/>
            ))}

            {/* Featured parcels (interactive) */}
            {PARCELS.map(p => {
              const isSel = p.id === selected;
              const isAvail = p.status === 'available';
              const size = isSel ? 14 : 10;
              return (
                <g key={p.id}
                   style={{ cursor: 'pointer' }}
                   onClick={() => setSelected(p.id)}
                   onMouseEnter={(e) => showTip(e, `${p.id} · ${p.name}`, isAvail ? 'Available now' : 'Reserved')}
                   onMouseLeave={() => setHover(null)}>
                  {isAvail && (
                    <circle cx={p.x} cy={p.y} r={isSel ? 32 : 22} fill="url(#glowAvail)"/>
                  )}
                  <rect
                    x={p.x - size/2} y={p.y - size/2}
                    width={size} height={size}
                    rx="1.5"
                    fill={isAvail ? '#e8a04a' : 'transparent'}
                    stroke={isAvail ? '#f6c886' : '#8a7d68'}
                    strokeWidth={isAvail ? 0 : 1.4}
                    strokeDasharray={isAvail ? '' : '2 2'}
                  />
                  {isSel && (
                    <rect x={p.x - size/2 - 4} y={p.y - size/2 - 4}
                          width={size + 8} height={size + 8}
                          fill="none" stroke="#f1ece2" strokeWidth="1.2" rx="2.5"/>
                  )}
                  {isAvail && (
                    <circle cx={p.x} cy={p.y} r={isSel ? 18 : 13}
                            fill="none" stroke="#e8a04a" strokeOpacity="0.55" strokeWidth="1">
                      <animate attributeName="r" from={isSel ? 8 : 6} to={isSel ? 26 : 20} dur="2.4s" repeatCount="indefinite"/>
                      <animate attributeName="stroke-opacity" from="0.6" to="0" dur="2.4s" repeatCount="indefinite"/>
                    </circle>
                  )}
                </g>
              );
            })}
          </svg>

          {hover && (
            <div className="parcel-tooltip show" style={{ left: tipPos.x, top: tipPos.y }}>
              <div>{hover.name}</div>
              <div className="t-status">{hover.status}</div>
            </div>
          )}
        </div>

        {/* Network ticker */}
        <div style={{
          marginTop: 16, paddingTop: 14,
          borderTop: '1px solid rgba(255,255,255,0.06)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          fontFamily: 'JetBrains Mono, monospace',
          fontSize: 10, color: '#5c594f', letterSpacing: '0.1em', flexWrap: 'wrap', gap: 8
        }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
            <span className="pulse-dot"></span>
            <span style={{ color: '#c9c3b6' }}>NETWORK · 84,210 INBOUND JOBS THIS MONTH</span>
          </span>
          <span>UPDATED 05.03.26 09:41 UTC</span>
        </div>
      </div>

      {/* Detail panel */}
      <div className="territory-detail">
        <div className={`detail-stamp ${sel.status}`}>
          {sel.status === 'available' ? '◉ Available now' : sel.status === 'reserved' ? '◐ Under contract review' : '● Held'}
        </div>
        <div className="detail-id">PARCEL · {sel.id}</div>
        <div className="detail-name">{sel.name}</div>
        <div className="detail-region">{sel.region} · {sel.trade}</div>

        <div className="detail-rows">
          <div className="detail-row"><span className="k">ZIP coverage</span><span className="v mono">{sel.zips}</span></div>
          <div className="detail-row"><span className="k">Inbound / mo</span><span className="v">~{sel.monthly} jobs</span></div>
          <div className="detail-row"><span className="k">Avg ticket</span><span className="v">{sel.ticket}</span></div>
          <div className="detail-row"><span className="k">Trade</span><span className="v">{sel.trade}</span></div>
        </div>

        <div className="detail-cta">
          {sel.status === 'available' ? (
            <a className="btn btn-primary" href="#claim">Claim this parcel →</a>
          ) : sel.status === 'reserved' ? (
            <a className="btn btn-ghost" href="#">Join waitlist</a>
          ) : (
            <div className="detail-claimed-by">
              <div className="avatar">●</div>
              <div>Held by operator · 4y 2mo</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ============================================
// FAQ
// ============================================
const FAQS = [
  {
    q: "What exactly am I paying for each month?",
    a: "A flat hold fee on the parcel. That covers all the demand-gen we run for it — paid search, SEO, branded micro-sites, direct response — plus exclusive routing of every inbound job inside it. No per-lead pricing, no surprise charges."
  },
  {
    q: "What if Parcel can't generate enough demand?",
    a: "Every parcel ships with a guaranteed monthly inbound floor written into your contract. If we miss it, your hold fee is credited that month. We only put a parcel on the registry once we've validated the demand model in that market."
  },
  {
    q: "Can someone else come in and outbid me?",
    a: "No. As long as you're an operator in good standing, the parcel is yours. If you ever decide to step away, you get right-of-first-refusal before it returns to the registry."
  },
  {
    q: "What trades do you currently operate?",
    a: "Plumbing, HVAC, electrical, roofing, garage doors, pest control, and tree service. We add a new vertical roughly every quarter based on operator demand."
  },
  {
    q: "How small can a parcel get?",
    a: "Parcels are sized to one operator's capacity. A small parcel might be 3–4 zip codes; a large one a full metro. We sit down with you to right-size before you sign."
  },
  {
    q: "What happens to my brand?",
    a: "It stays yours. We operate the demand-gen properties under a co-branded shell, but every booked customer becomes your customer of record. You keep the relationship, the reviews, and the lifetime value."
  },
];

function FAQ() {
  const [open, setOpen] = useState(0);
  return (
    <div className="faq-list">
      {FAQS.map((f, i) => (
        <div key={i} className={`faq-item ${open === i ? 'open' : ''}`} onClick={() => setOpen(open === i ? -1 : i)}>
          <div className="faq-q">
            <div className="faq-q-text">{f.q}</div>
            <div className="faq-toggle">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
              </svg>
            </div>
          </div>
          <div className="faq-a">{f.a}</div>
        </div>
      ))}
    </div>
  );
}

// ============================================
// Tweaks
// ============================================
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#e8a04a",
  "headlineStyle": "italic-accent",
  "tagline": "Own your market.",
  "density": "comfortable"
}/*EDITMODE-END*/;

function TweakRoot() {
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  // Apply CSS variables
  useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty('--accent', tweaks.accent);
    // Lighten for accent-2
    root.style.setProperty('--accent-2', shade(tweaks.accent, 0.25));
  }, [tweaks.accent]);

  // Headline style: italic-accent | underline | block
  useEffect(() => {
    document.querySelectorAll('h1.hero-title .accent, h2.sec-title .accent, .cta-title .accent').forEach(el => {
      if (tweaks.headlineStyle === 'italic-accent') {
        el.style.fontFamily = "'Instrument Serif', serif";
        el.style.fontStyle = 'italic';
        el.style.fontWeight = '400';
        el.style.borderBottom = 'none';
        el.style.background = 'none';
        el.style.padding = '0';
      } else if (tweaks.headlineStyle === 'underline') {
        el.style.fontFamily = "'Inter Tight', sans-serif";
        el.style.fontStyle = 'normal';
        el.style.fontWeight = '500';
        el.style.borderBottom = `3px solid ${tweaks.accent}`;
        el.style.background = 'none';
        el.style.padding = '0 0 4px';
      } else {
        el.style.fontFamily = "'Inter Tight', sans-serif";
        el.style.fontStyle = 'normal';
        el.style.fontWeight = '500';
        el.style.color = '#1a1410';
        el.style.background = tweaks.accent;
        el.style.padding = '0 12px';
        el.style.borderBottom = 'none';
      }
    });
  }, [tweaks.headlineStyle, tweaks.accent]);

  // Density
  useEffect(() => {
    document.querySelectorAll('section.sec').forEach(el => {
      el.style.padding = tweaks.density === 'tight' ? '80px 0' : tweaks.density === 'spacious' ? '160px 0' : '120px 0';
    });
  }, [tweaks.density]);

  // Tagline
  useEffect(() => {
    const heroTitle = document.querySelector('h1.hero-title');
    if (heroTitle && tweaks.tagline) {
      const accentSpan = heroTitle.querySelector('.accent');
      if (accentSpan) accentSpan.textContent = tweaks.tagline;
    }
  }, [tweaks.tagline]);

  const { TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakText } = window;

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Color">
        <TweakColor label="Accent" value={tweaks.accent} onChange={v => setTweak('accent', v)} />
      </TweakSection>
      <TweakSection title="Headline accent style">
        <TweakRadio
          value={tweaks.headlineStyle}
          onChange={v => setTweak('headlineStyle', v)}
          options={[
            { value: 'italic-accent', label: 'Italic' },
            { value: 'underline', label: 'Underline' },
            { value: 'block', label: 'Block' },
          ]}
        />
      </TweakSection>
      <TweakSection title="Tagline">
        <TweakText value={tweaks.tagline} onChange={v => setTweak('tagline', v)} />
      </TweakSection>
      <TweakSection title="Density">
        <TweakRadio
          value={tweaks.density}
          onChange={v => setTweak('density', v)}
          options={[
            { value: 'tight', label: 'Tight' },
            { value: 'comfortable', label: 'Comfortable' },
            { value: 'spacious', label: 'Spacious' },
          ]}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

function shade(hex, amount) {
  // Lighten hex color by amount (0..1)
  const h = hex.replace('#', '');
  const r = parseInt(h.substring(0, 2), 16);
  const g = parseInt(h.substring(2, 4), 16);
  const b = parseInt(h.substring(4, 6), 16);
  const nr = Math.min(255, Math.round(r + (255 - r) * amount));
  const ng = Math.min(255, Math.round(g + (255 - g) * amount));
  const nb = Math.min(255, Math.round(b + (255 - b) * amount));
  return '#' + [nr, ng, nb].map(x => x.toString(16).padStart(2, '0')).join('');
}

// ============================================
// Mount everything
// ============================================
ReactDOM.createRoot(document.getElementById('hero-card-mount')).render(<HeroParcelCard />);
ReactDOM.createRoot(document.getElementById('territory-mount')).render(<TerritoryMap />);
ReactDOM.createRoot(document.getElementById('faq-mount')).render(<FAQ />);

// Tweaks root — separate mount
const tweakNode = document.createElement('div');
document.body.appendChild(tweakNode);
ReactDOM.createRoot(tweakNode).render(<TweakRoot />);
