const { useState, useEffect, useRef } = React;

// ─── Logo ───
const PT_LOGO = "data:image/jpeg;base64,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";

// ─── Brand tokens ───
const N = {
  navy:    "#0F1E35", navyMid: "#1A2E4A", navyDeep: "#0A1628",
  navySoft:"#243D5E", gold:    "#C9A84C", goldDim:  "rgba(201,168,76,0.12)",
  goldLine:"rgba(201,168,76,0.25)", goldGlow:"rgba(201,168,76,0.06)",
  parch:   "#EDE8DF", parchD:  "rgba(237,232,223,0.55)", parchF: "rgba(237,232,223,0.1)",
  teal: "#2A9D8F", green: "#5CB85C", coral: "#E76F51", sky: "#5B9BD5", purple: "#7B68EE",
};


// ─── SVG Icon System (no emoji) ───
function Icon({name, size=20, color="currentColor", style={}}){
  const icons = {
    home: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>,
    plane: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"/></svg>,
    chat: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>,
    star: <svg width={size} height={size} viewBox="0 0 24 24" fill={color} stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>,
    users: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75"/></svg>,
    person: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>,
    map: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>,
    dollar: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/></svg>,
    doc: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>,
    hotel: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><rect x="2" y="2" width="20" height="20" rx="2"/><path d="M9 22V12h6v10M2 7h20"/></svg>,
    dining: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M18 8h1a4 4 0 010 8h-1"/><path d="M2 8h16v9a4 4 0 01-4 4H6a4 4 0 01-4-4V8z"/><line x1="6" y1="1" x2="6" y2="4"/><line x1="10" y1="1" x2="10" y2="4"/><line x1="14" y1="1" x2="14" y2="4"/></svg>,
    car: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><rect x="1" y="3" width="15" height="13"/><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg>,
    activity: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>,
    leisure: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>,
    upload: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polyline points="16 16 12 12 8 16"/><line x1="12" y1="12" x2="12" y2="21"/><path d="M20.39 18.39A5 5 0 0018 9h-1.26A8 8 0 103 16.3"/></svg>,
    check: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polyline points="20 6 9 17 4 12"/></svg>,
    arrow: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>,
    down: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><polyline points="8 6 12 10 16 6"/></svg>,
    edit: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>,
    send: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>,
    plus: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>,
    lock: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>,
    globe: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg>,
    close: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>,
    gear: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009.6 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9.6a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9c.26.604.852 1 1.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>,
    logout: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>,
    bell: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg>,
    alertTriangle: <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={style}><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>,
  };
  return icons[name] || null;
}

// ─── Mock data ───
const TRIPS = [
  { id:1, client:"Marcus W.", initials:"MW", type:"Corporate", destination:"New York City",
    subdest:"United States", dates:"Mar 10–14, 2027", nights:5, startDate:"2027-03-10", endDate:"2027-03-14", status:"Active", tier:"Executive", unread:2,
    hotel:"Four Seasons NYC Downtown", flight:"Delta DL 1847 · First Class", nextEvent:"Flight departs 9:15 AM",
    days:[
      { n:1, title:"Arrival & Check-In", date:"Mon Mar 10",
        entries:[
          {time:"9:15 AM", cat:"flight",    icon:"·", name:"Delta DL 1847 · AGS → JFK",        detail:"First Class · Seat 2A · Conf: DELTA-XK2891"},
          {time:"11:45 AM",cat:"transfer",  icon:"·", name:"Hertz · JFK → Four Seasons",detail:"Driver curbside T4 · ~45 min · Traffic accounted for"},
          {time:"12:30 PM",cat:"hotel",     icon:"·", name:"Four Seasons New York Downtown",    detail:"King Suite · Floor 38 · Early check-in confirmed · Conf: FS-NYC-88291"},
          {time:"3:00 PM", cat:"leisure",   icon:"·", name:"Exhale Spa · 60-min Deep Tissue",   detail:"Pre-booked · Cancellable until 2:30 PM"},
          {time:"7:30 PM", cat:"dining",    icon:"·", name:"Nobu Downtown",                    detail:"Omakase counter · No shellfish on file · Conf: NOBU-39871"},
        ]},
      { n:2, title:"Business & Midtown", date:"Tue Mar 11",
        entries:[
          {time:"7:45 AM", cat:"dining",    icon:"·", name:"In-Room Breakfast — Pre-ordered",   detail:"Steel cut oats, egg whites, cold brew · No need to call down"},
          {time:"9:30 AM", cat:"transfer",  icon:"·", name:"Hotel → 1221 Ave of the Americas",  detail:"Private car · Driver in lobby 9:15 AM"},
          {time:"10:00 AM",cat:"activity",  icon:"·", name:"Client Meeting — Harrington Group",  detail:"Suite 3400 · David Park (917) 555-0382 · ~90 min"},
          {time:"12:30 PM",cat:"dining",    icon:"·", name:"The Modern — MoMA",                 detail:"Table for 2 · Client lunch · Conf: MOD-11029"},
          {time:"8:00 PM", cat:"dining",    icon:"·", name:"Le Bernardin",                       detail:"3 Michelin Stars · Shellfish-free tasting menu confirmed · Conf: LB-92047"},
        ]},
      { n:3, title:"Financial District & Evening", date:"Wed Mar 12",
        entries:[
          {time:"7:30 AM", cat:"dining",    icon:"·", name:"In-Room Breakfast",                  detail:"Pre-ordered · Cold brew, egg whites, avocado toast"},
          {time:"9:00 AM", cat:"transfer",  icon:"·", name:"Hotel → One World Trade Center",     detail:"Private car · Driver in lobby 8:45 AM · ~10 min"},
          {time:"9:30 AM", cat:"activity",  icon:"·", name:"Meeting — Meridian Capital Partners", detail:"82nd Floor · James Thornton (212) 555-0741 · Due diligence review · ~2 hrs"},
          {time:"12:00 PM",cat:"dining",    icon:"·", name:"Manhatta — Lunch",                   detail:"28 Liberty St · 60th Floor · Private table · Conf: MAN-30821"},
          {time:"2:30 PM", cat:"activity",  icon:"·", name:"Meeting — Blackstone Group",         detail:"345 Park Ave · Conference Room 14B · ~90 min · Car on standby"},
          {time:"5:00 PM", cat:"transfer",  icon:"·", name:"Midtown → Four Seasons",             detail:"Private car · Driver waiting at 345 Park Ave lobby"},
          {time:"6:30 PM", cat:"leisure",   icon:"·", name:"Four Seasons Spa — Steam & Recovery",detail:"60-min recovery session · Pre-booked · Floor 5"},
          {time:"8:30 PM", cat:"dining",    icon:"·", name:"Eleven Madison Park",                detail:"11 Madison Ave · Chef's tasting menu · Shellfish-free noted · Conf: EMP-77412"},
        ]},
      { n:4, title:"Uptown & Leisure", date:"Thu Mar 13",
        entries:[
          {time:"8:00 AM", cat:"dining",    icon:"·", name:"In-Room Breakfast",                  detail:"Pre-ordered · Fruit, granola, cold brew"},
          {time:"9:30 AM", cat:"leisure",   icon:"·", name:"Central Park — Morning Walk",        detail:"Self-guided · Suggested route: Columbus Circle → Bethesda Terrace · ~1 hr"},
          {time:"11:00 AM",cat:"activity",  icon:"·", name:"Meeting — Atlas Ventures",           detail:"510 Madison Ave · Suite 2100 · Sarah Kim (212) 555-0399 · ~90 min"},
          {time:"1:00 PM", cat:"dining",    icon:"·", name:"The Grill — Lunch",                  detail:"99 E 52nd St · The Seagram Building · Private dining room · Conf: TGR-44201"},
          {time:"3:30 PM", cat:"leisure",   icon:"·", name:"The Metropolitan Museum of Art",     detail:"Curator-led private tour · Egyptian Wing + Modern Art · 1.5 hrs · Pre-arranged"},
          {time:"6:00 PM", cat:"transfer",  icon:"·", name:"Met → Four Seasons",                 detail:"Private car · Driver waiting at 82nd St entrance"},
          {time:"7:00 PM", cat:"leisure",   icon:"·", name:"Four Seasons — Lobby Lounge",        detail:"Pre-dinner drinks · Reservation not required"},
          {time:"8:00 PM", cat:"dining",    icon:"·", name:"Per Se",                             detail:"10 Columbus Circle · Thomas Keller · Shellfish-free tasting noted · Conf: PS-18843"},
        ]},
      { n:5, title:"Departure Day", date:"Fri Mar 14",
        entries:[
          {time:"7:00 AM", cat:"dining",    icon:"·", name:"In-Room Breakfast",                  detail:"Light continental · Pre-arranged · Charged to room"},
          {time:"8:30 AM", cat:"hotel",     icon:"·", name:"Four Seasons Check-Out",             detail:"Express checkout · Luggage to lobby by 8:15 AM · Bellman confirmed"},
          {time:"9:30 AM", cat:"transfer",  icon:"·", name:"Hertz · Four Seasons → JFK Airport", detail:"Private sedan · Driver in lobby 9:15 AM · ~50 min allow traffic"},
          {time:"11:00 AM",cat:"leisure",   icon:"·", name:"Delta Sky Club — JFK T4",            detail:"Level 3 · Access with First Class ticket · Shower available"},
          {time:"8:15 PM", cat:"flight",    icon:"·", name:"Delta DL 1848 · JFK → AGS",         detail:"First Class · Seat 2A · Departure on time"},
        ]},
    ],
    docs:[
      {name:"Flight Confirmation",  icon:"plane", size:"124 KB", date:"Mar 1"},
      {name:"Hotel Booking",        icon:"hotel", size:"98 KB",  date:"Mar 1"},
      {name:"Full Itinerary",       icon:"doc", size:"312 KB", date:"Mar 3"},
      {name:"Dinner Reservations",  icon:"dining", size:"76 KB",  date:"Mar 2"},
      {name:"Ground Transport",     icon:"car", size:"54 KB",  date:"Mar 1"},
    ],
    profile:{name:"Marcus W.", email:"marcus@company.com", phone:"+1 (404) 555-0192",
      cabin:"First Class", seat:"Window · Exit row if available", hotel:"Four Seasons · Ritz-Carlton",
      dietary:"No shellfish", schedule:"Fully planned", downtime:"Spa · Early hotel return",
      loyalty:"Delta Platinum · Marriott Gold", tsa:"Known Traveler: PT-1291"},
    hotelAddress:"121 Church St, New York, NY 10007",
    hotelPhone:"(212) 584-4800",hotelPhoneHref:"tel:+12125844800",
    carCompany:"Hertz",carPickup:"JFK Airport",carPickupTime:"12:18 PM",carDropoff:"JFK Airport",carDropoffTime:"5:15 PM",
    flightOut:"Delta · DL 1847",flightOutTime:"9:15 AM",flightOutArrivalTime:"11:48 AM",flightOutDate:"Mar 10, 2027",
    flightReturn:"Delta · DL 1848",flightReturnTime:"8:15 PM",flightReturnArrivalTime:"10:42 PM",flightReturnDate:"Mar 14, 2027",
  },
  { id:0, client:"Marcus W.", initials:"MW", type:"Corporate", destination:"London, England",
    subdest:"United Kingdom", dates:"Jan 12–17, 2026", nights:5, startDate:"2026-01-12", endDate:"2026-01-17", status:"Completed", tier:"Executive", unread:0,
    hotel:"The Savoy", flight:"British Airways BA 221 · First Class", nextEvent:"Completed",
    days:[
      {n:1,title:"Arrival & The Savoy",date:"Mon Jan 12",entries:[
        {time:"7:00 AM",cat:"flight",icon:"·",name:"British Airways BA 221 · AGS → LHR",detail:"First Class · Seat 1A · Conf: BA-XK7741"},
        {time:"7:25 PM",cat:"transfer",icon:"·",name:"Blacklane · LHR → The Savoy",detail:"Private sedan · Driver at arrivals · ~50 min"},
        {time:"9:00 PM",cat:"hotel",icon:"·",name:"The Savoy Check-In",detail:"River Suite · Floor 5 · Thames view · Conf: SAV-29871"},
        {time:"9:30 PM",cat:"dining",icon:"·",name:"The Savoy Grill",detail:"In-hotel dining · No shellfish noted · Conf: SG-44102"},
      ]},
      {n:2,title:"Business & Mayfair",date:"Tue Jan 13",entries:[
        {time:"8:00 AM",cat:"dining",icon:"·",name:"In-Room Breakfast",detail:"Pre-ordered · Full English, no shellfish · Delivered 8:00 AM"},
        {time:"9:30 AM",cat:"transfer",icon:"·",name:"The Savoy → Mayfair Office",detail:"Private car · Driver in lobby 9:15 AM"},
        {time:"10:00 AM",cat:"activity",icon:"·",name:"Client Meeting — Pemberton Capital",detail:"30 Berkeley Square · Mark Pemberton (44) 20 7946 0392 · ~2 hrs"},
        {time:"12:30 PM",cat:"dining",icon:"·",name:"Scott's Restaurant Mayfair",detail:"Mount Street · Private booth · Conf: SCOTTS-88201"},
        {time:"3:00 PM",cat:"activity",icon:"·",name:"Legal Review — Clifford Chance",detail:"10 Upper Bank St · Anna Hayes · Conf documentation"},
        {time:"7:30 PM",cat:"dining",icon:"·",name:"The Ritz Restaurant",detail:"150 Piccadilly · Dress code enforced · Conf: RITZ-10294"},
      ]},
      {n:3,title:"City & Culture",date:"Wed Jan 14",entries:[
        {time:"8:30 AM",cat:"dining",icon:"·",name:"The River Restaurant — Savoy",detail:"Breakfast with Thames view"},
        {time:"10:00 AM",cat:"activity",icon:"·",name:"Meeting — Barclays Canary Wharf",detail:"1 Churchill Place · James Whitfield · Due diligence session"},
        {time:"1:00 PM",cat:"dining",icon:"·",name:"Hawksmoor Guildhall",detail:"10 Basinghall St · Private dining room · Conf: HAWK-55392"},
        {time:"3:30 PM",cat:"leisure",icon:"·",name:"The Savoy Spa — 90-min Treatment",detail:"Pre-booked · Sports massage · Cancellable until 2:30 PM"},
        {time:"8:00 PM",cat:"dining",icon:"·",name:"Alain Ducasse at The Dorchester",detail:"Park Lane · 3 Michelin stars · Shellfish-free menu confirmed · Conf: AD-38871"},
      ]},
      {n:4,title:"Westminster & Leisure",date:"Thu Jan 15",entries:[
        {time:"9:00 AM",cat:"leisure",icon:"·",name:"Morning Walk — Embankment",detail:"Self-guided · Thames path from Savoy to Tower Bridge · ~1 hr"},
        {time:"11:00 AM",cat:"activity",icon:"·",name:"Meeting — Cabinet Office",detail:"70 Whitehall · Security pre-clearance confirmed · Photo ID required"},
        {time:"1:30 PM",cat:"dining",icon:"·",name:"Rules Restaurant",detail:"Oldest restaurant in London · 35 Maiden Lane · Conf: RULES-20193"},
        {time:"4:00 PM",cat:"leisure",icon:"·",name:"National Gallery — Private Tour",detail:"Trafalgar Square · Booked curator-led tour · 1.5 hrs"},
        {time:"8:30 PM",cat:"activity",icon:"·",name:"Royal Opera House",detail:"Covent Garden · Box seats · La Traviata · Conf: ROH-77102"},
      ]},
      {n:5,title:"Final Meetings & Shopping",date:"Fri Jan 16",entries:[
        {time:"8:00 AM",cat:"dining",icon:"·",name:"Breakfast — The Savoy Grill",detail:"À la carte · Charged to room"},
        {time:"10:00 AM",cat:"activity",icon:"·",name:"Final Briefing — Pemberton Capital",detail:"Berkeley Square · Contract signatures · ~1.5 hrs"},
        {time:"12:30 PM",cat:"dining",icon:"·",name:"C Restaurant at The Ivy",detail:"West Street · Private dining · Conf: IVY-44910"},
        {time:"3:00 PM",cat:"leisure",icon:"·",name:"Bond Street & Harrods",detail:"Scheduled car available · Driver on standby"},
        {time:"7:00 PM",cat:"dining",icon:"·",name:"Sketch — The Lecture Room",detail:"9 Conduit St · Mayfair · 2 Michelin stars · Conf: SK-91043"},
      ]},
      {n:6,title:"Departure Day",date:"Sat Jan 17",entries:[
        {time:"7:00 AM",cat:"dining",icon:"·",name:"Early Breakfast — The Savoy",detail:"Light continental · Pre-arranged · Room charge"},
        {time:"8:30 AM",cat:"hotel",icon:"·",name:"The Savoy Check-Out",detail:"12:00 PM standard · Early departure arranged · Luggage stored until transfer"},
        {time:"9:00 AM",cat:"leisure",icon:"·",name:"Final Morning Walk — Covent Garden",detail:"Self-guided · Last look at the city · 45 min"},
        {time:"10:30 AM",cat:"transfer",icon:"·",name:"Blacklane · The Savoy → LHR T5",detail:"Private sedan · Departure 10:30 AM · ~1 hr · Driver confirmed"},
        {time:"12:30 PM",cat:"activity",icon:"·",name:"BA First Lounge — Concorde Room",detail:"Level 5 · Pre-book spa · Free access with First Class ticket"},
        {time:"2:30 PM",cat:"flight",icon:"·",name:"British Airways BA 222 · LHR → AGS",detail:"First Class · Seat 1A · Conf: BA-RT8820"},
      ]},
    ],docs:[{name:"London Itinerary.pdf",icon:"doc",size:"182 KB",date:"Jan 3"}],
    hotelAddress:"Strand, London WC2R 0EZ",hotelPhone:"+44 20 7836 4343",hotelPhoneHref:"tel:+442078364343",
    carCompany:"Blacklane",carPickup:"LHR Airport",carPickupTime:"7:45 PM",carDropoff:"LHR Airport",carDropoffTime:"3:30 PM",
    flightOut:"British Airways · BA 221",flightOutTime:"7:00 AM",flightOutArrivalTime:"7:15 PM",flightOutDate:"Jan 12, 2026",
    flightReturn:"British Airways · BA 222",flightReturnTime:"6:30 PM",flightReturnArrivalTime:"9:15 PM",flightReturnDate:"Jan 17, 2026",
    profile:{name:"Marcus W.",email:"marcus@company.com",phone:"+1 (404) 555-0192",cabin:"First Class",seat:"Window",hotel:"The Savoy",dietary:"No shellfish",schedule:"Fully planned",downtime:"Spa",loyalty:"BA Gold / Marriott Bonvoy",tsa:"TSA PreCheck · KTN: A8B2C1"},
    type:"Corporate",
  },
  { id:2, client:"Johnson Family", initials:"JF", type:"Family", destination:"Cancún, Mexico",
    subdest:"Caribbean", dates:"Jul 4–11, 2027", nights:7, startDate:"2027-07-04", endDate:"2027-07-11", status:"Upcoming", tier:"Adventure", unread:0,
    hotel:"Excellence Playa Mujeres", flight:"Delta DL 2041 · Economy Plus", nextEvent:"78 days until departure",
    days:[
      { n:1, title:"Travel Day & Arrival", date:"Sat Jul 4",
        entries:[
          {time:"5:30 AM", cat:"transfer",  icon:"·", name:"Home → Augusta Regional Airport",  detail:"XL SUV · Car seat installed · Snacks packed for kids"},
          {time:"8:00 AM", cat:"flight",    icon:"·", name:"Delta DL 2041 · AGS → CUN",        detail:"Economy Plus · Seats 12A–D · Family row confirmed"},
          {time:"12:30 PM",cat:"hotel",     icon:"·", name:"Excellence Playa Mujeres",          detail:"2-bed ocean suite · All-inclusive · Kids club registered · Conf: EPM-7741"},
          {time:"7:00 PM", cat:"dining",    icon:"·", name:"Agave — Resort Mexican Restaurant", detail:"Kids menu · No shellfish for Mom on file"},
        ]},
      { n:2, title:"Beach & Kids Club", date:"Sun Jul 5",
        entries:[
          {time:"8:00 AM", cat:"dining",    icon:"·", name:"Breakfast Buffet — Agave Terrace",  detail:"All-inclusive · Poolside seating · Kids eat free"},
          {time:"9:30 AM", cat:"leisure",   icon:"·", name:"Kids Club Drop-Off",                detail:"Ages 4–12 · Full day program · Staff ratio 3:1 · Pre-registered"},
          {time:"10:00 AM",cat:"leisure",   icon:"·", name:"Adults — Beach & Cabana",           detail:"Cabana #7 reserved · Towels & drinks included"},
          {time:"1:00 PM", cat:"dining",    icon:"·", name:"Lunch — Spice Beach Club",          detail:"Beachfront · Casual · All-inclusive"},
          {time:"3:00 PM", cat:"leisure",   icon:"·", name:"Family Pool Time",                  detail:"Kids rejoining at 3 PM · Family pool · Floaties available at towel bar"},
          {time:"7:00 PM", cat:"dining",    icon:"·", name:"Dinner — Chez Isabelle",            detail:"French cuisine · Resort main restaurant · Shellfish-free option confirmed"},
        ]},
      { n:3, title:"Isla Mujeres Excursion", date:"Mon Jul 6",
        entries:[
          {time:"7:30 AM", cat:"dining",    icon:"·", name:"Early Breakfast Buffet",            detail:"Grab-and-go items at lobby café · Depart by 8:00 AM"},
          {time:"8:00 AM", cat:"transfer",  icon:"·", name:"Resort → Puerto Juárez Ferry",      detail:"Resort shuttle · ~20 min · Departs lobby 8:00 AM"},
          {time:"8:45 AM", cat:"activity",  icon:"·", name:"Ferry to Isla Mujeres",             detail:"Ultramar ferry · 20-min crossing · Round-trip tickets pre-purchased"},
          {time:"10:00 AM",cat:"activity",  icon:"·", name:"Golf Cart Rental — Island Tour",   detail:"4-seat cart · ~3 hrs · Punta Sur, sculptures, lighthouse"},
          {time:"1:00 PM", cat:"dining",    icon:"·", name:"Lunch — Lanchería Poc-Chuc",        detail:"Beachfront local restaurant · Fresh fish · Kid-friendly"},
          {time:"3:00 PM", cat:"leisure",   icon:"·", name:"Playa Norte Beach",                 detail:"Calm waters · Ideal for kids · Chair rentals on beach"},
          {time:"5:30 PM", cat:"transfer",  icon:"·", name:"Ferry Return to Cancún",            detail:"Last ferry 6:30 PM · Arrive ~7:00 PM · Shuttle back to resort"},
          {time:"8:00 PM", cat:"dining",    icon:"·", name:"Dinner — Flavor Market Buffet",     detail:"All-inclusive · International stations · Kids' favorites available"},
        ]},
      { n:4, title:"Water Park & Relaxation", date:"Tue Jul 7",
        entries:[
          {time:"8:30 AM", cat:"dining",    icon:"·", name:"Breakfast Buffet",                  detail:"Resort main buffet · Poolside"},
          {time:"9:30 AM", cat:"activity",  icon:"·", name:"Wet'n'Wild Cancún Water Park",      detail:"Tickets pre-purchased · Family of 4 · ~20 min from resort · Shuttle arranged"},
          {time:"1:00 PM", cat:"dining",    icon:"·", name:"Lunch at Water Park",               detail:"Food included with full-day ticket"},
          {time:"4:30 PM", cat:"transfer",  icon:"·", name:"Return to Resort",                  detail:"Shuttle picks up at main entrance · 4:30 PM"},
          {time:"6:00 PM", cat:"leisure",   icon:"·", name:"Spa — Couples Massage",             detail:"60-min · Ocean view treatment room · No shellfish products · Pre-booked"},
          {time:"8:00 PM", cat:"dining",    icon:"·", name:"Dinner — Krystal",                  detail:"Japanese-Peruvian fusion · Adults only · Kids Club dinner arranged"},
        ]},
      { n:5, title:"Chichen Itza Day Trip", date:"Wed Jul 8",
        entries:[
          {time:"6:30 AM", cat:"dining",    icon:"·", name:"Early Breakfast — Lobby Café",      detail:"Pre-packed items · Depart early for tour"},
          {time:"7:00 AM", cat:"transfer",  icon:"·", name:"Resort → Chichen Itza",             detail:"Private guided tour van · Family of 4 · ~2.5 hr drive · AC vehicle"},
          {time:"10:00 AM",cat:"activity",  icon:"·", name:"Chichen Itza Guided Tour",          detail:"Private English-speaking guide · El Castillo, Temple of Warriors · ~2 hrs"},
          {time:"12:30 PM",cat:"dining",    icon:"·", name:"Lunch — Hacienda Chichen",          detail:"On-site colonial hacienda · Yucatecan cuisine · Kids menu available"},
          {time:"2:00 PM", cat:"leisure",   icon:"·", name:"Cenote Ik Kil",                     detail:"Swim in natural cenote · Stairs to water · Life jackets available"},
          {time:"5:30 PM", cat:"transfer",  icon:"·", name:"Return to Resort",                  detail:"Private van · ~2.5 hr return · Kids can sleep en route"},
          {time:"8:30 PM", cat:"dining",    icon:"·", name:"Late Dinner — Agave",               detail:"All-inclusive · Casual · No reservation needed"},
        ]},
      { n:6, title:"Pool Day & Packing", date:"Thu Jul 10",
        entries:[
          {time:"9:00 AM", cat:"dining",    icon:"·", name:"Breakfast Buffet",                  detail:"Last full resort breakfast · Take your time"},
          {time:"10:00 AM",cat:"leisure",   icon:"·", name:"Final Beach & Pool Day",            detail:"Cabana available · Chairs held for family · No activities scheduled"},
          {time:"1:00 PM", cat:"dining",    icon:"·", name:"Lunch — Spice Beach Club",          detail:"Beachfront · All-inclusive"},
          {time:"4:00 PM", cat:"leisure",   icon:"·", name:"Souvenir Shopping — Hotel Boutiques",detail:"Resort boutiques + gift shop · Last chance"},
          {time:"7:00 PM", cat:"dining",    icon:"·", name:"Farewell Dinner — Chez Isabelle",   detail:"Special request: birthday décor for youngest · Pre-arranged"},
          {time:"9:00 PM", cat:"hotel",     icon:"·", name:"Pack & Prepare for Checkout",       detail:"Bags to lobby by 6:30 AM · Bellman can assist"},
        ]},
      { n:7, title:"Departure Day", date:"Fri Jul 11",
        entries:[
          {time:"6:00 AM", cat:"dining",    icon:"·", name:"Early Breakfast — Lobby Café",      detail:"Continental · Grab-and-go · Kids snacks packed"},
          {time:"6:30 AM", cat:"hotel",     icon:"·", name:"Excellence Check-Out",              detail:"Express checkout · Luggage to lobby 6:00 AM · Car seats retrieved from storage"},
          {time:"7:30 AM", cat:"transfer",  icon:"·", name:"Hertz · Resort → CUN Airport",      detail:"XL SUV · Driver at resort entrance · ~30 min"},
          {time:"9:30 AM", cat:"leisure",   icon:"·", name:"CUN Airport — Family Lounge",       detail:"Delta priority boarding with young children · Gate B22"},
          {time:"5:30 PM", cat:"flight",    icon:"·", name:"Delta DL 2042 · CUN → AGS",        detail:"Economy Plus · Family row 12A–D · Departure on time"},
        ]},
    ],
    docs:[
      {name:"Flight Confirmation",  icon:"plane", size:"108 KB", date:"Jun 1"},
      {name:"Resort Booking",       icon:"hotel", size:"142 KB", date:"Jun 1"},
      {name:"Family Itinerary",     icon:"doc", size:"445 KB", date:"Jun 5"},
      {name:"Excursion Bookings",   icon:"globe", size:"88 KB",  date:"Jun 4"},
    ],
    profile:{name:"Johnson Family (4)", email:"johnson@email.com", phone:"+1 (706) 555-0771",
      cabin:"Economy Plus", seat:"Family row together", hotel:"All-Inclusive Resort",
      dietary:"No shellfish (Mom)", schedule:"Mostly planned", downtime:"Beach · Pool · Kids club",
      loyalty:"Delta SkyMiles · Hilton Honors", tsa:"N/A"},
    hotelAddress:"Carretera Punta Sam km 3.1, Cancún, Mexico",
    hotelPhone:"+52 998 875 7400",hotelPhoneHref:"tel:+529988757400",
    carCompany:"Hertz",carPickup:"CUN Airport",carPickupTime:"11:45 AM",carDropoff:"CUN Airport",carDropoffTime:"2:30 PM",
    flightOut:"Delta · DL 2041",flightOutTime:"8:00 AM",flightOutArrivalTime:"11:15 AM",flightOutDate:"Jul 4",
    flightReturn:"Delta · DL 2042",flightReturnTime:"5:30 PM",flightReturnArrivalTime:"7:48 PM",flightReturnDate:"Jul 11",
  },
];

const CLIENTS = [
  {id:1, name:"Marcus W.",      initials:"MW", type:"Corporate", tier:"Executive", status:"Upcoming", next:"Mar 10, 2027", mem:"Annual",  unread:0, revenue:1500},
  {id:2, name:"Johnson Family", initials:"JF", type:"Family",    tier:"Adventure", status:"Upcoming", next:"Jul 4",  mem:"Annual",  unread:0, revenue:750},
  {id:3, name:"Simone T.",      initials:"ST", type:"Individual", tier:"Wanderer",  status:"Planning", next:"TBD",    mem:"Monthly", unread:0, revenue:399},
  {id:4, name:"David R.",       initials:"DR", type:"Corporate", tier:"Elite",     status:"Upcoming", next:"Apr 2, 2027",  mem:"Annual",  unread:0, revenue:3000},
];

const INIT_MSGS = [
  {id:1, from:"Marcus W.", time:"10:32 AM", text:"Can you confirm the Le Bernardin reservation is set for 8pm?", mine:false},
  {id:2, from:"Shayla L.",    time:"10:45 AM", text:"Confirmed! Table reserved under your name at 8:00 PM. Your no-shellfish preference is on file with the restaurant. You're all set.", mine:true},
  {id:3, from:"Marcus W.", time:"11:02 AM", text:"Perfect. What about the car Tuesday morning?", mine:false},
  {id:4, from:"Shayla L.",    time:"11:10 AM", text:"Private sedan confirmed. Driver will be in the hotel lobby at 9:15 AM with your name on a card. 22 minutes to your meeting — traffic already factored in.", mine:true},
];

// ─── Helpers ───
// Nights is always derived from the actual start/end dates, never typed in
// separately — that's the one number that should never be able to drift
// out of sync with the dates themselves. Returns null (not a fallback
// number) when either date is missing/invalid so callers can decide their
// own placeholder.
// Computed from a birthdate, never entered by hand — so it's always
// correct and never drifts out of date like a manually-typed age would.
function calcAge(birthdate){
  if(!birthdate) return null;
  const dob = new Date(birthdate+"T00:00:00");
  if(isNaN(dob)) return null;
  const now = new Date();
  let age = now.getFullYear()-dob.getFullYear();
  const m = now.getMonth()-dob.getMonth();
  if(m<0 || (m===0 && now.getDate()<dob.getDate())) age--;
  return age>=0 ? age : null;
}

function nightsBetween(startDate, endDate){
  if(!startDate || !endDate) return null;
  const start = new Date(startDate + "T00:00:00");
  const end = new Date(endDate + "T00:00:00");
  if(isNaN(start) || isNaN(end)) return null;
  const diff = Math.round((end - start) / (1000*60*60*24));
  return diff > 0 ? diff : null;
}

// Firestore timestamps come back as Timestamp objects (with .toDate()),
// not plain Dates or strings — this handles all three so a real client
// record's createdAt/agreedAt never throws when rendered.
function formatShortDate(value){
  if(!value) return "—";
  const d = typeof value.toDate==="function" ? value.toDate() : new Date(value);
  if(isNaN(d)) return "—";
  return d.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"});
}

// ─── Destination photos ───
// Looks up a real photo for any real destination (not just a hardcoded
// demo list) via Wikipedia's free, keyless REST API — works for basically
// any city/place name a concierge would type. Results are cached in memory
// (module-level, survives across component remounts within a session) so
// the same destination is never fetched twice. Fails silently to "no photo"
// if the place can't be found or the network hiccups — never blocks render.
const _destPhotoCache = {};
function fetchDestPhoto(destination){
  if(!destination) return Promise.resolve(null);
  if(_destPhotoCache[destination]!==undefined) return Promise.resolve(_destPhotoCache[destination]);
  const cityOnly = destination.split(",")[0].trim();
  if(!cityOnly) return Promise.resolve(null);
  return fetch(`https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(cityOnly)}`)
    .then(r => r.ok ? r.json() : null)
    .then(data => {
      const url = data?.thumbnail?.source || data?.originalimage?.source || null;
      _destPhotoCache[destination] = url;
      return url;
    })
    .catch(() => { _destPhotoCache[destination] = null; return null; });
}
function DestPhoto({destination, size=44, radius=8, style={}, showPlaceholder=false}){
  const [url, setUrl] = useState(() => _destPhotoCache[destination] !== undefined ? _destPhotoCache[destination] : null);
  useEffect(() => {
    let cancelled = false;
    fetchDestPhoto(destination).then(u => { if(!cancelled) setUrl(u); });
    return () => { cancelled = true; };
  }, [destination]);
  if(!url){
    if(!showPlaceholder) return null;
    return <div style={{width:size,height:size,borderRadius:radius,background:`${N.gold}15`,flexShrink:0,...style}}/>;
  }
  return (
    <div style={{width:size,height:size,borderRadius:radius,overflow:"hidden",flexShrink:0,...style}}>
      <img src={url} alt={destination} style={{width:"100%",height:"100%",objectFit:"cover",display:"block"}}/>
    </div>
  );
}

// ─── Time zones ───
// The client's IANA time zone (e.g. "America/Chicago") is captured
// automatically from their browser on login/signup — see the useEffect in
// App that calls PT.updateClientTimezone — so there's nothing for either
// side to type in manually, and it stays correct even if a client travels.
// getTzOffsetMinutes computes a zone's real UTC offset *right now* (handles
// DST correctly, unlike a static offset table) using the standard
// format-then-diff trick: render "now" as if its wall-clock digits were UTC,
// then compare that to the real UTC instant.
function getTzOffsetMinutes(tz, date = new Date()){
  try{
    const dtf = new Intl.DateTimeFormat("en-US", {
      timeZone: tz, hourCycle: "h23",
      year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",
    });
    const parts = dtf.formatToParts(date).reduce((acc,p)=>{ if(p.type!=="literal") acc[p.type]=p.value; return acc; },{});
    const asUTC = Date.UTC(+parts.year, +parts.month-1, +parts.day, +parts.hour, +parts.minute, +parts.second);
    return (asUTC - date.getTime())/60000;
  }catch{ return null; }
}
function myTimeZone(){
  try{ return Intl.DateTimeFormat().resolvedOptions().timeZone; }catch{ return null; }
}
// Human summary of a client's time relative to whoever's looking at the
// screen right now (the concierge's own device clock/time zone) — e.g.
// "2:34 PM · 3 hrs ahead of you". Recomputed live wherever it's used.
function describeClientTime(clientTz){
  if(!clientTz) return null;
  const now = new Date();
  const myTz = myTimeZone();
  let timeStr;
  try{ timeStr = now.toLocaleTimeString("en-US",{timeZone:clientTz, hour:"numeric", minute:"2-digit"}); }
  catch{ return null; }
  let diffLabel = "";
  if(myTz && myTz!==clientTz){
    const clientOffset = getTzOffsetMinutes(clientTz, now);
    const myOffset = getTzOffsetMinutes(myTz, now);
    if(clientOffset!=null && myOffset!=null){
      const diffHrs = (clientOffset - myOffset)/60;
      if(Math.abs(diffHrs) < 0.01) diffLabel = "same time as you";
      else {
        const rounded = Math.abs(diffHrs%1)<0.01 ? Math.abs(diffHrs).toFixed(0) : Math.abs(diffHrs).toFixed(1);
        diffLabel = `${rounded} hr${rounded==="1"?"":"s"} ${diffHrs>0?"ahead of":"behind"} you`;
      }
    }
  } else if(myTz===clientTz){
    diffLabel = "same time as you";
  }
  const cityLabel = clientTz.split("/").pop().replace(/_/g," ");
  return { timeStr, diffLabel, cityLabel, tz:clientTz };
}

function tripStatus(trip){
  // A trip with no startDate yet (e.g. just created via "Create Blank
  // Itinerary", before travel dates are known) isn't Active/Upcoming/
  // Completed — it's still being planned. This used to call tripStatus(trip)
  // on itself here, which is infinite recursion for any trip missing a
  // startDate and would hang/crash the whole Itineraries screen.
  if(!trip.startDate)return trip.status||"Planning";
  const today=new Date(); today.setHours(0,0,0,0);
  const start=new Date(trip.startDate);
  const end=new Date(trip.endDate);
  end.setHours(23,59,59,999);
  if(today>end) return "Completed";
  if(today>=start) return "Active";
  return "Upcoming";
}

const catColor = {flight:N.sky, hotel:N.purple, dining:N.gold, transfer:N.coral, activity:N.teal, leisure:"rgba(237,232,223,0.35)"};
const statusColor = {Active:N.green, Upcoming:N.gold, Planning:N.sky, Completed:N.parchD};
const statusOrder={Active:0,Upcoming:1,Planning:2,Completed:3};
function sortTrips(arr){return [...arr].sort((a,b)=>(statusOrder[tripStatus(a)]||1)-(statusOrder[tripStatus(b)]||1));}

function Badge({label, color=N.gold}){
  return <span style={{background:`${color}18`,color,fontSize:8,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",padding:"3px 9px",borderRadius:20}}>{label}</span>;
}

// Shared "voice to talk" mic button — used in Sage (both client & concierge)
// and the human Messages composers. Uses the browser's built-in Web Speech
// API (no server/API key needed): tap to start listening, speak, and the
// transcript is handed back via onResult. Renders nothing at all in
// browsers that don't support it (Firefox desktop, most non-Chrome mobile
// browsers as of writing) rather than showing a button that would just
// error when tapped.
function MicButton({onResult, disabled}){
  const [listening, setListening] = useState(false);
  const recRef = useRef(null);
  const SR = (typeof window!=="undefined") && (window.SpeechRecognition || window.webkitSpeechRecognition);

  useEffect(()=>()=>{ try{recRef.current?.stop();}catch{} },[]);

  if(!SR) return null;

  function toggle(){
    if(disabled) return;
    if(listening){
      try{recRef.current?.stop();}catch{}
      return;
    }
    const rec = new SR();
    rec.lang = "en-US";
    rec.interimResults = false;
    rec.maxAlternatives = 1;
    rec.onresult = (e)=>{
      const transcript = Array.from(e.results).map(r=>r[0].transcript).join(" ").trim();
      if(transcript) onResult(transcript);
    };
    rec.onerror = ()=>setListening(false);
    rec.onend = ()=>setListening(false);
    // Stop as soon as the browser detects the person has stopped talking,
    // rather than waiting for the engine's own (often multi-second) silence
    // timeout before onend fires — this is what makes the mic "light"
    // linger on after a sentence is finished.
    rec.onspeechend = ()=>{ try{ rec.stop(); }catch{} };
    recRef.current = rec;
    try{ rec.start(); setListening(true); }catch{ setListening(false); }
  }

  return (
    <button type="button" onClick={toggle} disabled={disabled} title={listening?"Stop listening":"Speak your message"}
      style={{background:listening?"#e5737322":N.navyMid,border:`1px solid ${listening?"#e57373":N.goldLine}`,borderRadius:"50%",width:40,height:40,flexShrink:0,display:"flex",alignItems:"center",justifyContent:"center",cursor:disabled?"not-allowed":"pointer",fontSize:15,opacity:disabled?0.5:1,animation:listening?"micPulse 1.2s ease-in-out infinite":"none"}}>
      {listening?"⏹":"🎤"}
      <style>{`@keyframes micPulse{0%,100%{box-shadow:0 0 0 0 rgba(229,115,115,0.4)}50%{box-shadow:0 0 0 6px rgba(229,115,115,0)}}`}</style>
    </button>
  );
}

function GoldBar(){return <div style={{height:1,background:N.goldLine,margin:"14px 0"}}/>;}

function Avatar({initials, size=40, photo=null, onClick=null}){
  if(photo) return <div onClick={onClick} style={{width:size,height:size,borderRadius:"50%",overflow:"hidden",border:`1px solid ${N.gold}`,cursor:onClick?"pointer":"default",flexShrink:0}}><img src={photo} style={{width:"100%",height:"100%",objectFit:"cover"}}/></div>;
  return <div onClick={onClick} style={{width:size,height:size,borderRadius:"50%",background:`${N.gold}18`,border:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",justifyContent:"center",fontFamily:"Georgia,serif",fontSize:size*0.35,fontWeight:600,color:N.gold,cursor:onClick?"pointer":"default",flexShrink:0}}>{initials}</div>;
}

function Screen({children, pad=true}){
  return <div style={{padding:pad?"0 0 88px 0":"0 0 88px 0",minHeight:"calc(100vh - 100px)"}}>{children}</div>;
}

function SectionEye({label}){
  return <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.28em",textTransform:"uppercase",color:N.gold,marginBottom:4}}>{label}</div>;
}

function SectionTitle({children, small}){
  return <div style={{fontFamily:"Georgia,serif",fontSize:small?13:22,color:small?N.gold:N.parch,fontWeight:small?700:400,letterSpacing:small?"0.1em":"normal",marginBottom:16,lineHeight:1.2,textTransform:small?"uppercase":"none"}}>{children}</div>;
}

function EmptyState({icon,title,body}){
  return <div style={{textAlign:"center",padding:"48px 24px"}}>
    <div style={{fontSize:44,marginBottom:12}}>{icon}</div>
    <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,marginBottom:6}}>{title}</div>
    <div style={{fontSize:11,color:N.parchD,lineHeight:1.7}}>{body}</div>
  </div>;
}

// ─── NavBar ───
function NavBar({role,fixedRole,conciergeLabel,onSettingsClick,onAlertsClick,alertCount=0}){
  // fixedRole locks the app to a single mode with no in-app switcher —
  // ClientApp passes fixedRole="Client", ConciergeApp passes fixedRole="Concierge".
  return(
    <nav style={{background:N.navy,borderBottom:`1px solid ${N.goldLine}`,padding:"12px 20px",display:"flex",alignItems:"center",justifyContent:"space-between",position:"sticky",top:0,zIndex:100,boxShadow:"0 2px 20px rgba(0,0,0,0.3)"}}>
      <div style={{display:"flex",alignItems:"center",gap:10}}>
        <img src={PT_LOGO} alt="PT" style={{width:36,height:36,borderRadius:8,objectFit:"cover"}}/>
        <div style={{lineHeight:1}}>
          <div style={{fontFamily:"Georgia,serif",fontSize:15,color:N.parch,fontWeight:700}}>Provisions <em style={{color:N.gold,fontStyle:"italic",fontWeight:400}}>Travel</em></div>
          <div style={{fontSize:8,color:N.parchD,marginTop:1}}>Every detail. Provisioned for you.</div>
        </div>
      </div>
      <div style={{display:"flex",alignItems:"center",gap:10}}>
        {fixedRole==="Concierge" && (
          <div style={{padding:"5px 14px",borderRadius:17,border:`1px solid ${N.goldLine}`,fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold}}>
            Concierge
          </div>
        )}
        {onAlertsClick && (
          <button type="button" onClick={onAlertsClick} title="Alerts" style={{position:"relative",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:"50%",width:36,height:36,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:N.parchD}}>
            <Icon name="bell" size={17} color={alertCount>0?N.gold:N.parchD}/>
            {alertCount>0 && (
              <span style={{position:"absolute",top:-3,right:-3,minWidth:16,height:16,borderRadius:8,background:"#e57373",color:"#fff",fontSize:9,fontWeight:700,display:"flex",alignItems:"center",justifyContent:"center",padding:"0 3px",border:`1.5px solid ${N.navy}`}}>{alertCount>9?"9+":alertCount}</span>
            )}
          </button>
        )}
        {onSettingsClick && (
          <button type="button" onClick={onSettingsClick} title="Settings" style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:"50%",width:36,height:36,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:N.parchD}}>
            <Icon name="gear" size={18} color={N.parchD}/>
          </button>
        )}
      </div>
    </nav>
  );
}

// ─── Alerts overlay (shared by Client + Concierge) ───
// Client sees only their own open alerts and can dismiss (hides it for them
// only — the concierge still sees it as open until they resolve it).
// Concierge sees every open alert across all clients and can resolve.
function AlertsScreen({role,alerts,onClose,onDismiss,onResolve}){
  const severityColor = {critical:"#e57373",warning:N.gold,info:N.sky};
  const typeLabel = {document_expiry:"Travel Document",weather:"Weather",flight_delay:"Flight"};
  return(
    <div style={{position:"fixed",inset:0,background:"rgba(10,22,40,0.96)",zIndex:250,display:"flex",justifyContent:"center"}}>
      <div style={{width:"100%",maxWidth:"var(--pt-shell-width)",height:"100vh",overflowY:"auto",background:N.navyDeep}}>
        <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14,position:"sticky",top:0,zIndex:2}}>
          <button onClick={onClose} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,flex:1}}>Alerts</div>
        </div>
        <div style={{padding:"20px"}}>
          {(!alerts||alerts.length===0) ? (
            <div style={{textAlign:"center",padding:"60px 20px",color:N.parchD}}>
              <Icon name="bell" size={32} color={N.parchD} style={{marginBottom:14,opacity:0.5}}/>
              <div style={{fontSize:12}}>Nothing needs attention right now.</div>
            </div>
          ):(
            alerts.map(a=>(
              <div key={a.id} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderLeft:`3px solid ${severityColor[a.severity]||N.gold}`,borderRadius:10,padding:"14px 16px",marginBottom:12}}>
                <div style={{display:"flex",alignItems:"flex-start",gap:10,marginBottom:8}}>
                  <Icon name="alertTriangle" size={16} color={severityColor[a.severity]||N.gold} style={{flexShrink:0,marginTop:2}}/>
                  <div style={{flex:1}}>
                    <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.parchD,marginBottom:3}}>{typeLabel[a.type]||"Alert"}</div>
                    <div style={{fontSize:13,fontWeight:600,color:N.parch,marginBottom:4}}>{a.title}</div>
                    <div style={{fontSize:11,color:N.parchD,lineHeight:1.6}}>{a.message}</div>
                  </div>
                </div>
                <div style={{display:"flex",gap:8,justifyContent:"flex-end"}}>
                  {role==="Client" && onDismiss && (
                    <button onClick={()=>onDismiss(a.id)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 12px",fontSize:9,fontWeight:700,letterSpacing:"0.08em",color:N.parchD,cursor:"pointer"}}>DISMISS</button>
                  )}
                  {role==="Concierge" && onResolve && (
                    <button onClick={()=>onResolve(a.id)} style={{background:N.gold,border:"none",borderRadius:6,padding:"6px 12px",fontSize:9,fontWeight:700,letterSpacing:"0.08em",color:N.navy,cursor:"pointer"}}>MARK RESOLVED</button>
                  )}
                </div>
              </div>
            ))
          )}
        </div>
      </div>
    </div>
  );
}

// ─── Settings overlay (shared by Client + Concierge) ───
function SettingsScreen({role,currentClient,onClose,onOpenProfile,onOpenKeys,onOpenIntake,onCardSaved}){
  const [loggingOut,setLoggingOut]=useState(false);
  const [resetStatus,setResetStatus]=useState("idle"); // idle | sending | sent | error
  const [resetError,setResetError]=useState("");
  const [showLegal,setShowLegal]=useState(false);
  const [showPayment,setShowPayment]=useState(false);
  const email = role==="Client" ? (currentClient&&currentClient.email) : (PT.auth.currentUser&&PT.auth.currentUser.email);
  const name = role==="Client" ? ((currentClient&&currentClient.full_name)||(currentClient&&currentClient.fullName)||"") : "Concierge";

  function logOut(){
    setLoggingOut(true);
    PT.signOut().then(()=>{ window.location.reload(); }).catch(()=>{ setLoggingOut(false); });
  }

  async function changePassword(){
    if(!email) return;
    setResetStatus("sending"); setResetError("");
    try{
      await PT.sendPasswordReset(email);
      setResetStatus("sent");
    }catch(e){
      setResetError(e.message||"Something went wrong.");
      setResetStatus("error");
    }
  }

  const rowStyle={display:"flex",alignItems:"center",justifyContent:"space-between",padding:"14px 16px",borderRadius:10,background:N.navyMid,border:`1px solid ${N.goldLine}`,marginBottom:10,cursor:"pointer"};

  return(
    <div style={{position:"fixed",inset:0,zIndex:200,background:N.navyDeep,maxWidth:"var(--pt-shell-width)",margin:"0 auto",overflowY:"auto",WebkitFontSmoothing:"antialiased"}}>
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:`1px solid ${N.goldLine}`,position:"sticky",top:0,background:N.navyDeep,zIndex:1}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>Settings</div>
        <button type="button" onClick={onClose} style={{background:"transparent",border:"none",cursor:"pointer",color:N.parchD}}>
          <Icon name="close" size={20} color={N.parchD}/>
        </button>
      </div>

      <div style={{padding:20}}>
        <div style={{fontSize:10,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:10}}>Account</div>
        <div style={{padding:"14px 16px",borderRadius:10,background:N.navyMid,border:`1px solid ${N.goldLine}`,marginBottom:24}}>
          {name && <div style={{color:N.parch,fontSize:15,fontWeight:600,marginBottom:2}}>{name}</div>}
          <div style={{color:N.parchD,fontSize:13}}>{email||"—"}</div>
        </div>

        <div style={{fontSize:10,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:10}}>Preferences</div>

        {role==="Client" && (
          <div style={rowStyle} onClick={onOpenProfile}>
            <span style={{color:N.parch,fontSize:14}}>Travel Preferences</span>
            <Icon name="arrow" size={16} color={N.parchD}/>
          </div>
        )}

        {role==="Client" && currentClient && (
          <div style={rowStyle} onClick={()=>setShowPayment(true)}>
            <span style={{color:N.parch,fontSize:14}}>
              {currentClient.cardOnFile?.last4 ? `Payment Method — ${(currentClient.cardOnFile.brand||"card").toUpperCase()} ••••${currentClient.cardOnFile.last4}` : "Add Payment Method"}
            </span>
            <Icon name="arrow" size={16} color={N.parchD}/>
          </div>
        )}

        {role==="Concierge" && (
          <div style={rowStyle} onClick={onOpenKeys}>
            <span style={{color:N.parch,fontSize:14}}>Manage Access Keys</span>
            <Icon name="arrow" size={16} color={N.parchD}/>
          </div>
        )}

        {role==="Concierge" && onOpenIntake && (
          <div style={rowStyle} onClick={onOpenIntake}>
            <span style={{color:N.parch,fontSize:14}}>Client Intake Links</span>
            <Icon name="arrow" size={16} color={N.parchD}/>
          </div>
        )}

        <div style={rowStyle} onClick={resetStatus==="sending"?undefined:changePassword}>
          <span style={{color:N.parch,fontSize:14}}>
            {resetStatus==="sending" ? "Sending reset link..." : resetStatus==="sent" ? "Reset link sent — check your email" : "Change Password"}
          </span>
          {resetStatus!=="sent" && <Icon name="lock" size={16} color={N.parchD}/>}
          {resetStatus==="sent" && <Icon name="check" size={16} color={N.gold}/>}
        </div>
        {resetStatus==="error" && <div style={{color:N.coral,fontSize:12,marginBottom:10}}>{resetError}</div>}

        <div style={rowStyle} onClick={()=>setShowLegal(true)}>
          <span style={{color:N.parch,fontSize:14}}>Terms & Privacy Policy</span>
          <Icon name="arrow" size={16} color={N.parchD}/>
        </div>

        <div style={{marginTop:24}}>
          <button type="button" onClick={logOut} disabled={loggingOut} style={{width:"100%",padding:"13px",borderRadius:10,border:`1px solid ${N.goldLine}`,background:"transparent",color:"#e57373",fontWeight:600,fontSize:14,cursor:loggingOut?"not-allowed":"pointer",display:"flex",alignItems:"center",justifyContent:"center",gap:8}}>
            <Icon name="logout" size={16} color="#e57373"/>
            {loggingOut ? "Logging out..." : "Log Out"}
          </button>
        </div>
      </div>
      {showLegal && <TermsPrivacyPanel onClose={()=>setShowLegal(false)}/>}
      {showPayment && currentClient && (
        <ClientPaymentMethod
          clientId={currentClient.id}
          cardOnFile={currentClient.cardOnFile}
          onClose={()=>setShowPayment(false)}
          onSaved={onCardSaved}
        />
      )}
    </div>
  );
}

// ─── Bottom Tab Bar ───
function TabBar({tabs,active,setActive}){
  const col = t => t.id===active ? N.gold : "rgba(237,232,223,0.35)";
  return(
    <div style={{background:N.navy,borderTop:`1px solid ${N.goldLine}`,position:"fixed",bottom:0,left:0,right:0,display:"flex",zIndex:99,maxWidth:"var(--pt-shell-width)",margin:"0 auto"}}>
      {tabs.map(t=>(
        <button key={t.id} onClick={()=>setActive(t.id)}
          style={{flex:1,padding:"12px 4px 10px",border:"none",cursor:"pointer",background:"transparent",
            display:"flex",flexDirection:"column",alignItems:"center",gap:4,
            borderTop:t.id===active?`1px solid ${N.gold}`:"1px solid transparent",
            transition:"all 0.2s",position:"relative"}}>
          {t.icon==="S"
            ? <div style={{width:24,height:24,borderRadius:"50%",background:t.id===active?N.gold:"rgba(201,168,76,0.2)",border:`1px solid ${t.id===active?N.gold:N.goldLine}`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,fontFamily:"Georgia,serif",color:t.id===active?N.navy:N.parchD,transition:"all 0.2s"}}>S</div>
            : <Icon name={t.icon} size={18} color={col(t)}/>
          }
          <span style={{fontSize:7.5,fontWeight:500,letterSpacing:"0.12em",color:col(t),textTransform:"uppercase",transition:"color 0.2s"}}>{t.label}</span>
          {t.badge>0&&<span style={{position:"absolute",top:8,right:"calc(50% - 16px)",background:N.gold,color:N.navy,fontSize:7,fontWeight:700,borderRadius:"50%",width:13,height:13,display:"flex",alignItems:"center",justifyContent:"center"}}>{t.badge}</span>}
        </button>
      ))}
    </div>
  );
}



// Shared legal text, defined once here and reused both by the required
// first-login AgreementScreen below and by the read-only "Terms & Privacy
// Policy" viewer reachable from Settings (see TermsPrivacyPanel), so the
// two never drift out of sync.
const TERMS_TEXT = "Effective Date: July 4, 2027\n\nThese Terms and Conditions (\"Agreement\") govern the relationship between Provisions Travel LLC, an independent travel concierge (\"Travel Advisor\" or \"we\") and you, the purchaser of travel services or lead traveler (\"Client\" or \"you\"). By booking a consultation, signing a service agreement, or otherwise engaging our services, you acknowledge that you have read, understood, and agree to be bound by this Agreement on behalf of yourself and all members of your traveling party.\n\n1. ELIGIBILITY & REPRESENTATIONS\nYou represent and warrant that: (a) you are at least 18 years of age and authorized to enter into this Agreement; (b) all information you provide is true, accurate, and current; and (c) you will abide by the terms of this Agreement and any applicable terms of our travel suppliers.\n\n2. SERVICES & ROLE AS AGENT\nProvisions Travel LLC provides premium travel concierge and planning services. We act as an independent agent on your behalf in arranging travel with airlines, hotels, cruise lines, tour operators, car rental companies, and other travel suppliers (\"Suppliers\"). We are not a Supplier. Each Supplier is an independent entity not subject to our control, and we bear no responsibility for any changes, delays, alterations, or cancellations made by a Supplier or due to force majeure.\n\n3. PLANNING FEES & PAYMENT\nOur service fees are separate from and in addition to all travel costs. Any planning fees are 100% non-refundable once planning has commenced. A non-refundable expedited planning fee of $150 applies to any request requiring turnaround within 72 hours. All quoted prices are in USD and are subject to change until a booking is confirmed.\n\n4. CREDIT CARD AUTHORIZATION; CHARGEBACKS\nYou certify that you are an authorized user of any credit card provided to Provisions Travel. YOU AGREE NOT TO FILE ANY DISPUTE WITH YOUR BANK OR CREDIT CARD COMPANY TO AVOID OR VIOLATE ANY BOOKING TERMS AND CONDITIONS OF PROVISIONS TRAVEL OR OUR TRAVEL SUPPLIERS, INCLUDING CANCELLATIONS OR CHANGES FOR REASONS BEYOND OUR CONTROL.\n\n5. CANCELLATIONS & MODIFICATIONS\nAll cancellation or modification requests must be submitted in writing to info@provisionstravel.com with a minimum of 48 hours' notice. Provisions Travel has no authority to waive Supplier cancellation penalties, which may include forfeiture of up to 100% of travel costs.\n\n6. TRAVEL INSURANCE\nTravel insurance is not included unless expressly stated and purchased. THE PURCHASE OF TRAVEL INSURANCE IS HIGHLY RECOMMENDED ON ALL TRIPS. Without appropriate coverage, cancellation penalties may result in the loss of the full cost of your booking.\n\n7. PASSPORTS, VISAS & TRAVEL DOCUMENTS\nIt is each traveler's sole responsibility to ensure they hold a valid passport (valid at least six months beyond return date), all required visas, travel authorizations, and health documentation. ALL NAMES ON TRAVEL DOCUMENTS MUST MATCH THE LEGAL NAME ON GOVERNMENT-ISSUED PHOTO I.D. BEING DENIED ENTRY FOR ANY REASON MAY RESULT IN COMPLETE FINANCIAL LOSS AND DOES NOT ENTITLE YOU TO ANY REFUND.\n\n8. TRAVEL ADVISORIES\nChanges in government-issued travel advisories do not supersede Supplier cancellation and refund policies. CLIENT'S PARTICIPATION IN ANY TRAVEL CONSTITUTES ACCEPTANCE OF SUCH RISK.\n\n9. LIMITATION OF LIABILITY\nPROVISIONS TRAVEL ACTS SOLELY AS AN AGENT FOR DISCLOSED TRAVEL SUPPLIERS AND HAS NO CONTROL OVER THEIR OPERATIONS. ANY RECOVERY FROM PROVISIONS TRAVEL SHALL BE LIMITED TO THE AMOUNT OF SERVICE FEES ACTUALLY RECEIVED BY PROVISIONS TRAVEL FOR THE TRIP AT ISSUE. IN NO EVENT SHALL PROVISIONS TRAVEL BE LIABLE FOR INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, OR EXEMPLARY DAMAGES.\n\n10. FORCE MAJEURE\nProvisions Travel is not liable for any failure or delay due to causes beyond its reasonable control, including natural disasters, civil unrest, war, terrorism, pandemics, equipment failures, or government actions.\n\n11. MILITARY & VETERAN DISCOUNT\nA 5% discount on service fees is available to active-duty U.S. military personnel and veterans. Valid military ID or DD-214 required prior to booking confirmation.\n\n12. REFERRAL PROGRAM\nClients who refer five (5) individuals who complete a paid booking are eligible for a 10% credit toward a future service fee. Credits expire 12 months from issuance.\n\n13. CLAIMS; CLASS ACTION WAIVER\nAny claim must be brought within 12 months after completion of the trip. YOU WAIVE ANY RIGHT TO CLAIM PUNITIVE OR EXEMPLARY DAMAGES. YOU AGREE TO BRING CLAIMS ONLY IN YOUR INDIVIDUAL CAPACITY.\n\n14. GOVERNING LAW & VENUE\nThis Agreement is governed by the laws of the State of South Carolina. Exclusive jurisdiction and venue: courts in North Augusta, South Carolina.\n\n15. CONTACT\nProvisions Travel LLC · PO Box 6244, N. Augusta, SC 29861-6244 · info@provisionstravel.com";
const PRIVACY_TEXT = "Effective Date: July 4, 2027\n\nProvisions Travel LLC (\"we,\" \"us,\" or \"our\") is committed to protecting the privacy and security of your personal information. This Privacy Policy describes how we collect, use, disclose, and safeguard information when you visit our website or engage our travel concierge services.\n\n1. INFORMATION WE COLLECT\nWe collect information you voluntarily provide, including: full name; email address; mailing address; phone number; date of birth; passport and travel document details; travel preferences, dietary restrictions, and accessibility needs; emergency contact information; and payment method information. We may also collect information automatically when you visit our website, such as IP address, browser type, and pages visited.\n\n2. PAYMENT CARD INFORMATION\nProvisions Travel LLC does not store, retain, or have access to your full credit or debit card numbers. All payment transactions are processed by PCI-DSS compliant third-party payment processors. We retain only confirmation numbers and transaction amounts for record-keeping purposes.\n\n3. HOW WE USE YOUR INFORMATION\nWe use your personal information to: plan, coordinate, and book your travel arrangements; communicate regarding your itinerary and service updates; process service fee payments; verify military/veteran status; administer our referral program; and comply with applicable legal obligations. We do not sell, rent, or trade your personal information to any third parties for their own marketing purposes.\n\n4. DISCLOSURE TO THIRD PARTIES\nTo fulfill your travel arrangements, we may share necessary personal information with airlines, hotels, cruise lines, tour operators, ground transportation providers, and other travel suppliers. These third parties are governed by their own privacy policies. We may also disclose information when required by law or to protect the rights and safety of Provisions Travel LLC and our clients.\n\n5. DATA RETENTION\nWe retain your personal information for as long as necessary to fulfill the purposes described in this policy and to comply with applicable legal, tax, and regulatory obligations.\n\n6. DATA SECURITY\nWe implement commercially reasonable administrative, technical, and physical safeguards to protect your personal information. No method of transmission over the internet is 100% secure. We encourage the use of strong passwords and secure connections.\n\n7. CHILDREN'S PRIVACY\nOur services are not directed to individuals under the age of 18. We do not knowingly collect personal information from minors.\n\n8. YOUR RIGHTS\nDepending on your state of residence, you may have the right to: access the personal information we hold; request correction of inaccurate information; request deletion; opt out of certain data uses; and receive a portable copy of your data. Contact us at info@provisionstravel.com. We respond within 30 days.\n\n9. CHANGES TO THIS POLICY\nWe reserve the right to update this Privacy Policy at any time. Your continued use of our services constitutes acceptance of the revised policy.\n\n10. CONTACT\nProvisions Travel LLC · PO Box 6244, N. Augusta, SC 29861-6244 · info@provisionstravel.com";
function renderLegalText(text){
  return text.split("\n").map((line,i)=>line?React.createElement("span",{key:i},line,React.createElement("br",null)):React.createElement("br",{key:i}));
}

// ─── Terms & Privacy Policy viewer (read-only, reached from Settings) ───
function TermsPrivacyPanel({onClose}){
  return(
    <div style={{position:"fixed",inset:0,zIndex:220,background:N.navyDeep,maxWidth:"var(--pt-shell-width)",margin:"0 auto",overflowY:"auto",WebkitFontSmoothing:"antialiased"}}>
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:`1px solid ${N.goldLine}`,position:"sticky",top:0,background:N.navyDeep,zIndex:1}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>Terms &amp; Privacy</div>
        <button type="button" onClick={onClose} style={{background:"transparent",border:"none",cursor:"pointer",color:N.parchD}}>
          <Icon name="close" size={20} color={N.parchD}/>
        </button>
      </div>
      <div style={{padding:20}}>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Terms of Service</div>
        <div style={{fontSize:10,color:N.parchD,lineHeight:1.8,marginBottom:24}}>{renderLegalText(TERMS_TEXT)}</div>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Privacy Policy</div>
        <div style={{fontSize:10,color:N.parchD,lineHeight:1.8}}>{renderLegalText(PRIVACY_TEXT)}</div>
      </div>
    </div>
  );
}

// ─── Payment Method (Stripe card on file) ───
// The card number is typed directly into a Stripe-hosted Elements field —
// it goes straight from the browser to Stripe and never passes through our
// server or database. We only ever store the resulting Stripe IDs and
// display-safe details (brand/last4/exp). See api/stripe-*.js.
function ClientPaymentMethod({clientId, cardOnFile, onClose, onSaved}){
  const [stage,setStage]=useState("idle"); // idle | loading | ready | saving | done | error
  const [error,setError]=useState("");
  const cardElRef = React.useRef(null);
  const stripeRef = React.useRef(null);
  const elementsRef = React.useRef(null);
  const cardRef = React.useRef(null);

  useEffect(()=>{
    let cancelled=false;
    setStage("loading");
    PT.createCardSetupIntent(clientId).then(({clientSecret, publishableKey})=>{
      if(cancelled) return;
      if(!window.Stripe){ setError("Payments aren't available right now — try again in a moment."); setStage("error"); return; }
      const stripe = window.Stripe(publishableKey);
      const elements = stripe.elements();
      const card = elements.create("card", {
        style: { base: { color: N.parch, fontSize: "15px", fontFamily: "'Montserrat','Helvetica Neue',sans-serif", "::placeholder": { color: N.parchD } }, invalid: { color: "#e57373" } },
      });
      card.mount(cardElRef.current);
      stripeRef.current = stripe; elementsRef.current = { clientSecret }; cardRef.current = card;
      setStage("ready");
    }).catch(e=>{ if(!cancelled){ setError(e.message||"Could not start card setup."); setStage("error"); } });
    return ()=>{ cancelled=true; if(cardRef.current) cardRef.current.unmount(); };
  },[clientId]);

  async function submit(e){
    e.preventDefault();
    if(!stripeRef.current || stage!=="ready") return;
    setStage("saving"); setError("");
    try{
      const { setupIntent, error: stripeErr } = await stripeRef.current.confirmCardSetup(
        elementsRef.current.clientSecret,
        { payment_method: { card: cardRef.current } }
      );
      if(stripeErr) throw new Error(stripeErr.message);
      const saved = await PT.saveCardOnFile(clientId, setupIntent.payment_method);
      setStage("done");
      if(onSaved) onSaved(saved.cardOnFile);
    }catch(e){
      setError(e.message||"Could not save this card.");
      setStage("ready");
    }
  }

  return(
    <div style={{position:"fixed",inset:0,zIndex:230,background:N.navyDeep,maxWidth:"var(--pt-shell-width)",margin:"0 auto",overflowY:"auto",WebkitFontSmoothing:"antialiased"}}>
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:`1px solid ${N.goldLine}`,position:"sticky",top:0,background:N.navyDeep,zIndex:1}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>Payment Method</div>
        <button type="button" onClick={onClose} style={{background:"transparent",border:"none",cursor:"pointer",color:N.parchD}}>
          <Icon name="close" size={20} color={N.parchD}/>
        </button>
      </div>
      <div style={{padding:20}}>
        {cardOnFile?.last4 && (
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"14px 16px",marginBottom:20}}>
            <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>Card On File</div>
            <div style={{fontSize:14,color:N.parch}}>{(cardOnFile.brand||"Card").toUpperCase()} •••• {cardOnFile.last4}{cardOnFile.expMonth?` · exp ${cardOnFile.expMonth}/${cardOnFile.expYear}`:""}</div>
          </div>
        )}
        <div style={{fontSize:11,color:N.parchD,lineHeight:1.7,marginBottom:16}}>
          {cardOnFile?.last4 ? "Add a new card below to replace the one on file." : "Save a card so your concierge can handle hotel and vendor bookings on your behalf. Your card number goes straight to our payment processor (Stripe) and is never stored on our servers."}
        </div>
        <form onSubmit={submit}>
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"14px 14px",marginBottom:14}} ref={cardElRef}/>
          {stage==="loading" && <div style={{fontSize:11,color:N.parchD}}>Loading secure payment form…</div>}
          {error && <div style={{color:"#e57373",fontSize:12,marginBottom:12}}>{error}</div>}
          {stage==="done" ? (
            <div style={{fontSize:12,color:N.green,textAlign:"center",padding:"8px 0"}}>✓ Card saved</div>
          ) : (
            <button type="submit" disabled={stage!=="ready"} style={{width:"100%",padding:"13px",borderRadius:8,border:"none",background:N.gold,color:N.navy,fontWeight:700,fontSize:14,cursor:stage==="ready"?"pointer":"not-allowed"}}>
              {stage==="saving" ? "Saving…" : "Save Card"}
            </button>
          )}
        </form>
      </div>
    </div>
  );
}

// ─── Invoice payment screen (reached via ?invoice=<id> deep link) ───
// Client opens a link the concierge sent, sees the amount + description,
// and pays with their card on file (one click) or a new card via Stripe
// Elements. On success we generate a simple PDF receipt right here in the
// browser and file it in the client's own Documents — the same Storage/
// Firestore documents the Documents tab already reads from, so there's no
// separate invoicing system to keep in sync.
function InvoiceScreen({invoiceId, currentClient, onDone}){
  const [invoice,setInvoice]=useState(null);
  const [loading,setLoading]=useState(true);
  const [notFound,setNotFound]=useState(false);
  const [useNewCard,setUseNewCard]=useState(false);
  const [payStage,setPayStage]=useState("idle"); // idle | preparing | ready | paying | done | error
  const [error,setError]=useState("");
  const [filingDoc,setFilingDoc]=useState(false);
  const cardElRef=useRef(null);
  const stripeRef=useRef(null);
  const cardRef=useRef(null);
  const clientSecretRef=useRef(null);

  useEffect(()=>{
    let cancelled=false;
    PT.fetchInvoice(invoiceId).then(inv=>{
      if(cancelled) return;
      if(!inv){ setNotFound(true); setLoading(false); return; }
      setInvoice(inv);
      setLoading(false);
    }).catch(()=>{ if(!cancelled){ setNotFound(true); setLoading(false); } });
    return ()=>{cancelled=true;};
  },[invoiceId]);

  const hasCardOnFile = !!currentClient?.cardOnFile?.paymentMethodId;
  const showCardForm = invoice?.status==="pending" && (useNewCard || !hasCardOnFile);

  useEffect(()=>{
    if(!showCardForm) return;
    let cancelled=false;
    setPayStage("preparing");
    PT.createInvoicePaymentIntent(invoiceId).then(({clientSecret,publishableKey})=>{
      if(cancelled) return;
      if(!window.Stripe){ setError("Payments aren't available right now."); setPayStage("error"); return; }
      const stripe=window.Stripe(publishableKey);
      const elements=stripe.elements();
      const card=elements.create("card",{style:{base:{color:N.parch,fontSize:"15px",fontFamily:"'Montserrat','Helvetica Neue',sans-serif","::placeholder":{color:N.parchD}},invalid:{color:"#e57373"}}});
      card.mount(cardElRef.current);
      stripeRef.current=stripe; clientSecretRef.current=clientSecret; cardRef.current=card;
      setPayStage("ready");
    }).catch(e=>{ if(!cancelled){ setError(e.message||"Could not start payment."); setPayStage("error"); } });
    return ()=>{ cancelled=true; if(cardRef.current) cardRef.current.unmount(); };
  },[showCardForm, invoiceId]);

  async function fileReceipt(paidInvoice){
    // Best-effort: generate a simple PDF receipt and drop it in the
    // client's own Documents folder. Non-fatal if it fails — the payment
    // itself already succeeded either way.
    try{
      setFilingDoc(true);
      const {jsPDF}=window.jspdf;
      const pdf=new jsPDF({unit:"pt",format:"letter"});
      const margin=60; const lineH=20; let y=margin;
      pdf.setFont("helvetica","bold"); pdf.setFontSize(18); pdf.setTextColor(10,22,40);
      pdf.text("PROVISIONS TRAVEL",margin,y); y+=lineH*1.5;
      pdf.setFontSize(13); pdf.text("Payment Receipt",margin,y); y+=lineH*1.5;
      pdf.setFont("helvetica","normal"); pdf.setFontSize(10); pdf.setTextColor(80,80,80);
      const amt=(paidInvoice.amountCents/100).toLocaleString("en-US",{style:"currency",currency:"USD"});
      [`Amount: ${amt}`, `For: ${paidInvoice.description||"Provisions Travel services"}`, `Date: ${new Date().toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}`, `Invoice ID: ${invoiceId}`].forEach(line=>{ pdf.text(line,margin,y); y+=lineH; });
      y+=lineH; pdf.setDrawColor(180,150,80); pdf.line(margin,y,612-margin,y); y+=lineH*1.5;
      pdf.setFontSize(10); pdf.setTextColor(60,60,60);
      pdf.text("Thank you for your business — Provisions Travel",margin,y);
      const blob=pdf.output("blob");
      blob.name=`Invoice Receipt - ${amt}.pdf`;
      if(currentClient?.id && PT.auth.currentUser){
        await PT.uploadDocument(PT.auth.currentUser.uid, currentClient.id, blob, "invoice", "client", paidInvoice.tripId||null);
      }
    }catch(e){ console.warn("Could not file invoice receipt",e); }
    setFilingDoc(false);
  }

  async function payWithSavedCard(){
    setPayStage("paying"); setError("");
    try{
      const {clientSecret, publishableKey} = await PT.createInvoicePaymentIntent(invoiceId);
      const stripe = window.Stripe(publishableKey);
      const {paymentIntent, error:stripeErr} = await stripe.confirmCardPayment(clientSecret,{payment_method:currentClient.cardOnFile.paymentMethodId});
      if(stripeErr) throw new Error(stripeErr.message);
      await PT.markInvoicePaid(invoiceId, paymentIntent.id);
      const paid={...invoice,status:"paid"};
      setInvoice(paid);
      setPayStage("done");
      fileReceipt(paid);
    }catch(e){
      setError(e.message||"Payment failed.");
      setPayStage("idle");
    }
  }

  async function payWithNewCard(e){
    e.preventDefault();
    if(!stripeRef.current) return;
    setPayStage("paying"); setError("");
    try{
      const {paymentIntent, error:stripeErr} = await stripeRef.current.confirmCardPayment(clientSecretRef.current,{payment_method:{card:cardRef.current}});
      if(stripeErr) throw new Error(stripeErr.message);
      await PT.markInvoicePaid(invoiceId, paymentIntent.id);
      const paid={...invoice,status:"paid"};
      setInvoice(paid);
      setPayStage("done");
      fileReceipt(paid);
    }catch(e){
      setError(e.message||"Payment failed.");
      setPayStage("ready");
    }
  }

  if(loading) return <div style={{minHeight:"100vh",background:N.navyDeep}}/>;

  if(notFound) return (
    <div style={{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:N.navyDeep,fontFamily:"'Montserrat','Helvetica Neue',sans-serif",padding:20}}>
      <div style={{maxWidth:380,width:"100%",background:N.navy,borderRadius:14,padding:32,border:`1px solid ${N.goldLine}`,textAlign:"center"}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,marginBottom:8}}>Invoice not found</div>
        <div style={{fontSize:12,color:N.parchD,lineHeight:1.7,marginBottom:20}}>This link may be out of date. Reach out to Shayla for a new one.</div>
        <button onClick={onDone} style={{width:"100%",padding:"12px",borderRadius:8,border:"none",background:N.gold,color:N.navy,fontWeight:700,fontSize:14,cursor:"pointer"}}>Continue to App</button>
      </div>
    </div>
  );

  const amt=(invoice.amountCents/100).toLocaleString("en-US",{style:"currency",currency:"USD"});

  return(
    <div style={{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:N.navyDeep,fontFamily:"'Montserrat','Helvetica Neue',sans-serif",padding:20}}>
      <div style={{maxWidth:380,width:"100%",background:N.navy,borderRadius:14,padding:32,border:`1px solid ${N.goldLine}`}}>
        <div style={{textAlign:"center",marginBottom:20}}>
          <img src={PT_LOGO} alt="PT" style={{width:44,height:44,borderRadius:10,objectFit:"cover"}}/>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,marginTop:10}}>Provisions <em style={{color:N.gold,fontStyle:"italic"}}>Travel</em></div>
        </div>

        {invoice.status==="paid" ? (
          <>
            <div style={{textAlign:"center",padding:"12px 0 20px"}}>
              <div style={{fontSize:32,color:N.green,marginBottom:8}}>✓</div>
              <div style={{fontFamily:"Georgia,serif",fontSize:20,color:N.parch,marginBottom:6}}>Payment Received</div>
              <div style={{fontSize:12,color:N.parchD,lineHeight:1.7}}>{amt} for {invoice.description||"your Provisions Travel invoice"}.{filingDoc?" Filing your receipt…":" A receipt has been added to your Documents."}</div>
            </div>
            <button onClick={onDone} style={{width:"100%",padding:"12px",borderRadius:8,border:"none",background:N.gold,color:N.navy,fontWeight:700,fontSize:14,cursor:"pointer"}}>Continue to App</button>
          </>
        ) : (
          <>
            <div style={{textAlign:"center",marginBottom:20}}>
              <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:6}}>Invoice</div>
              <div style={{fontFamily:"Georgia,serif",fontSize:36,color:N.parch,marginBottom:6}}>{amt}</div>
              <div style={{fontSize:12,color:N.parchD}}>{invoice.description||"Provisions Travel services"}</div>
            </div>

            {hasCardOnFile && !useNewCard && (
              <>
                <button onClick={payWithSavedCard} disabled={payStage==="paying"} style={{width:"100%",padding:"13px",borderRadius:8,border:"none",background:N.gold,color:N.navy,fontWeight:700,fontSize:14,cursor:payStage==="paying"?"not-allowed":"pointer",marginBottom:10}}>
                  {payStage==="paying"?"Processing…":`Pay with ${(currentClient.cardOnFile.brand||"card").toUpperCase()} •••• ${currentClient.cardOnFile.last4}`}
                </button>
                <button type="button" onClick={()=>setUseNewCard(true)} style={{width:"100%",background:"transparent",border:"none",color:N.parchD,fontSize:11,cursor:"pointer",textDecoration:"underline"}}>Use a different card</button>
              </>
            )}

            {showCardForm && (
              <form onSubmit={payWithNewCard}>
                <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"14px 14px",marginBottom:14}} ref={cardElRef}/>
                {payStage==="preparing" && <div style={{fontSize:11,color:N.parchD,marginBottom:10}}>Loading secure payment form…</div>}
                <button type="submit" disabled={payStage!=="ready"} style={{width:"100%",padding:"13px",borderRadius:8,border:"none",background:N.gold,color:N.navy,fontWeight:700,fontSize:14,cursor:payStage==="ready"?"pointer":"not-allowed"}}>
                  {payStage==="paying" ? "Processing…" : `Pay ${amt}`}
                </button>
                {hasCardOnFile && <button type="button" onClick={()=>setUseNewCard(false)} style={{width:"100%",background:"transparent",border:"none",color:N.parchD,fontSize:11,cursor:"pointer",textDecoration:"underline",marginTop:10}}>Use card on file instead</button>}
              </form>
            )}

            {error && <div style={{color:"#e57373",fontSize:12,marginTop:12,textAlign:"center"}}>{error}</div>}
          </>
        )}
      </div>
    </div>
  );
}

// ─── First Login Agreement ───
function AgreementScreen({onAccept}){
  const [checkedTerms,setCheckedTerms]=useState(false);
  const [checkedPrivacy,setCheckedPrivacy]=useState(false);
  const [signature,setSignature]=useState("");
  const canSubmit = checkedTerms && checkedPrivacy && signature.trim().length > 2;

  return(
    <div style={{fontFamily:"'Montserrat','Helvetica Neue',sans-serif",background:N.navyDeep,minHeight:"100vh",display:"flex",flexDirection:"column"}}>
      <div style={{background:N.navy,borderBottom:`1px solid ${N.goldLine}`,padding:"16px 20px",display:"flex",alignItems:"center",gap:10}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,fontWeight:700}}>Provisions <em style={{color:N.gold,fontStyle:"italic",fontWeight:400}}>Travel</em></div>
      </div>

      <div style={{flex:1,overflowY:"auto",padding:"24px 20px 120px"}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:22,color:N.parch,marginBottom:4}}>Welcome</div>
        <div style={{fontSize:10,color:N.parchD,marginBottom:24,lineHeight:1.7}}>Before accessing your account, please review and acknowledge our Terms of Service and Privacy Policy.</div>

        {/* Terms of Service */}
        <div style={{marginBottom:20}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Terms of Service</div>
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"16px",height:180,overflowY:"auto",fontSize:10,color:N.parchD,lineHeight:1.8}}>
            <div style={{fontWeight:700,color:N.parch,marginBottom:8}}>Provisions Travel LLC — Terms & Conditions</div>
            {renderLegalText(TERMS_TEXT)}
          </div>
          <label style={{display:"flex",alignItems:"flex-start",gap:12,marginTop:12,cursor:"pointer"}}>
            <input type="checkbox" checked={checkedTerms} onChange={e=>setCheckedTerms(e.target.checked)} style={{marginTop:2,accentColor:N.gold,width:16,height:16,flexShrink:0}}/>
            <span style={{fontSize:10,color:N.parchD,lineHeight:1.6}}>I have read and agree to the <span style={{color:N.gold}}>Terms of Service</span></span>
          </label>
        </div>

        {/* Privacy Policy */}
        <div style={{marginBottom:24}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Privacy Policy</div>
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"16px",height:180,overflowY:"auto",fontSize:10,color:N.parchD,lineHeight:1.8}}>
            <div style={{fontWeight:700,color:N.parch,marginBottom:8}}>Provisions Travel LLC — Privacy Policy</div>
            {renderLegalText(PRIVACY_TEXT)}
          </div>
          <label style={{display:"flex",alignItems:"flex-start",gap:12,marginTop:12,cursor:"pointer"}}>
            <input type="checkbox" checked={checkedPrivacy} onChange={e=>setCheckedPrivacy(e.target.checked)} style={{marginTop:2,accentColor:N.gold,width:16,height:16,flexShrink:0}}/>
            <span style={{fontSize:10,color:N.parchD,lineHeight:1.6}}>I have read and agree to the <span style={{color:N.gold}}>Privacy Policy</span></span>
          </label>
        </div>

        {/* Signature */}
        <div style={{marginBottom:24}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:8}}>Electronic Signature</div>
          <div style={{fontSize:10,color:N.parchD,marginBottom:10,lineHeight:1.6}}>Type your full legal name below as your electronic acknowledgment of the above agreements.</div>
          <input
            value={signature}
            onChange={e=>setSignature(e.target.value)}
            placeholder="Your full legal name"
            style={{width:"100%",background:N.navyMid,border:`1px solid ${checkedTerms&&checkedPrivacy?N.gold:N.goldLine}`,borderRadius:8,padding:"12px 16px",color:N.parch,fontSize:14,outline:"none",fontFamily:"Georgia,serif",fontStyle:"italic"}}
          />
          {signature.trim().length>0&&<div style={{fontSize:9,color:N.parchD,marginTop:4}}>Signed: {signature} · {new Date().toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}</div>}
        </div>
      </div>

      {/* CTA */}
      <div style={{position:"fixed",bottom:0,left:0,right:0,padding:"16px 20px",background:N.navy,borderTop:`1px solid ${N.goldLine}`,maxWidth:"var(--pt-shell-width)",margin:"0 auto",boxSizing:"border-box"}}>
        <button onClick={()=>canSubmit&&onAccept(signature)} disabled={!canSubmit}
          style={{width:"100%",background:canSubmit?N.gold:"rgba(201,168,76,0.2)",border:"none",borderRadius:10,padding:"14px",color:canSubmit?N.navy:N.parchD,fontSize:11,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:canSubmit?"pointer":"not-allowed",transition:"all 0.2s"}}>
          {canSubmit?"I Agree — Enter My Account":"Complete All Fields Above"}
        </button>
        <div style={{fontSize:8,color:N.parchD,textAlign:"center",marginTop:8}}>This agreement is legally binding · Provisions Travel LLC</div>
      </div>
    </div>
  );
}

// ─── CLIENT: Profile Edit ───
function ClientProfileEdit({profile, onSave, onBack}){
  const trip = sortTrips(TRIPS).find(t=>tripStatus(t)!=="Completed")||TRIPS[0];
  const defaults = trip?.profile||{};
  const [form, setForm] = useState(()=>({
    name: profile.name||defaults.name||"",
    email: profile.email||defaults.email||"",
    phone: profile.phone||defaults.phone||"",
    cabin: profile.cabin||defaults.cabin||"First Class",
    seat: profile.seat||defaults.seat||"Window",
    hotel: profile.hotel||defaults.hotel||"",
    dietary: profile.dietary||defaults.dietary||"",
    downtime: profile.downtime||defaults.downtime||"",
    tsa: profile.tsa||defaults.tsa||"",
    travelingWith: profile.travelingWith||defaults.travelingWith||"",
    childrenAges: profile.childrenAges||defaults.childrenAges||"",
    loyalties: profile.loyalties||[],
    travelers: profile.travelers||defaults.travelers||[],
    notes: profile.notes||"",
    passportExpiry: profile.passportExpiry||defaults.passportExpiry||"",
  }));
  const addLoyalty=()=>setForm(f=>({...f,loyalties:[...f.loyalties,{program:"",number:""}]}));
  const removeLoyalty=(i)=>setForm(f=>({...f,loyalties:f.loyalties.filter((_,j)=>j!==i)}));
  const updateLoyalty=(i,key,val)=>setForm(f=>({...f,loyalties:f.loyalties.map((l,j)=>j===i?{...l,[key]:val}:l)}));
  const addTraveler=()=>setForm(f=>({...f,travelers:[...f.travelers,{name:"",birthdate:""}]}));
  const removeTraveler=(i)=>setForm(f=>({...f,travelers:f.travelers.filter((_,j)=>j!==i)}));
  const updateTraveler=(i,key,val)=>setForm(f=>({...f,travelers:f.travelers.map((t,j)=>j===i?{...t,[key]:val}:t)}));

  const sel=(key,label,opts)=>(
    <div key={key} style={{marginBottom:14}}>
      <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>{label}</div>
      <select value={form[key]||""} onChange={e=>setForm(f=>({...f,[key]:e.target.value}))}
        style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:form[key]?N.parch:N.parchD,fontSize:12,outline:"none",fontFamily:"inherit",appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23B8976A' stroke-width='1.5' fill='none'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 14px center"}}>
        <option value="" disabled>Select…</option>
        {opts.map(o=><option key={o} value={o}>{o}</option>)}
      </select>
    </div>
  );

  const txt=(key,label,placeholder="")=>(
    <div key={key} style={{marginBottom:14}}>
      <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>{label}</div>
      <input value={form[key]||""} onChange={e=>setForm(f=>({...f,[key]:e.target.value}))} placeholder={placeholder}
        style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit"}}/>
    </div>
  );
  const dateInput=(key,label)=>(
    <div key={key} style={{marginBottom:14}}>
      <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>{label}</div>
      <input type="date" value={form[key]||""} onChange={e=>setForm(f=>({...f,[key]:e.target.value}))}
        style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",colorScheme:"dark"}}/>
    </div>
  );

  return(
    <Screen>
      <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
        <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,flex:1}}>My Profile</div>
      </div>
      <div style={{padding:"20px"}}>
        <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 14px",marginBottom:20,fontSize:10,color:N.parchD,lineHeight:1.7}}>
          Your preferences are pre-filled from your intake. Update anything below — Shayla will be notified.
        </div>

        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12,marginTop:4}}>Contact</div>
        {txt("name","Full Name","Marcus W.")}
        {txt("email","Email","marcus@company.com")}
        {txt("phone","Phone","+1 (404) 555-0192")}

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Travel Documents</div>
        {dateInput("passportExpiry","Passport Expiration Date")}
        <div style={{fontSize:9,color:N.parchD,marginTop:-8,marginBottom:14,lineHeight:1.6}}>We'll give Shayla a heads-up automatically if this is set to expire close to an upcoming trip.</div>

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Flight Preferences</div>
        {sel("cabin","Cabin Class",["Economy","Premium Economy","Business Class","First Class"])}
        {sel("seat","Seat Preference",["Window","Aisle","No preference","Exit row if available","Window · Exit row if available","Aisle · Exit row if available"])}
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:8}}>Loyalty Programs</div>
        {form.loyalties.map((l,i)=>(
          <div key={i} style={{display:"flex",gap:8,marginBottom:8,alignItems:"center"}}>
            <select value={l.program} onChange={e=>updateLoyalty(i,"program",e.target.value)}
              style={{flex:"0 0 48%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:l.program?N.parch:N.parchD,fontSize:11,outline:"none",fontFamily:"inherit",appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23B8976A' stroke-width='1.5' fill='none'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 10px center"}}>
              <option value="" disabled>Program…</option>
              {["Delta SkyMiles","United MileagePlus","American AAdvantage","Southwest Rapid Rewards","Alaska Mileage Plan","JetBlue TrueBlue","Air France Flying Blue","British Airways Avios","Emirates Skywards","Marriott Bonvoy","Hilton Honors","World of Hyatt","IHG Rewards","Wyndham Rewards","Choice Privileges","Hertz Gold Plus","National Emerald","Avis Preferred","Global Entry","TSA PreCheck","CLEAR","Other"].map(o=><option key={o} value={o}>{o}</option>)}
            </select>
            <input value={l.number} onChange={e=>updateLoyalty(i,"number",e.target.value)} placeholder="Member #"
              style={{flex:1,background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit"}}/>
            <button onClick={()=>removeLoyalty(i)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,width:28,height:38,cursor:"pointer",color:N.parchD,fontSize:14,flexShrink:0}}>×</button>
          </div>
        ))}
        <button onClick={addLoyalty} style={{background:"transparent",border:`1px dashed ${N.gold}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:10,fontWeight:700,letterSpacing:"0.1em",cursor:"pointer",marginBottom:14,width:"100%"}}>+ Add Program</button>
        {sel("tsa","TSA / Global Entry",["TSA PreCheck","Global Entry","Both","Neither / Not enrolled"])}

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Hotel Preferences</div>
        {sel("hotel","Brand Preference",["No preference","Four Seasons","Ritz-Carlton","St. Regis","Aman","Rosewood","Mandarin Oriental","Waldorf Astoria","Four Seasons · Ritz-Carlton","Boutique / Independent"])}

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Lifestyle</div>
        {sel("dietary","Dietary Restrictions",["None","No shellfish","Vegetarian","Vegan","Gluten-free","Kosher","Halal","Nut allergy","No shellfish · Nut allergy","Other (see notes)"])}
        {sel("downtime","Downtime Style",["Spa & relaxation","Early hotel return","Fitness / gym","Explore locally","Shopping","Cultural / museums","Nightlife","Spa · Early hotel return","Active / outdoor"])}

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Travel Party</div>
        {txt("travelingWith","Traveling With (names)","e.g. Sarah W., James W.")}
        {txt("childrenAges","Children Ages","e.g. 4, 7, 12")}

        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginTop:14,marginBottom:8}}>Travelers &amp; Birthdates</div>
        <div style={{fontSize:9,color:N.parchD,marginBottom:10,lineHeight:1.6}}>Add everyone traveling — age is calculated automatically from their birthdate, so it's always current.</div>
        {form.travelers.map((t,i)=>{
          const age = calcAge(t.birthdate);
          return(
            <div key={i} style={{display:"flex",gap:8,marginBottom:8,alignItems:"center"}}>
              <input value={t.name} onChange={e=>updateTraveler(i,"name",e.target.value)} placeholder="Full name"
                style={{flex:"1 1 40%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit"}}/>
              <input type="date" value={t.birthdate} onChange={e=>updateTraveler(i,"birthdate",e.target.value)}
                style={{flex:"1 1 34%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit",colorScheme:"dark"}}/>
              <div style={{flex:"0 0 40px",textAlign:"center",fontSize:11,color:N.gold,fontWeight:700}}>{age!=null?age:"—"}</div>
              <button onClick={()=>removeTraveler(i)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,width:28,height:38,cursor:"pointer",color:N.parchD,fontSize:14,flexShrink:0}}>×</button>
            </div>
          );
        })}
        <button onClick={addTraveler} style={{background:"transparent",border:`1px dashed ${N.gold}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:10,fontWeight:700,letterSpacing:"0.1em",cursor:"pointer",marginBottom:14,width:"100%"}}>+ Add Traveler</button>

        <div style={{height:1,background:N.goldLine,margin:"16px 0"}}/>
        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",color:N.parchD,marginBottom:12}}>Notes</div>
        <div style={{marginBottom:14}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>Additional Notes for Shayla</div>
          <textarea value={form.notes||""} onChange={e=>setForm(f=>({...f,notes:e.target.value}))} placeholder="Anything else your concierge should know…" rows={4}
            style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",resize:"vertical",lineHeight:1.6}}/>
        </div>

        <button onClick={()=>onSave(form)} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:14,color:N.navy,fontSize:10,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:"pointer",marginTop:8}}>
          Save & Notify Shayla
        </button>
      </div>
    </Screen>
  );
}

// ─── StyleCast Card ───
const DEST_COORDS = {
  "New York City":   {lat:40.7128, lon:-74.006},
  "London, England": {lat:51.5074, lon:-0.1278},
  "Cancún, Mexico":  {lat:21.1619, lon:-86.8515},
};
const WMO_DESC = {0:"Clear",1:"Mainly Clear",2:"Partly Cloudy",3:"Overcast",45:"Fog",51:"Drizzle",61:"Rain",71:"Snow",80:"Showers",95:"Thunderstorm"};

function StyleCastCard({trip}){
  const [linked, setLinked] = React.useState(()=>localStorage.getItem("pt_sc_linked")==="1");
  const [weather, setWeather] = React.useState(null);
  const [showLogin, setShowLogin] = React.useState(false);
  const [email, setEmail] = React.useState("");
  const [pass, setPass] = React.useState("");
  const [err, setErr] = React.useState("");

  React.useEffect(()=>{
    if(!linked||!trip) return;
    const coords = DEST_COORDS[trip.destination];
    if(!coords) return;
    fetch(`https://api.open-meteo.com/v1/forecast?latitude=${coords.lat}&longitude=${coords.lon}&current=temperature_2m,weathercode&temperature_unit=fahrenheit`)
      .then(r=>r.json())
      .then(d=>{
        const c=d.current;
        setWeather({temp:Math.round(c.temperature_2m), desc:WMO_DESC[c.weathercode]||"Clear"});
      }).catch(()=>{});
  },[linked, trip?.destination]);

  function doLogin(){
    if(!email||!pass){setErr("Please enter your StyleCast email and password.");return;}
    if(!email.includes("@")){setErr("Please enter a valid email.");return;}
    localStorage.setItem("pt_sc_linked","1");
    setLinked(true);
    setShowLogin(false);
    setErr("");
  }

  return(
    <>
    {showLogin&&(
      <div onClick={()=>setShowLogin(false)} style={{position:"fixed",inset:0,background:"rgba(10,22,40,0.92)",zIndex:200,display:"flex",alignItems:"center",justifyContent:"center",padding:24}}>
        <div onClick={e=>e.stopPropagation()} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:16,padding:24,width:"100%",maxWidth:340}}>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,marginBottom:4}}>Log in to StyleCast</div>
          <div style={{fontSize:9,color:N.parchD,marginBottom:18,lineHeight:1.7}}>An active StyleCast subscription is required to use this feature.</div>
          {err&&<div style={{fontSize:9,color:"#e57373",marginBottom:10}}>{err}</div>}
          <input value={email} onChange={e=>setEmail(e.target.value)} placeholder="StyleCast email" type="email"
            style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 12px",color:N.parch,fontSize:11,marginBottom:10,outline:"none"}}/>
          <input value={pass} onChange={e=>setPass(e.target.value)} placeholder="Password" type="password"
            style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 12px",color:N.parch,fontSize:11,marginBottom:16,outline:"none"}}/>
          <button onClick={doLogin} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:13,color:N.navy,fontWeight:700,fontSize:11,cursor:"pointer",letterSpacing:"0.1em",marginBottom:10}}>LOG IN</button>
          <div style={{textAlign:"center"}}>
            <a href="https://www.getstylecast.com/" target="_blank" style={{fontSize:9,color:N.sky,textDecoration:"none"}}>Don't have an account? Sign up at StyleCast →</a>
          </div>
        </div>
      </div>
    )}
    <button onClick={linked?undefined:()=>setShowLogin(true)}
      style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"18px 14px",cursor:linked?"default":"pointer",textAlign:"left",position:"relative"}}>
      <div style={{marginBottom:10,display:"flex",alignItems:"center",justifyContent:"space-between"}}>
        <Icon name="star" size={20} color={N.gold}/>
        {linked&&<span onClick={e=>{e.stopPropagation();localStorage.removeItem("pt_sc_linked");setLinked(false);setWeather(null);}} style={{fontSize:8,color:N.parchD,cursor:"pointer",letterSpacing:"0.08em",textDecoration:"underline"}}>Unlink</span>}
      </div>
      <div style={{fontSize:12,fontWeight:600,color:N.parch,marginBottom:4}}>StyleCast</div>
      {linked&&weather?(
        <div>
          <div style={{fontSize:18,fontWeight:700,color:N.gold,lineHeight:1}}>{weather.temp}°F</div>
          <div style={{fontSize:9,color:N.parchD,marginTop:2}}>{weather.desc} · {trip?.destination?.split(",")[0]}</div>
        </div>
      ):(
        <div style={{fontSize:9,color:N.parchD}}>{linked?"Loading weather…":"Subscription required"}</div>
      )}
    </button>
    </>
  );
}

// ─── CLIENT: Home ───
function ClientHome({trips, currentClient, conciergeActive=true, setTab, onEditProfile, docsUnread=0, onTripSelect, onDocsOpen}){
  trips = trips || [];
  // A brand-new client (just signed up, no trip booked yet) legitimately has
  // an empty trips array. Rather than hiding the whole home page behind a
  // bare "welcome" message, we still render the full layout below — every
  // card just falls back to a placeholder/empty state instead of crashing
  // on trip.startDate/trip.destination/etc.
  const [clientPhoto, setClientPhoto] = React.useState(()=>localStorage.getItem("pt_client_photo")||null);
  const photoInputRef = React.useRef(null);
  function handlePhotoChange(e){
    const file = e.target.files?.[0];
    if(!file) return;
    const reader = new FileReader();
    reader.onload = ev => { const url = ev.target.result; localStorage.setItem("pt_client_photo", url); setClientPhoto(url); };
    reader.readAsDataURL(file);
  }
  // Real document count — pulled straight from Firestore, same source
  // ClientDocs itself reads from. No more fake localStorage counters.
  const [totalDocs, setTotalDocs] = useState(0);
  useEffect(()=>{
    if(!currentClient?.id){ setTotalDocs(0); return; }
    let cancelled=false;
    PT.fetchDocuments(currentClient.id).then(docs=>{ if(!cancelled) setTotalDocs(docs.length); }).catch(()=>{});
    return ()=>{cancelled=true;};
  },[currentClient?.id]);
  const trip = trips.length ? (sortTrips(trips).find(t=>tripStatus(t)!=="Completed")||trips[0]) : null;
  const [daysLeft] = useState(()=>trip&&trip.startDate?Math.max(0,Math.ceil((new Date(trip.startDate+"T00:00:00")-new Date())/(1000*60*60*24))):0);
  const upcomingTrips = trips.length ? sortTrips(trips).filter(t=>tripStatus(t)!=="Completed") : [];

  // Real client name/initials — was hardcoded to the demo "Marcus W." before.
  const clientName = (currentClient&&(currentClient.full_name||currentClient.fullName))||"";
  const nameParts = clientName.trim().split(/\s+/).filter(Boolean);
  const firstName = nameParts[0]||"there";
  const lastInitial = nameParts.length>1 ? nameParts[nameParts.length-1][0]+"." : "";
  const initials = nameParts.length ? (nameParts[0][0]+(nameParts.length>1?nameParts[nameParts.length-1][0]:"")).toUpperCase() : "?";

  return(
    <Screen>
      {/* Hero header */}
      <div style={{background:`linear-gradient(160deg, ${N.navyMid} 0%, ${N.navy} 100%)`,padding:"28px 20px 26px",borderBottom:`1px solid ${N.goldLine}`,position:"relative",overflow:"hidden"}}>
        <div style={{position:"absolute",top:-40,right:-40,width:180,height:180,borderRadius:"50%",background:`radial-gradient(circle, ${N.gold}08 0%, transparent 70%)`}}/>
        <div style={{display:"flex",alignItems:"center",gap:14,marginBottom:22}}>
          <div style={{position:"relative",cursor:"pointer"}} onClick={()=>photoInputRef.current?.click()}>
            <Avatar initials={initials} size={52} photo={clientPhoto}/>
            <div style={{position:"absolute",bottom:0,right:0,width:16,height:16,borderRadius:"50%",background:N.gold,display:"flex",alignItems:"center",justifyContent:"center"}}>
              <span style={{fontSize:9,color:N.navy,fontWeight:700,lineHeight:1}}>+</span>
            </div>
            <input ref={photoInputRef} type="file" accept="image/*" style={{display:"none"}} onChange={handlePhotoChange}/>
          </div>
          <div>
            <div style={{fontSize:11,color:N.parchD,marginBottom:2}}>Welcome back,</div>
            <div style={{fontFamily:"Georgia,serif",fontSize:24,color:N.parch,fontWeight:400,lineHeight:1.1}}>{firstName} {lastInitial&&<em style={{color:N.gold,fontStyle:"italic"}}>{lastInitial}</em>}</div>
          </div>
        </div>
        {/* Countdown card */}
        <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"22px 20px",display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:22}}>
          <div>
            <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:4}}>Next Departure</div>
            <div style={{fontFamily:"Georgia,serif",fontSize:20,color:N.parch,marginBottom:4}}>{trip?trip.destination:"No trip booked yet"}</div>
            <div style={{fontSize:10,color:N.parchD}}>{trip?trip.dates:"Your concierge is working on it"}</div>
          </div>
          <div style={{textAlign:"right"}}>
            <div style={{fontFamily:"Georgia,serif",fontSize:44,color:N.gold,lineHeight:1}}>{trip?daysLeft:"—"}</div>
            <div style={{fontSize:9,color:N.parchD,letterSpacing:"0.1em"}}>DAYS AWAY</div>
          </div>
        </div>
        {/* Status strip — 3 columns */}
        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:8}}>
          {/* Flight */}
          <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
            <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>FLIGHT</div>
            {/* Departure */}
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>DEPARTURE</div>
            <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{trip?.flightOut||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {trip?.flightOutTime||"—"} · Arr: {trip?.flightOutArrivalTime||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{trip?.flightOutDate||""}</div>
            <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
            {/* Return */}
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>RETURN</div>
            <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{trip?.flightReturn||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {trip?.flightReturnTime||"—"} · Arr: {trip?.flightReturnArrivalTime||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{trip?.flightReturnDate||""}</div>
          </div>
          {/* Transport */}
          <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
            <div style={{display:"flex",alignItems:"center",gap:4,marginBottom:6}}>

              <span style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em"}}>TRANSPORT</span>
            </div>
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>PICKUP</div>
            <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{trip?(trip.carCompany||"Private Sedan"):"—"} {trip&&`· ${trip.carPickup||"Airport"}`}</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{trip?.carPickupTime||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{trip?.flightOutDate||""}</div>
            <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>DROP-OFF</div>
            <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{trip?(trip.carCompany||"Private Sedan"):"—"} {trip&&`· ${trip.carDropoff||"Airport"}`}</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{trip?.carDropoffTime||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{trip?(trip.flightReturnDate||trip.endDate):""}</div>
          </div>
          {/* Hotel */}
          <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
            <div style={{display:"flex",alignItems:"center",gap:4,marginBottom:6}}>

              <span style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em"}}>HOTEL</span>
            </div>
            <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:2,lineHeight:1.3}}>{trip?.hotel||"—"}</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:4,lineHeight:1.3}}>{trip?.hotelAddress||""}</div>
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-IN</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:3}}>{trip?(trip.days?.[0]?.entries?.find(e=>e.cat==="hotel")?.time||"12:30 PM"):"—"} {trip&&`· ${trip.flightOutDate||""}`}</div>
            <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-OUT</div>
            <div style={{fontSize:7,color:N.parchD,marginBottom:4}}>{trip?(trip.days?.[trip.days.length-1]?.entries?.find(e=>e.cat==="hotel")?.time||"12:00 PM"):"—"} {trip&&`· ${trip.flightReturnDate||trip.endDate||""}`}</div>
            {trip?.hotelPhone&&<a href={trip.hotelPhoneHref} style={{fontSize:7,color:N.sky,textDecoration:"none",display:"flex",alignItems:"center",gap:3}}>{trip.hotelPhone}</a>}
          </div>
        </div>
      </div>

      {/* Quick Actions */}
      <div style={{padding:"26px 20px 0"}}>
        <SectionTitle small>Quick Actions</SectionTitle>
        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12,marginBottom:26}}>
          {[
            {icon:"map",   label:"View Itinerary",   sub:"Day-by-day plan",   tab:"__itinerary__"},
            {icon:"doc",   label:"My Documents",     sub:`${totalDocs} file${totalDocs===1?"":"s"} ready`, tab:"__docs__", badge:docsUnread},
            {icon:"edit",  label:"My Profile",       sub:"Update preferences", tab:"__profile__"},
          ].map(a=>{
            const disabled = a.tab==="__itinerary__" && !trip;
            return(
            <button key={a.label} disabled={disabled} onClick={()=>a.tab==="__profile__"?onEditProfile():a.tab==="__itinerary__"?(trip&&onTripSelect&&onTripSelect(trip)):a.tab==="__docs__"?setTab("docs"):setTab(a.tab)}
              style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"18px 14px",cursor:disabled?"not-allowed":"pointer",opacity:disabled?0.5:1,textAlign:"left",transition:"border-color 0.2s",position:"relative"}}>
              {a.badge>0&&<span style={{position:"absolute",top:8,right:8,background:N.gold,color:N.navy,fontSize:8,fontWeight:700,borderRadius:"50%",width:16,height:16,display:"flex",alignItems:"center",justifyContent:"center"}}>{a.badge}</span>}
              <div style={{marginBottom:10}}><Icon name={a.icon} size={20} color={N.gold}/></div>
              <div style={{fontSize:12,fontWeight:600,color:N.parch,marginBottom:4}}>{a.label}</div>
              <div style={{fontSize:9,color:N.parchD}}>{disabled?"No trip yet":a.sub}</div>
            </button>
            );
          })}
          <StyleCastCard trip={trip}/>
        </div>

        {/* Contact Concierge */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px 18px",marginBottom:26}}>
          <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:12}}>
            <Avatar initials="SL" size={38}/>
            <div style={{flex:1}}>
              <div style={{fontSize:12,fontWeight:600,color:N.parch,marginBottom:3}}>Shayla L.</div>
              <div style={{fontSize:9,color:N.parchD}}>Your Personal Concierge</div>
            </div>
            <div style={{display:"flex",alignItems:"center",gap:5}}>
              <div style={{width:7,height:7,borderRadius:"50%",background:conciergeActive?N.green:N.parchD}}/>
              <span style={{fontSize:9,fontWeight:700,color:conciergeActive?N.green:N.parchD,letterSpacing:"0.08em"}}>{conciergeActive?"ACTIVE":"OFFLINE"}</span>
            </div>
          </div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}}>
            <a href="tel:+17067998978" onClick={e=>{if(!/Mobi|Android/i.test(navigator.userAgent)){e.preventDefault();navigator.clipboard&&navigator.clipboard.writeText("+17067998978").then(()=>alert("Number copied: +1 (706) 799-8978"));}}} style={{background:N.gold,border:`1px solid ${N.gold}`,borderRadius:8,padding:"11px 0",textAlign:"center",textDecoration:"none",display:"block"}}>
              <div style={{fontSize:10,fontWeight:700,color:N.navy,letterSpacing:"0.1em"}}>CALL</div>
            </a>
            <button onClick={()=>setTab("messages")} style={{background:N.gold,border:`1px solid ${N.gold}`,borderRadius:8,padding:"11px 0",cursor:"pointer",textAlign:"center",width:"100%"}}>
              <div style={{fontSize:10,fontWeight:700,color:N.navy,letterSpacing:"0.1em"}}>MESSAGE</div>
            </button>
          </div>
        </div>

        {/* Upcoming Trips */}
        <SectionTitle small>Upcoming Trips</SectionTitle>
        {upcomingTrips.length===0 ? (
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"20px 18px",marginBottom:20,textAlign:"center"}}>
            <div style={{fontSize:11,color:N.parchD,lineHeight:1.7}}>No trips booked yet. Your concierge will add your itinerary here — flights, hotels, and a day-by-day plan — as soon as it's ready.</div>
          </div>
        ) : (
          <div style={{display:"flex",flexDirection:"column",gap:10,marginBottom:20}}>
            {upcomingTrips.map(t=>{
              return(
              <div key={t.id} onClick={()=>onTripSelect&&onTripSelect(t)}
                style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"14px 16px",cursor:"pointer",display:"flex",justifyContent:"space-between",alignItems:"center",gap:12}}>
                <DestPhoto destination={t.destination} size={44} radius={8}/>
                <div style={{flex:1}}>
                  <div style={{fontFamily:"Georgia,serif",fontSize:15,color:N.parch,marginBottom:3}}>{t.destination}</div>
                  <div style={{fontSize:10,color:N.parchD}}>{t.dates}</div>
                </div>
                <div style={{display:"flex",alignItems:"center",gap:10}}>
                  {t.startDate&&(()=>{
                    const d=Math.max(0,Math.ceil((new Date(t.startDate+"T00:00:00")-new Date())/(1000*60*60*24)));
                    return <div style={{textAlign:"right"}}><div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.gold,lineHeight:1}}>{d}</div><div style={{fontSize:7,color:N.parchD,letterSpacing:"0.08em"}}>DAYS</div></div>;
                  })()}
                  <span style={{color:N.gold,fontSize:16}}>›</span>
                </div>
              </div>
            );})}
          </div>
        )}
      </div>
    </Screen>
  );
}

// ─── CLIENT: Trips ───
function ClientTrips({trips, initialTrip=null, onClearTrip, onDocsOpen}){
  trips = trips || TRIPS;
  const [selected, setSelected] = useState(initialTrip);
  const scrollRef = React.useRef();
  useEffect(()=>{if(initialTrip){setSelected(initialTrip);window.scrollTo(0,0);}},[initialTrip]);

  const TripCard=({t, onSelect})=>(
    <div onClick={()=>onSelect(t)} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px 18px",cursor:"pointer",marginBottom:10,display:"flex",justifyContent:"space-between",alignItems:"center",gap:12}}>
      <DestPhoto destination={t.destination} size={44} radius={8}/>
      <div style={{flex:1}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:16,color:N.parch,marginBottom:3}}>{t.destination}</div>
        <div style={{fontSize:10,color:N.parchD,marginBottom:6}}>{t.dates} · {t.nights} nights · {t.hotel}</div>
        <div style={{fontSize:9,color:N.parchD}}>{t.type} · {t.tier}</div>
      </div>
      <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:8}}>
        {t.startDate&&tripStatus(t)!=="Completed"&&tripStatus(t)!=="Active"&&(()=>{
          const d=Math.max(0,Math.ceil((new Date(t.startDate+"T00:00:00")-new Date())/(1000*60*60*24)));
          return <div style={{textAlign:"right"}}><span style={{fontFamily:"Georgia,serif",fontSize:18,color:N.gold,lineHeight:1}}>{d}</span><div style={{fontSize:7,color:N.parchD,letterSpacing:"0.08em"}}>DAYS</div></div>;
        })()}
        {tripStatus(t)==="Active"&&<span style={{fontSize:8,fontWeight:700,color:N.green,letterSpacing:"0.12em"}}>ACTIVE</span>}
        {tripStatus(t)==="Completed"&&<span style={{fontSize:8,color:N.parchD,letterSpacing:"0.08em"}}>DONE</span>}
        <span style={{color:N.gold,fontSize:18}}>›</span>
      </div>
    </div>
  );

  if(selected){
    const s=selected;
    const daysLeft = s.startDate ? Math.max(0,Math.ceil((new Date(s.startDate+"T00:00:00")-new Date())/(1000*60*60*24))) : 0;
    return(
      <Screen>
        {/* Hero header — mirrors home screen */}
        <div style={{background:`linear-gradient(160deg, ${N.navyMid} 0%, ${N.navy} 100%)`,padding:"28px 20px 26px",borderBottom:`1px solid ${N.goldLine}`,position:"relative",overflow:"hidden"}}>
          <div style={{position:"absolute",top:-40,right:-40,width:180,height:180,borderRadius:"50%",background:`radial-gradient(circle, ${N.gold}08 0%, transparent 70%)`}}/>
          {/* Back button */}
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,position:"relative",zIndex:2}}>
            <button onClick={()=>{setSelected(null);onClearTrip&&onClearTrip();}} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Trips</button>
            <button onClick={()=>{if(onDocsOpen)onDocsOpen("trip-"+s.id);}} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>Documents →</button>
          </div>
          {/* Countdown card */}
          <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"22px 20px",display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:22}}>
            <div>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:4}}>Next Departure</div>
              <div style={{fontFamily:"Georgia,serif",fontSize:20,color:N.parch,marginBottom:4}}>{s.destination}</div>
              <div style={{fontSize:10,color:N.parchD}}>{s.dates}</div>
            </div>
            <div style={{textAlign:"right"}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:44,color:N.gold,lineHeight:1}}>{daysLeft}</div>
              <div style={{fontSize:9,color:N.parchD,letterSpacing:"0.1em"}}>DAYS AWAY</div>
            </div>
          </div>
          {/* 3-column status strip */}
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:8}}>
            {/* Flight */}
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>FLIGHT</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>DEPARTURE</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.flightOut}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {s.flightOutTime} · Arr: {s.flightOutArrivalTime||"—"}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{s.flightOutDate}</div>
              <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>RETURN</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.flightReturn}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {s.flightReturnTime} · Arr: {s.flightReturnArrivalTime||"—"}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{s.flightReturnDate}</div>
            </div>
            {/* Transport */}
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>TRANSPORT</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>PICKUP</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.carCompany||"Private Sedan"} · {s.carPickup||"Airport"}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{s.carPickupTime}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{s.flightOutDate}</div>
              <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>DROP-OFF</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.carCompany||"Private Sedan"} · {s.carDropoff||"Airport"}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{s.carDropoffTime}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{s.flightReturnDate||s.endDate}</div>
            </div>
            {/* Hotel */}
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>HOTEL</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:2,lineHeight:1.3}}>{s.hotel}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:4,lineHeight:1.3}}>{s.hotelAddress}</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-IN</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:3}}>{s.days?.[0]?.entries?.find(e=>e.cat==="hotel")?.time||"12:30 PM"} · {s.flightOutDate}</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-OUT</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:4}}>{s.days?.[s.days.length-1]?.entries?.find(e=>e.cat==="hotel")?.time||"12:00 PM"} · {s.flightReturnDate||s.endDate}</div>
              {s.hotelPhone&&<a href={s.hotelPhoneHref} style={{fontSize:7,color:N.sky,textDecoration:"none"}}>{s.hotelPhone}</a>}
            </div>
          </div>
        </div>
        {/* Day-by-day itinerary */}
        <div style={{padding:"20px 20px 0"}}>
          <SectionTitle small>Day-by-Day Itinerary</SectionTitle>
          {(s.days||[]).length===0&&<div style={{fontSize:10,color:N.parchD,fontStyle:"italic",padding:"12px 0"}}>No itinerary yet.</div>}
          {(s.days||[]).map(day=>(
            <div key={day.n} style={{marginBottom:20}}>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",textTransform:"uppercase",color:N.gold,marginBottom:10,paddingBottom:6,borderBottom:`1px solid ${N.goldLine}`}}>DAY {day.n} · {day.title} · {day.date}</div>
              {(day.entries||[]).map((e,i)=>(
                <div key={i} style={{display:"flex",gap:10,marginBottom:10,paddingLeft:4}}>
                  <div style={{display:"flex",flexDirection:"column",alignItems:"center",gap:2}}>
                    <div style={{fontSize:10,color:N.gold,lineHeight:1,fontWeight:700}}>{e.icon||"·"}</div>
                    {i<(day.entries.length-1)&&<div style={{width:1,flex:1,background:N.goldLine,minHeight:12}}/>}
                  </div>
                  <div style={{flex:1,paddingBottom:2}}>
                    <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:2}}>
                      <div style={{fontSize:11,fontWeight:600,color:N.parch,lineHeight:1.3,flex:1,paddingRight:8}}>{e.name}</div>
                      <div style={{fontSize:9,color:N.gold,fontWeight:700,flexShrink:0}}>{e.time}</div>
                    </div>
                    <div style={{fontSize:9,color:N.parchD,lineHeight:1.5}}>{e.detail}</div>
                  </div>
                </div>
              ))}
            </div>
          ))}
        </div>
      </Screen>
    );
  }

  return(
    <Screen>
      <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`}}>
        <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>My Trips</div>
      </div>
      <div style={{padding:"20px"}}>
        {trips.length===0 && (
          <EmptyState title="No trips yet" body="Your concierge is putting together your first itinerary. It'll show up here as soon as it's booked."/>
        )}
        {["Active","Upcoming","Completed"].map(section=>{
          const filtered=sortTrips(trips).filter(t=>{
            const st=tripStatus(t);
            if(section==="Upcoming") return st==="Upcoming"||st==="Planning";
            if(section==="Active") return st==="Active";
            if(section==="Completed") return st==="Completed";
            return false;
          });
          if(filtered.length===0) return null;
          return(
            <div key={section} style={{marginBottom:24}}>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10,paddingBottom:6,borderBottom:`1px solid ${N.goldLine}`}}>{section}</div>
              {filtered.map(t=><TripCard key={t.id} t={t} onSelect={(t)=>{setSelected(t);window.scrollTo(0,0);}}/>)}
            </div>
          );
        })}
      </div>
    </Screen>
  );
}

// ─── CLIENT: Messages ───
function ClientMessages({msgs, setMsgs, onOpen, onNewMsg, persistSend}){
  const [text, setText] = useState("");
  const bottomRef = React.useRef();
  useEffect(()=>{onOpen&&onOpen();},[]);
  useEffect(()=>{bottomRef.current&&(bottomRef.current.scrollTop=bottomRef.current.scrollHeight);},[msgs]);

  function send(){
    if(!text.trim())return;
    const sent=text;
    setMsgs(m=>[...m,{id:m.length+1,from:"You",time:"Now",text:sent,mine:false}]);
    setText("");
    if(onNewMsg)onNewMsg();
    if(persistSend)persistSend(sent).catch(()=>{});
  }

  return(
    <div style={{display:"flex",flexDirection:"column",position:"fixed",top:0,left:0,right:0,bottom:52,maxWidth:"var(--pt-shell-width)",margin:"0 auto",overflow:"hidden"}}>
      <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:12,flexShrink:0}}>
        <Avatar initials="SL" size={32}/>
        <div>
          <div style={{fontSize:12,fontWeight:600,color:N.parch}}>Shayla L.</div>
          <div style={{fontSize:9,color:N.gold}}>Your Concierge · Provisions Travel</div>
        </div>
      </div>
      <div ref={bottomRef} style={{flex:1,overflowY:"auto",padding:"16px 16px 8px",display:"flex",flexDirection:"column",gap:10}}>
        {msgs.map(m=>(
          <div key={m.id} style={{display:"flex",flexDirection:m.mine?"row":"row-reverse",gap:8,alignItems:"flex-end"}}>
            {m.mine&&<Avatar initials="SL" size={28}/>}
            <div style={{maxWidth:"75%"}}>
              <div style={{background:m.mine?`${N.gold}18`:N.navyMid,border:`1px solid ${m.mine?N.gold:N.goldLine}`,borderRadius:m.mine?"14px 14px 14px 4px":"14px 14px 4px 14px",padding:"10px 13px"}}>
                <div style={{fontSize:11,color:N.parch,lineHeight:1.5}}>{m.text}</div>
              </div>
              <div style={{fontSize:8,color:N.parchD,marginTop:3,textAlign:m.mine?"left":"right"}}>{m.time}</div>
            </div>
          </div>
        ))}
      </div>
      <div style={{padding:"10px 14px",borderTop:`1px solid ${N.goldLine}`,background:N.navyMid,display:"flex",gap:8,flexShrink:0}}>
        <input value={text} onChange={e=>setText(e.target.value)} onKeyDown={e=>e.key==="Enter"&&send()} placeholder="Message Shayla…"
          style={{flex:1,background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"10px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit"}}/>
        <MicButton onResult={(transcript)=>setText(prev=>prev?`${prev} ${transcript}`:transcript)}/>
        <button onClick={send} style={{background:N.gold,border:"none",borderRadius:20,padding:"10px 18px",color:N.navy,fontSize:11,fontWeight:700,cursor:"pointer"}}>Send</button>
      </div>
    </div>
  );
}

// ─── CLIENT: Documents ───
function ClientDocs({trips=[], currentClient=null, onOpen, initialFolder=null, onBack=null}){
  const agreements=JSON.parse(localStorage.getItem("pt_agreements")||"[]");
  const [openFolder,setOpenFolder]=useState(initialFolder);
  useEffect(()=>{if(initialFolder)setOpenFolder(initialFolder);},[initialFolder]);

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

  // Real documents (Firestore `documents` collection — populated whenever
  // the concierge uploads a source file for AI itinerary extraction, or a
  // client/concierge uploads anything else). No more mock data — every row
  // here is a real Storage-backed file for THIS client.
  const [realDocs,setRealDocs]=useState([]);
  const [docsLoading,setDocsLoading]=useState(true);
  useEffect(()=>{
    if(!currentClient?.id){ setRealDocs([]); setDocsLoading(false); return; }
    let cancelled=false;
    setDocsLoading(true);
    PT.fetchDocuments(currentClient.id)
      .then(docs=>{ if(!cancelled){ setRealDocs(docs); setDocsLoading(false); } })
      .catch(e=>{ console.warn("Could not load documents",e); if(!cancelled){ setRealDocs([]); setDocsLoading(false); } });
    return ()=>{cancelled=true;};
  },[currentClient?.id]);

  function docDisplayName(d){
    return d.fileName || d.name || "Document";
  }
  function docDate(d){
    return d.createdAt ? formatShortDate(d.createdAt) : "";
  }

  // Build folder list — one folder per real trip (matched by tripId), plus
  // an "Other Documents" catch-all for anything uploaded before a trip
  // existed or without a trip association, plus signed agreements.
  const sortedTrips = [...trips].sort((a,b)=>new Date(a.startDate||0)-new Date(b.startDate||0));
  const docsByTrip = {};
  const looseDocs = [];
  realDocs.forEach(d=>{
    if(d.tripId && sortedTrips.some(t=>t.id===d.tripId)){
      (docsByTrip[d.tripId] = docsByTrip[d.tripId]||[]).push(d);
    } else {
      looseDocs.push(d);
    }
  });

  const folders=[
    ...sortedTrips.filter(t=>(docsByTrip[t.id]||[]).length>0).map(t=>({
      id:"trip-"+t.id, label:t.destination, sub:t.dates, destination:t.destination,
      count:(docsByTrip[t.id]||[]).length, isNew:false,
      docs:(docsByTrip[t.id]||[]).map(d=>({name:docDisplayName(d),icon:"doc",size:"",date:docDate(d),isNew:false,storagePath:d.storagePath}))
    })),
    ...(looseDocs.length>0?[{
      id:"other", label:"Other Documents", sub:"From your concierge", destination:null,
      count:looseDocs.length, isNew:false,
      docs:looseDocs.map(d=>({name:docDisplayName(d),icon:"doc",size:"",date:docDate(d),isNew:false,storagePath:d.storagePath}))
    }]:[]),
    ...(agreements.length>0?[{
      id:"agreements", label:"Signed Agreements", sub:"Legal documents", destination:null,
      count:agreements.length, isNew:false,
      docs:agreements.map(ag=>({name:"Client Agreement — "+ag.date,icon:"doc",size:"",date:ag.date,isNew:false,sig:ag.signature}))
    }]:[]),
  ];

  function markRead(){}

  const DocRow=({doc})=>(
    <div onClick={()=>doc.isNew&&markRead(doc.name)}
      style={{background:doc.isNew?`${N.gold}10`:N.navyMid,border:`1px solid ${doc.isNew?N.gold:N.goldLine}`,borderRadius:10,padding:"14px 16px",display:"flex",alignItems:"center",gap:14,cursor:doc.isNew?"pointer":"default"}}>
      <div style={{width:40,height:40,borderRadius:8,background:`${N.gold}15`,border:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}><Icon name="doc" size={18} color={N.gold}/></div>
      <div style={{flex:1}}>
        <div style={{fontSize:12,fontWeight:600,color:N.parch,marginBottom:2}}>{doc.name}</div>
        <div style={{fontSize:9,color:N.parchD}}>{doc.size?doc.size+" · ":""}{doc.date?"Added "+doc.date:""}{doc.sig?" · Signed by "+doc.sig:""}</div>
      </div>
      {doc.isNew&&<span style={{background:N.gold,color:N.navy,fontSize:8,fontWeight:700,letterSpacing:"0.1em",padding:"3px 8px",borderRadius:20,flexShrink:0}}>NEW</span>}
      {!doc.isNew&&<div onClick={(e)=>{
        e.stopPropagation();
        if(doc.storagePath){
          // Real uploaded file — pull the actual download URL from Storage.
          PT.getDocumentUrl(doc.storagePath).then(url=>window.open(url,"_blank")).catch(()=>alert("Could not open this file — try again in a moment."));
          return;
        }
        // No real file behind this row (e.g. a signed-agreement summary) —
        // synthesize a simple PDF from the metadata we do have.
        try{const {jsPDF}=window.jspdf;const pdf=new jsPDF({unit:"pt",format:"letter"});const margin=60;const lineH=20;let y=margin;pdf.setFont("helvetica","bold");pdf.setFontSize(18);pdf.setTextColor(10,22,40);pdf.text("PROVISIONS TRAVEL",margin,y);y+=lineH*1.5;pdf.setFontSize(13);pdf.text(doc.name,margin,y);y+=lineH*1.5;pdf.setFont("helvetica","normal");pdf.setFontSize(10);pdf.setTextColor(80,80,80);const meta=[doc.size&&`Size: ${doc.size}`,doc.date&&`Added: ${doc.date}`,doc.sig&&`Signed by: ${doc.sig}`].filter(Boolean);meta.forEach(m=>{pdf.text(m,margin,y);y+=lineH;});y+=lineH;pdf.setDrawColor(180,150,80);pdf.line(margin,y,612-margin,y);y+=lineH*1.5;pdf.setFontSize(10);pdf.setTextColor(60,60,60);pdf.text("This document was provided by your Provisions Travel concierge.",margin,y);pdf.save(doc.name+".pdf");}catch(err){const blob=new Blob([doc.name+"\n\nDocument provided by Provisions Travel."],{type:"application/pdf"});const a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download=doc.name+".pdf";a.click();}
      }} style={{fontSize:20,color:N.gold,cursor:"pointer",padding:"4px 8px"}}>↓</div>}
    </div>
  );

  // Open folder view
  if(openFolder){
    const folder=folders.find(f=>f.id===openFolder);
    return(
      <Screen>
        <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
          <button onClick={()=>onBack?onBack():setOpenFolder(null)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD}}>{onBack?"← Itinerary":"← Documents"}</button>
          <div style={{fontFamily:"Georgia,serif",fontSize:17,color:N.parch,flex:1}}>{folder?.label}</div>
          <div style={{fontSize:9,color:N.parchD}}>{folder?.count} file{folder?.count===1?"":"s"}</div>
        </div>
        <div style={{padding:"20px"}}>
          <div style={{display:"flex",flexDirection:"column",gap:10}}>
            {(folder?.docs||[]).map((doc,i)=>(<DocRow key={i} doc={doc}/>))}
          </div>
        </div>
      </Screen>
    );
  }

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        <SectionEye label="Document Wallet"/>
        <SectionTitle>Your Trip Files</SectionTitle>
        <div style={{display:"flex",flexDirection:"column",gap:10}}>
          {folders.map(folder=>{
            return(
            <div key={folder.id} onClick={()=>setOpenFolder(folder.id)}
              style={{background:N.navyMid,border:`1px solid ${folder.isNew?N.gold:N.goldLine}`,borderRadius:12,padding:"16px 18px",display:"flex",alignItems:"center",gap:14,cursor:"pointer",transition:"all 0.2s"}}>
              {folder.destination
                ? <DestPhoto destination={folder.destination} size={48} radius={10} showPlaceholder style={{border:`1px solid ${folder.isNew?N.gold:N.goldLine}`}}/>
                : <div style={{width:48,height:48,borderRadius:10,border:`1px solid ${folder.isNew?N.gold:N.goldLine}`,background:`${N.gold}15`,flexShrink:0}}/>}
              <div style={{flex:1}}>
                <div style={{fontSize:13,fontWeight:600,color:N.parch,marginBottom:3}}>{folder.label}</div>
                <div style={{fontSize:9,color:N.parchD}}>{folder.sub} · {folder.count} file{folder.count===1?"":"s"}</div>
              </div>
              {folder.isNew&&<span style={{background:N.gold,color:N.navy,fontSize:8,fontWeight:700,letterSpacing:"0.1em",padding:"3px 8px",borderRadius:20,flexShrink:0}}>NEW</span>}
              <div style={{fontSize:18,color:N.gold}}>›</div>
            </div>
            );
          })}
          {folders.length===0&&docsLoading&&(
            <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"28px 20px",textAlign:"center"}}>
              <div style={{fontSize:11,color:N.parchD}}>Loading your documents…</div>
            </div>
          )}
          {folders.length===0&&!docsLoading&&(
            <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"28px 20px",textAlign:"center"}}>
              <div style={{fontSize:28,marginBottom:8}}></div>
              <div style={{fontSize:11,color:N.parchD}}>No documents yet. Your concierge will upload files here.</div>
            </div>
          )}
        </div>
      </div>
    </Screen>
  );
}
// ─── CLIENT: Profile ───
function ClientProfile({profile={}, onBack, onEdit}){
  const loyalties = profile.loyalties||[];
  const travelers = profile.travelers||[];
  const fields=[
    ["Name",profile.name],["Email",profile.email],["Phone",profile.phone],
    ["Cabin Class",profile.cabin],["Seat",profile.seat],["Hotel Preference",profile.hotel],
    ["Dietary",profile.dietary],["Downtime",profile.downtime],
    ["Traveling With",profile.travelingWith],["Children's Ages",profile.childrenAges],
    ["TSA / Global Entry",profile.tsa],
    ["Loyalty Programs",loyalties.length?loyalties.map(l=>`${l.program||"—"}${l.number?" · "+l.number:""}`).join(", "):""],
    ["Travelers",travelers.length?travelers.map(t=>{const age=calcAge(t.birthdate);return `${t.name||"Traveler"}${age!=null?` (${age})`:""}`;}).join(", "):""],
    ["Notes",profile.notes],
  ].filter(([,v])=>v);
  return(
    <Screen>
      {onBack && (
        <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
          <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,flex:1}}>Traveler Profile</div>
        </div>
      )}
      <div style={{padding:"20px 20px 0"}}>
        {!onBack && <><SectionEye label="Traveler Profile"/><SectionTitle>Your Preferences</SectionTitle></>}
        <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 14px",marginBottom:20,fontSize:10,color:N.parchD,lineHeight:1.7}}>
          This profile is shared with Shayla and refined after every trip. You never repeat yourself.
        </div>
        {fields.length===0 && <div style={{fontSize:12,color:N.parchD,marginBottom:16}}>No preferences on file yet — add some to help your concierge plan ahead.</div>}
        {fields.map(([k,v])=>(
          <div key={k}>
            <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",padding:"11px 0",gap:12}}>
              <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.parchD,flexShrink:0,width:110}}>{k}</div>
              <div style={{fontSize:11,color:N.parch,textAlign:"right",flex:1,lineHeight:1.5}}>{v}</div>
            </div>
            <GoldBar/>
          </div>
        ))}
        <button onClick={onEdit} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:13,color:N.gold,fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:"pointer",marginTop:8}}>
          Edit Preferences
        </button>
      </div>
    </Screen>
  );
}

// ─── CLIENT: Membership (My Profile) ───
// profile comes from the same clientProfile state that Travel Preferences
// edits, so the two screens can never drift out of sync. points/tier are
// computed from this client's own real trips (quoteAmount on any trip
// marked "deposit" or "paid" counts, 1 pt/$1) — no fabricated numbers.
function ClientMembership({profile={}, currentClient, trips=[]}){
  const points = React.useMemo(()=>{
    return trips.reduce((sum,t)=>{
      const counts = t.paymentStatus==="paid" || t.paymentStatus==="deposit";
      return sum + (counts && t.quoteAmount ? Math.round(t.quoteAmount) : 0);
    },0);
  },[trips]);
  const lifetimeSpend = points; // 1 pt / $1, so these are the same number today

  const [activeTier, setActiveTier] = useState(null); // null = follow currentTier

  const refLink = currentClient ? `https://provisionstravel.com/?ref=${currentClient.id}` : "";
  const [copied, setCopied] = useState(false);
  function copyRef(){
    try{
      if(navigator.clipboard){navigator.clipboard.writeText(refLink).then(()=>{setCopied(true);setTimeout(()=>setCopied(false),2500);}).catch(fallback);}
      else{fallback();}
    }catch{fallback();}
    function fallback(){
      const el=document.createElement("textarea");
      el.value=refLink;el.style.position="fixed";el.style.opacity="0";
      document.body.appendChild(el);el.focus();el.select();
      try{document.execCommand("copy");setCopied(true);setTimeout(()=>setCopied(false),2500);}catch{}
      document.body.removeChild(el);
    }
  }

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        <SectionTitle>My Profile</SectionTitle>

        {/* Membership Plan — real tier from the client record + real lifetime spend, not a fabricated plan/renewal date */}
        <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"14px 16px",marginBottom:14,display:"flex",justifyContent:"space-between",alignItems:"center"}}>
          <div>
            <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:3}}>Membership</div>
            <div style={{fontSize:14,fontWeight:600,color:N.parch,fontFamily:"Georgia,serif"}}>{(currentClient&&currentClient.tier)||"Standard"} Member</div>
            <div style={{fontSize:9,color:N.parchD,marginTop:2}}>Member since {formatShortDate(currentClient&&currentClient.createdAt)} · ${lifetimeSpend.toLocaleString()} lifetime</div>
          </div>
          <div style={{background:N.gold,borderRadius:20,padding:"5px 12px"}}>
            <div style={{fontSize:8,fontWeight:700,color:N.navy,letterSpacing:"0.1em"}}>ACTIVE</div>
          </div>
        </div>

        {/* Loyalty Program */}
        {(()=>{
          const tiers=[
            {name:"Silver",color:"#C0C0C0",min:0,max:2500,perks:["Dedicated concierge messaging","Digital document wallet","Traveler preference profile","Early access to new destinations"]},
            {name:"Gold",color:N.gold,min:2500,max:7500,perks:["All Silver perks","Priority booking within 48 hrs","Complimentary trip review call","Hotel upgrade requests","Exclusive travel guides","Birthday trip bonus: 500 pts"]},
            {name:"Platinum",color:"#E5D5FF",min:7500,max:null,perks:["All Gold perks","Quarterly VIP check-in","Airport lounge access coordination","First access to limited trip packages","Exclusive destination guides","Complimentary rush booking (1x/yr)"]},
          ];
          const currentTier = tiers.slice().reverse().find(t=>points>=(t.min))||tiers[0];
          const nextTier = tiers.find(t=>t.min>points);
          const effectiveTier = activeTier || currentTier.name;
          const displayTier = tiers.find(t=>t.name===effectiveTier)||currentTier;
          const progressPct = nextTier ? Math.min(100,((points-currentTier.min)/(nextTier.min-currentTier.min))*100) : 100;
          return(
            <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px",marginBottom:14}}>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:12}}>Loyalty Program</div>
              {/* Current status */}
              <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-end",marginBottom:10}}>
                <div>
                  <div style={{fontFamily:"Georgia,serif",fontSize:32,color:N.parch,lineHeight:1}}>{points.toLocaleString()}</div>
                  <div style={{fontSize:9,color:N.parchD,marginTop:3}}>pts · <span style={{color:currentTier.color,fontWeight:700}}>{currentTier.name} Member</span></div>
                </div>
                <div style={{textAlign:"right",fontSize:9,color:N.parchD}}>
                  <div style={{color:N.parch,fontWeight:600}}>Points = Status</div>
                  {nextTier&&<div>{(nextTier.min-points).toLocaleString()} to {nextTier.name}</div>}
                </div>
              </div>
              <div style={{background:N.navy,borderRadius:4,height:6,marginBottom:10}}>
                <div style={{background:`linear-gradient(to right,${currentTier.color},${nextTier?nextTier.color:currentTier.color})`,borderRadius:4,height:6,width:`${progressPct}%`,transition:"width 1s"}}/>
              </div>
              {/* Tier tabs */}
              <div style={{display:"flex",gap:6,marginBottom:12}}>
                {tiers.map(t=>(
                  <button key={t.name} onClick={()=>setActiveTier(t.name)}
                    style={{flex:1,background:effectiveTier===t.name?`${t.color}20`:"transparent",border:`1px solid ${effectiveTier===t.name?t.color:N.goldLine}`,borderRadius:8,padding:"7px 0",cursor:"pointer",fontSize:9,fontWeight:700,color:effectiveTier===t.name?t.color:N.parchD,letterSpacing:"0.08em"}}>
                    {t.name.toUpperCase()}
                    {t.name===currentTier.name&&<div style={{fontSize:6,color:t.color,marginTop:2}}>CURRENT</div>}
                  </button>
                ))}
              </div>
              {/* Perks */}
              <div style={{background:N.navy,borderRadius:8,padding:"12px 14px"}}>
                <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.14em",color:displayTier.color,textTransform:"uppercase",marginBottom:10}}>{displayTier.name} Perks</div>
                {displayTier.perks.map((p,i)=>(
                  <div key={i} style={{display:"flex",alignItems:"flex-start",gap:8,marginBottom:7}}>
                    <div style={{width:5,height:5,borderRadius:"50%",background:displayTier.color,flexShrink:0,marginTop:4}}/>
                    <div style={{fontSize:10,color:N.parch,lineHeight:1.5}}>{p}</div>
                  </div>
                ))}
                {displayTier.min>0&&<div style={{fontSize:8,color:N.parchD,marginTop:10,borderTop:`1px solid ${N.goldLine}`,paddingTop:8}}>Requires {displayTier.min.toLocaleString()} pts to unlock</div>}
              </div>
            </div>
          );
        })()}

        {/* Refer a friend — real, unique link tied to this client's account.
            Conversions (someone signing up + booking through it) are tracked
            automatically and only visible on the concierge side. */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px",marginBottom:14}}>
          <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Refer a Friend</div>
          <div style={{fontSize:10,color:N.parchD,marginBottom:10,lineHeight:1.6}}>Share your link — when someone signs up and books through it, it's tracked automatically.</div>
          <div style={{fontSize:9,color:N.parchD,marginBottom:8,fontFamily:"monospace",background:N.navy,padding:"8px 10px",borderRadius:6,wordBreak:"break-all"}}>{refLink||"—"}</div>
          <button onClick={copyRef} disabled={!refLink} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:"11px",color:N.navy,fontSize:9,fontWeight:700,letterSpacing:"0.12em",cursor:refLink?"pointer":"not-allowed",opacity:refLink?1:0.6}}>
            {copied?"✓ COPIED — SHARE WITH FRIENDS":"COPY MY LINK"}
          </button>
        </div>

        {/* Preferences — same data as the Traveler Preferences screen (Settings
            → Travel Preferences), so an edit there shows up here immediately. */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px",marginBottom:14}}>
          <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Travel Preferences</div>
          {[
            ["Cabin",profile.cabin],["Seat",profile.seat],["Hotel",profile.hotel],
            ["Dietary",profile.dietary],["Downtime",profile.downtime],
            ["TSA",profile.tsa],
          ].map(([k,v])=>v&&(
            <div key={k} style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",paddingBottom:6,marginBottom:6,borderBottom:`1px solid ${N.goldLine}`}}>
              <div style={{fontSize:9,color:N.parchD,width:80,flexShrink:0}}>{k}</div>
              <div style={{fontSize:10,color:N.parch,textAlign:"right",flex:1}}>{v}</div>
            </div>
          ))}
          {!profile.cabin&&!profile.seat&&!profile.hotel&&!profile.dietary&&!profile.downtime&&!profile.tsa&&(
            <div style={{fontSize:10,color:N.parchD,fontStyle:"italic"}}>No preferences on file yet — add some from Settings → Travel Preferences.</div>
          )}
        </div>
      </div>
    </Screen>
  );
}


// ─── CONCIERGE: Client Profile Edit ───
function ConciergeClientProfileEdit({client, trip, onBack, onSaved}){
  const profile = trip?.profile || client.profile || {};
  const [form, setForm] = useState({
    name: profile.name||client.name,
    email: profile.email||client.email||"",
    phone: profile.phone||"",
    cabin: profile.cabin||"",
    seat: profile.seat||"",
    hotel: profile.hotel||"",
    dietary: profile.dietary||"",
    downtime: profile.downtime||"",
    loyalty: profile.loyalty||"",
    tsa: profile.tsa||"",
    passportExpiry: profile.passportExpiry||"",
  });
  const [travelers, setTravelers] = useState(profile.travelers||[]);
  const addTraveler=()=>setTravelers(t=>[...t,{name:"",birthdate:""}]);
  const removeTraveler=(i)=>setTravelers(t=>t.filter((_,j)=>j!==i));
  const updateTraveler=(i,key,val)=>setTravelers(t=>t.map((tr,j)=>j===i?{...tr,[key]:val}:tr));
  const [saving, setSaving] = useState(false);
  const fields=[
    ["name","Full Name","text"],["email","Email","email"],["phone","Phone","tel"],
    ["cabin","Cabin Class","text"],["seat","Seat Preference","text"],["hotel","Hotel Preference","text"],
    ["dietary","Dietary Restrictions","text"],["downtime","Downtime Preference","text"],
    ["loyalty","Loyalty Programs","text"],["tsa","TSA / Global Entry","text"],
    ["passportExpiry","Passport Expiration Date","date"],
  ];
  async function save(){
    setSaving(true);
    try{
      // Profile lives on the client's own Firestore record — the same
      // field the client's own "My Profile" screen writes to — so an edit
      // made here is visible to them too, not just stored locally.
      await PT.updateClientProfile(client.id, {...profile, ...form, travelers});
      if(onSaved) onSaved({...form, travelers});
    }catch(e){
      console.error("Could not save client profile",e);
      alert("Could not save changes — check the console for details.");
    }
    setSaving(false);
    onBack();
  }
  return(
    <Screen>
      <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
        <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
        <div style={{fontFamily:"Georgia,serif",fontSize:17,color:N.parch,flex:1}}>Edit — {client.name}</div>
      </div>
      <div style={{padding:"20px"}}>
        {fields.map(([key,label,type])=>(
          <div key={key} style={{marginBottom:14}}>
            <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",color:N.gold,textTransform:"uppercase",marginBottom:5}}>{label}</div>
            <input value={form[key]} onChange={e=>setForm(f=>({...f,[key]:e.target.value}))} type={type}
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 12px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit"}}/>
          </div>
        ))}

        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",color:N.gold,textTransform:"uppercase",marginBottom:5,marginTop:10}}>Travelers &amp; Birthdates</div>
        <div style={{fontSize:9,color:N.parchD,marginBottom:10,lineHeight:1.6}}>Age is calculated automatically from birthdate.</div>
        {travelers.map((t,i)=>{
          const age = calcAge(t.birthdate);
          return(
            <div key={i} style={{display:"flex",gap:8,marginBottom:8,alignItems:"center"}}>
              <input value={t.name} onChange={e=>updateTraveler(i,"name",e.target.value)} placeholder="Full name"
                style={{flex:"1 1 40%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit"}}/>
              <input type="date" value={t.birthdate} onChange={e=>updateTraveler(i,"birthdate",e.target.value)}
                style={{flex:"1 1 34%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 10px",color:N.parch,fontSize:11,outline:"none",fontFamily:"inherit",colorScheme:"dark"}}/>
              <div style={{flex:"0 0 40px",textAlign:"center",fontSize:11,color:N.gold,fontWeight:700}}>{age!=null?age:"—"}</div>
              <button onClick={()=>removeTraveler(i)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,width:28,height:38,cursor:"pointer",color:N.parchD,fontSize:14,flexShrink:0}}>×</button>
            </div>
          );
        })}
        <button onClick={addTraveler} style={{background:"transparent",border:`1px dashed ${N.gold}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:10,fontWeight:700,letterSpacing:"0.1em",cursor:"pointer",marginBottom:14,width:"100%"}}>+ Add Traveler</button>

        <button onClick={save} disabled={saving} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:13,color:N.navy,fontWeight:700,fontSize:11,cursor:saving?"not-allowed":"pointer",letterSpacing:"0.1em",marginTop:8}}>
          {saving?"SAVING…":"SAVE CHANGES"}
        </button>
      </div>
    </Screen>
  );
}

// Live "what time is it for them" card — recomputes every 30s so it stays
// accurate while the concierge has the screen open, without a full re-render
// of anything else. tz comes from client.timezone, which is captured
// automatically from the client's own browser (see the useEffect in App /
// PT.updateClientTimezone) — nothing for either side to type in.
function ClientTimeZoneCard({tz}){
  const [info,setInfo]=useState(()=>describeClientTime(tz));
  useEffect(()=>{
    setInfo(describeClientTime(tz));
    const id=setInterval(()=>setInfo(describeClientTime(tz)),30000);
    return ()=>clearInterval(id);
  },[tz]);
  if(!tz) return(
    <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"12px 16px",marginBottom:20,fontSize:10,color:N.parchD}}>
      Time zone not on file yet — this fills in automatically the next time they log in.
    </div>
  );
  if(!info) return null;
  return(
    <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 16px",marginBottom:20,display:"flex",justifyContent:"space-between",alignItems:"center",gap:12}}>
      <div>
        <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:3}}>Their Local Time</div>
        <div style={{fontSize:9,color:N.parchD}}>{info.cityLabel}{info.diffLabel?` · ${info.diffLabel}`:""}</div>
      </div>
      <div style={{fontFamily:"Georgia,serif",fontSize:20,color:N.parch}}>{info.timeStr}</div>
    </div>
  );
}

// ─── CONCIERGE: Client Profile ───
function ConciergeClientProfile({client, trip, onBack}){
  const [editing, setEditing] = useState(false);
  const [showAgreement,setShowAgreement]=useState(false);
  const [intakeStatus,setIntakeStatus]=useState("idle"); // idle | working | copied | error
  const [showCharge,setShowCharge]=useState(false);
  const [chargeForm,setChargeForm]=useState({amount:"",description:""});
  const [chargeStatus,setChargeStatus]=useState("idle"); // idle | charging | done | error
  const [chargeError,setChargeError]=useState("");
  const [showInvoice,setShowInvoice]=useState(false);
  const [invoiceForm,setInvoiceForm]=useState({amount:"",description:""});
  const [invoiceStatus,setInvoiceStatus]=useState("idle"); // idle | creating | copied | error
  const [invoiceError,setInvoiceError]=useState("");
  async function submitInvoice(e){
    e.preventDefault();
    const dollars = parseFloat(invoiceForm.amount);
    if(!dollars || dollars<=0) return;
    setInvoiceStatus("creating"); setInvoiceError("");
    try{
      const invoiceId = await PT.createInvoice(client.id, Math.round(dollars*100), invoiceForm.description, trip?.id||null);
      const url = `${window.location.origin}/client/?invoice=${invoiceId}`;
      try{ await navigator.clipboard.writeText(url); }
      catch{
        const ta=document.createElement("textarea"); ta.value=url; document.body.appendChild(ta); ta.select();
        try{document.execCommand("copy");}catch{} document.body.removeChild(ta);
      }
      setInvoiceStatus("copied");
      setInvoiceForm({amount:"",description:""});
    }catch(e){
      setInvoiceError(e.message||"Could not create the invoice.");
      setInvoiceStatus("error");
    }
  }
  async function submitCharge(e){
    e.preventDefault();
    const dollars = parseFloat(chargeForm.amount);
    if(!dollars || dollars<=0) return;
    setChargeStatus("charging"); setChargeError("");
    try{
      await PT.chargeClientCard(client.id, Math.round(dollars*100), chargeForm.description, trip?.id||null);
      setChargeStatus("done");
      setChargeForm({amount:"",description:""});
    }catch(e){
      setChargeError(e.message||"Charge failed.");
      setChargeStatus("error");
    }
  }
  async function copyIntakeLink(){
    setIntakeStatus("working");
    try{
      const token = await PT.createIntakeLink({clientId:client.id, clientName:client.name});
      const url = `${window.location.origin}/client/?intake=${token}`;
      try{ await navigator.clipboard.writeText(url); }
      catch{ /* clipboard may be blocked — fall back below */
        const ta=document.createElement("textarea"); ta.value=url; document.body.appendChild(ta); ta.select();
        try{document.execCommand("copy");}catch{} document.body.removeChild(ta);
      }
      setIntakeStatus("copied");
      setTimeout(()=>setIntakeStatus("idle"),2500);
    }catch(e){
      console.error("Could not create intake link",e);
      setIntakeStatus("error");
      setTimeout(()=>setIntakeStatus("idle"),2500);
    }
  }
  // Agreement now lives on the client's real Firestore record (recordAgreement
  // in pt-data.js writes agreedAt/agreementSignature there directly) instead
  // of a localStorage list keyed by name — so this reflects what the client
  // actually signed, for real accounts, not a demo-data lookup that could
  // never match a real name.
  const signed = !!client.agreedAt;
  if(editing) return <ConciergeClientProfileEdit client={client} trip={trip} onBack={()=>setEditing(false)}/>;
  const profile = trip?.profile || client.profile || {};
  const sections = [
    {title:"Contact", fields:[
      ["Full Name", profile.name||client.name],
      ["Email", profile.email||client.email||"—"],
      ["Phone", profile.phone||"—"],
    ]},
    {title:"Travel Preferences", fields:[
      ["Cabin Class", profile.cabin||"—"],
      ["Seat Preference", profile.seat||"—"],
      ["Hotel Preference", profile.hotel||"—"],
      ["Downtime", profile.downtime||"—"],
    ]},
    {title:"Dietary & Health", fields:[
      ["Dietary Restrictions", profile.dietary||"None on file"],
    ]},
    {title:"Travel Documents", fields:[
      ["Passport Expiration", profile.passportExpiry||"Not on file"],
    ]},
    {title:"Loyalty Programs", fields:[
      ["Programs", profile.loyalty||"—"],
      ["TSA / Global Entry", profile.tsa||"—"],
    ]},
    {title:"Travelers", fields:
      (profile.travelers||[]).length
        ? (profile.travelers||[]).map(t=>[t.name||"Traveler", t.birthdate?`${formatShortDate(t.birthdate+"T00:00:00")} · Age ${calcAge(t.birthdate)!=null?calcAge(t.birthdate):"—"}`:"No birthdate on file"])
        : [["On File","No travelers added yet"]]
    },
    {title:"Trip Schedule", fields:[
      ["Destination", trip?.destination||"—"],
      ["Dates", trip?.dates||"—"],
      ["Hotel", trip?.hotel||"—"],
      ["Flight", trip?.flight||"—"],
      ["Schedule Style", profile.schedule||"—"],
    ]},
    {title:"Account", fields:[
      ["Tier", client.tier||"Standard"],
      ["Member Since", client.createdAt?formatShortDate(client.createdAt):"—"],
    ]},
  ];

  return(
    <Screen>
      <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
        <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
        <div style={{flex:1}}>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>{client.name}</div>
          <div style={{fontSize:9,color:N.parchD}}>{client.tier||"Standard"}</div>
        </div>
        <Badge label={trip?tripStatus(trip):"No trip yet"} color={{Active:N.green,Upcoming:N.gold,Planning:N.sky,Completed:N.parchD}[trip?tripStatus(trip):""]||N.parchD}/>
      </div>

      <div style={{padding:"20px 20px 0"}}>
        <ClientTimeZoneCard tz={client.timezone}/>

        {/* Payment — card on file, for booking hotels/vendors on the client's behalf */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"14px 16px",marginBottom:20}}>
          <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Payment</div>
          {client.cardOnFile?.last4 && (
            <div style={{fontSize:13,color:N.parch,marginBottom:10}}>{(client.cardOnFile.brand||"Card").toUpperCase()} •••• {client.cardOnFile.last4}{client.cardOnFile.expMonth?` · exp ${client.cardOnFile.expMonth}/${client.cardOnFile.expYear}`:""}</div>
          )}
          {!client.cardOnFile?.last4 && (
            <div style={{fontSize:11,color:N.parchD,marginBottom:10}}>No card on file yet — the client can add one from Settings, pay an invoice, or you can charge them once they do.</div>
          )}
          <div style={{display:"flex",gap:8}}>
            {client.cardOnFile?.last4 && (
              <button onClick={()=>{setShowCharge(true);setChargeStatus("idle");setChargeError("");}} style={{flex:1,background:N.gold,border:"none",borderRadius:8,padding:11,color:N.navy,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>
                Charge Card
              </button>
            )}
            <button onClick={()=>{setShowInvoice(true);setInvoiceStatus("idle");setInvoiceError("");}} style={{flex:1,background:"transparent",border:`1px solid ${N.gold}`,borderRadius:8,padding:11,color:N.gold,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>
              Send Invoice
            </button>
          </div>
        </div>
        {showInvoice && (
          <div style={{position:"fixed",inset:0,background:"rgba(10,22,40,0.95)",zIndex:100,display:"flex",alignItems:"center",justifyContent:"center",padding:20}}>
            <div style={{background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:24,width:"100%",maxWidth:360}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:17,color:N.parch,marginBottom:4}}>Send {client.name} an Invoice</div>
              <div style={{fontSize:10,color:N.parchD,marginBottom:16}}>Creates a payable link — the client pays with their card on file or a new one. It's marked paid automatically and lands in their Documents.</div>
              {invoiceStatus==="copied" ? (
                <>
                  <div style={{fontSize:13,color:N.green,textAlign:"center",padding:"12px 0"}}>✓ Link copied — paste it into a text or email to {client.name}</div>
                  <button onClick={()=>setShowInvoice(false)} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:11,color:N.parch,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>Done</button>
                </>
              ) : (
                <form onSubmit={submitInvoice}>
                  <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>Amount (USD)</div>
                  <input type="number" min="0.01" step="0.01" required value={invoiceForm.amount} onChange={e=>setInvoiceForm(f=>({...f,amount:e.target.value}))}
                    style={{width:"100%",padding:"11px 13px",marginBottom:12,borderRadius:8,border:`1px solid ${N.goldLine}`,background:N.navyMid,color:N.parch,fontSize:14,boxSizing:"border-box"}}/>
                  <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>What's this for?</div>
                  <input placeholder="e.g. Trip deposit — Four Seasons Bora Bora" value={invoiceForm.description} onChange={e=>setInvoiceForm(f=>({...f,description:e.target.value}))}
                    style={{width:"100%",padding:"11px 13px",marginBottom:16,borderRadius:8,border:`1px solid ${N.goldLine}`,background:N.navyMid,color:N.parch,fontSize:14,boxSizing:"border-box"}}/>
                  {invoiceStatus==="error" && <div style={{color:"#e57373",fontSize:12,marginBottom:12}}>{invoiceError}</div>}
                  <div style={{display:"flex",gap:10}}>
                    <button type="button" onClick={()=>setShowInvoice(false)} style={{flex:1,background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:8,padding:11,color:N.parchD,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>Cancel</button>
                    <button type="submit" disabled={invoiceStatus==="creating"} style={{flex:1,background:N.gold,border:"none",borderRadius:8,padding:11,color:N.navy,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:invoiceStatus==="creating"?"not-allowed":"pointer"}}>
                      {invoiceStatus==="creating"?"Creating…":"Create & Copy Link"}
                    </button>
                  </div>
                </form>
              )}
            </div>
          </div>
        )}
        {showCharge && (
          <div style={{position:"fixed",inset:0,background:"rgba(10,22,40,0.95)",zIndex:100,display:"flex",alignItems:"center",justifyContent:"center",padding:20}}>
            <div style={{background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:24,width:"100%",maxWidth:360}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:17,color:N.parch,marginBottom:4}}>Charge {client.name}'s Card</div>
              <div style={{fontSize:10,color:N.parchD,marginBottom:16}}>{(client.cardOnFile?.brand||"Card").toUpperCase()} •••• {client.cardOnFile?.last4}</div>
              {chargeStatus==="done" ? (
                <>
                  <div style={{fontSize:13,color:N.green,textAlign:"center",padding:"12px 0"}}>✓ Charge submitted</div>
                  <button onClick={()=>setShowCharge(false)} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:11,color:N.parch,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>Done</button>
                </>
              ) : (
                <form onSubmit={submitCharge}>
                  <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>Amount (USD)</div>
                  <input type="number" min="0.01" step="0.01" required value={chargeForm.amount} onChange={e=>setChargeForm(f=>({...f,amount:e.target.value}))}
                    style={{width:"100%",padding:"11px 13px",marginBottom:12,borderRadius:8,border:`1px solid ${N.goldLine}`,background:N.navyMid,color:N.parch,fontSize:14,boxSizing:"border-box"}}/>
                  <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.12em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>What's this for?</div>
                  <input placeholder="e.g. Four Seasons deposit" value={chargeForm.description} onChange={e=>setChargeForm(f=>({...f,description:e.target.value}))}
                    style={{width:"100%",padding:"11px 13px",marginBottom:16,borderRadius:8,border:`1px solid ${N.goldLine}`,background:N.navyMid,color:N.parch,fontSize:14,boxSizing:"border-box"}}/>
                  {chargeStatus==="error" && <div style={{color:"#e57373",fontSize:12,marginBottom:12}}>{chargeError}</div>}
                  <div style={{display:"flex",gap:10}}>
                    <button type="button" onClick={()=>setShowCharge(false)} style={{flex:1,background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:8,padding:11,color:N.parchD,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>Cancel</button>
                    <button type="submit" disabled={chargeStatus==="charging"} style={{flex:1,background:N.gold,border:"none",borderRadius:8,padding:11,color:N.navy,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:chargeStatus==="charging"?"not-allowed":"pointer"}}>
                      {chargeStatus==="charging"?"Charging…":"Confirm Charge"}
                    </button>
                  </div>
                </form>
              )}
            </div>
          </div>
        )}

        {sections.map((sec,si)=>(
          <div key={si} style={{marginBottom:20}}>
            <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:10,paddingBottom:6,borderBottom:`1px solid ${N.goldLine}`}}>{sec.title}</div>
            {sec.fields.map(([k,v],fi)=>(
              <div key={fi} style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",padding:"9px 0",borderBottom:fi<sec.fields.length-1?`1px solid ${N.goldLine}22`:"none",gap:12}}>
                <div style={{fontSize:9,color:N.parchD,flexShrink:0,width:120,fontWeight:600,letterSpacing:"0.08em",textTransform:"uppercase"}}>{k}</div>
                <div style={{fontSize:11,color:N.parch,textAlign:"right",flex:1,lineHeight:1.5}}>{v}</div>
              </div>
            ))}
          </div>
        ))}
        <div style={{display:"flex",gap:10,marginBottom:12}}>
          <button onClick={()=>setEditing(true)} style={{flex:1,background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:13,color:N.gold,fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:"pointer"}}>
            Edit Profile
          </button>
          <button onClick={()=>setShowAgreement(true)} style={{flex:1,background:signed?`${N.gold}22`:N.navyMid,border:`1px solid ${signed?N.gold:N.goldLine}`,borderRadius:8,padding:13,color:signed?N.gold:N.parchD,fontSize:9,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:"pointer"}}>
            {signed?"✓ Signed Docs":"No Agreements"}
          </button>
        </div>
        <button onClick={copyIntakeLink} disabled={intakeStatus==="working"} style={{width:"100%",background:"transparent",border:`1px dashed ${N.gold}`,borderRadius:8,padding:12,color:N.gold,fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:intakeStatus==="working"?"not-allowed":"pointer",marginBottom:20}}>
          {intakeStatus==="working"?"Generating…":intakeStatus==="copied"?"✓ Link Copied — Send It Over":intakeStatus==="error"?"Couldn't create link — try again":"Copy Intake Link"}
        </button>
        {showAgreement&&(
          <div style={{position:"fixed",inset:0,background:"rgba(10,22,40,0.95)",zIndex:100,overflowY:"auto",padding:"20px"}}>
            <div style={{display:"flex",alignItems:"center",gap:14,marginBottom:20}}>
              <button onClick={()=>setShowAgreement(false)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD}}>← Close</button>
              <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch}}>Signed Agreements</div>
            </div>
            {!signed?(
              <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"28px 20px",textAlign:"center"}}>
                <div style={{fontSize:11,color:N.parchD}}>No signed agreements on file for {client.name}.</div>
              </div>
            ):(
              <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px 18px",marginBottom:12}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12}}>
                  <div style={{fontSize:13,fontWeight:600,color:N.parch}}>Client Agreement & Privacy Policy</div>
                  <span style={{background:`${N.green}22`,color:N.green,fontSize:8,fontWeight:700,padding:"3px 8px",borderRadius:20}}>✓ SIGNED</span>
                </div>
                {[["Electronic Signature",{color:N.parch,fontStyle:"italic"},client.agreementSignature||"—"],["Date Signed",{color:N.parch},formatShortDate(client.agreedAt)],["Client ID",{color:N.parchD,fontFamily:"monospace"},"PT-"+client.id.slice(0,8).toUpperCase()]].map(([k,vs,v])=>(
                  <div key={k} style={{display:"flex",justifyContent:"space-between",fontSize:9,padding:"7px 0",borderBottom:`1px solid ${N.goldLine}33`}}>
                    <span style={{fontWeight:700,textTransform:"uppercase",letterSpacing:"0.1em",color:N.parchD}}>{k}</span>
                    <span style={{...vs}}>{v}</span>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>
    </Screen>
  );
}


// ─── CONCIERGE: Agreements ───
function ConciergeAgreements({onOpen}){
  useEffect(()=>{if(onOpen)onOpen();},[]);
  const agreements=JSON.parse(localStorage.getItem("pt_agreements")||"[]");
  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        <SectionEye label="Agreements"/>
        <SectionTitle>Signed Client Agreements</SectionTitle>
        {agreements.length===0?(
          <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"28px 20px",textAlign:"center",marginTop:8}}>
            <div style={{fontSize:28,marginBottom:8}}></div>
            <div style={{fontSize:11,color:N.parchD}}>No signed agreements yet. Clients sign on first login.</div>
          </div>
        ):(
          <div style={{display:"flex",flexDirection:"column",gap:10}}>
            {agreements.map((ag,i)=>(
              <div key={i} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px 18px"}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:10}}>
                  <div>
                    <div style={{fontSize:13,fontWeight:600,color:N.parch,marginBottom:2}}>{ag.client}</div>
                    <div style={{fontSize:9,color:N.parchD}}>Client Agreement & Privacy Policy</div>
                  </div>
                  <span style={{background:`${N.green}22`,color:N.green,fontSize:8,fontWeight:700,letterSpacing:"0.12em",padding:"3px 8px",borderRadius:20}}>✓ SIGNED</span>
                </div>
                <div style={{display:"flex",gap:6,flexDirection:"column"}}>
                  <div style={{display:"flex",justifyContent:"space-between",fontSize:9,color:N.parchD,padding:"7px 0",borderBottom:`1px solid ${N.goldLine}33`}}>
                    <span style={{fontWeight:700,textTransform:"uppercase",letterSpacing:"0.1em"}}>Electronic Signature</span>
                    <span style={{color:N.parch,fontStyle:"italic"}}>{ag.signature}</span>
                  </div>
                  <div style={{display:"flex",justifyContent:"space-between",fontSize:9,color:N.parchD,padding:"7px 0",borderBottom:`1px solid ${N.goldLine}33`}}>
                    <span style={{fontWeight:700,textTransform:"uppercase",letterSpacing:"0.1em"}}>Date Signed</span>
                    <span style={{color:N.parch}}>{ag.date}</span>
                  </div>
                  <div style={{display:"flex",justifyContent:"space-between",fontSize:9,color:N.parchD,padding:"7px 0"}}>
                    <span style={{fontWeight:700,textTransform:"uppercase",letterSpacing:"0.1em"}}>Agreement ID</span>
                    <span style={{color:N.parchD,fontFamily:"monospace"}}>PT-{ag.id}</span>
                  </div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </Screen>
  );
}

// ─── CONCIERGE: Clients ───
// Real clients only — this used to fall back to a hardcoded demo roster
// (4 fictional people) whenever localStorage was empty, which meant it
// showed fake clients forever on a fresh account since nothing ever wrote
// real ones into that localStorage key. Now it reads straight from
// Firestore (PT.fetchAllClients — the same real signup records used
// elsewhere in the app) and shows an honest empty state until people
// actually sign up with an access key.
function ConciergeClients({concUnread=0, trips=[]}){
  const [clients,setClients]=useState(null); // null = still loading
  const [selectedClient,setSelectedClient]=useState(null);
  const [loadError,setLoadError]=useState(false);

  function loadClients(){
    PT.fetchAllClients()
      .then(rows=>setClients(rows.map(c=>({
        id:c.id,
        name:c.fullName||c.email||"Unnamed",
        initials:(c.fullName||c.email||"?").split(" ").map(w=>w[0]).join("").slice(0,2).toUpperCase(),
        tier:c.tier||"Standard",
        email:c.email||"",
        authUserId:c.authUserId||"",
        profile:c.profile||{},
        timezone:c.timezone||"",
        agreedAt:c.agreedAt,
        agreementSignature:c.agreementSignature,
        createdAt:c.createdAt,
      }))))
      .catch(e=>{console.error("Could not load client roster",e);setLoadError(true);});
  }
  useEffect(()=>{ loadClients(); },[]);

  if(selectedClient){
    const trip=trips.find(t=>t.clientId===selectedClient.id);
    return <ConciergeClientProfile client={selectedClient} trip={trip} onBack={()=>{setSelectedClient(null);loadClients();}}/>;
  }

  const sColor={Active:N.green,Upcoming:N.gold,Planning:N.sky,Completed:N.parchD};
  function clientTrip(c){ return trips.find(t=>t.clientId===c.id); }
  function clientStatus(c){
    const trip=clientTrip(c);
    return trip ? tripStatus(trip) : "No trip yet";
  }

  const loading = clients===null;
  const list = clients||[];
  const activeCount = list.filter(c=>clientStatus(c)==="Active").length;
  const upcomingCount = list.filter(c=>clientStatus(c)==="Upcoming").length;
  const planningCount = list.filter(c=>clientStatus(c)==="Planning"||clientStatus(c)==="No trip yet").length;

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        {/* Stats row — all real counts derived from actual signed-up
            clients and their trips. No revenue/CSAT tile since there's no
            real billing or satisfaction data source wired up yet; showing
            a fabricated number there would be worse than not showing one. */}
        <div style={{display:"grid",gridTemplateColumns:"repeat(4,1fr)",gap:8,marginBottom:20}}>
          {[[String(list.length),"Clients"],[String(activeCount),"Active"],[String(upcomingCount),"Upcoming"],[String(planningCount),"Planning"]].map(([n,l])=>(
            <div key={l} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px",textAlign:"center"}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.gold,fontWeight:600,lineHeight:1}}>{n}</div>
              <div style={{fontSize:8,color:N.parchD,marginTop:3,letterSpacing:"0.1em",textTransform:"uppercase"}}>{l}</div>
            </div>
          ))}
        </div>

        <SectionEye label="All Clients"/>

        {loading&&<div style={{fontSize:10,color:N.parchD,fontStyle:"italic",padding:"12px 0"}}>Loading clients…</div>}

        {loadError&&(
          <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"20px",textAlign:"center",marginBottom:16}}>
            <div style={{fontSize:11,color:N.parchD}}>Couldn't load your client list. Check your connection and try reopening this tab.</div>
          </div>
        )}

        {!loading&&!loadError&&list.length===0&&(
          <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"28px 20px",textAlign:"center",marginBottom:16}}>
            <div style={{fontSize:28,marginBottom:8}}></div>
            <div style={{fontSize:11,color:N.parchD,lineHeight:1.6}}>No clients yet. Once you send someone an access key and they sign up, they'll show up here automatically.</div>
          </div>
        )}

        {!loading&&list.length>0&&(
          <div style={{display:"flex",flexDirection:"column",gap:10}}>
            {list.map(c=>{
              const trip=clientTrip(c);
              const status=clientStatus(c);
              return (
                <div key={c.id} onClick={()=>setSelectedClient(c)}
                  style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"14px 16px",cursor:"pointer",transition:"all 0.2s",display:"flex",alignItems:"center",gap:14}}>
                  <Avatar initials={c.initials} size={46}/>
                  <div style={{flex:1}}>
                    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:4}}>
                      <div style={{fontSize:13,fontWeight:600,color:N.parch}}>{c.name}</div>
                      <Badge label={status} color={sColor[status]||N.parchD}/>
                    </div>
                    <div style={{fontSize:9,color:N.parchD,marginBottom:3}}>{c.tier}{c.email?` · ${c.email}`:""}{c.timezone?` · ${describeClientTime(c.timezone)?.timeStr||""} their time`:""}</div>
                    <div style={{fontSize:9,color:N.gold,fontWeight:600}}>
                      {trip?`${trip.destination} · ${trip.dates}`:"No trip planned yet"}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}

        <div style={{background:N.navyMid,border:`1px dashed ${N.goldLine}`,borderRadius:10,padding:"14px 16px",marginTop:16,fontSize:9,color:N.parchD,lineHeight:1.6}}>
          New clients join by signing up with an access key — there's no manual "add client" here, so this list always matches who's actually in the system.
        </div>
      </div>
    </Screen>
  );
}

// ─── AI Document Upload ───
async function extractItineraryFromDoc(base64Data, fileName, mimeType) {
  const isImage = mimeType.startsWith("image/");
  const isPdf = mimeType === "application/pdf";

  const contentBlock = isPdf
    ? { type: "document", source: { type: "base64", media_type: "application/pdf", data: base64Data } }
    : { type: "image",    source: { type: "base64", media_type: mimeType,            data: base64Data } };

  const prompt = `Extract ALL travel details from this document. You MUST respond with ONLY a raw JSON object — no markdown, no code fences, no explanation text before or after. Start your response with { and end with }.

Use this exact structure:
{"destination":"City, Country","subdest":"Region or neighborhood","startDate":"YYYY-MM-DD","endDate":"YYYY-MM-DD","dates":"Mon DD – Mon DD, YYYY","nights":3,"client":"Client Name if visible","hotel":"Hotel Name","flight":"Airline Flight# · Cabin","nextEvent":"First upcoming event","days":[{"n":1,"title":"Day Title","date":"Day Mon DD","entries":[{"time":"9:00 AM","cat":"flight","icon":"✈️","name":"Event name","detail":"Full details including Conf: XXXXX if present"}]}],"docs":[]}

Rules:
- cat must be one of: flight, hotel, dining, transfer, activity, leisure
- Extract EVERY time, location, confirmation number visible
- startDate/endDate MUST be real calendar dates in YYYY-MM-DD format (this is what the app sorts and counts down by) — infer the year if not shown (assume the next upcoming occurrence of that date from today)
- If a field is unknown use "TBD" (except startDate/endDate/nights, which must always be your best real guess, never "TBD")
- nights should be an integer
- ONLY output the JSON object, nothing else`;

  // Routed through our own /api/sage serverless function (see pt-data.js) —
  // the Anthropic key lives server-side only, never in this browser code.
  const data = await PT.askSage([{role:"user",content:[contentBlock,{type:"text",text:prompt}]}], {max_tokens:4000});
  const raw = data.content?.map(b=>b.text||"").join("").trim();

  const clean = (raw||"").replace(/```json|```/g, "").trim();
  // Find first { ... } block in case there's extra text
  const jsonStart = clean.indexOf('{');
  const jsonEnd = clean.lastIndexOf('}');
  if(jsonStart===-1||jsonEnd===-1) throw new Error("Claude returned: " + clean.slice(0,100));
  try{
    return JSON.parse(clean.slice(jsonStart, jsonEnd+1));
  }catch(e){
    throw new Error("JSON parse failed: " + e.message + " | " + clean.slice(jsonStart,jsonStart+80));
  }
}

// Shared by both the "add doc to an existing trip" upload and the "start a
// brand-new trip from a document" upload — reads a File into the base64
// payload extractItineraryFromDoc needs. PDFs go straight through; images
// get downscaled to keep the request small.
async function fileToBase64(file){
  if (file.type === "application/pdf") {
    const base64 = await new Promise((res, rej) => {
      const reader = new FileReader();
      reader.onload = () => res(reader.result.split(",")[1]);
      reader.onerror = rej;
      reader.readAsDataURL(file);
    });
    return { base64, mimeType: "application/pdf" };
  }
  const base64 = await new Promise((res, rej) => {
    const img = new Image();
    const url = URL.createObjectURL(file);
    img.onload = () => {
      URL.revokeObjectURL(url);
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const TARGET = 180000;
      let quality = 0.6;
      let scale = 1.0;
      let result = "";
      for(let attempt=0; attempt<6; attempt++){
        const w = Math.round(img.width*scale);
        const h = Math.round(img.height*scale);
        canvas.width = w; canvas.height = h;
        ctx.drawImage(img, 0, 0, w, h);
        result = canvas.toDataURL('image/jpeg', quality);
        if(result.length * 0.75 < TARGET) break;
        quality -= 0.1;
        scale *= 0.8;
        if(quality < 0.2) quality = 0.2;
      }
      res(result.split(",")[1]);
    };
    img.onerror = rej;
    img.src = url;
  });
  return { base64, mimeType: "image/jpeg" };
}

// ─── CONCIERGE: Itineraries ───
function ConciergeItineraries({setTrips, trips, onDocUploaded}){
  const [active, setActive] = useState(trips[0]);
  const [viewTrip, setViewTrip] = useState(null);
  const [editEntry, setEditEntry] = useState(null); // {dayN, entryIdx}
  const [editForm, setEditForm] = useState({time:"",name:"",detail:"",cat:"activity"});

  // Updates local state immediately for a snappy UI, then persists the
  // trip's full day/entry list to Firestore so a manual edit here (add,
  // edit, or delete an itinerary entry) actually survives a reload and
  // shows up in the client's own app — this used to be local-state-only.
  function updateViewTrip(updatedTrip){
    setViewTrip(updatedTrip);
    setTrips(prev=>prev.map(t=>t.id===updatedTrip.id?updatedTrip:t));
    if(updatedTrip.id) PT.replaceTripDays(updatedTrip.id, updatedTrip.days||[]).catch(e=>console.error("Could not save itinerary changes",e));
  }
  function saveEntry(){
    if(!editEntry) return;
    const t={...viewTrip,days:(viewTrip.days||[]).map(d=>{
      if(d.n!==editEntry.dayN) return d;
      const entries=[...(d.entries||[])];
      if(editEntry.entryIdx===-1) entries.push({...editForm,icon:"·"});
      else entries[editEntry.entryIdx]={...entries[editEntry.entryIdx],...editForm};
      return {...d,entries};
    })};
    updateViewTrip(t);
    setEditEntry(null);
  }
  function deleteEntry(dayN, idx){
    const t={...viewTrip,days:(viewTrip.days||[]).map(d=>{
      if(d.n!==dayN) return d;
      const entries=[...(d.entries||[])];
      entries.splice(idx,1);
      return {...d,entries};
    })};
    updateViewTrip(t);
  }
  const [uploading, setUploading] = useState(false);
  const [uploadStep, setUploadStep] = useState("idle"); // idle | reading | processing | done | error
  const [uploadMsg, setUploadMsg] = useState("");
  const [dragOver, setDragOver] = useState(false);
  const [showUpload, setShowUpload] = useState(false);
  const [uploadForTrip, setUploadForTrip] = useState(null);
  const [sentTrip, setSentTrip] = useState(null);
  const [sentDocTrip, setSentDocTrip] = useState(null);

  const SAMPLE_DOCS = [
    {name:"Flight Confirmation.pdf",   icon:"doc", size:"124 KB", type:"PDF"},
    {name:"Hotel Reservation.pdf",     icon:"doc", size:"89 KB",  type:"PDF"},
    {name:"Day-by-Day Itinerary.pdf",  icon:"doc", size:"210 KB", type:"PDF"},
    {name:"Transfer Details.pdf",      icon:"doc", size:"56 KB",  type:"PDF"},
    {name:"Dining Reservations.pdf",   icon:"doc", size:"78 KB",  type:"PDF"},
  ];

  function sendSampleDoc(trip){
    const doc = SAMPLE_DOCS[Math.floor(Math.random()*SAMPLE_DOCS.length)];
    const date = new Date().toLocaleDateString("en-US",{month:"short",day:"numeric"});
    const entry = {...doc, date, trip:trip.destination};
    // Save to shared docs store
    try{
      const docs=JSON.parse(localStorage.getItem("pt_uploaded_docs")||"[]");
      docs.unshift(entry);
      localStorage.setItem("pt_uploaded_docs",JSON.stringify(docs));
      const newDocs=JSON.parse(localStorage.getItem("pt_new_docs")||"[]");
      newDocs.push(doc.name);
      localStorage.setItem("pt_new_docs",JSON.stringify(newDocs));
    }catch{}
    if(onDocUploaded)onDocUploaded();
    setSentDocTrip(trip.id);
    setTimeout(()=>setSentDocTrip(null),3000);
  }
  const [showBlank, setShowBlank] = useState(false);
  const [blankForm, setBlankForm] = useState({clientId:"",destination:"",startDate:"",endDate:"",hotel:""});
  // Real signed-up clients (Firestore), so "Create Blank Itinerary" attaches
  // to an actual client account instead of a typed-in name that the real
  // client would never see in their own app.
  const [realClients, setRealClients] = useState([]);
  useEffect(()=>{ PT.fetchAllClients().then(setRealClients).catch(e=>console.error("Could not load client roster",e)); },[]);

  function sendToClient(trip){
    const email = trip.profile?.email || "";
    const subject = encodeURIComponent(`Your ${trip.destination} Itinerary · ${trip.dates}`);
    const body = encodeURIComponent(
      `Hi ${trip.profile?.name||trip.client},\n\nYour upcoming trip itinerary is ready!\n\nDestination: ${trip.destination}\nDates: ${trip.dates}\nHotel: ${trip.hotel||"TBD"}\nFlight: ${trip.flightOut||"TBD"}\n\nFull itinerary is available in your Provisions Travel app.\n\nSafe travels,\nShayla Lee\nProvisions Travel\ninfo@provisionstravel.com`
    );
    if(email) window.open(`mailto:${email}?subject=${subject}&body=${body}`);
    else window.open(`mailto:?subject=${subject}&body=${body}`);
    // Push notification
    if("Notification" in window){
      const doNotify=()=>{
        new Notification("Itinerary Sent",{body:`${trip.destination} itinerary sent to ${trip.profile?.name||trip.client}`,icon:"/favicon.ico"});
      };
      if(Notification.permission==="granted") doNotify();
      else if(Notification.permission!=="denied") Notification.requestPermission().then(p=>{if(p==="granted")doNotify();});
    }
    setSentTrip(trip.id);
    setTimeout(()=>setSentTrip(null),3000);
  }
  const [creatingBlank, setCreatingBlank] = useState(false);
  async function createBlank(){
    const chosenClient = realClients.find(c=>c.id===blankForm.clientId);
    if(!chosenClient||!blankForm.destination) return;
    setCreatingBlank(true);
    // Nights is always computed from the dates, never entered by hand —
    // falls back to 1 only when dates aren't set yet (blank itinerary
    // created before travel dates are known).
    const nights = nightsBetween(blankForm.startDate, blankForm.endDate) || 1;
    try{
      const tripId = await PT.createTrip(chosenClient.id, {
        destination: blankForm.destination,
        startDate: blankForm.startDate || "",
        endDate: blankForm.endDate || "",
        nights,
        status: "Planning",
        hotel: blankForm.hotel||"TBD",
        flight: "TBD",
        nextEvent: "Trip planning in progress",
      });
      const initials=(chosenClient.fullName||"?").split(" ").map(w=>w[0]).join("").slice(0,2).toUpperCase();
      const newTrip={
        id:tripId, clientId:chosenClient.id, clientAuthUid:chosenClient.authUserId||"",
        client:chosenClient.fullName||"", initials, type:"Individual",
        destination:blankForm.destination, subdest:"",
        startDate:blankForm.startDate||"", endDate:blankForm.endDate||"",
        dates:(blankForm.startDate&&blankForm.endDate)?`${blankForm.startDate} – ${blankForm.endDate}`:"",
        nights, status:"Planning", tier:chosenClient.tier||"Standard",
        hotel:blankForm.hotel||"TBD", flight:"TBD", nextEvent:"Trip planning in progress",
        days:[], profile:chosenClient.profile||{},
      };
      setTrips(prev=>[newTrip,...prev]);
      setActive(newTrip);
      setViewTrip(newTrip);
      setBlankForm({clientId:"",destination:"",startDate:"",endDate:"",hotel:""});
      setShowBlank(false);
      if(onDocUploaded)onDocUploaded();
    }catch(e){
      console.error("Could not create trip",e);
      alert("Could not create the itinerary — check the console for details.");
    }
    setCreatingBlank(false);
  }

  const [clientName, setClientName] = useState("");
  const fileRef = useRef(null);
  const sColor = {Active:N.green, Upcoming:N.gold, Planning:N.sky};

  // ---------- Start a brand-new trip straight from an uploaded document ----------
  // Separate from "+ UPLOAD DOC" above (which enriches a trip that already
  // exists) — this skips the manual "Create Blank Itinerary" step entirely:
  // pick who it's for, drop in the confirmation PDF/photo, and Claude
  // creates the trip with everything it found already filled in.
  const [showNewUpload, setShowNewUpload] = useState(false);
  const [newUploadClientId, setNewUploadClientId] = useState("");
  const [newUploadStep, setNewUploadStep] = useState("idle"); // idle | reading | processing | done | error
  const [newUploadMsg, setNewUploadMsg] = useState("");
  const [newUploading, setNewUploading] = useState(false);
  const [newDragOver, setNewDragOver] = useState(false);
  const newFileRef = useRef(null);

  async function handleNewUploadFile(file){
    if(!file) return;
    const allowed = ["application/pdf","image/jpeg","image/png","image/webp","image/gif"];
    if(!allowed.includes(file.type)){
      setNewUploadStep("error");
      setNewUploadMsg("Please upload a PDF or image file (JPG, PNG, WebP).");
      return;
    }
    const chosenClient = realClients.find(c=>c.id===newUploadClientId);
    if(!chosenClient){
      setNewUploadStep("error");
      setNewUploadMsg("Select which client this trip is for first.");
      return;
    }
    setNewUploading(true);
    setNewUploadStep("reading");
    setNewUploadMsg(`Reading "${file.name}"...`);
    try{
      const { base64, mimeType } = await fileToBase64(file);
      setNewUploadStep("processing");
      setNewUploadMsg("Claude is reading your document and building the itinerary...");
      const extracted = await extractItineraryFromDoc(base64, file.name, mimeType);
      const nights = nightsBetween(extracted.startDate, extracted.endDate) || extracted.nights || 1;

      const tripId = await PT.createTrip(chosenClient.id, {
        destination: extracted.destination || "TBD",
        subdest: extracted.subdest || "",
        startDate: extracted.startDate || "",
        endDate: extracted.endDate || "",
        nights,
        status: "Planning",
        hotel: extracted.hotel || "TBD",
        flight: extracted.flight || "TBD",
        nextEvent: extracted.nextEvent || "",
        days: extracted.days || [],
      });

      // Best-effort: keep a copy of the source document in the client's
      // own Storage folder. Non-fatal if Storage isn't configured.
      if(chosenClient.authUserId){
        try { await PT.uploadDocument(chosenClient.authUserId, chosenClient.id, file, "itinerary", "concierge", tripId); }
        catch(e){ console.warn("Could not save source document to Storage", e); }
      }

      const initials=(chosenClient.fullName||"?").split(" ").map(w=>w[0]).join("").slice(0,2).toUpperCase();
      const newTrip={
        id:tripId, clientId:chosenClient.id, clientAuthUid:chosenClient.authUserId||"",
        client:chosenClient.fullName||"", initials, type:"Individual",
        destination:extracted.destination||"TBD", subdest:extracted.subdest||"",
        startDate:extracted.startDate||"", endDate:extracted.endDate||"",
        dates:(extracted.startDate&&extracted.endDate)?`${extracted.startDate} – ${extracted.endDate}`:"",
        nights, status:"Planning", tier:chosenClient.tier||"Standard",
        hotel:extracted.hotel||"TBD", flight:extracted.flight||"TBD",
        nextEvent:extracted.nextEvent||"", days:extracted.days||[], profile:chosenClient.profile||{},
      };
      setTrips(prev=>[newTrip,...prev]);
      setActive(newTrip);
      setViewTrip(newTrip);

      setNewUploadStep("done");
      setNewUploadMsg(`✓ Trip created for ${newTrip.destination}!`);
      if(onDocUploaded) onDocUploaded();
      setTimeout(()=>{ setShowNewUpload(false); setNewUploadClientId(""); setNewUploadStep("idle"); setNewUploading(false); },2000);
    }catch(err){
      console.error(err);
      setNewUploadStep("error");
      setNewUploadMsg("Error: " + (err?.message||"Could not process document. Check console for details."));
      setNewUploading(false);
    }
  }
  function onNewDrop(e){
    e.preventDefault(); setNewDragOver(false);
    handleNewUploadFile(e.dataTransfer.files[0]);
  }

  async function handleFile(file) {
    if (!file) return;
    const allowed = ["application/pdf","image/jpeg","image/png","image/webp","image/gif"];
    if (!allowed.includes(file.type)) {
      setUploadStep("error");
      setUploadMsg("Please upload a PDF or image file (JPG, PNG, WebP).");
      return;
    }
    const targetTrip = trips.find(t=>t.id===uploadForTrip);
    if(!targetTrip){
      setUploadStep("error");
      setUploadMsg("Couldn't find that trip — close and reopen the upload panel and try again.");
      return;
    }

    setUploading(true);
    setUploadStep("reading");
    setUploadMsg(`Reading "${file.name}"...`);

    try {
      const { base64, mimeType } = await fileToBase64(file);

      setUploadStep("processing");
      setUploadMsg("Claude is reading your document and building the itinerary...");

      const extracted = await extractItineraryFromDoc(base64, file.name, mimeType);

      // Write straight to Firestore, onto the REAL trip the concierge had
      // open — this is what makes the extracted itinerary actually show up
      // in the client's own app, not just in this concierge session.
      await PT.applyExtractedItinerary(targetTrip.id, extracted);

      // Best-effort: also keep a copy of the source document itself in
      // Storage under the client's own folder, so there's a record of what
      // was uploaded. Non-fatal if it fails (e.g. Storage not configured) —
      // the itinerary write above already succeeded either way.
      if (targetTrip.clientAuthUid) {
        try {
          await PT.uploadDocument(targetTrip.clientAuthUid, targetTrip.clientId, file, "itinerary", "concierge", targetTrip.id);
        } catch (e) { console.warn("Could not save source document to Storage", e); }
      }

      const newStartDate = extracted.startDate || targetTrip.startDate;
      const newEndDate = extracted.endDate || targetTrip.endDate;
      const updatedTrip = {
        ...targetTrip,
        destination: extracted.destination || targetTrip.destination,
        subdest: extracted.subdest || targetTrip.subdest,
        startDate: newStartDate,
        endDate: newEndDate,
        dates: (extracted.startDate && extracted.endDate) ? `${extracted.startDate} – ${extracted.endDate}` : targetTrip.dates,
        // Always trust the dates over whatever number Claude put in
        // "nights" — the two can disagree if the document was ambiguous,
        // and the dates are the ground truth the rest of the app sorts by.
        nights: nightsBetween(newStartDate, newEndDate) || extracted.nights || targetTrip.nights,
        hotel: extracted.hotel || targetTrip.hotel,
        flight: extracted.flight || targetTrip.flight,
        nextEvent: extracted.nextEvent || targetTrip.nextEvent,
        days: extracted.days && extracted.days.length ? extracted.days : targetTrip.days,
      };
      setTrips(prev => prev.map(t => t.id===targetTrip.id ? updatedTrip : t));
      if(viewTrip && viewTrip.id===targetTrip.id) setViewTrip(updatedTrip);
      setActive(updatedTrip);

      setUploadStep("done");
      setUploadMsg(`✓ Itinerary updated for ${updatedTrip.destination}!`);
      if(onDocUploaded)onDocUploaded();
      setTimeout(() => { setShowUpload(false); setUploadForTrip(null); setUploadStep("idle"); setUploading(false); setClientName(""); }, 2000);

    } catch (err) {
      console.error(err);
      setUploadStep("error");
      setUploadMsg("Error: " + (err?.message||"Could not process document. Check console for details."));
      setUploading(false);
    }
  }

  function onDrop(e) {
    e.preventDefault(); setDragOver(false);
    handleFile(e.dataTransfer.files[0]);
  }

  const stepColors = { reading: N.sky, processing: N.gold, done: N.green, error: N.coral };

  if(viewTrip){
    const s=viewTrip;
    const daysLeft=s.startDate?Math.max(0,Math.ceil((new Date(s.startDate+"T00:00:00")-new Date())/(1000*60*60*24))):0;
    return(
      <Screen>
        <div style={{background:`linear-gradient(160deg,${N.navyMid} 0%,${N.navy} 100%)`,padding:"28px 20px 26px",borderBottom:`1px solid ${N.goldLine}`,position:"relative",overflow:"hidden"}}>
          <div style={{position:"absolute",top:-40,right:-40,width:180,height:180,borderRadius:"50%",background:`radial-gradient(circle,${N.gold}08 0%,transparent 70%)`}}/>
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,position:"relative",zIndex:2}}>
            <button onClick={()=>setViewTrip(null)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Trips</button>
            <span style={{fontSize:9,color:N.gold,fontWeight:700,letterSpacing:"0.1em"}}>{s.client}</span>
          </div>
          <div style={{background:N.goldGlow,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"22px 20px",display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:22}}>
            <div>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:4}}>Next Departure</div>
              <div style={{fontFamily:"Georgia,serif",fontSize:20,color:N.parch,marginBottom:4}}>{s.destination}</div>
              <div style={{fontSize:10,color:N.parchD}}>{s.dates}</div>
            </div>
            <div style={{textAlign:"right"}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:44,color:N.gold,lineHeight:1}}>{daysLeft}</div>
              <div style={{fontSize:9,color:N.parchD,letterSpacing:"0.1em"}}>DAYS AWAY</div>
            </div>
          </div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:8}}>
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>FLIGHT</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>DEPARTURE</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.flightOut}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {s.flightOutTime} · Arr: {s.flightOutArrivalTime||"—"}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{s.flightOutDate}</div>
              <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>RETURN</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.flightReturn}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>Dep: {s.flightReturnTime} · Arr: {s.flightReturnArrivalTime||"—"}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{s.flightReturnDate}</div>
            </div>
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>TRANSPORT</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:2}}>PICKUP</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.carCompany||"Private Sedan"} · {s.carPickup||"Airport"}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{s.carPickupTime}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:4}}>{s.flightOutDate}</div>
              <div style={{height:1,background:N.goldLine,margin:"4px 0"}}/>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",margin:"4px 0 2px"}}>DROP-OFF</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:1}}>{s.carCompany||"Private Sedan"} · {s.carDropoff||"Airport"}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:1}}>{s.carDropoffTime}</div>
              <div style={{fontSize:7,color:N.parchD,opacity:0.7,marginBottom:2}}>{s.flightReturnDate||s.endDate}</div>
            </div>
            <div style={{background:`${N.navy}CC`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 8px"}}>
              <div style={{fontSize:7,color:N.gold,fontWeight:700,letterSpacing:"0.12em",marginBottom:6}}>HOTEL</div>
              <div style={{fontSize:8,fontWeight:700,color:N.parch,marginBottom:2,lineHeight:1.3}}>{s.hotel}</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:4,lineHeight:1.3}}>{s.hotelAddress}</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-IN</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:3}}>{s.days?.[0]?.entries?.find(e=>e.cat==="hotel")?.time||"12:30 PM"} · {s.flightOutDate}</div>
              <div style={{fontSize:7,color:N.gold,letterSpacing:"0.08em",marginBottom:1}}>CHECK-OUT</div>
              <div style={{fontSize:7,color:N.parchD,marginBottom:4}}>{s.days?.[s.days.length-1]?.entries?.find(e=>e.cat==="hotel")?.time||"12:00 PM"} · {s.flightReturnDate||s.endDate}</div>
              {s.hotelPhone&&<a href={s.hotelPhoneHref} style={{fontSize:7,color:N.sky,textDecoration:"none"}}>{s.hotelPhone}</a>}
            </div>
          </div>
        </div>
        <div style={{padding:"20px 20px 0"}}>
          <SectionTitle small>Payment</SectionTitle>
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"14px 16px",marginBottom:20,display:"flex",gap:12,alignItems:"flex-end"}}>
            <div style={{flex:1}}>
              <div style={{fontSize:8,color:N.parchD,letterSpacing:"0.1em",marginBottom:5}}>TRIP VALUE ($)</div>
              <input type="number" min="0" step="1" defaultValue={s.quoteAmount||""} onBlur={(e)=>{
                const val = e.target.value===""?null:Math.max(0,Math.round(Number(e.target.value)||0));
                const updated={...viewTrip,quoteAmount:val};
                setViewTrip(updated); setTrips(prev=>prev.map(t=>t.id===updated.id?updated:t));
                PT.updateTripPayment(updated.id,{quoteAmount:val}).catch(err=>console.error("Could not save trip value",err));
              }} placeholder="e.g. 4500" style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"9px 12px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",boxSizing:"border-box"}}/>
            </div>
            <div style={{flex:1}}>
              <div style={{fontSize:8,color:N.parchD,letterSpacing:"0.1em",marginBottom:5}}>STATUS</div>
              <select value={s.paymentStatus||"unpaid"} onChange={(e)=>{
                const updated={...viewTrip,paymentStatus:e.target.value};
                setViewTrip(updated); setTrips(prev=>prev.map(t=>t.id===updated.id?updated:t));
                PT.updateTripPayment(updated.id,{paymentStatus:e.target.value}).catch(err=>console.error("Could not save payment status",err));
              }} style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"9px 12px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit"}}>
                <option value="unpaid">Unpaid</option>
                <option value="deposit">Deposit Paid</option>
                <option value="paid">Paid in Full</option>
              </select>
            </div>
          </div>
          <div style={{fontSize:9,color:N.parchD,marginTop:-14,marginBottom:20,lineHeight:1.6}}>Marking a trip "Paid in Full" or "Deposit Paid" counts its value toward the client's loyalty points (1 pt/$1) and, if they were referred, credits the referral automatically.</div>
          <SectionTitle small>Day-by-Day Itinerary</SectionTitle>
          {(s.days||[]).length===0&&<div style={{fontSize:10,color:N.parchD,fontStyle:"italic",padding:"12px 0"}}>No itinerary yet.</div>}
          {(s.days||[]).map(day=>(
            <div key={day.n} style={{marginBottom:20}}>
              <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",textTransform:"uppercase",color:N.gold,marginBottom:10,paddingBottom:6,borderBottom:`1px solid ${N.goldLine}`,display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                <span>DAY {day.n} · {day.title} · {day.date}</span>
                <button onClick={()=>{setEditEntry({dayN:day.n,entryIdx:-1});setEditForm({time:"",name:"",detail:"",cat:"activity"});}} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"3px 8px",cursor:"pointer",fontSize:8,color:N.gold}}>+ Add</button>
              </div>
              {(day.entries||[]).map((e,i)=>(
                <div key={i} style={{marginBottom:8}}>
                  {editEntry?.dayN===day.n&&editEntry?.entryIdx===i?(
                    <div style={{background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:10}}>
                      <input value={editForm.time} onChange={ev=>setEditForm(f=>({...f,time:ev.target.value}))} placeholder="Time (e.g. 9:00 AM)" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:6,fontFamily:"inherit"}}/>
                      <input value={editForm.name} onChange={ev=>setEditForm(f=>({...f,name:ev.target.value}))} placeholder="Entry name" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:6,fontFamily:"inherit"}}/>
                      <input value={editForm.detail} onChange={ev=>setEditForm(f=>({...f,detail:ev.target.value}))} placeholder="Details" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:8,fontFamily:"inherit"}}/>
                      <div style={{display:"flex",gap:6}}>
                        <button onClick={saveEntry} style={{flex:1,background:N.gold,border:"none",borderRadius:6,padding:"7px",color:N.navy,fontSize:8,fontWeight:700,cursor:"pointer"}}>SAVE</button>
                        <button onClick={()=>setEditEntry(null)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"7px 10px",color:N.parchD,fontSize:8,cursor:"pointer"}}>Cancel</button>
                      </div>
                    </div>
                  ):(
                    <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start"}}>
                      <div style={{flex:1}}>
                        <div style={{display:"flex",gap:8,alignItems:"flex-start"}}>
                          <span style={{fontSize:9,color:N.gold,fontWeight:700,flexShrink:0,width:58}}>{e.time}</span>
                          <span style={{fontSize:10,fontWeight:600,color:N.parch}}>{e.name}</span>
                        </div>
                        {e.detail&&<div style={{fontSize:9,color:N.parchD,marginLeft:66,marginTop:2}}>{e.detail}</div>}
                      </div>
                      <div style={{display:"flex",gap:4,flexShrink:0,marginLeft:8}}>
                        <button onClick={()=>{setEditEntry({dayN:day.n,entryIdx:i});setEditForm({time:e.time,name:e.name,detail:e.detail||"",cat:e.cat||"activity"});}} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"3px 7px",cursor:"pointer",fontSize:9,color:N.parchD}}>Edit</button>
                        <button onClick={()=>deleteEntry(day.n,i)} style={{background:"transparent",border:"1px solid rgba(229,115,115,0.3)",borderRadius:6,padding:"3px 7px",cursor:"pointer",fontSize:9,color:"#e57373"}}>✕</button>
                      </div>
                    </div>
                  )}
                </div>
              ))}
              {editEntry?.dayN===day.n&&editEntry?.entryIdx===-1&&(
                <div style={{background:N.navy,border:`1px solid ${N.gold}`,borderRadius:8,padding:10,marginTop:6}}>
                  <div style={{fontSize:8,color:N.gold,fontWeight:700,marginBottom:8,letterSpacing:"0.1em"}}>NEW ENTRY</div>
                  <input value={editForm.time} onChange={ev=>setEditForm(f=>({...f,time:ev.target.value}))} placeholder="Time (e.g. 9:00 AM)" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:6,fontFamily:"inherit"}}/>
                  <input value={editForm.name} onChange={ev=>setEditForm(f=>({...f,name:ev.target.value}))} placeholder="Entry name" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:6,fontFamily:"inherit"}}/>
                  <input value={editForm.detail} onChange={ev=>setEditForm(f=>({...f,detail:ev.target.value}))} placeholder="Details (optional)" style={{width:"100%",background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"6px 8px",color:N.parch,fontSize:10,outline:"none",marginBottom:8,fontFamily:"inherit"}}/>
                  <div style={{display:"flex",gap:6}}>
                    <button onClick={saveEntry} style={{flex:1,background:N.gold,border:"none",borderRadius:6,padding:"7px",color:N.navy,fontSize:8,fontWeight:700,cursor:"pointer"}}>ADD ENTRY</button>
                    <button onClick={()=>setEditEntry(null)} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:6,padding:"7px 10px",color:N.parchD,fontSize:8,cursor:"pointer"}}>Cancel</button>
                  </div>
                </div>
              )}
            </div>
          ))}
        </div>
      </Screen>
    );
  }

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:4}}>
          <SectionEye label="Itinerary Management"/>
          <span></span>
        </div>

        {/* Trip list */}
        <SectionTitle>All Trips</SectionTitle>
        {sortTrips(trips).map(trip=>(
          <div key={trip.id} style={{background:N.navyMid,border:`1px solid ${active?.id===trip.id?N.gold:N.goldLine}`,borderRadius:12,padding:16,marginBottom:14,transition:"all 0.2s"}}>
            <div onClick={()=>setViewTrip(trip)} style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:12,cursor:"pointer"}}>
              <div>
                <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.16em",color:N.gold,textTransform:"uppercase",marginBottom:4}}>{trip.client}</div>
                <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,marginBottom:2}}>{trip.destination}</div>
                <div style={{fontSize:10,color:N.parchD}}>{trip.dates} · {trip.type} · {trip.tier}</div>
              </div>
              <Badge label={tripStatus(trip)} color={sColor[tripStatus(trip)]}/>
            </div>

            <div style={{display:"flex",gap:8,marginTop:4}}>
              <button onClick={e=>{e.stopPropagation();const next=uploadForTrip===trip.id?null:trip.id;setUploadForTrip(next);if(next){setClientName(trip.client);setUploadStep("idle");setUploading(false);}}} style={{flex:1,background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:7,padding:"9px 0",fontSize:8,fontWeight:700,letterSpacing:"0.12em",color:N.parchD,cursor:"pointer"}}>
                + UPLOAD DOC
              </button>
              <button onClick={e=>{e.stopPropagation();sendToClient(trip);}} style={{flex:1,background:sentTrip===trip.id?`${N.green}22`:N.goldGlow,border:`1px solid ${sentTrip===trip.id?N.green:N.goldLine}`,borderRadius:7,padding:"9px 0",fontSize:8,fontWeight:700,letterSpacing:"0.12em",color:sentTrip===trip.id?N.green:N.gold,cursor:"pointer"}}>
                {sentTrip===trip.id?"✓ SENT":"SEND ITINERARY"}
              </button>
            </div>
          {uploadForTrip===trip.id&&(
            <div onClick={e=>e.stopPropagation()} style={{background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:16,marginTop:14}}>
              <div style={{fontFamily:"Georgia,serif",fontSize:15,color:N.parch,marginBottom:4}}>Upload for {trip.destination}</div>
              <div style={{fontSize:9,color:N.parchD,marginBottom:12,lineHeight:1.7}}>Upload a flight confirmation, hotel booking, itinerary PDF, or screenshot. Claude will build the itinerary automatically.</div>
              <div onDrop={onDrop} onDragOver={e=>{e.preventDefault();setDragOver(true);}} onDragLeave={()=>setDragOver(false)} onClick={()=>!uploading&&fileRef.current?.click()} style={{border:`2px dashed ${dragOver?N.gold:N.goldLine}`,borderRadius:10,padding:"20px",textAlign:"center",cursor:uploading?"not-allowed":"pointer",background:dragOver?N.goldGlow:"transparent"}}>
                {uploadStep==="idle"&&(<><div style={{fontSize:28,marginBottom:6}}></div><div style={{fontSize:10,color:N.parchD}}>Drag & drop or tap to upload</div><div style={{fontSize:9,color:N.parchD,opacity:0.6,marginTop:4}}>PDF, JPG, PNG supported</div></>)}
                {uploadStep==="reading"&&<div style={{fontSize:10,color:N.gold}}>Reading document…</div>}
                {uploadStep==="processing"&&<div style={{fontSize:10,color:N.gold}}>Claude is building itinerary…</div>}
                {uploadStep==="done"&&<div style={{fontSize:10,color:N.green,fontWeight:700}}>{uploadMsg}</div>}
                {uploadStep==="error"&&<div style={{fontSize:10,color:"#e57373"}}>{uploadMsg}</div>}
              </div>
              <input ref={fileRef} type="file" accept=".pdf,image/*" style={{display:"none"}} onChange={e=>handleFile(e.target.files[0])}/>
            </div>
          )}
          </div>
        ))}

        <div style={{display:"flex",gap:8,marginTop:4}}>
          <button onClick={()=>{setShowNewUpload(!showNewUpload);setShowBlank(false);}} style={{flex:1,background:showNewUpload?N.navyMid:N.gold,border:showNewUpload?`1px solid ${N.goldLine}`:"none",borderRadius:8,padding:14,color:showNewUpload?N.gold:N.navy,fontSize:10,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>
            {showNewUpload?"✕ Cancel":"+ Upload New Itinerary"}
          </button>
          <button onClick={()=>{setShowBlank(!showBlank);setShowNewUpload(false);}} style={{flex:1,background:showBlank?N.navyMid:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:8,padding:14,color:showBlank?N.gold:N.parchD,fontSize:10,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",cursor:"pointer"}}>
            {showBlank?"✕ Cancel":"+ Blank Itinerary"}
          </button>
        </div>
        {showNewUpload&&(
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:18,marginTop:12}}>
            <div style={{fontFamily:"Georgia,serif",fontSize:16,color:N.parch,marginBottom:4}}>Upload New Itinerary</div>
            <div style={{fontSize:9,color:N.parchD,marginBottom:14,lineHeight:1.7}}>Pick who it's for, then upload a flight confirmation, hotel booking, or itinerary PDF/photo — Claude will create the trip and fill in everything it finds.</div>
            <div style={{marginBottom:14}}>
              <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>Client</div>
              <select value={newUploadClientId} onChange={e=>setNewUploadClientId(e.target.value)}
                style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:newUploadClientId?N.parch:N.parchD,fontSize:12,outline:"none",fontFamily:"inherit",cursor:"pointer",appearance:"none"}}>
                <option value="">{realClients.length?"Select a client...":"No clients signed up yet"}</option>
                {realClients.map(c=>(<option key={c.id} value={c.id}>{c.fullName||c.email}</option>))}
              </select>
            </div>
            <div onDrop={onNewDrop} onDragOver={e=>{e.preventDefault();setNewDragOver(true);}} onDragLeave={()=>setNewDragOver(false)}
              onClick={()=>newUploadClientId&&!newUploading&&newFileRef.current?.click()}
              style={{border:`2px dashed ${newDragOver?N.gold:N.goldLine}`,borderRadius:10,padding:"20px",textAlign:"center",cursor:newUploadClientId&&!newUploading?"pointer":"not-allowed",background:newDragOver?N.goldGlow:"transparent",opacity:newUploadClientId?1:0.5}}>
              {newUploadStep==="idle"&&(<><div style={{fontSize:28,marginBottom:6}}></div><div style={{fontSize:10,color:N.parchD}}>{newUploadClientId?"Drag & drop or tap to upload":"Select a client first"}</div><div style={{fontSize:9,color:N.parchD,opacity:0.6,marginTop:4}}>PDF, JPG, PNG supported</div></>)}
              {newUploadStep==="reading"&&<div style={{fontSize:10,color:N.gold}}>Reading document…</div>}
              {newUploadStep==="processing"&&<div style={{fontSize:10,color:N.gold}}>Claude is building the itinerary…</div>}
              {newUploadStep==="done"&&<div style={{fontSize:10,color:N.green,fontWeight:700}}>{newUploadMsg}</div>}
              {newUploadStep==="error"&&<div style={{fontSize:10,color:"#e57373"}}>{newUploadMsg}</div>}
            </div>
            <input ref={newFileRef} type="file" accept=".pdf,image/*" style={{display:"none"}} onChange={e=>handleNewUploadFile(e.target.files[0])}/>
          </div>
        )}
        {showBlank&&(
          <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:18,marginTop:12}}>
            <div style={{fontFamily:"Georgia,serif",fontSize:16,color:N.parch,marginBottom:14}}>New Itinerary</div>
            {[
              {key:"clientId",label:"Client",placeholder:"Select a client...",type:"select"},
              {key:"destination",label:"Destination",placeholder:"e.g. Paris, France"},
              {key:"startDate",label:"Start Date",placeholder:"YYYY-MM-DD",type:"date"},
              {key:"endDate",label:"End Date",placeholder:"YYYY-MM-DD",type:"date"},
              {key:"hotel",label:"Hotel (optional)",placeholder:"e.g. Four Seasons Paris"},
            ].map(({key,label,placeholder,type})=>(
              <div key={key} style={{marginBottom:12}}>
                <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold,marginBottom:6}}>{label}</div>
                {type==="select"?(
                  <select value={blankForm[key]} onChange={e=>setBlankForm(f=>({...f,[key]:e.target.value}))}
                    style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:blankForm[key]?N.parch:N.parchD,fontSize:12,outline:"none",fontFamily:"inherit",cursor:"pointer",appearance:"none"}}>
                    <option value="">{realClients.length?"Select a client...":"No clients signed up yet"}</option>
                    {realClients.map(c=>(<option key={c.id} value={c.id}>{c.fullName||c.email}</option>))}
                  </select>
                ):(
                  <input type={type==="date"?"date":"text"} value={blankForm[key]} onChange={e=>setBlankForm(f=>({...f,[key]:e.target.value}))} placeholder={placeholder}
                    style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",colorScheme:"dark"}}/>
                )}
              </div>
            ))}
            {/* Nights is never typed in — it's always derived from the two
                dates above so it can't drift out of sync with them. */}
            <div style={{marginBottom:14,display:"flex",justifyContent:"space-between",alignItems:"center",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"10px 14px"}}>
              <span style={{fontSize:9,fontWeight:700,letterSpacing:"0.14em",textTransform:"uppercase",color:N.gold}}>Nights</span>
              <span style={{fontSize:12,color:blankForm.startDate&&blankForm.endDate?N.parch:N.parchD}}>
                {nightsBetween(blankForm.startDate,blankForm.endDate) ?? "— set both dates —"}
              </span>
            </div>
            <button onClick={createBlank} disabled={!blankForm.clientId||!blankForm.destination||creatingBlank}
              style={{width:"100%",background:blankForm.clientId&&blankForm.destination?N.gold:"rgba(201,168,76,0.2)",border:"none",borderRadius:8,padding:13,color:blankForm.clientId&&blankForm.destination?N.navy:N.parchD,fontSize:10,fontWeight:700,letterSpacing:"0.18em",textTransform:"uppercase",cursor:blankForm.clientId&&blankForm.destination&&!creatingBlank?"pointer":"not-allowed",marginTop:4}}>
              {creatingBlank?"Creating…":"Create Itinerary"}
            </button>
          </div>
        )}
      </div>
    </Screen>
  );
}

// ─── CONCIERGE: Messages ───
function ConciergeMessages({allMsgs={},setClientMsgs,conciergeActive=true,toggleConciergeActive,onOpen,onNewMsg,clients,persistSend}){
  // `clients` is the real client roster (id, name, initials, unread) derived
  // from actual trips in Firestore. No demo-data fallback — an empty list
  // just means no one has a trip yet, which the UI below already handles.
  const roster = clients||[];
  const [activeClient,setActiveClientRaw]=useState(roster[0]);
  useEffect(()=>{if(!activeClient && roster.length) setActiveClientRaw(roster[0]);},[roster]);
  const setActiveClient=setActiveClientRaw;
  useEffect(()=>{if(onOpen)onOpen();},[]);
  const [text,setText]=useState("");
  const bottomRef=useRef(null);
  const msgs = activeClient ? (allMsgs[activeClient.id]||[]) : [];

  useEffect(()=>{if(bottomRef.current){const el=bottomRef.current;el.parentNode&&(el.parentNode.scrollTop=el.parentNode.scrollHeight);}},[msgs,activeClient]);

  function send(){
    if(!text.trim()||!activeClient)return;
    const sent=text;
    setClientMsgs(activeClient.id,m=>[...m,{id:(m.length||0)+1,from:"Shayla L.",time:"Now",text:sent,mine:true}]);
    setText("");
    if(onNewMsg)onNewMsg();
    if(persistSend)persistSend(activeClient.id,sent).catch(()=>{});
  }

  return(
    <Screen>
      {/* Status toggle + client selector */}
      <div style={{background:N.navyMid,padding:"10px 20px",borderBottom:`1px solid ${N.goldLine}`}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10}}>
          <div style={{fontSize:11,fontWeight:600,color:N.parch}}>Messages</div>
          <button onClick={toggleConciergeActive} style={{display:"flex",alignItems:"center",gap:6,background:conciergeActive?`${N.green}20`:`${N.parchD}15`,border:`1px solid ${conciergeActive?N.green:N.parchD}`,borderRadius:20,padding:"5px 12px",cursor:"pointer"}}>
            <div style={{width:7,height:7,borderRadius:"50%",background:conciergeActive?N.green:N.parchD}}/>
            <span style={{fontSize:8,fontWeight:700,color:conciergeActive?N.green:N.parchD,letterSpacing:"0.1em"}}>{conciergeActive?"ACTIVE":"OFFLINE"}</span>
          </button>
        </div>
        <div style={{display:"flex",gap:10,overflowX:"auto",scrollbarWidth:"none"}}>
          {roster.map(c=>(
            <div key={c.id} onClick={()=>{setActiveClient(c);setText("");}}
              style={{flexShrink:0,background:activeClient&&activeClient.id===c.id?N.goldGlow:N.navy,border:`1px solid ${activeClient&&activeClient.id===c.id?N.gold:N.goldLine}`,borderRadius:20,padding:"6px 14px",cursor:"pointer",display:"flex",alignItems:"center",gap:6,transition:"all 0.2s"}}>
              <span style={{fontSize:10,fontWeight:600,color:activeClient&&activeClient.id===c.id?N.gold:N.parchD}}>{c.name.split(" ")[0]}</span>
              {c.unread>0&&<span style={{background:N.gold,color:N.navy,fontSize:7,fontWeight:700,borderRadius:"50%",width:14,height:14,display:"flex",alignItems:"center",justifyContent:"center"}}>{c.unread}</span>}
            </div>
          ))}
          {!roster.length && <div style={{fontSize:10,color:N.parchD,padding:"6px 4px"}}>No clients yet.</div>}
        </div>
      </div>

      <div style={{padding:"16px 20px",display:"flex",flexDirection:"column",gap:10,paddingBottom:80}}>
        <div style={{textAlign:"center",fontSize:9,color:N.parchD}}>{activeClient?`Conversation with ${activeClient.name}`:"Select a client to message"}</div>
        {msgs.map(m=>(
          <div key={m.id} style={{display:"flex",flexDirection:"column",alignItems:m.mine?"flex-end":"flex-start"}}>
            <div style={{maxWidth:"80%",background:m.mine?N.gold:N.navyMid,borderRadius:m.mine?"18px 18px 4px 18px":"18px 18px 18px 4px",padding:"11px 15px"}}>
              <div style={{fontSize:11,color:m.mine?N.navy:N.parch,lineHeight:1.6}}>{m.text}</div>
            </div>
            <div style={{fontSize:8,color:N.parchD,marginTop:4}}>{m.from} · {m.time}</div>
          </div>
        ))}
        <div ref={bottomRef}/>
      </div>

      <div style={{position:"fixed",bottom:56,left:0,right:0,padding:"10px 16px",background:N.navy,borderTop:`1px solid ${N.goldLine}`,display:"flex",gap:10,maxWidth:"var(--pt-shell-width)",margin:"0 auto",boxSizing:"border-box"}}>
        <input value={text} onChange={e=>setText(e.target.value)} onKeyDown={e=>e.key==="Enter"&&send()}
          placeholder={activeClient?`Reply to ${activeClient.name.split(" ")[0]}...`:"Select a client first..."}
          style={{flex:1,background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:24,padding:"11px 16px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit"}}/>
        <MicButton disabled={!activeClient} onResult={(transcript)=>setText(prev=>prev?`${prev} ${transcript}`:transcript)}/>
        <button onClick={send} style={{background:N.gold,border:"none",borderRadius:24,padding:"11px 20px",cursor:"pointer",fontSize:11,fontWeight:700,color:N.navy}}>Send</button>
      </div>
    </Screen>
  );
}

// ─── CONCIERGE: Revenue ───
function ConciergeRevenue(){
  const [showKeys, setShowKeys] = useState(false);
  const [showSecurity, setShowSecurity] = useState(false);
  const CATEGORIES = ["Corporate Retainers","Family Packages","Membership Fees","Rush Add-ons","Other"];
  const [invoices, setInvoices] = useState(()=>{
    try{return JSON.parse(localStorage.getItem("pt_invoices")||"null")||[];}catch{return [];}
  });
  const [uploading,setUploading]=useState(false);
  const [uploadMsg,setUploadMsg]=useState("");
  const [uploadStep,setUploadStep]=useState("idle");
  const [invoiceFolderOpen,setInvoiceFolderOpen]=useState(false);
  const fileRef=useRef(null);

  // Real referral tracking — populated automatically whenever someone signs
  // up through a client's ?ref= link (see maybeTrackReferral in pt-data.js)
  // and flipped to "booked" the moment the concierge marks that referred
  // client's trip Deposit Paid/Paid in Full (see updateTripPayment).
  const [referrals,setReferrals]=useState([]);
  const [referralsLoading,setReferralsLoading]=useState(true);
  useEffect(()=>{
    PT.fetchReferrals().then(setReferrals).catch(e=>console.error("Could not load referrals",e)).finally(()=>setReferralsLoading(false));
  },[]);

  // Real payable invoice links (Settings → client profile → "Send Invoice")
  // — separate from the manual bookkeeping log above. This reflects actual
  // Stripe payments: pending until the client pays, then flipped to "paid"
  // by /api/invoice-confirm once Stripe confirms the charge.
  const [clientInvoices,setClientInvoices]=useState([]);
  const [clientInvoicesLoading,setClientInvoicesLoading]=useState(true);
  const [clientsById,setClientsById]=useState({});
  useEffect(()=>{
    PT.fetchAllInvoices().then(setClientInvoices).catch(e=>console.error("Could not load invoices",e)).finally(()=>setClientInvoicesLoading(false));
    PT.fetchAllClients().then(list=>{
      const map={}; list.forEach(c=>{map[c.id]=c.fullName||c.full_name||"Client";});
      setClientsById(map);
    }).catch(()=>{});
  },[]);
  const pendingInvoices = clientInvoices.filter(i=>i.status==="pending");
  const paidInvoices = clientInvoices.filter(i=>i.status==="paid");
  const paidTotal = paidInvoices.reduce((s,i)=>s+(i.amountCents||0),0)/100;

  function saveInvoices(list){setInvoices(list);try{localStorage.setItem("pt_invoices",JSON.stringify(list));}catch{}}

  async function handleInvoiceFile(file){
    if(!file) return;
    setUploading(true);setUploadStep("reading");setUploadMsg("");
    const reader=new FileReader();
    reader.onload=async(ev)=>{
      try{
        setUploadStep("processing");
        const base64=ev.target.result.split(",")[1];
        const isImage=file.type.startsWith("image/");
        // Routed through /api/sage — no API key in browser code (see pt-data.js).
        const data=await PT.askSage([{role:"user",content:[
            isImage?{type:"image",source:{type:"base64",media_type:file.type,data:base64}}:{type:"text",text:"[PDF invoice - extract text content]"},
            {type:"text",text:`Extract invoice details and return ONLY JSON: {"label":"description of invoice","cat":"one of: Corporate Retainers, Family Packages, Membership Fees, Rush Add-ons, Other","amt":number,"date":"Month DD, YYYY","note":"brief note"}`}
          ]}],{model:"claude-opus-4-8",max_tokens:400});
        const text=data.content?.[0]?.text||"{}";
        const match=text.match(/\{[\s\S]*\}/);
        const extracted=match?JSON.parse(match[0]):{};
        const newInv={id:Date.now(),label:extracted.label||file.name,cat:extracted.cat||"Other",amt:parseFloat(extracted.amt)||0,date:extracted.date||new Date().toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}),note:extracted.note||""};
        saveInvoices([newInv,...invoices]);
        setUploadStep("done");setUploadMsg(`✓ Added: ${newInv.label} — $${newInv.amt.toLocaleString()}`);
      }catch(e){setUploadStep("error");setUploadMsg("Could not read invoice. Try a clearer image.");}
      setUploading(false);
    };
    reader.readAsDataURL(file);
  }

  if(showKeys) return <div><ConciergeKeys/><button onClick={()=>setShowKeys(false)} style={{position:"fixed",bottom:70,left:"50%",transform:"translateX(-50%)",background:N.gold,border:"none",borderRadius:20,padding:"8px 20px",color:N.navy,fontSize:9,fontWeight:700,cursor:"pointer",zIndex:10}}>← Back to Revenue</button></div>;
  if(showSecurity) return <div><ConciergeSecurity/><button onClick={()=>setShowSecurity(false)} style={{position:"fixed",bottom:70,left:"50%",transform:"translateX(-50%)",background:N.gold,border:"none",borderRadius:20,padding:"8px 20px",color:N.navy,fontSize:9,fontWeight:700,cursor:"pointer",zIndex:10}}>← Back to Revenue</button></div>;

  // Compute streams from invoices
  const byCategory = CATEGORIES.map(cat=>({
    label:cat,
    amt:invoices.filter(i=>i.cat===cat).reduce((s,i)=>s+i.amt,0),
    count:invoices.filter(i=>i.cat===cat).length
  })).filter(c=>c.amt>0);
  const total = invoices.reduce((s,i)=>s+i.amt,0);
  const totalPct = (a)=>total>0?Math.round((a/total)*100):0;

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        {/* Hero */}
        <div style={{background:`linear-gradient(135deg, ${N.navyMid} 0%, ${N.navySoft} 100%)`,border:`1px solid ${N.goldLine}`,borderRadius:14,padding:20,marginBottom:20}}>
          <div style={{fontSize:8,fontWeight:700,letterSpacing:"0.22em",color:N.gold,textTransform:"uppercase",marginBottom:6}}>This Month · July 2027</div>
          <div style={{fontFamily:"Georgia,serif",fontSize:40,color:N.parch,fontWeight:600,lineHeight:1,marginBottom:4}}>${total.toLocaleString()}</div>
          <div style={{fontSize:10,color:N.green,display:"flex",alignItems:"center",gap:5,marginBottom:12}}>
            <span>{invoices.length} invoice{invoices.length===1?"":"s"} logged this month</span>
          </div>
          <button onClick={()=>setShowKeys(true)} style={{background:N.goldGlow,border:`1px solid ${N.gold}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:9,fontWeight:700,cursor:"pointer",letterSpacing:"0.1em",marginBottom:8,width:"100%"}}>
            MANAGE CLIENT KEYS
          </button>
          <button onClick={()=>setShowSecurity(true)} style={{background:N.goldGlow,border:`1px solid ${N.gold}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:9,fontWeight:700,cursor:"pointer",letterSpacing:"0.1em",marginBottom:12,width:"100%"}}>
            VIEW SECURITY LOG
          </button>
        </div>

        {/* Invoice Upload */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:14,marginBottom:14}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>Upload Invoice</div>
          <div onClick={()=>!uploading&&fileRef.current?.click()} style={{border:`2px dashed ${uploadStep==="done"?N.green:N.goldLine}`,borderRadius:10,padding:"16px",textAlign:"center",cursor:uploading?"not-allowed":"pointer",background:"transparent",marginBottom:8}}>
            {uploadStep==="idle"&&<div style={{fontSize:10,color:N.parchD}}>Tap to upload invoice (PDF or image) — Claude reads & categorizes</div>}
            {uploadStep==="reading"&&<div style={{fontSize:10,color:N.gold}}>Reading invoice…</div>}
            {uploadStep==="processing"&&<div style={{fontSize:10,color:N.gold}}>Claude is extracting details…</div>}
            {uploadStep==="done"&&<div style={{fontSize:10,color:N.green,fontWeight:700}}>{uploadMsg}</div>}
            {uploadStep==="error"&&<div style={{fontSize:10,color:"#e57373"}}>{uploadMsg}</div>}
          </div>
          <input ref={fileRef} type="file" accept=".pdf,image/*" style={{display:"none"}} onChange={e=>handleInvoiceFile(e.target.files[0])}/>
          {uploadStep!=="idle"&&<button onClick={()=>{setUploadStep("idle");setUploadMsg("");}} style={{fontSize:8,color:N.parchD,background:"transparent",border:"none",cursor:"pointer",textDecoration:"underline"}}>Upload another</button>}
        </div>

        {/* Revenue Breakdown */}
        <SectionEye label="Revenue Breakdown"/>
        {byCategory.map((r,i)=>(
          <div key={i} style={{background:N.navyMid,borderRadius:10,padding:"14px 16px",marginBottom:10}}>
            <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:8}}>
              <div>
                <div style={{fontSize:11,fontWeight:600,color:N.parch,marginBottom:2}}>{r.label}</div>
                <div style={{fontSize:9,color:N.parchD}}>{r.count} invoice{r.count===1?"":"s"}</div>
              </div>
              <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.gold,fontWeight:600}}>${r.amt.toLocaleString()}</div>
            </div>
            <div style={{background:N.navyDeep,borderRadius:4,height:5}}>
              <div style={{background:`linear-gradient(to right,${N.gold},#E8C870)`,borderRadius:4,height:5,width:`${totalPct(r.amt)}%`,transition:"width 1s"}}/>
            </div>
            <div style={{display:"flex",justifyContent:"flex-end",fontSize:8,color:N.parchD,marginTop:3}}>{totalPct(r.amt)}%</div>
          </div>
        ))}
        {byCategory.length===0&&<div style={{fontSize:10,color:N.parchD,fontStyle:"italic",padding:"12px 0"}}>No invoices yet. Upload your first invoice above.</div>}

        {/* Client Invoices — real payable links, see note above */}
        <SectionEye label="Client Invoices"/>
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px",marginBottom:20}}>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12}}>
            <div style={{fontSize:9,color:N.parchD}}>{paidInvoices.length} paid · {pendingInvoices.length} pending</div>
            <div style={{fontFamily:"Georgia,serif",fontSize:16,color:N.green,fontWeight:600}}>${paidTotal.toLocaleString()} collected</div>
          </div>
          {clientInvoicesLoading && <div style={{fontSize:10,color:N.parchD}}>Loading…</div>}
          {!clientInvoicesLoading && clientInvoices.length===0 && (
            <div style={{fontSize:10,color:N.parchD,fontStyle:"italic"}}>No invoice links sent yet. Open a client's profile and tap "Send Invoice" to create one.</div>
          )}
          {clientInvoices.slice(0,15).map((inv,i)=>(
            <div key={inv.id} style={{display:"flex",justifyContent:"space-between",alignItems:"center",paddingBottom:10,marginBottom:10,borderBottom:i<Math.min(clientInvoices.length,15)-1?`1px solid ${N.goldLine}`:"none"}}>
              <div>
                <div style={{fontSize:11,fontWeight:600,color:N.parch}}>{clientsById[inv.clientId]||"Client"}</div>
                <div style={{fontSize:9,color:N.parchD}}>{inv.description||"Provisions Travel invoice"}</div>
              </div>
              <div style={{textAlign:"right"}}>
                <div style={{fontFamily:"Georgia,serif",fontSize:14,color:N.gold,fontWeight:600,marginBottom:3}}>${(inv.amountCents/100).toLocaleString()}</div>
                <span style={{background:inv.status==="paid"?`${N.green}20`:`${N.gold}15`,border:`1px solid ${inv.status==="paid"?N.green:N.goldLine}`,borderRadius:20,padding:"3px 8px",fontSize:8,fontWeight:700,color:inv.status==="paid"?N.green:N.gold,letterSpacing:"0.08em",textTransform:"uppercase"}}>
                  {inv.status==="paid"?"Paid":"Pending"}
                </span>
              </div>
            </div>
          ))}
        </div>

        {/* Referrals — automated, see note above */}
        <SectionEye label="Referrals"/>
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:"16px",marginBottom:20}}>
          {referralsLoading && <div style={{fontSize:10,color:N.parchD}}>Loading…</div>}
          {!referralsLoading && referrals.length===0 && <div style={{fontSize:10,color:N.parchD,fontStyle:"italic"}}>No referrals yet. Every client's My Profile page has their own shareable link — it's tracked here automatically once someone signs up and books.</div>}
          {referrals.map((r,i)=>(
            <div key={r.id} style={{display:"flex",justifyContent:"space-between",alignItems:"center",paddingBottom:10,marginBottom:10,borderBottom:i<referrals.length-1?`1px solid ${N.goldLine}`:"none"}}>
              <div>
                <div style={{fontSize:11,fontWeight:600,color:N.parch}}>{r.referredClientName||"New client"}</div>
                <div style={{fontSize:9,color:N.parchD}}>referred by {r.referringClientName||"—"}</div>
              </div>
              <div style={{background:r.status==="booked"?`${N.green}20`:`${N.gold}15`,border:`1px solid ${r.status==="booked"?N.green:N.goldLine}`,borderRadius:20,padding:"4px 10px",fontSize:8,fontWeight:700,color:r.status==="booked"?N.green:N.gold,letterSpacing:"0.08em",textTransform:"uppercase"}}>
                {r.status==="booked"?"Booked":"Signed Up"}
              </div>
            </div>
          ))}
        </div>

        {/* Invoice Log Folder — by year */}
        {(()=>{
          const years=[...new Set(invoices.map(inv=>{const m=inv.date?.match(/\d{4}/);return m?m[0]:"Unknown";}))].sort((a,b)=>b-a);
          return(
            <div style={{marginBottom:20}}>
              <div onClick={()=>setInvoiceFolderOpen(v=>!v)} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:invoiceFolderOpen?"12px 12px 0 0":12,padding:"14px 18px",cursor:"pointer",display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                <div style={{display:"flex",alignItems:"center",gap:12}}>
                  <Icon name="doc" size={22} color={N.gold}/>
                  <div>
                    <div style={{fontSize:13,fontWeight:600,color:N.parch}}>Invoice Folder</div>
                    <div style={{fontSize:9,color:N.parchD}}>{invoices.length} invoice{invoices.length===1?"":"s"} · ${total.toLocaleString()} total</div>
                  </div>
                </div>
                <span style={{color:N.gold,fontSize:18,display:"inline-block",transform:invoiceFolderOpen?"rotate(90deg)":"none",transition:"transform 0.2s"}}>›</span>
              </div>
              {invoiceFolderOpen&&(
                <div style={{background:N.navy,border:`1px solid ${N.goldLine}`,borderTop:"none",borderRadius:"0 0 12px 12px",padding:"8px 14px 14px"}}>
                  {invoices.length===0&&<div style={{fontSize:10,color:N.parchD,fontStyle:"italic",padding:"12px 0"}}>No invoices yet.</div>}
                  {years.map(year=>{
                    const yearInvs=invoices.filter(inv=>{const m=inv.date?.match(/\d{4}/);return (m?m[0]:"Unknown")===year;});
                    const yearTotal=yearInvs.reduce((s,i)=>s+i.amt,0);
                    return(
                      <div key={year} style={{marginTop:10}}>
                        <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:6,display:"flex",justifyContent:"space-between"}}>
                          <span>{year}</span><span>${yearTotal.toLocaleString()}</span>
                        </div>
                        {yearInvs.map((inv,i)=>(
                          <div key={inv.id} style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",padding:"8px 0",borderBottom:i<yearInvs.length-1?`1px solid ${N.goldLine}33`:"none"}}>
                            <div style={{flex:1}}>
                              <div style={{fontSize:10,fontWeight:600,color:N.parch,marginBottom:1}}>{inv.label}</div>
                              <div style={{fontSize:8,color:N.parchD}}>{inv.cat} · {inv.date}</div>
                            </div>
                            <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:4,marginLeft:8}}>
                              <div style={{fontFamily:"Georgia,serif",fontSize:14,color:N.gold,fontWeight:600}}>${inv.amt.toLocaleString()}</div>
                              <button onClick={()=>saveInvoices(invoices.filter(v=>v.id!==inv.id))} style={{fontSize:8,color:"#e57373",background:"transparent",border:"none",cursor:"pointer"}}>Remove</button>
                            </div>
                          </div>
                        ))}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })()}
      </div>
    </Screen>
  );
}



// ─── Markdown renderer (bold + line breaks) ───
function renderMD(text){
  if(!text) return null;
  return text.split("\n").map((line,li)=>{
    const parts=[];let last=0;
    const re=/\*\*([^*]+)\*\*/g;let m;
    while((m=re.exec(line))!==null){
      if(m.index>last)parts.push(line.slice(last,m.index));
      parts.push(React.createElement("span",{key:m.index,style:{color:"#EDE8DF",fontWeight:700}},m[1]));
      last=m.index+m[0].length;
    }
    if(last<line.length)parts.push(line.slice(last));
    return React.createElement(React.Fragment,{key:li},...parts,li<text.split("\n").length-1?React.createElement("br",null):null);
  });
}

// ─── CLIENT: Sage ───
function ClientAI({concierge=false, currentClient=null, profile={}, trips=[]}){
  // First name only, for a natural greeting — falls back to "there" for a
  // brand-new client with no name on file yet rather than a hardcoded demo name.
  const clientFullName = (currentClient&&(currentClient.full_name||currentClient.fullName)) || profile.name || "";
  const clientFirstName = clientFullName.trim().split(/\s+/)[0] || "there";
  const upcomingTrip = !concierge ? (trips.length ? (sortTrips(trips).find(t=>tripStatus(t)!=="Completed")||trips[0]) : null) : null;

  const initText = concierge
    ? "Hi Shayla! I'm Sage, your concierge assistant. I can help you research destinations, draft client messages, suggest itinerary ideas, look up travel tips, and anything you need to serve your clients better. What can I help with?"
    : `Hi ${clientFirstName}! I'm Sage, your personal Provisions Travel guide. I can help with destination ideas, travel advice, local customs, currency, and anything about your trips. What can I help with today?`;

  const [msgs, setMsgs] = useState([{id:1, role:"assistant", text:initText, time:"Now"}]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const bottomRef = useRef(null);

  const suggestions = concierge ? [
    "Draft a welcome message for a new client",
    "Best luxury hotels in Cancún?",
    "What should I include in a NYC itinerary?",
    "Top restaurants for a client dinner in NYC",
    "What visa does a US citizen need for Japan?",
  ] : [
    "Best restaurants near the Four Seasons?",
    "What time should I arrive at the airport?",
    "Tell me about tipping customs in NYC",
    "What's the currency exchange rate?",
  ];

  const tripContext = upcomingTrip
    ? `They have an upcoming trip to ${upcomingTrip.destination}${upcomingTrip.dates?` (${upcomingTrip.dates})`:""}${upcomingTrip.hotel?`, staying at ${upcomingTrip.hotel}`:""}${upcomingTrip.flightOut?`, flying ${upcomingTrip.flightOut}`:""}.`
    : "They don't have a trip booked yet.";
  const systemPrompt = concierge
    ? "You are Sage, an expert travel assistant for Shayla Lee, founder of Provisions Travel — a premium personal travel concierge service. Shayla is a U.S. Military Officer with 14 years of active duty. Help her research destinations, draft professional client communications, suggest itinerary ideas, provide travel industry knowledge, recommend hotels and restaurants, and answer any travel questions. Be concise, professional, and on-brand with Provisions Travel's premium positioning."
    : `You are Sage, the personal travel guide for Provisions Travel. You are speaking with ${clientFullName||clientFirstName}, a Provisions Travel client. ${tripContext} Help them with destination tips, packing advice, local recommendations, weather, customs, currency, and travel questions. Be warm, knowledgeable, and concise. For actual booking changes, remind them to message Shayla directly.`;

  useEffect(()=>{bottomRef.current?.scrollIntoView({behavior:"smooth"});},[msgs, loading]);

  async function send(text){
    const q = text || input.trim();
    if(!q || loading) return;
    setInput("");
    setMsgs(m=>[...m, {id:Date.now(), role:"user", text:q, time:"Now"}]);
    setLoading(true);
    try {
      const history = msgs.map(m=>({role:m.role==="assistant"?"assistant":"user", content:m.text}));
      // Routed through /api/sage — no API key in browser code (see pt-data.js).
      const data = await PT.askSage([...history, {role:"user", content:q}], {system:systemPrompt, max_tokens:1000});
      let reply = data.content?.map(b=>b.text||"").join("").trim();
      reply = reply || "Having trouble connecting. Try again shortly.";
      setMsgs(m=>[...m, {id:Date.now()+1, role:"assistant", text:reply, time:"Just now"}]);
    } catch(err) {
      setMsgs(m=>[...m, {id:Date.now()+1, role:"assistant", text:"Having trouble connecting. Please try again.", time:"Just now"}]);
    }
    setLoading(false);
  }

  return(
    <Screen>
      {/* Header */}
      <div style={{background:N.navyMid,padding:"16px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
        <div style={{width:44,height:44,borderRadius:"50%",background:`linear-gradient(135deg, ${N.gold}, #E8C870)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:20,fontWeight:700,fontFamily:"Georgia,serif",color:N.navy,flexShrink:0}}>S</div>
        <div style={{flex:1}}>
          <div style={{fontSize:13,fontWeight:600,color:N.parch,marginBottom:2}}>Sage</div>
          <div style={{display:"flex",alignItems:"center",gap:5,fontSize:9,color:N.green}}>
            <span style={{width:6,height:6,borderRadius:"50%",background:N.green,display:"inline-block"}}/>
            Your personal travel guide · Always available
          </div>
        </div>
        <div style={{fontSize:9,color:N.parchD,textAlign:"right",lineHeight:1.5}}>Travel<br/>Guide</div>
      </div>

      {/* Messages */}
      <div style={{padding:"16px 20px",display:"flex",flexDirection:"column",gap:12,paddingBottom:160}}>

        {/* Suggestion chips — show only at start */}
        {msgs.length === 1 && (
          <div>
            <div style={{fontSize:9,color:N.parchD,marginBottom:10,textAlign:"center"}}>Try asking me:</div>
            <div style={{display:"flex",flexWrap:"wrap",gap:8,justifyContent:"center"}}>
              {suggestions.map((s,i)=>(
                <button key={i} onClick={()=>send(s)}
                  style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"7px 12px",cursor:"pointer",fontSize:10,color:N.parchD,fontFamily:"inherit",transition:"all 0.2s"}}>
                  {s}
                </button>
              ))}
            </div>
          </div>
        )}

        {msgs.map(m=>(
          <div key={m.id} style={{display:"flex",flexDirection:"column",alignItems:m.role==="user"?"flex-end":"flex-start"}}>
            {m.role==="assistant" && (
              <div style={{width:24,height:24,borderRadius:"50%",background:`linear-gradient(135deg, ${N.gold}, #E8C870)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,fontFamily:"Georgia,serif",color:N.navy,marginBottom:4}}>S</div>
            )}
            <div style={{maxWidth:"82%",background:m.role==="user"?N.gold:N.navyMid,borderRadius:m.role==="user"?"18px 18px 4px 18px":"18px 18px 18px 4px",padding:"12px 15px",boxShadow:"0 2px 8px rgba(0,0,0,0.15)"}}>
              <div style={{fontSize:11,color:m.role==="user"?N.navy:N.parch,lineHeight:1.7}}>{m.role==="user"?m.text:renderMD(m.text)}</div>
            </div>
            <div style={{fontSize:8,color:N.parchD,marginTop:4,paddingLeft:m.role==="user"?0:4}}>{m.time}</div>
          </div>
        ))}

        {/* Loading indicator */}
        {loading && (
          <div style={{display:"flex",flexDirection:"column",alignItems:"flex-start"}}>
            <div style={{width:24,height:24,borderRadius:"50%",background:`linear-gradient(135deg, ${N.gold}, #E8C870)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,fontFamily:"Georgia,serif",color:N.navy,marginBottom:4}}>S</div>
            <div style={{background:N.navyMid,borderRadius:"18px 18px 18px 4px",padding:"12px 18px",display:"flex",gap:5,alignItems:"center"}}>
              {[0,1,2].map(i=>(
                <div key={i} style={{width:6,height:6,borderRadius:"50%",background:N.gold,animation:`dot 1.2s ease-in-out ${i*0.2}s infinite`}}/>
              ))}
            </div>
          </div>
        )}

        <style>{`
          @keyframes dot {
            0%,80%,100%{opacity:0.3;transform:scale(0.8)}
            40%{opacity:1;transform:scale(1)}
          }
        `}</style>

        <div ref={bottomRef}/>
      </div>

      {/* Input bar */}
      <div style={{position:"fixed",bottom:66,left:0,right:0,padding:"10px 16px",background:N.navy,borderTop:`1px solid ${N.goldLine}`,maxWidth:"var(--pt-shell-width)",margin:"0 auto",boxSizing:"border-box"}}>
        <div style={{display:"flex",gap:10}}>
          <input
            value={input}
            onChange={e=>setInput(e.target.value)}
            onKeyDown={e=>e.key==="Enter"&&!e.shiftKey&&send()}
            placeholder="Ask Sage anything about your trip..."
            disabled={loading}
            style={{flex:1,background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:24,padding:"11px 16px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",opacity:loading?0.6:1}}
          />
          <MicButton disabled={loading} onResult={(transcript)=>setInput(prev=>prev?`${prev} ${transcript}`:transcript)}/>
          <button onClick={()=>send()} disabled={loading||!input.trim()}
            style={{background:input.trim()&&!loading?N.gold:"rgba(201,168,76,0.3)",border:"none",borderRadius:24,padding:"11px 20px",cursor:input.trim()&&!loading?"pointer":"not-allowed",fontSize:11,fontWeight:700,color:N.navy,transition:"all 0.2s",flexShrink:0}}>
            {loading?"..." : "Send"}
          </button>
        </div>
        <div style={{fontSize:8,color:N.parchD,textAlign:"center",marginTop:6}}>
          For reservations & bookings, message Shayla directly ✦
        </div>
      </div>
    </Screen>
  );
}

// ─── Valid Client Keys (issued by Shayla) ───
const VALID_KEYS_DEFAULT = {
  "PT-MARCUS-2027":  {name:"Marcus W.",    email:"marcus@company.com",   initials:"MW"},
  "PT-JOHNSON-2027": {name:"Johnson Family",email:"johnson@email.com",    initials:"JF"},
  "PT-SIMONE-2027":  {name:"Simone T.",    email:"simone@email.com",     initials:"ST"},
  "PT-DAVID-2027":   {name:"David R.",     email:"david@company.com",    initials:"DR"},
};
function getValidKeys(){
  try{const s=localStorage.getItem("pt_valid_keys");return s?{...VALID_KEYS_DEFAULT,...JSON.parse(s)}:VALID_KEYS_DEFAULT;}catch{return VALID_KEYS_DEFAULT;}
}
function saveValidKeys(keys){
  try{localStorage.setItem("pt_valid_keys",JSON.stringify(keys));}catch{}
}

// ─── Login Screen ───
function LoginScreen({onLogin}){
  const [mode, setMode] = useState("login"); // login | signup | forgotpw
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [clientKey, setClientKey] = useState("");
  const [confirmPw, setConfirmPw] = useState("");
  const [err, setErr] = useState("");
  const [loading, setLoading] = useState(false);
  const [showPw, setShowPw] = useState(false);

  function simulateOAuth(provider){
    setLoading(true);
    setErr("");
    const timer = setTimeout(()=>{
      setLoading(false);
      onLogin();
    },800);
    return ()=>clearTimeout(timer);
  }

  function handleLogin(){
    if(!email||!password){setErr("Please enter your email and password.");return;}
    setLoading(true);
    setTimeout(()=>{setLoading(false);onLogin();},800);
  }

  function handleSignup(){
    if(!email||!password||!clientKey){setErr("All fields are required.");return;}
    if(password!==confirmPw){setErr("Passwords do not match.");return;}
    if(password.length<8){setErr("Password must be at least 8 characters.");return;}
    const keyData=getValidKeys()[clientKey.toUpperCase().trim()];
    if(!keyData){setErr("Invalid client key. Contact Shayla at Provisions Travel to receive your key.");return;}
    setLoading(true);
    setTimeout(()=>{
      localStorage.setItem("pt_client_name",keyData.name);
      localStorage.setItem("pt_client_email",email);
      // Credit referrer if came via referral link
      const refCode=(new URLSearchParams(window.location.search)).get("ref");
      if(refCode){
        const refKey="pt_ref_processed_"+refCode;
        if(!localStorage.getItem(refKey)){
          const date=new Date().toLocaleDateString("en-US",{month:"short",year:"numeric"});
          try{
            const refs=JSON.parse(localStorage.getItem("pt_referrals")||"[]");
            const idx=refs.findIndex(r=>r._ref===refCode);
            if(idx>=0){refs[idx]={...refs[idx],name:keyData.name,status:"Active"};}
            else{refs.push({name:keyData.name,date,status:"Active",pts:"+250",_ref:refCode});}
            localStorage.setItem("pt_referrals",JSON.stringify(refs));
            localStorage.setItem(refKey,"1");
          }catch{}
          const subj=encodeURIComponent("New Referral — Provisions Travel");
          const bod=encodeURIComponent(`${keyData.name} signed up with a valid client key via referral code: ${refCode}\n\nDate: ${date}`);
          window.open(`mailto:slee@provisionstravel.com?subject=${subj}&body=${bod}`);
        }
      }
      setLoading(false);
      onLogin();
    },1000);
  }

  const logoText = (
    <div style={{textAlign:"center",marginBottom:32}}>
      <div style={{fontFamily:"Georgia,serif",fontSize:11,color:N.gold,letterSpacing:"0.4em",marginBottom:6}}>PROVISIONS</div>
      <div style={{fontFamily:"Georgia,serif",fontSize:11,color:N.parchD,letterSpacing:"0.4em"}}>TRAVEL</div>
    </div>
  );

  return(
    <div style={{minHeight:"100vh",background:`linear-gradient(160deg,${N.navyMid} 0%,${N.navy} 100%)`,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:28,position:"relative",overflow:"hidden"}}>
      <div style={{position:"absolute",top:-80,right:-80,width:300,height:300,borderRadius:"50%",background:`radial-gradient(circle,${N.gold}06 0%,transparent 70%)`}}/>
      <div style={{position:"absolute",bottom:-60,left:-60,width:220,height:220,borderRadius:"50%",background:`radial-gradient(circle,${N.gold}05 0%,transparent 70%)`}}/>

      <div style={{width:"100%",maxWidth:340,position:"relative",zIndex:1}}>
        {logoText}

        {mode==="login"&&(
          <>
            <div style={{fontFamily:"Georgia,serif",fontSize:22,color:N.parch,textAlign:"center",marginBottom:8}}>Welcome Back</div>
            <div style={{fontSize:10,color:N.parchD,textAlign:"center",marginBottom:28}}>Sign in to your Provisions Travel account</div>

            {/* OAuth buttons */}
            <button onClick={()=>simulateOAuth("Google")} disabled={loading} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"13px 16px",display:"flex",alignItems:"center",justifyContent:"center",gap:10,cursor:"pointer",marginBottom:10,color:N.parch,fontSize:11,fontWeight:600}}>
              <svg width="18" height="18" viewBox="0 0 24 24"><path fill="#EA4335" d="M5.27 9.76A7.08 7.08 0 0112 4.9c1.7 0 3.22.6 4.42 1.57l3.3-3.3A11.95 11.95 0 0012 .9C7.7.9 4.01 3.36 2.05 6.97l3.22 2.79z"/><path fill="#34A853" d="M16.04 18.01A7.02 7.02 0 0112 19.1a7.08 7.08 0 01-6.72-4.84L2.05 17.03A11.95 11.95 0 0012 23.1c3.22 0 5.95-1.16 8.03-3.06l-4-2.03z"/><path fill="#FBBC05" d="M19.1 12c0-.6-.06-1.18-.16-1.74H12v3.38h4.01A3.56 3.56 0 0114.7 15.7l4 2.03A9.86 9.86 0 0019.1 12z"/><path fill="#4285F4" d="M5.27 14.24A7.15 7.15 0 014.9 12c0-.78.14-1.54.37-2.24L2.05 6.97A11.94 11.94 0 00.9 12c0 1.83.41 3.56 1.15 5.1l3.22-2.86z"/></svg>
              Continue with Google
            </button>
            <button onClick={()=>simulateOAuth("Apple")} disabled={loading} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"13px 16px",display:"flex",alignItems:"center",justifyContent:"center",gap:10,cursor:"pointer",marginBottom:22,color:N.parch,fontSize:11,fontWeight:600}}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill={N.parch}><path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.7 9.05 7.4c1.42.07 2.38.74 3.19.8.98-.19 1.9-.89 3-.96 1.33.07 2.38.65 3.07 1.66-2.76 1.66-2.1 5.3.48 6.34-.56 1.53-1.3 3.04-1.74 4.04zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/></svg>
              Continue with Apple
            </button>

            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:20}}>
              <div style={{flex:1,height:1,background:N.goldLine}}/>
              <span style={{fontSize:9,color:N.parchD}}>OR</span>
              <div style={{flex:1,height:1,background:N.goldLine}}/>
            </div>

            {err&&<div style={{fontSize:9,color:"#e57373",marginBottom:10,textAlign:"center"}}>{err}</div>}
            <input value={email} onChange={e=>{setEmail(e.target.value);setErr("");}} placeholder="Email address" type="email"
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",marginBottom:10,fontFamily:"inherit",boxSizing:"border-box"}}/>
            <div style={{position:"relative",marginBottom:18}}>
              <input value={password} onChange={e=>{setPassword(e.target.value);setErr("");}} placeholder="Password" type={showPw?"text":"password"}
                style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",boxSizing:"border-box"}}/>
              <button onClick={()=>setShowPw(v=>!v)} style={{position:"absolute",right:12,top:"50%",transform:"translateY(-50%)",background:"transparent",border:"none",color:N.parchD,fontSize:9,cursor:"pointer"}}>{showPw?"Hide":"Show"}</button>
            </div>
            <button onClick={handleLogin} disabled={loading} style={{width:"100%",background:N.gold,border:"none",borderRadius:10,padding:"14px",color:N.navy,fontSize:11,fontWeight:700,cursor:"pointer",letterSpacing:"0.12em",marginBottom:14}}>
              {loading?"SIGNING IN...":"SIGN IN"}
            </button>
            <div style={{textAlign:"center",fontSize:9,color:N.parchD}}>
              <span onClick={()=>{setMode("forgotpw");setErr("");}} style={{cursor:"pointer",textDecoration:"underline"}}>Forgot password?</span>
              {"  ·  "}
              <span onClick={()=>{setMode("signup");setErr("");}} style={{cursor:"pointer",color:N.gold}}>New client? Sign up</span>
            </div>
          </>
        )}

        {mode==="signup"&&(
          <>
            <div style={{fontFamily:"Georgia,serif",fontSize:22,color:N.parch,textAlign:"center",marginBottom:8}}>Create Account</div>
            <div style={{fontSize:10,color:N.parchD,textAlign:"center",marginBottom:24}}>Enter your unique client key from Shayla to get started</div>

            <button onClick={()=>simulateOAuth("Google")} disabled={loading} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"13px 16px",display:"flex",alignItems:"center",justifyContent:"center",gap:10,cursor:"pointer",marginBottom:10,color:N.parch,fontSize:11,fontWeight:600}}>
              <svg width="18" height="18" viewBox="0 0 24 24"><path fill="#EA4335" d="M5.27 9.76A7.08 7.08 0 0112 4.9c1.7 0 3.22.6 4.42 1.57l3.3-3.3A11.95 11.95 0 0012 .9C7.7.9 4.01 3.36 2.05 6.97l3.22 2.79z"/><path fill="#34A853" d="M16.04 18.01A7.02 7.02 0 0112 19.1a7.08 7.08 0 01-6.72-4.84L2.05 17.03A11.95 11.95 0 0012 23.1c3.22 0 5.95-1.16 8.03-3.06l-4-2.03z"/><path fill="#FBBC05" d="M19.1 12c0-.6-.06-1.18-.16-1.74H12v3.38h4.01A3.56 3.56 0 0114.7 15.7l4 2.03A9.86 9.86 0 0019.1 12z"/><path fill="#4285F4" d="M5.27 14.24A7.15 7.15 0 014.9 12c0-.78.14-1.54.37-2.24L2.05 6.97A11.94 11.94 0 00.9 12c0 1.83.41 3.56 1.15 5.1l3.22-2.86z"/></svg>
              Sign up with Google
            </button>
            <button onClick={()=>simulateOAuth("Apple")} disabled={loading} style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"13px 16px",display:"flex",alignItems:"center",justifyContent:"center",gap:10,cursor:"pointer",marginBottom:20,color:N.parch,fontSize:11,fontWeight:600}}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill={N.parch}><path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.7 9.05 7.4c1.42.07 2.38.74 3.19.8.98-.19 1.9-.89 3-.96 1.33.07 2.38.65 3.07 1.66-2.76 1.66-2.1 5.3.48 6.34-.56 1.53-1.3 3.04-1.74 4.04zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/></svg>
              Sign up with Apple
            </button>

            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:18}}>
              <div style={{flex:1,height:1,background:N.goldLine}}/>
              <span style={{fontSize:9,color:N.parchD}}>OR EMAIL</span>
              <div style={{flex:1,height:1,background:N.goldLine}}/>
            </div>

            {err&&<div style={{fontSize:9,color:"#e57373",marginBottom:10,textAlign:"center"}}>{err}</div>}
            <input value={clientKey} onChange={e=>{setClientKey(e.target.value);setErr("");}} placeholder="Client key (e.g. PT-MARCUS-2027)"
              style={{width:"100%",background:`${N.gold}10`,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.gold,fontSize:11,outline:"none",marginBottom:10,fontFamily:"monospace",letterSpacing:"0.05em",boxSizing:"border-box"}}/>
            <input value={email} onChange={e=>{setEmail(e.target.value);setErr("");}} placeholder="Email address" type="email"
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",marginBottom:10,fontFamily:"inherit",boxSizing:"border-box"}}/>
            <input value={password} onChange={e=>{setPassword(e.target.value);setErr("");}} placeholder="Create password (min 8 chars)" type="password"
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",marginBottom:10,fontFamily:"inherit",boxSizing:"border-box"}}/>
            <input value={confirmPw} onChange={e=>{setConfirmPw(e.target.value);setErr("");}} placeholder="Confirm password" type="password"
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",marginBottom:18,fontFamily:"inherit",boxSizing:"border-box"}}/>
            <button onClick={handleSignup} disabled={loading} style={{width:"100%",background:N.gold,border:"none",borderRadius:10,padding:"14px",color:N.navy,fontSize:11,fontWeight:700,cursor:"pointer",letterSpacing:"0.12em",marginBottom:14}}>
              {loading?"CREATING ACCOUNT...":"CREATE ACCOUNT"}
            </button>
            <div style={{textAlign:"center",fontSize:9,color:N.parchD}}>
              Already have an account?{" "}
              <span onClick={()=>{setMode("login");setErr("");}} style={{cursor:"pointer",color:N.gold}}>Sign in</span>
            </div>
          </>
        )}

        {mode==="forgotpw"&&(
          <>
            <div style={{fontFamily:"Georgia,serif",fontSize:22,color:N.parch,textAlign:"center",marginBottom:8}}>Reset Password</div>
            <div style={{fontSize:10,color:N.parchD,textAlign:"center",marginBottom:24}}>Enter your email and we'll send a reset link</div>
            {err&&<div style={{fontSize:9,color:"#e57373",marginBottom:10,textAlign:"center"}}>{err}</div>}
            <input value={email} onChange={e=>{setEmail(e.target.value);setErr("");}} placeholder="Email address" type="email"
              style={{width:"100%",background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"11px 14px",color:N.parch,fontSize:12,outline:"none",marginBottom:18,fontFamily:"inherit",boxSizing:"border-box"}}/>
            <button onClick={()=>{if(!email){setErr("Enter your email.");return;}setErr("");setMode("login");}} style={{width:"100%",background:N.gold,border:"none",borderRadius:10,padding:"14px",color:N.navy,fontSize:11,fontWeight:700,cursor:"pointer",letterSpacing:"0.12em",marginBottom:14}}>
              SEND RESET LINK
            </button>
            <div style={{textAlign:"center",fontSize:9,color:N.parchD}}>
              <span onClick={()=>{setMode("login");setErr("");}} style={{cursor:"pointer",color:N.gold}}>Back to sign in</span>
            </div>
          </>
        )}

        <div style={{textAlign:"center",marginTop:32,fontSize:8,color:N.parchD,lineHeight:1.8,letterSpacing:"0.05em"}}>
          Don't have a key? Contact Shayla Lee at{"\n"}
          <span style={{color:N.gold}}>provisions.travel</span> to begin your membership.
        </div>
      </div>
    </div>
  );
}

// ─── CONCIERGE: Key Management ───
// Real Firestore-backed (db.collection("access_keys")) — this is the exact
// same collection signUpClient/completeClientSignup check when a visitor
// enters a code. A key generated here works immediately for real signup;
// nothing else needs to be kept in sync.
function ConciergeKeys({onBack}){
  const [keys, setKeys] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [label, setLabel] = useState("");
  const [creating, setCreating] = useState(false);
  const [copiedCode, setCopiedCode] = useState("");

  async function load(){
    setLoading(true); setError("");
    try{
      const rows = await PT.fetchAccessKeys();
      setKeys(rows);
    }catch(e){
      setError(e.message||"Could not load access keys.");
    }
    setLoading(false);
  }
  useEffect(()=>{ load(); },[]);

  async function addKey(){
    setCreating(true); setError("");
    try{
      await PT.createAccessKey({label: label.trim()});
      setLabel("");
      await load();
    }catch(e){
      setError(e.message||"Could not create key.");
    }
    setCreating(false);
  }

  async function removeKey(code){
    setKeys(prev=>prev.filter(k=>k.code!==code)); // optimistic
    try{
      await PT.deleteAccessKey(code);
    }catch(e){
      setError(e.message||"Could not delete key.");
      load(); // resync on failure
    }
  }

  function copyCode(code){
    try{ navigator.clipboard.writeText(code); }catch{}
    setCopiedCode(code);
    setTimeout(()=>setCopiedCode(""),1500);
  }

  const unused = keys.filter(k=>k.status==="unused");
  const assigned = keys.filter(k=>k.status!=="unused");

  return(
    <Screen>
      {onBack && (
        <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
          <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,flex:1}}>Access Keys</div>
        </div>
      )}
      <div style={{padding:"20px 20px 0"}}>
        {!onBack && <SectionTitle>Client Key Management</SectionTitle>}
        <div style={{fontSize:10,color:N.parchD,marginBottom:16,lineHeight:1.7}}>Generate a key and send it to a new client — they'll enter it during signup to create their account. Keys are checked live against Firestore, so a generated key works immediately.</div>

        {error && <div style={{fontSize:10,color:"#e57373",marginBottom:12,padding:"8px 12px",background:"rgba(229,115,115,0.1)",borderRadius:8}}>{error}</div>}

        {/* Generate new key */}
        <div style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:12,padding:16,marginBottom:20}}>
          <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:12}}>Generate New Key</div>
          <div style={{marginBottom:10}}>
            <div style={{fontSize:8,color:N.parchD,letterSpacing:"0.1em",marginBottom:4}}>LABEL (OPTIONAL)</div>
            <input value={label} onChange={e=>setLabel(e.target.value)} placeholder="e.g. Marcus W. — referral"
              style={{width:"100%",background:N.navy,border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"9px 12px",color:N.parch,fontSize:12,outline:"none",fontFamily:"inherit",boxSizing:"border-box"}}/>
          </div>
          <button onClick={addKey} disabled={creating} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:12,color:N.navy,fontSize:10,fontWeight:700,cursor:creating?"not-allowed":"pointer",letterSpacing:"0.12em",marginTop:4,opacity:creating?0.7:1}}>
            {creating?"GENERATING...":"GENERATE KEY"}
          </button>
        </div>

        {loading ? (
          <div style={{fontSize:11,color:N.parchD,textAlign:"center",padding:20}}>Loading keys…</div>
        ) : (
          <>
            <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>{unused.length} Unused Key{unused.length===1?"":"s"}</div>
            {unused.length===0 && <div style={{fontSize:11,color:N.parchD,marginBottom:16}}>No unused keys — generate one above.</div>}
            {unused.map(k=>(
              <div key={k.code} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 14px",marginBottom:8,display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                <div style={{flex:1}}>
                  <div onClick={()=>copyCode(k.code)} style={{fontFamily:"monospace",fontSize:12,color:N.gold,letterSpacing:"0.05em",marginBottom:3,cursor:"pointer"}}>
                    {k.code} {copiedCode===k.code?"✓ Copied":""}
                  </div>
                  {k.label && <div style={{fontSize:10,color:N.parchD}}>{k.label}</div>}
                </div>
                <button onClick={()=>removeKey(k.code)} style={{background:"transparent",border:`1px solid rgba(229,115,115,0.3)`,borderRadius:6,padding:"4px 8px",cursor:"pointer",fontSize:9,color:"#e57373",flexShrink:0,marginLeft:8}}>Remove</button>
              </div>
            ))}

            {assigned.length>0 && (
              <>
                <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginTop:20,marginBottom:10}}>{assigned.length} Claimed</div>
                {assigned.map(k=>(
                  <div key={k.code} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 14px",marginBottom:8,opacity:0.6}}>
                    <div style={{fontFamily:"monospace",fontSize:11,color:N.parchD,letterSpacing:"0.05em",marginBottom:3}}>{k.code}</div>
                    {k.label && <div style={{fontSize:9,color:N.parchD}}>{k.label}</div>}
                  </div>
                ))}
              </>
            )}
          </>
        )}
      </div>
    </Screen>
  );
}

// ─── CONCIERGE: Client Intake Links ───
// New-lead links (no clientId yet) show up here after someone submits so
// Shay can review and convert them into a real client + access key with one
// click. Links created FOR an existing client (from ConciergeClientProfile's
// "Copy Intake Link" button) don't need review — the app-wide realtime
// listener in App auto-merges those onto the client's profile the moment
// they're submitted (see subscribeToSubmittedIntakes / applyIntakeToClient
// in pt-data.js), so they just show up here afterward as "Applied" history.
function ConciergeIntake({onBack}){
  const [links, setLinks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [creating, setCreating] = useState(false);
  const [copiedToken, setCopiedToken] = useState("");
  const [converting, setConverting] = useState("");

  async function load(){
    setLoading(true); setError("");
    try{
      const rows = await PT.fetchIntakeSubmissions();
      setLinks(rows);
    }catch(e){
      setError(e.message||"Could not load intake links.");
    }
    setLoading(false);
  }
  useEffect(()=>{ load(); },[]);

  async function newLeadLink(){
    setCreating(true); setError("");
    try{
      const token = await PT.createIntakeLink({});
      const url = `${window.location.origin}/client/?intake=${token}`;
      try{ await navigator.clipboard.writeText(url); }catch{}
      setCopiedToken(token);
      setTimeout(()=>setCopiedToken(""),2500);
      await load();
    }catch(e){
      setError(e.message||"Could not create intake link.");
    }
    setCreating(false);
  }

  async function convert(token){
    setConverting(token); setError("");
    try{
      await PT.convertIntakeToClient(token);
      await load();
    }catch(e){
      setError(e.message||"Could not convert this intake into a client.");
    }
    setConverting("");
  }

  const pendingLeads = links.filter(l=>l.status==="submitted" && !l.clientId);
  const history = links.filter(l=>!(l.status==="submitted" && !l.clientId));
  const statusColor = {pending:N.parchD, submitted:N.gold, applied:N.green};

  return(
    <Screen>
      {onBack && (
        <div style={{background:N.navyMid,padding:"14px 20px",borderBottom:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",gap:14}}>
          <button onClick={onBack} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:20,padding:"6px 12px",cursor:"pointer",fontSize:9,fontWeight:700,color:N.parchD,letterSpacing:"0.1em"}}>← Back</button>
          <div style={{fontFamily:"Georgia,serif",fontSize:18,color:N.parch,flex:1}}>Client Intake Links</div>
        </div>
      )}
      <div style={{padding:"20px 20px 0"}}>
        <div style={{fontSize:10,color:N.parchD,marginBottom:16,lineHeight:1.7}}>Send this link to someone who doesn't have an account yet. They fill out their travel preferences once; existing clients' links merge straight into their profile automatically, and new leads show up below for you to convert into a client with one click.</div>

        {error && <div style={{fontSize:10,color:"#e57373",marginBottom:12,padding:"8px 12px",background:"rgba(229,115,115,0.1)",borderRadius:8}}>{error}</div>}

        <button onClick={newLeadLink} disabled={creating} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:13,color:N.navy,fontSize:10,fontWeight:700,cursor:creating?"not-allowed":"pointer",letterSpacing:"0.12em",marginBottom:24,opacity:creating?0.7:1}}>
          {creating?"GENERATING…":copiedToken?"✓ LINK COPIED — SEND IT OVER":"NEW LEAD INTAKE LINK"}
        </button>

        {loading ? (
          <div style={{fontSize:11,color:N.parchD,textAlign:"center",padding:20}}>Loading…</div>
        ) : (
          <>
            <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginBottom:10}}>{pendingLeads.length} Awaiting Review</div>
            {pendingLeads.length===0 && <div style={{fontSize:11,color:N.parchD,marginBottom:20}}>No new lead submissions right now.</div>}
            {pendingLeads.map(l=>(
              <div key={l.token} style={{background:N.navyMid,border:`1px solid ${N.gold}`,borderRadius:10,padding:"14px 16px",marginBottom:10}}>
                <div style={{fontSize:13,fontWeight:600,color:N.parch,marginBottom:3}}>{(l.profile&&l.profile.name)||"Unnamed lead"}</div>
                <div style={{fontSize:10,color:N.parchD,marginBottom:10}}>{(l.profile&&l.profile.email)||"No email on file"}{l.profile&&l.profile.phone?` · ${l.profile.phone}`:""}</div>
                <button onClick={()=>convert(l.token)} disabled={converting===l.token} style={{width:"100%",background:N.gold,border:"none",borderRadius:8,padding:10,color:N.navy,fontSize:9,fontWeight:700,letterSpacing:"0.1em",cursor:converting===l.token?"not-allowed":"pointer"}}>
                  {converting===l.token?"CONVERTING…":"CONVERT TO CLIENT + GENERATE KEY"}
                </button>
              </div>
            ))}

            {history.length>0 && (
              <>
                <div style={{fontSize:9,fontWeight:700,letterSpacing:"0.18em",color:N.gold,textTransform:"uppercase",marginTop:20,marginBottom:10}}>History</div>
                {history.map(l=>(
                  <div key={l.token} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"12px 14px",marginBottom:8,opacity:0.7,display:"flex",justifyContent:"space-between",alignItems:"center",gap:10}}>
                    <div style={{flex:1}}>
                      <div style={{fontSize:11,color:N.parch,marginBottom:2}}>{l.clientName||(l.profile&&l.profile.name)||"—"}</div>
                      <div style={{fontFamily:"monospace",fontSize:9,color:N.parchD,letterSpacing:"0.05em"}}>{l.token}</div>
                    </div>
                    <Badge label={l.status} color={statusColor[l.status]||N.parchD}/>
                  </div>
                ))}
              </>
            )}
          </>
        )}
      </div>
    </Screen>
  );
}

// ─── CONCIERGE: Security Log ───
// The practical, right-sized equivalent of an "IDS" for a static-site +
// managed-backend (Firebase) architecture: every login, signup, agreement
// signature, and denied concierge attempt is written to the security_events
// collection by pt-data.js. This screen just makes that log visible.
const SECURITY_EVENT_LABELS = {
  login: "Sign-in",
  signup: "Client sign-up",
  agreement_signed: "Terms accepted",
  concierge_login: "Concierge sign-in",
  concierge_login_denied: "Concierge sign-in DENIED",
};
const SECURITY_EVENT_COLORS = {
  concierge_login_denied: "#e57373",
  agreement_signed: "#8fbf8f",
};

function ConciergeSecurity(){
  const [events, setEvents] = useState([]);
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState("");

  function load(){
    setLoading(true);
    setErr("");
    PT.fetchSecurityEvents(200)
      .then(rows=>setEvents(rows))
      .catch(e=>setErr(e.message||"Could not load the security log."))
      .finally(()=>setLoading(false));
  }
  useEffect(()=>{ load(); },[]);

  function fmtTime(ts){
    try{
      const d = ts && ts.toDate ? ts.toDate() : (ts ? new Date(ts) : null);
      if(!d) return "—";
      return d.toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});
    }catch{return "—";}
  }

  const deniedCount = events.filter(e=>e.type==="concierge_login_denied").length;

  return(
    <Screen>
      <div style={{padding:"20px 20px 0"}}>
        <SectionTitle>Security Log</SectionTitle>
        <div style={{fontSize:10,color:N.parchD,marginBottom:16,lineHeight:1.7}}>
          Every sign-in, sign-up, terms acceptance, and denied concierge access attempt across the app. Encryption in transit (HTTPS) and at rest is handled by Firebase and Vercel; this log is the audit trail on top of that.
        </div>

        {deniedCount>0 && (
          <div style={{background:"rgba(229,115,115,0.1)",border:"1px solid rgba(229,115,115,0.3)",borderRadius:10,padding:"10px 14px",marginBottom:16,fontSize:10,color:"#e57373"}}>
            ⚠ {deniedCount} denied concierge sign-in attempt{deniedCount===1?"":"s"} in this log.
          </div>
        )}

        <button onClick={load} style={{background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:8,padding:"8px 14px",color:N.gold,fontSize:9,fontWeight:700,cursor:"pointer",letterSpacing:"0.1em",marginBottom:16}}>
          {loading?"REFRESHING...":"↻ REFRESH"}
        </button>

        {err && <div style={{fontSize:10,color:"#e57373",marginBottom:12}}>{err}</div>}
        {!loading && !err && events.length===0 && (
          <div style={{fontSize:11,color:N.parchD,fontStyle:"italic"}}>No security events logged yet.</div>
        )}

        {events.map(ev=>(
          <div key={ev.id} style={{background:N.navyMid,border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"10px 14px",marginBottom:8}}>
            <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:3}}>
              <div style={{fontSize:11,fontWeight:700,color:SECURITY_EVENT_COLORS[ev.type]||N.gold}}>
                {SECURITY_EVENT_LABELS[ev.type]||ev.type}
              </div>
              <div style={{fontSize:9,color:N.parchD}}>{fmtTime(ev.createdAt)}</div>
            </div>
            {ev.details && (ev.details.uid || ev.details.clientId || ev.details.method) && (
              <div style={{fontSize:9,color:N.parchD}}>
                {ev.details.method?`method: ${ev.details.method}`:""}
                {ev.details.uid?` · uid: ${String(ev.details.uid).slice(0,10)}…`:""}
                {ev.details.clientId?` · client: ${String(ev.details.clientId).slice(0,10)}…`:""}
              </div>
            )}
          </div>
        ))}
      </div>
    </Screen>
  );
}

// ─── Tutorial Overlay ───
function TutorialOverlay({onDone}){
  const [step,setStep]=useState(0);
  const steps=[
    {icon:"home",title:"Welcome to Provisions Travel",body:"This is your home screen. You'll see your upcoming trips, countdown to departure, flight details, and quick access to everything you need."},
    {icon:"map",title:"Your Itinerary",body:"Tap 'View Itinerary' to see your full day-by-day plan — flights, hotels, transfers, dining, and every detail of your trip. Your concierge keeps it updated in real time."},
    {icon:"chat",title:"Message Your Concierge",body:"Tap the Messages tab to reach Shayla directly. They're active and ready to help with any requests, changes, or questions — any time."},
    {icon:"doc",title:"Your Documents",body:"All your travel documents — confirmations, bookings, and agreements — live in one secure place under the Documents tab. Access them anytime, anywhere."},
    {icon:"star",title:"StyleCast & Loyalty",body:"Link your StyleCast account for destination weather and outfit picks. Earn loyalty points on every trip — Earn points toward Silver, Gold & Platinum status. Refer friends to level up faster."},
    {icon:"person",title:"You're All Set",body:"Your concierge has everything they need to make every trip seamless. Sit back — Provisions Travel handles the details so you don't have to."},
  ];
  const s=steps[step];
  const isLast=step===steps.length-1;
  return(
    <div style={{position:"fixed",inset:0,background:`linear-gradient(160deg,${N.navyMid} 0%,${N.navy} 100%)`,zIndex:200,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:32,textAlign:"center",overflow:"hidden"}}>
      <div style={{position:"absolute",top:-60,right:-60,width:240,height:240,borderRadius:"50%",background:`radial-gradient(circle,${N.gold}08 0%,transparent 70%)`}}/>
      <div style={{position:"absolute",bottom:-40,left:-40,width:180,height:180,borderRadius:"50%",background:`radial-gradient(circle,${N.gold}06 0%,transparent 70%)`}}/>
      <div style={{fontFamily:"Georgia,serif",fontSize:13,color:N.gold,letterSpacing:"0.3em",marginBottom:40,opacity:0.7}}>PROVISIONS TRAVEL</div>
      <div style={{width:72,height:72,borderRadius:"50%",background:N.goldGlow,border:`1px solid ${N.goldLine}`,display:"flex",alignItems:"center",justifyContent:"center",marginBottom:28}}>
        <Icon name={s.icon} size={28} color={N.gold}/>
      </div>
      <div style={{fontFamily:"Georgia,serif",fontSize:24,color:N.parch,marginBottom:16,lineHeight:1.3,maxWidth:320}}>{s.title}</div>
      <div style={{fontSize:13,color:N.parchD,lineHeight:1.8,maxWidth:300,marginBottom:48}}>{s.body}</div>
      <div style={{display:"flex",gap:8,marginBottom:36}}>
        {steps.map((_,i)=>(<div key={i} style={{width:i===step?20:7,height:7,borderRadius:4,background:i===step?N.gold:`${N.gold}30`,transition:"all 0.3s"}}/>))}
      </div>
      <div style={{display:"flex",gap:12,width:"100%",maxWidth:300}}>
        {step>0&&<button onClick={()=>setStep(s=>s-1)} style={{flex:1,background:"transparent",border:`1px solid ${N.goldLine}`,borderRadius:10,padding:"13px",color:N.parchD,fontSize:11,fontWeight:700,cursor:"pointer",letterSpacing:"0.1em"}}>BACK</button>}
        <button onClick={()=>isLast?onDone():setStep(s=>s+1)} style={{flex:2,background:N.gold,border:"none",borderRadius:10,padding:"13px",color:N.navy,fontSize:11,fontWeight:700,cursor:"pointer",letterSpacing:"0.1em"}}>{isLast?"GET STARTED →":"NEXT →"}</button>
      </div>
      {!isLast&&<button onClick={onDone} style={{marginTop:16,background:"transparent",border:"none",color:N.parchD,fontSize:9,cursor:"pointer",letterSpacing:"0.1em",textDecoration:"underline"}}>Skip tutorial</button>}
    </div>
  );
}

// ─── ROOT APP ───
function App({forcedRole="Client"}={}){
  // role is locked by whichever entry point mounted this app (ClientApp vs
  // ConciergeApp) — there is no in-app switcher, by design.
  const role = forcedRole;
  const [clientTab,setClientTab]=useState("home");
  const [concTab,setConcTab]=useState("clients");
  const [showSettings,setShowSettings]=useState(false);

  // Referral detection on load — add Pending entry when link is opened
  useEffect(()=>{
    const params=new URLSearchParams(window.location.search);
    const ref=params.get("ref");
    if(!ref) return;
    if(localStorage.getItem("pt_ref_processed_"+ref)) return;
    // Add pending entry if not already there
    const date=new Date().toLocaleDateString("en-US",{month:"short",year:"numeric"});
    try{
      const refs=JSON.parse(localStorage.getItem("pt_referrals")||"[]");
      const already=refs.find(r=>r._ref===ref);
      if(!already){
        refs.push({name:"Pending Client",date,status:"Pending",pts:"+250",_ref:ref});
        localStorage.setItem("pt_referrals",JSON.stringify(refs));
      }
    }catch{}
  },[]);
  // Auto-merge intake submissions onto existing clients' profiles the moment
  // they come in — this is what makes "fill out the intake link once" also
  // mean "it's already in My Profile" without the concierge doing anything.
  // Leads (no clientId) are intentionally left alone here — those need a
  // human to convert them into a real client (see ConciergeIntake).
  useEffect(()=>{
    if(forcedRole!=="Concierge") return;
    const unsub = PT.subscribeToSubmittedIntakes(rows=>{
      rows.filter(r=>r.clientId).forEach(r=>{
        PT.applyIntakeToClient(r.token).catch(e=>console.warn("Could not auto-apply intake",r.token,e));
      });
    });
    return ()=>unsub&&unsub();
  },[forcedRole]);
  const [conciergeActive,setConciergeActive]=useState(()=>localStorage.getItem("pt_conc_active")!=="0");
  function toggleConciergeActive(){
    const next=!conciergeActive;
    setConciergeActive(next);
    localStorage.setItem("pt_conc_active",next?"1":"0");
  }
  // ---------- Real shared data (Supabase) — replaces hardcoded TRIPS/localStorage ----------
  const [trips,setTrips]=useState([]);
  const [currentClient,setCurrentClient]=useState(null);
  const [allMsgs,setAllMsgs]=useState({});
  const [clientProfile,setClientProfile]=useState({});

  useEffect(()=>{
    let cancelled=false;
    (async()=>{
      try{
        if(forcedRole==="Client"){
          const client = await PT.getCurrentClient();
          if(cancelled||!client) return;
          setCurrentClient(client);
          setClientProfile(client.profile||{});
          // Auto-detect the client's time zone from their own browser and
          // save it if it's new/changed — no form field, no manual entry,
          // and it self-corrects if they're traveling next time they log in.
          const detectedTz = myTimeZone();
          if(detectedTz && detectedTz!==client.timezone){
            PT.updateClientTimezone(client.id, detectedTz).catch(()=>{});
          }
          // Agreement lives on the client record in Firestore now — not
          // localStorage — so it's per-account (survives new devices) and
          // the concierge can audit that a signature is actually on file.
          setAgreed(!!client.agreedAt);
          const [tripRows,msgRows]=await Promise.all([
            PT.fetchTripsForClient(client.id),
            PT.fetchMessages(client.id),
          ]);
          if(cancelled) return;
          // fetchTripsForClient already returns fully-mapped trip objects
          // (it has to resolve day/entry sub-collections internally) — no
          // second mapping pass needed here.
          setTrips(tripRows);
          setAllMsgs({[client.id]:msgRows.map(m=>PT.mapMessageRow(m,client.full_name))});
        } else {
          const [tripRows,grouped]=await Promise.all([
            PT.fetchAllTrips(),
            PT.fetchAllMessagesGrouped(),
          ]);
          if(cancelled) return;
          setTrips(tripRows);
          setAllMsgs(grouped);
        }
      }catch(e){
        console.error("Provisions Travel: failed to load data from Firebase",e);
      }
    })();
    return ()=>{cancelled=true;};
  },[forcedRole]);

  // Proactive alerts (flight/weather/document-expiry) — realtime, live-updates
  // the bell badge as the daily /api/alerts-check cron writes new rows, or as
  // the concierge resolves one. Clients only ever see their own; concierge
  // sees every open alert across the whole roster.
  const [alerts,setAlerts]=useState([]);
  const [showAlerts,setShowAlerts]=useState(false);
  useEffect(()=>{
    if(forcedRole==="Client"){
      if(!currentClient) return;
      const unsub=PT.subscribeToClientAlerts(currentClient.id,setAlerts);
      return ()=>unsub&&unsub();
    } else {
      const unsub=PT.subscribeToOpenAlerts(setAlerts);
      return ()=>unsub&&unsub();
    }
  },[forcedRole,currentClient]);

  // setClientMsgs updates local state immediately (snappy UI) — actual
  // persistence to Supabase happens in ClientMessages/ConciergeMessages'
  // send() functions via PT.sendMessage, so a reload always shows the
  // real, shared conversation.
  function setClientMsgs(clientId,updater){
    setAllMsgs(prev=>{
      const cur=prev[clientId]||[];
      const next=typeof updater==="function"?updater(cur):updater;
      return {...prev,[clientId]:next};
    });
  }
  const sharedMsgs = currentClient ? (allMsgs[currentClient.id]||[]) : [];
  const setMsgsPersist = (u)=>currentClient && setClientMsgs(currentClient.id,u);
  // Real client roster for the Concierge Messages chip-selector, derived
  // from actual trips loaded from Supabase (replaces the hardcoded demo
  // CLIENTS list). Falls back to an empty list until trips have loaded.
  const conciergeClientRoster = React.useMemo(()=>{
    const seen=new Map();
    for(const t of trips){
      if(t.clientId && !seen.has(t.clientId)){
        seen.set(t.clientId,{id:t.clientId,name:t.client,initials:t.initials,unread:0});
      }
    }
    return Array.from(seen.values());
  },[trips]);
  const [editingProfile,setEditingProfile]=useState(false);
  const [selectedTrip,setSelectedTrip]=useState(null);
  // Concierge (you) never sees the client Terms/Privacy/signature screen —
  // that's a consumer-facing legal agreement, not something the business
  // owner signs into her own console. Clients start un-agreed until the
  // data-load effect above confirms (or doesn't) an agreedAt on their record.
  const [agreed,setAgreed]=useState(forcedRole==="Concierge");
  // Real authentication now happens before this component ever mounts —
  // see client/index.html and concierge/index.html, which gate access via
  // Firebase Auth (PT.signInClient / PT.signInWithGoogle / PT.signInWithApple /
  // PT.signInConcierge) and only render <PTClientApp/> / <PTConciergeApp/>
  // once there's a valid session. The old in-app LoginScreen (fake OAuth
  // simulation) has been removed.
  const [showTutorial,setShowTutorial]=useState(false);
  function handleAgree(sig){
    if(currentClient) PT.recordAgreement(currentClient.id,sig).catch(e=>console.error("Could not save agreement",e));
    setAgreed(true);
    setShowTutorial(true);
  }
  const [clientUnread,setClientUnreadRaw]=useState(()=>{try{const v=localStorage.getItem("pt_cu");return v!==null?parseInt(v):0;}catch{return 0;}});
  const setClientUnread=(v)=>{const n=typeof v==="function"?v(clientUnread):v;try{localStorage.setItem("pt_cu",n);}catch{}setClientUnreadRaw(n);};
  const [docsUnread,setDocsUnreadRaw]=useState(()=>{try{const v=localStorage.getItem("pt_du");return v!==null?parseInt(v):0;}catch{return 0;}});
  const [docsInitialFolder,setDocsInitialFolder]=useState(null);
  const setDocsUnread=(v)=>{const n=typeof v==="function"?v(docsUnread):v;try{localStorage.setItem("pt_du",n);}catch{}setDocsUnreadRaw(n);};
  const [concUnread,setConcUnreadRaw]=useState(()=>{try{const v=localStorage.getItem("pt_pu");return v!==null?parseInt(v):0;}catch{return 0;}});
  const setConcUnread=(v)=>{const n=typeof v==="function"?v(concUnread):v;try{localStorage.setItem("pt_pu",n);}catch{}setConcUnreadRaw(n);};

  const clientTabs=[
    {id:"home",       icon:"home",   label:"Home",       badge:0},
    {id:"trips",      icon:"plane",  label:"Trips",      badge:0},
    {id:"sage",       icon:"S",      label:"Sage",       badge:0},
    {id:"messages",   icon:"chat",   label:"Messages",   badge:clientUnread},
    {id:"membership", icon:"person",  label:"My Profile", badge:0},
  ];
  const concTabs=[
    {id:"clients",    icon:"users",  label:"Clients",    badge:0},
    {id:"itineraries",icon:"map",    label:"Trips",      badge:0},
    {id:"sage",       icon:"S",      label:"Sage",       badge:0},
    {id:"messages",   icon:"chat",   label:"Messages",   badge:concUnread},
    {id:"revenue",    icon:"dollar", label:"Revenue",    badge:0},
  ];

  if(!agreed) return <AgreementScreen onAccept={handleAgree}/>;

  if(showTutorial&&role==="Client") return <TutorialOverlay onDone={()=>setShowTutorial(false)}/>;

  return(
    <div style={{fontFamily:"'Montserrat','Helvetica Neue',sans-serif",maxWidth:"var(--pt-shell-width)",margin:"0 auto",minHeight:"100vh",background:N.navyDeep,WebkitFontSmoothing:"antialiased",position:"relative"}}>
      <NavBar role={role} fixedRole={forcedRole} onSettingsClick={()=>setShowSettings(true)} onAlertsClick={()=>setShowAlerts(true)} alertCount={alerts.length}/>

      {showSettings && (
        <SettingsScreen
          role={role}
          currentClient={currentClient}
          onClose={()=>setShowSettings(false)}
          onOpenProfile={()=>{setShowSettings(false);setClientTab("profile");}}
          onOpenKeys={()=>{setShowSettings(false);setConcTab("keys");}}
          onOpenIntake={role==="Concierge"?()=>{setShowSettings(false);setConcTab("intake");}:null}
          onCardSaved={(cardOnFile)=>setCurrentClient(c=>c?{...c,cardOnFile}:c)}
        />
      )}

      {showAlerts && (
        <AlertsScreen
          role={role}
          alerts={alerts}
          onClose={()=>setShowAlerts(false)}
          onDismiss={role==="Client"?(id)=>PT.dismissAlertForClient(id).catch(()=>{}):null}
          onResolve={role==="Concierge"?(id)=>PT.resolveAlert(id).catch(()=>{}):null}
        />
      )}

      {role==="Client"?(
        <>
          {clientTab==="home"       && !editingProfile && <ClientHome trips={trips} currentClient={currentClient} conciergeActive={conciergeActive} setTab={setClientTab} onEditProfile={()=>setEditingProfile(true)} docsUnread={docsUnread} onTripSelect={(t)=>{setSelectedTrip(t);setClientTab("trips");}} onDocsOpen={(folderId)=>{setDocsInitialFolder(folderId);setDocsUnread(0);setClientTab("docs");}}/>}
          {clientTab==="home"       && editingProfile && <ClientProfileEdit profile={clientProfile} onBack={()=>setEditingProfile(false)} onSave={(updated)=>{setClientProfile(updated);setEditingProfile(false);if(currentClient){PT.updateClientProfile(currentClient.id,updated).catch(()=>{});}setMsgsPersist(m=>[...m,{id:Date.now(),from:"System",time:"Just now",text:`📋 ${(currentClient&&currentClient.full_name)||"A client"} has updated their traveler profile. Please review the changes.`,mine:true,system:true}]);setConcUnread(n=>n+1);}}/>}
          {clientTab==="trips"      && <ClientTrips trips={trips} initialTrip={selectedTrip} onClearTrip={()=>setSelectedTrip(null)} onDocsOpen={(folder)=>{setDocsInitialFolder(folder);setClientTab("docs");}}/>}
          {clientTab==="messages"   && <ClientMessages msgs={sharedMsgs} setMsgs={setMsgsPersist} persistSend={(text)=>currentClient?PT.sendMessage(currentClient.id,"client",text):Promise.resolve()} onOpen={()=>setClientUnread(0)} onNewMsg={()=>setConcUnread(n=>n+1)}/>}
          {clientTab==="docs"       && <ClientDocs trips={trips} currentClient={currentClient} onOpen={()=>setDocsUnread(0)} initialFolder={docsInitialFolder} onBack={docsInitialFolder?()=>{setClientTab("trips");}:null}/>}
          {clientTab==="sage"       && <ClientAI currentClient={currentClient} profile={clientProfile} trips={trips}/>}
          {clientTab==="membership" && <ClientMembership profile={clientProfile} currentClient={currentClient} trips={trips}/>}
          {clientTab==="profile"    && <ClientProfile profile={clientProfile} onBack={()=>setClientTab("home")} onEdit={()=>{setEditingProfile(true);setClientTab("home");}}/>}
          <TabBar tabs={clientTabs} active={clientTab} setActive={(t)=>{if(t==="trips")setSelectedTrip(null);if(t!=="docs")setDocsInitialFolder(null);setClientTab(t);}}/>
        </>
      ):(
        <>
          {concTab==="clients"     && <ConciergeClients concUnread={concUnread} trips={trips}/>}
          {concTab==="itineraries" && <ConciergeItineraries trips={trips} setTrips={setTrips} onDocUploaded={()=>setDocsUnread(n=>n+1)}/>}
          {concTab==="messages"    && <ConciergeMessages allMsgs={allMsgs} setClientMsgs={setClientMsgs} clients={conciergeClientRoster} persistSend={(clientId,text)=>PT.sendMessage(clientId,"concierge",text)} conciergeActive={conciergeActive} toggleConciergeActive={toggleConciergeActive} onOpen={()=>setConcUnread(0)} onNewMsg={()=>setClientUnread(n=>n+1)}/>}
          {concTab==="sage"        && <ClientAI concierge={true}/>}
          {concTab==="revenue"     && <ConciergeRevenue/>}
          {concTab==="keys"        && <ConciergeKeys onBack={()=>setConcTab("clients")}/>}
          {concTab==="intake"      && <ConciergeIntake onBack={()=>setConcTab("clients")}/>}
          <TabBar tabs={concTabs} active={concTab} setActive={setConcTab}/>
        </>
      )}
    </div>
  );
}

// Two locked entry points — no in-app role switcher.
// client/index.html mounts window.PTClientApp; concierge/index.html mounts window.PTConciergeApp.
window.PTClientApp = function PTClientApp(props){ return <App forcedRole="Client" {...props}/>; };
window.PTConciergeApp = function PTConciergeApp(props){ return <App forcedRole="Concierge" {...props}/>; };