// MaxAMove — Step Form Components
// Exports: StepCustomer, StepMove, StepInventory, StepPricing

const { useState } = React;

function FieldGroup({ label, children }) {
  return (
    <div style={{ marginBottom: 20 }}>
      <label style={{ display: 'block', fontSize: 12, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--text-muted)', marginBottom: 6 }}>{label}</label>
      {children}
    </div>
  );
}

function Input({ value, onChange, placeholder, type = 'text', style = {} }) {
  return (
    <input
      type={type}
      value={value}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder}
      style={{
        width: '100%', boxSizing: 'border-box',
        padding: '11px 14px', borderRadius: 10,
        border: '1.5px solid var(--border)',
        background: 'var(--input-bg)',
        color: 'var(--text)',
        fontSize: 15, fontFamily: 'inherit',
        outline: 'none', transition: 'border-color 0.15s',
        ...style
      }}
      onFocus={e => e.target.style.borderColor = 'var(--accent)'}
      onBlur={e => e.target.style.borderColor = 'var(--border)'}
    />
  );
}

function Select({ value, onChange, children, style = {} }) {
  return (
    <select
      value={value}
      onChange={e => onChange(e.target.value)}
      style={{
        width: '100%', boxSizing: 'border-box',
        padding: '11px 14px', borderRadius: 10,
        border: '1.5px solid var(--border)',
        background: 'var(--input-bg)',
        color: 'var(--text)',
        fontSize: 15, fontFamily: 'inherit',
        outline: 'none', 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='%23999' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")`,
        backgroundRepeat: 'no-repeat',
        backgroundPosition: 'right 14px center',
        cursor: 'pointer',
        ...style
      }}
    >{children}</select>
  );
}

function Row({ children, gap = 16 }) {
  return <div style={{ display: 'grid', gridTemplateColumns: `repeat(${children.length}, 1fr)`, gap }}>{children}</div>;
}

// ─── STEP 1: Customer Info ───
function StepCustomer({ data, onChange }) {
  const u = (field, val) => onChange({ ...data, [field]: val });
  return (
    <div>
      <SectionTitle icon="user" title="Customer Information" />
      <Row>
        <FieldGroup label="First Name">
          <Input value={data.firstName} onChange={v => u('firstName', v)} placeholder="Jane" />
        </FieldGroup>
        <FieldGroup label="Last Name">
          <Input value={data.lastName} onChange={v => u('lastName', v)} placeholder="Smith" />
        </FieldGroup>
      </Row>
      <Row>
        <FieldGroup label="Email Address">
          <Input value={data.email} onChange={v => u('email', v)} type="email" placeholder="jane@email.com" />
        </FieldGroup>
        <FieldGroup label="Phone Number">
          <Input value={data.phone} onChange={v => u('phone', v)} type="tel" placeholder="(555) 000-0000" />
        </FieldGroup>
      </Row>
      <FieldGroup label="Current Address">
        <Input value={data.currentAddress} onChange={v => u('currentAddress', v)} placeholder="123 Main St, City, State 00000" />
      </FieldGroup>
      <Row>
        <FieldGroup label="Preferred Contact">
          <Select value={data.contactPref} onChange={v => u('contactPref', v)}>
            <option value="email">Email</option>
            <option value="phone">Phone</option>
            <option value="text">Text</option>
          </Select>
        </FieldGroup>
        <FieldGroup label="How did you hear about us?">
          <Select value={data.source} onChange={v => u('source', v)}>
            <option value="">Select...</option>
            <option value="google">Google Search</option>
            <option value="referral">Referral</option>
            <option value="yelp">Yelp</option>
            <option value="facebook">Facebook</option>
            <option value="nextdoor">Nextdoor</option>
            <option value="other">Other</option>
          </Select>
        </FieldGroup>
      </Row>
      <FieldGroup label="Notes">
        <textarea
          value={data.notes}
          onChange={e => u('notes', e.target.value)}
          placeholder="Any additional info about the customer..."
          rows={3}
          style={{
            width: '100%', boxSizing: 'border-box',
            padding: '11px 14px', borderRadius: 10,
            border: '1.5px solid var(--border)',
            background: 'var(--input-bg)',
            color: 'var(--text)',
            fontSize: 15, fontFamily: 'inherit',
            outline: 'none', resize: 'vertical'
          }}
        />
      </FieldGroup>
    </div>
  );
}

// ─── STEP 2: Move Details ───
function StepMove({ data, onChange, pricing, onPricingChange }) {
  const u = (field, val) => onChange({ ...data, [field]: val });
  const serviceType = (pricing && pricing.serviceType) || 'full_service';
  const setServiceType = (t) => {
    if (!onPricingChange || !pricing) return;
    // Switching to labor-only also nudges the hourly rate to the labor-only baseline for
    // the current crew size so the wizard reflects the new pricing immediately.
    onPricingChange({ ...pricing, serviceType: t });
  };
  return (
    <div>
      <SectionTitle icon="truck" title="Move Details" />

      {/* Service Type — drives which hourly-rate tier table the pricing wizard reads from */}
      {onPricingChange && (
        <div style={{ marginBottom: 18, padding: 14, background: 'var(--bg)', borderRadius: 12, border: '1.5px solid var(--border)' }}>
          <div style={{ fontSize: 11, fontWeight: 800, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.08em', marginBottom: 10 }}>Service Type</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            {[
              { id: 'full_service', label: 'Full Service Local Move', sub: 'Crew + truck + full handling' },
              { id: 'labor_only', label: 'Labor Only', sub: 'Hands only — customer provides truck' },
            ].map(opt => {
              const on = serviceType === opt.id;
              return (
                <button key={opt.id} type="button" onClick={() => setServiceType(opt.id)}
                  style={{ padding: '14px', borderRadius: 12, border: `2px solid ${on ? 'var(--accent)' : 'var(--border)'}`, background: on ? 'var(--accent-light)' : '#fff', color: 'var(--text)', cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit' }}>
                  <div style={{ fontWeight: 800, fontSize: 14, color: on ? 'var(--accent-dark)' : 'var(--text)', marginBottom: 3, display: 'flex', alignItems: 'center', gap: 6 }}>
                    {on && <Icon name="check" size={14}/>}<span>{opt.label}</span>
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', lineHeight: 1.4 }}>{opt.sub}</div>
                </button>
              );
            })}
          </div>
        </div>
      )}

      <Row>
        <FieldGroup label="Move Date">
          <Input value={data.moveDate} onChange={v => u('moveDate', v)} type="date" />
        </FieldGroup>
        <FieldGroup label="Move Size">
          <Select value={data.moveSize} onChange={v => u('moveSize', v)}>
            <option value="">Select size...</option>
            <option value="studio">Studio / 1 Room</option>
            <option value="1br">1 Bedroom</option>
            <option value="2br">2 Bedrooms</option>
            <option value="3br">3 Bedrooms</option>
            <option value="4br">4+ Bedrooms</option>
            <option value="office">Office / Commercial</option>
          </Select>
        </FieldGroup>
      </Row>

      <FieldGroup label="Arrival Time (optional)">
        <div style={{ display: 'flex', gap: 6, marginBottom: 8 }}>
          {[
            { id: 'none', label: 'Not set' },
            { id: 'exact', label: 'Exact time' },
            { id: 'window', label: 'Arrival window' },
          ].map(opt => {
            const current = data.arrivalType || 'none';
            const active = current === opt.id;
            return (
              <button key={opt.id} type="button" onClick={() => {
                // Single onChange — chained u() calls would clobber each other because
                // u captures `data` from the closure, so each call merges into the same
                // stale snapshot. Picking "Exact time" previously lost arrivalType when
                // the follow-up u('arrivalWindowEnd','') call overwrote the first merge.
                const next = { ...data, arrivalType: opt.id === 'none' ? '' : opt.id };
                if (opt.id === 'none') { next.arrivalTime = ''; next.arrivalWindowEnd = ''; }
                if (opt.id === 'exact') { next.arrivalWindowEnd = ''; }
                onChange(next);
              }} style={{ flex: 1, padding: '8px 6px', borderRadius: 8, border: active ? '2px solid var(--accent)' : '1.5px solid var(--border)', background: active ? 'var(--accent-light)' : '#fff', fontWeight: active ? 800 : 600, fontSize: 12, color: 'var(--text)', cursor: 'pointer', fontFamily: 'inherit' }}>
                {opt.label}
              </button>
            );
          })}
        </div>
        {data.arrivalType === 'exact' && (
          <Input value={data.arrivalTime || ''} onChange={v => u('arrivalTime', v)} type="time" />
        )}
        {data.arrivalType === 'window' && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr auto 1fr', gap: 8, alignItems: 'center' }}>
            <Input value={data.arrivalTime || ''} onChange={v => u('arrivalTime', v)} type="time" />
            <span style={{ color: 'var(--text-muted)', fontWeight: 700 }}>–</span>
            <Input value={data.arrivalWindowEnd || ''} onChange={v => u('arrivalWindowEnd', v)} type="time" />
          </div>
        )}
      </FieldGroup>
      <FieldGroup label="Origin Address (Pick-up)">
        <Input value={data.fromAddress} onChange={v => u('fromAddress', v)} placeholder="123 Old St, City, State 00000" />
      </FieldGroup>
      <Row>
        <FieldGroup label="Origin Floor">
          <Select value={data.fromFloor} onChange={v => u('fromFloor', v)}>
            <option value="ground">Ground floor</option>
            <option value="2">2nd floor</option>
            <option value="3">3rd floor</option>
            <option value="4+">4th floor+</option>
          </Select>
        </FieldGroup>
        <FieldGroup label="Elevator Available?">
          <Select value={data.fromElevator} onChange={v => u('fromElevator', v)}>
            <option value="yes">Yes</option>
            <option value="no">No</option>
            <option value="na">N/A</option>
          </Select>
        </FieldGroup>
      </Row>
      <FieldGroup label="Destination Address (Drop-off)">
        <Input value={data.toAddress} onChange={v => u('toAddress', v)} placeholder="456 New Ave, City, State 00000" />
      </FieldGroup>
      <Row>
        <FieldGroup label="Destination Floor">
          <Select value={data.toFloor} onChange={v => u('toFloor', v)}>
            <option value="ground">Ground floor</option>
            <option value="2">2nd floor</option>
            <option value="3">3rd floor</option>
            <option value="4+">4th floor+</option>
          </Select>
        </FieldGroup>
        <FieldGroup label="Elevator Available?">
          <Select value={data.toElevator} onChange={v => u('toElevator', v)}>
            <option value="yes">Yes</option>
            <option value="no">No</option>
            <option value="na">N/A</option>
          </Select>
        </FieldGroup>
      </Row>
      <Row>
        <FieldGroup label="Estimated Distance (miles)">
          <Input value={data.distance} onChange={v => u('distance', v)} type="number" placeholder="0" />
        </FieldGroup>
        <FieldGroup label="Packing Service Needed?">
          <Select value={data.packing} onChange={v => u('packing', v)}>
            <option value="none">No packing needed</option>
            <option value="partial">Partial packing</option>
            <option value="full">Full packing service</option>
          </Select>
        </FieldGroup>
      </Row>
      <FieldGroup label="Special Instructions">
        <textarea
          value={data.specialInstructions}
          onChange={e => u('specialInstructions', e.target.value)}
          placeholder="Piano, fragile items, long carry distance, parking notes, etc."
          rows={3}
          style={{
            width: '100%', boxSizing: 'border-box',
            padding: '11px 14px', borderRadius: 10,
            border: '1.5px solid var(--border)',
            background: 'var(--input-bg)',
            color: 'var(--text)',
            fontSize: 15, fontFamily: 'inherit',
            outline: 'none', resize: 'vertical'
          }}
        />
      </FieldGroup>
    </div>
  );
}

// ─── STEP 3: Inventory (room-first, catalog-driven) ───
// Data shape per entry: { id, room, categoryId, name, size: 's'|'m'|'l'|'xl', qty, notes }

// Core rooms present in (almost) every home — always available, not driven by bedroom count
const CORE_ROOMS = [
  { id: 'living',  label: 'Living Room',  icon: 'sofa' },
  { id: 'kitchen', label: 'Kitchen',      icon: 'chef-hat' },
  { id: 'dining',  label: 'Dining Room',  icon: 'utensils' },
];

// Extra rooms the user can add on-demand (not bathrooms — tracked inventory usually lives elsewhere)
const OPTIONAL_ROOMS = [
  { id: 'garage',    label: 'Garage',         icon: 'car' },
  { id: 'patio',     label: 'Patio / Deck',   icon: 'tree' },
  { id: 'shed',      label: 'Shed',           icon: 'home' },
  { id: 'basement',  label: 'Basement',       icon: 'arrow-down' },
  { id: 'attic',     label: 'Attic',          icon: 'arrow-up' },
  { id: 'office',    label: 'Office',         icon: 'briefcase' },
  { id: 'laundry',   label: 'Laundry Room',   icon: 'box' },
  { id: 'storage',   label: 'Storage Unit',   icon: 'box' },
  { id: 'other',     label: 'Other / Misc',   icon: 'sparkles' },
];

// Figure out how many bedrooms from the move-size string
function bedroomCountFromMoveSize(ms) {
  if (!ms) return 0;
  if (ms === 'studio') return 0;
  if (ms === 'office') return 0;
  const m = String(ms).match(/^(\d+)br$/);
  return m ? parseInt(m[1]) : 0;
}

// Build the default room list for a move — bedrooms (numbered) + core rooms
function defaultRoomsForMove(moveData) {
  const n = bedroomCountFromMoveSize(moveData?.moveSize);
  const bedrooms = [];
  for (let i = 1; i <= n; i++) {
    bedrooms.push({ id: `bedroom${i}`, label: `Bedroom ${i}`, icon: 'bed' });
  }
  if (moveData?.moveSize === 'studio') {
    bedrooms.push({ id: 'bedroom1', label: 'Main Living Area', icon: 'sofa' });
    return bedrooms; // studios have it all in one space
  }
  if (moveData?.moveSize === 'office') {
    return [{ id: 'office_main', label: 'Main Office', icon: 'briefcase' }];
  }
  return [...bedrooms, ...CORE_ROOMS];
}

function StepInventory({ items, onChange, moveData }) {
  // rooms stored alongside items — seeded from move size
  const [rooms, setRooms] = useState(() => {
    try {
      const saved = localStorage.getItem('inv_rooms_' + (moveData?.moveSize || 'default'));
      if (saved) return JSON.parse(saved);
    } catch {}
    return defaultRoomsForMove(moveData);
  });

  const [activeRoom, setActiveRoom] = useState(() => (defaultRoomsForMove(moveData)[0]?.id) || null);
  const [activeCat, setActiveCat] = useState(null);
  const [search, setSearch] = useState('');
  const [renamingRoom, setRenamingRoom] = useState(null);
  const [addMenuOpen, setAddMenuOpen] = useState(false);
  const [swapTargetId, setSwapTargetId] = useState(null);  // entry.id of the inventory line being swapped, or null

  // If move size changes → refresh default rooms but keep any custom user rooms (ids not in CORE/OPTIONAL and not starting with bedroom)
  React.useEffect(() => {
    const defaults = defaultRoomsForMove(moveData);
    setRooms(prev => {
      // Preserve any user-added rooms (optional or custom) that already have items
      const customKept = prev.filter(r => {
        if (CORE_ROOMS.find(c => c.id === r.id)) return false;
        if (/^bedroom\d+$/.test(r.id)) return false;
        return true;
      });
      const merged = [...defaults, ...customKept];
      // Dedupe by id
      const seen = {};
      return merged.filter(r => seen[r.id] ? false : (seen[r.id] = true));
    });
  }, [moveData?.moveSize]);

  React.useEffect(() => {
    try { localStorage.setItem('inv_rooms_' + (moveData?.moveSize || 'default'), JSON.stringify(rooms)); } catch {}
  }, [rooms, moveData?.moveSize]);

  // Make sure activeRoom is always a valid one
  React.useEffect(() => {
    if (rooms.length && !rooms.find(r => r.id === activeRoom)) {
      setActiveRoom(rooms[0].id);
    }
  }, [rooms]);

  const cats = window.INVENTORY_CATEGORIES || [];
  const allItems = window.ALL_INVENTORY_ITEMS || [];

  const getItemWeight = (entry) => {
    const item = allItems.find(i => i.name === entry.name && i.categoryId === entry.categoryId);
    if (!item) return 0;
    return item[entry.size || 'm'] || item.m || 0;
  };

  const totalWeight = items.reduce((s, e) => s + getItemWeight(e) * (e.qty || 1), 0);
  const totalQty = items.reduce((s, e) => s + (parseInt(e.qty) || 0), 0);

  const roomItems = (roomId) => items.filter(e => (e.room || rooms[0]?.id) === roomId);

  const addItem = (catId, itemDef) => {
    const defaultSize = itemDef.m ? 'm' : (itemDef.s ? 's' : 'l');
    // same item+size+room exists → +1
    const existing = items.find(e => e.categoryId === catId && e.name === itemDef.name && e.size === defaultSize && (e.room || rooms[0]?.id) === activeRoom);
    if (existing) {
      onChange(items.map(e => e.id === existing.id ? { ...e, qty: (e.qty || 1) + 1 } : e));
    } else {
      onChange([...items, { id: Date.now() + Math.random(), room: activeRoom, categoryId: catId, name: itemDef.name, size: defaultSize, qty: 1, notes: '' }]);
    }
  };
  const removeItem = (id) => onChange(items.filter(e => e.id !== id));
  const updateItem = (id, field, val) => onChange(items.map(e => e.id === id ? { ...e, [field]: val } : e));
  // Swap one inventory line for a different item — keeps qty/notes/room.
  // Tries to keep the same size; falls back to 'm' (then 's') if the new item doesn't have it.
  const swapEntry = (entryId, newItemDef) => {
    if (!entryId || !newItemDef) return;
    onChange(items.map(e => {
      if (e.id !== entryId) return e;
      const oldSize = e.size || 'm';
      const newSize = newItemDef[oldSize] != null ? oldSize
        : newItemDef.m != null ? 'm'
        : newItemDef.s != null ? 's'
        : newItemDef.l != null ? 'l' : 'xl';
      return { ...e, name: newItemDef.name, categoryId: newItemDef.categoryId, size: newSize };
    }));
    setSwapTargetId(null);
  };
  const swapTargetEntry = swapTargetId ? items.find(e => e.id === swapTargetId) : null;

  // Search (across all items in all categories) — adds to active room
  const searchResults = search.trim() ? allItems.filter(i => i.name.toLowerCase().includes(search.toLowerCase())).slice(0, 10) : [];

  const activeCategory = cats.find(c => c.id === activeCat);
  const activeRoomObj = rooms.find(r => r.id === activeRoom);

  // Room helpers
  const addRoom = (tpl) => {
    // If already present, just switch to it
    if (rooms.find(r => r.id === tpl.id)) { setActiveRoom(tpl.id); setAddMenuOpen(false); return; }
    setRooms([...rooms, tpl]);
    setActiveRoom(tpl.id);
    setAddMenuOpen(false);
  };
  const duplicateRoom = (r) => {
    const base = r.label.replace(/\s+\d+$/, '');
    let i = 2;
    while (rooms.find(x => x.label === `${base} ${i}`)) i++;
    const newId = r.id + '_copy' + Date.now();
    setRooms([...rooms, { id: newId, label: `${base} ${i}`, icon: r.icon }]);
    setActiveRoom(newId);
  };
  const removeRoom = (id) => {
    const itemsInRoom = items.filter(e => (e.room || rooms[0]?.id) === id).length;
    if (itemsInRoom > 0 && !confirm(`This room has ${itemsInRoom} item(s). Remove the room and its items?`)) return;
    const newRooms = rooms.filter(r => r.id !== id);
    setRooms(newRooms);
    onChange(items.filter(e => (e.room || rooms[0]?.id) !== id));
    if (activeRoom === id) setActiveRoom(newRooms[0]?.id || null);
  };
  const renameRoom = (id, label) => setRooms(rooms.map(r => r.id === id ? { ...r, label } : r));

  // Rooms not yet added — for the "+ Add room" menu
  const availableToAdd = OPTIONAL_ROOMS.filter(o => !rooms.find(r => r.id === o.id));

  return (
    <div>
      <SectionTitle icon="box" title="Inventory / Item List" />

      {/* Running totals */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 14, marginBottom: 18, alignItems: 'center' }}>
        <div style={{ position: 'relative' }}>
          <span style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', display: 'inline-flex', zIndex: 1 }}><Icon name="search" size={15} color="var(--muted)"/></span>
          <input
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder={`Search items → adds to ${activeRoomObj?.label || 'active room'}`}
            style={{ width: '100%', padding: '11px 14px 11px 36px', borderRadius: 10, border: '1.5px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text)', fontSize: 14, fontFamily: 'inherit', outline: 'none', boxSizing: 'border-box' }}
          />
          {searchResults.length > 0 && (
            <div style={{ position: 'absolute', top: '100%', left: 0, right: 0, marginTop: 4, background: 'var(--card-bg, #fff)', border: '1.5px solid var(--border)', borderRadius: 10, boxShadow: '0 10px 30px rgba(0,0,0,0.1)', zIndex: 10, maxHeight: 320, overflowY: 'auto' }}>
              {searchResults.map((r, i) => (
                <div key={i} onClick={() => { addItem(r.categoryId, r); setSearch(''); }}
                  style={{ padding: '10px 14px', cursor: 'pointer', fontSize: 13, display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: i < searchResults.length - 1 ? '1px solid var(--border)' : 'none' }}
                  onMouseOver={e => e.currentTarget.style.background = 'var(--accent-light)'}
                  onMouseOut={e => e.currentTarget.style.background = 'transparent'}>
                  <span><span style={{ marginRight: 8 }}>{r.categoryIcon}</span><b>{r.name}</b></span>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>→ {activeRoomObj?.label} · {r.m} lbs</span>
                </div>
              ))}
            </div>
          )}
        </div>
        <div style={{ padding: '10px 14px', background: 'var(--accent-light)', borderRadius: 10, minWidth: 110, textAlign: 'center' }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--accent-dark)', textTransform: 'uppercase', letterSpacing: '.08em' }}>Items</div>
          <div style={{ fontSize: 18, fontWeight: 900, color: 'var(--accent-dark)', fontFamily: 'Poppins,sans-serif' }}>{totalQty}</div>
        </div>
        <div style={{ padding: '10px 14px', background: 'var(--accent-light)', borderRadius: 10, minWidth: 120, textAlign: 'center' }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--accent-dark)', textTransform: 'uppercase', letterSpacing: '.08em' }}>Weight</div>
          <div style={{ fontSize: 18, fontWeight: 900, color: 'var(--accent-dark)', fontFamily: 'Poppins,sans-serif' }}>{totalWeight.toLocaleString()}<span style={{ fontSize: 10, fontWeight: 600, marginLeft: 3 }}>lbs</span></div>
        </div>
      </div>

      {/* ───── Room chooser ───── */}
      <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--text-muted)', marginBottom: 10, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span>Rooms {moveData?.moveSize && <span style={{ color: 'var(--text-muted)', opacity: .7, fontWeight: 500, textTransform: 'none', letterSpacing: 0 }}>· auto-built from your {moveData.moveSize} move</span>}</span>
        <div style={{ position: 'relative' }}>
          <button onClick={() => setAddMenuOpen(v => !v)}
            style={{ padding: '5px 11px', borderRadius: 7, border: '1.5px dashed var(--accent)', background: 'transparent', color: 'var(--accent-dark)', fontFamily: 'inherit', fontSize: 11, fontWeight: 700, cursor: 'pointer', textTransform: 'none', letterSpacing: 0 }}>
            + Add room
          </button>
          {addMenuOpen && (
            <div style={{ position: 'absolute', top: '100%', right: 0, marginTop: 6, background: 'var(--card-bg, #fff)', border: '1.5px solid var(--border)', borderRadius: 10, boxShadow: '0 10px 30px rgba(0,0,0,0.12)', zIndex: 20, minWidth: 220, padding: 6 }}>
              {availableToAdd.length === 0 && <div style={{ padding: 10, fontSize: 12, color: 'var(--text-muted)', textTransform: 'none', letterSpacing: 0, fontWeight: 400 }}>All optional rooms are added.</div>}
              {availableToAdd.map(o => (
                <button key={o.id} onClick={() => addRoom(o)}
                  style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '8px 10px', border: 'none', background: 'transparent', cursor: 'pointer', borderRadius: 6, fontSize: 13, fontFamily: 'inherit', textAlign: 'left', textTransform: 'none', letterSpacing: 0, fontWeight: 500, color: 'var(--text)' }}
                  onMouseOver={e => e.currentTarget.style.background = 'var(--accent-light)'}
                  onMouseOut={e => e.currentTarget.style.background = 'transparent'}>
                  <span style={{ fontSize: 18 }}>{o.icon}</span>{o.label}
                </button>
              ))}
              <div style={{ borderTop: '1px solid var(--border)', margin: '4px 0' }}/>
              <button onClick={() => {
                const label = prompt('Name this extra bedroom / room:', `Bedroom ${rooms.filter(r => /^bedroom/i.test(r.label)).length + 1}`);
                if (label) addRoom({ id: 'custom_' + Date.now(), label, icon: 'bed' });
              }}
                style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '8px 10px', border: 'none', background: 'transparent', cursor: 'pointer', borderRadius: 6, fontSize: 13, fontFamily: 'inherit', textAlign: 'left', textTransform: 'none', letterSpacing: 0, fontWeight: 500, color: 'var(--accent-dark)' }}
                onMouseOver={e => e.currentTarget.style.background = 'var(--accent-light)'}
                onMouseOut={e => e.currentTarget.style.background = 'transparent'}>
                <Icon name="plus" size={16} color="var(--accent)"/>Custom room name…
              </button>
            </div>
          )}
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(160px,1fr))', gap: 10, marginBottom: 20 }}>
        {rooms.map(r => {
          const rItems = roomItems(r.id);
          const rQty = rItems.reduce((s, e) => s + (parseInt(e.qty) || 0), 0);
          const rWeight = rItems.reduce((s, e) => s + getItemWeight(e) * (e.qty || 1), 0);
          const isActive = activeRoom === r.id;
          return (
            <button key={r.id} onClick={() => { setActiveRoom(r.id); setActiveCat(null); }}
              style={{ position: 'relative', padding: '14px 12px 12px', borderRadius: 12, border: `2px solid ${isActive ? 'var(--accent)' : 'var(--border)'}`, background: isActive ? 'var(--accent-light)' : 'var(--card-bg, #fff)', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 4, transition: 'all .15s', fontFamily: 'inherit', textAlign: 'left' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%' }}>
                <Icon name={r.icon} size={22} color={isActive ? 'var(--accent)' : 'var(--muted)'}/>
                {renamingRoom === r.id ? (
                  <input autoFocus value={r.label} onChange={e => renameRoom(r.id, e.target.value)} onBlur={() => setRenamingRoom(null)}
                    onKeyDown={e => { if (e.key === 'Enter') setRenamingRoom(null); }}
                    onClick={e => e.stopPropagation()}
                    style={{ flex: 1, padding: '2px 4px', border: '1px solid var(--accent)', borderRadius: 4, fontSize: 13, fontWeight: 700, fontFamily: 'inherit' }}/>
                ) : (
                  <span style={{ fontSize: 13, fontWeight: 800, color: isActive ? 'var(--accent-dark)' : 'var(--text)', flex: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.label}</span>
                )}
              </div>
              {rQty > 0 ? (
                <div style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500 }}>{rQty} item{rQty !== 1 ? 's' : ''} · {rWeight.toLocaleString()} lbs</div>
              ) : (
                <div style={{ fontSize: 11, color: 'var(--text-muted)', fontStyle: 'italic', opacity: .7 }}>empty</div>
              )}
              {isActive && (
                <div style={{ position: 'absolute', top: 6, right: 6, display: 'flex', gap: 2 }}>
                  <span title="Rename" onClick={e => { e.stopPropagation(); setRenamingRoom(r.id); }} style={{ padding: '2px 5px', borderRadius: 4, background: 'rgba(255,255,255,.7)', cursor: 'pointer', display: 'inline-flex' }}><Icon name="pencil" size={11}/></span>
                  <span title="Duplicate" onClick={e => { e.stopPropagation(); duplicateRoom(r); }} style={{ padding: '2px 5px', borderRadius: 4, background: 'rgba(255,255,255,.7)', cursor: 'pointer', display: 'inline-flex' }}><Icon name="plus" size={11}/></span>
                  {rooms.length > 1 && <span title="Remove" onClick={e => { e.stopPropagation(); removeRoom(r.id); }} style={{ padding: '2px 5px', borderRadius: 4, background: 'rgba(255,255,255,.7)', cursor: 'pointer', display: 'inline-flex' }}><Icon name="trash" size={11}/></span>}
                </div>
              )}
            </button>
          );
        })}
      </div>

      {/* ───── Categories (scoped to active room) ───── */}
      {activeRoomObj && (
        <div style={{ padding: 18, borderRadius: 14, background: 'var(--card-bg, #fff)', border: '1.5px solid var(--border)', marginBottom: 18 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
            <span style={{ fontSize: 24 }}>{activeRoomObj.icon}</span>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 16, fontWeight: 800, color: 'var(--accent-dark)', fontFamily: 'Poppins,sans-serif' }}>{activeRoomObj.label}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Pick a category to add furniture, or use search above</div>
            </div>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(110px,1fr))', gap: 8 }}>
            {cats.map(cat => {
              const catItemCount = items.filter(e => (e.room || rooms[0]?.id) === activeRoom && e.categoryId === cat.id).reduce((s, e) => s + (e.qty || 0), 0);
              const isActive = activeCat === cat.id;
              return (
                <button key={cat.id} onClick={() => setActiveCat(isActive ? null : cat.id)}
                  style={{ position: 'relative', padding: '12px 8px', borderRadius: 10, border: `2px solid ${isActive ? cat.color : 'var(--border)'}`, background: isActive ? cat.color + '15' : 'var(--input-bg)', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, transition: 'all .15s', fontFamily: 'inherit' }}>
                  <div style={{ fontSize: 22, lineHeight: 1 }}>{cat.icon}</div>
                  <div style={{ fontSize: 11, fontWeight: 700, color: isActive ? cat.color : 'var(--text)', textAlign: 'center', lineHeight: 1.2 }}>{cat.label}</div>
                  {catItemCount > 0 && (
                    <div style={{ position: 'absolute', top: 5, right: 5, background: cat.color, color: '#fff', borderRadius: 20, padding: '1px 6px', fontSize: 9, fontWeight: 800, minWidth: 16, textAlign: 'center' }}>{catItemCount}</div>
                  )}
                </button>
              );
            })}
          </div>

          {/* Expanded category → items */}
          {activeCategory && (
            <div style={{ marginTop: 14, padding: 14, background: activeCategory.color + '08', borderRadius: 10, border: `1.5px solid ${activeCategory.color}35` }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontSize: 18 }}>{activeCategory.icon}</span>
                  <h3 style={{ margin: 0, fontSize: 14, fontWeight: 800, color: activeCategory.color, fontFamily: 'Poppins,sans-serif' }}>{activeCategory.label}</h3>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>· tap to add to <b>{activeRoomObj.label}</b></span>
                </div>
                <button onClick={() => setActiveCat(null)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted)', fontSize: 18, padding: 0, width: 24, height: 24 }}>×</button>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(200px,1fr))', gap: 6 }}>
                {activeCategory.items.map(item => (
                  <div key={item.name} onClick={() => addItem(activeCategory.id, item)}
                    style={{ padding: '8px 11px', background: 'var(--card-bg, #fff)', borderRadius: 7, cursor: 'pointer', display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12, border: '1px solid transparent', transition: 'all .1s' }}
                    onMouseOver={e => { e.currentTarget.style.borderColor = activeCategory.color; e.currentTarget.style.background = activeCategory.color + '10'; }}
                    onMouseOut={e => { e.currentTarget.style.borderColor = 'transparent'; e.currentTarget.style.background = 'var(--card-bg, #fff)'; }}>
                    <span style={{ fontWeight: 600 }}>{item.name}</span>
                    <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>~{item.m} lbs</span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* ───── Items grouped by room ───── */}
      {items.length === 0 ? (
        <div style={{ textAlign: 'center', padding: '40px 20px', color: 'var(--text-muted)', fontSize: 14, background: 'var(--input-bg)', borderRadius: 12, border: '2px dashed var(--border)' }}>
          <div style={{ marginBottom: 6, opacity: .5, display: 'flex', justifyContent: 'center' }}><Icon name="box" size={32}/></div>
          No items yet. Select a room above, then pick a category or search.
        </div>
      ) : (
        <div>
          <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--text-muted)', marginBottom: 10 }}>Inventory by room</div>
          {rooms.map(r => {
            const rItems = roomItems(r.id);
            if (rItems.length === 0) return null;
            const rWeight = rItems.reduce((s, e) => s + getItemWeight(e) * (e.qty || 1), 0);
            const rQty = rItems.reduce((s, e) => s + (parseInt(e.qty) || 0), 0);
            return (
              <div key={r.id} style={{ marginBottom: 14, background: 'var(--card-bg, #fff)', border: '1px solid var(--border)', borderRadius: 12, overflow: 'hidden' }}>
                <div style={{ padding: '10px 14px', background: 'var(--accent-light)', display: 'flex', alignItems: 'center', gap: 10, borderBottom: '1px solid var(--border)' }}>
                  <span style={{ fontSize: 18 }}>{r.icon}</span>
                  <span style={{ fontSize: 13, fontWeight: 800, color: 'var(--accent-dark)', fontFamily: 'Poppins,sans-serif', flex: 1 }}>{r.label}</span>
                  <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--accent-dark)' }}>{rQty} item{rQty !== 1 ? 's' : ''} · {rWeight.toLocaleString()} lbs</span>
                </div>
                <div style={{ padding: '8px 10px' }}>
                  {rItems.map(entry => {
                    const itemDef = allItems.find(i => i.name === entry.name && i.categoryId === entry.categoryId);
                    const cat = cats.find(c => c.id === entry.categoryId);
                    const availableSizes = itemDef ? ['s', 'm', 'l', 'xl'].filter(k => itemDef[k] != null) : ['s', 'm', 'l'];
                    const lbs = getItemWeight(entry) * (entry.qty || 1);
                    return (
                      <div key={entry.id} style={{ display: 'grid', gridTemplateColumns: '28px 1fr 130px 56px 1fr 100px 28px 28px', gap: 6, marginBottom: 4, alignItems: 'center', padding: '6px 4px' }}>
                        <div style={{ display: 'flex', justifyContent: 'center' }}><Icon name={cat?.icon || 'box'} size={16} color={cat?.color || 'var(--muted)'}/></div>
                        <div>
                          <div style={{ fontSize: 13, fontWeight: 700 }}>{entry.name}</div>
                          <div style={{ fontSize: 10, color: 'var(--text-muted)' }}>{cat?.label} · {getItemWeight(entry)} lbs → {lbs.toLocaleString()}</div>
                        </div>
                        <div style={{ display: 'flex', gap: 3, background: 'var(--input-bg)', borderRadius: 6, padding: 2 }}>
                          {availableSizes.map(sz => (
                            <button key={sz} onClick={() => updateItem(entry.id, 'size', sz)}
                              style={{ flex: 1, padding: '4px 2px', border: 'none', borderRadius: 4, background: entry.size === sz ? (cat?.color || 'var(--accent)') : 'transparent', color: entry.size === sz ? '#fff' : 'var(--text-muted)', fontWeight: 700, fontSize: 9, cursor: 'pointer', fontFamily: 'inherit', textTransform: 'uppercase' }}>
                              {sz}
                            </button>
                          ))}
                        </div>
                        <Input value={entry.qty} onChange={v => updateItem(entry.id, 'qty', parseInt(v) || 1)} type="number" placeholder="1" />
                        <Input value={entry.notes} onChange={v => updateItem(entry.id, 'notes', v)} placeholder="Fragile..." />
                        <select
                          value={entry.room || rooms[0]?.id || ''}
                          onChange={e => updateItem(entry.id, 'room', e.target.value)}
                          title="Move to a different room"
                          style={{ width: '100%', padding: '6px 4px', borderRadius: 6, border: '1px solid var(--border)', background: 'var(--input-bg)', fontSize: 11, color: 'var(--text)', fontFamily: 'inherit', cursor: 'pointer' }}>
                          {rooms.map(r => (
                            <option key={r.id} value={r.id}>{r.label}</option>
                          ))}
                        </select>
                        <button
                          onClick={() => setSwapTargetId(entry.id)}
                          title="Change this item"
                          style={{ width: 28, height: 32, borderRadius: 6, border: 'none', background: '#e0f2fe', color: '#0284c7', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                          <Icon name="pencil" size={13} color="#0284c7"/>
                        </button>
                        <button onClick={() => removeItem(entry.id)} title="Remove this item" style={{ width: 28, height: 32, borderRadius: 6, border: 'none', background: '#fee2e2', color: '#ef4444', cursor: 'pointer', fontSize: 14 }}>×</button>
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })}

          {/* Crew / hours auto-estimate */}
          {window.estimateLaborHours && totalWeight > 0 && (
            <div style={{ marginTop: 18, padding: 16, background: 'var(--accent-light)', borderRadius: 12, border: '1.5px solid var(--accent)' }}>
              <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--accent-dark)', marginBottom: 10, display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="bolt" size={12}/> Auto-estimate (industry avg, from weight)</div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 10 }}>
                {[2, 3, 4].map(crew => {
                  const hrs = window.estimateLaborHours(totalWeight, crew);
                  return (
                    <div key={crew} style={{ padding: 12, background: 'var(--card-bg, #fff)', borderRadius: 10, textAlign: 'center', border: '1px solid var(--border)' }}>
                      <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.08em', marginBottom: 4 }}>{crew}-man crew</div>
                      <div style={{ fontSize: 22, fontWeight: 900, color: 'var(--accent-dark)', fontFamily: 'Poppins,sans-serif' }}>~{hrs}<span style={{ fontSize: 12, fontWeight: 600, marginLeft: 3 }}>hrs</span></div>
                      <div style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 2 }}>{(window.CREW_PRODUCTIVITY[crew] * crew).toLocaleString()} lbs/hr</div>
                    </div>
                  );
                })}
              </div>
              <div style={{ marginTop: 10, fontSize: 11, color: 'var(--text-muted)', textAlign: 'center', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5 }}><Icon name="info" size={11}/> <span>These roll forward to <b>Step 4: Pricing</b> automatically when you pick a crew size.</span></div>
            </div>
          )}
        </div>
      )}

      {swapTargetEntry && (
        <SwapItemModal
          entry={swapTargetEntry}
          allItems={allItems}
          cats={cats}
          onSwap={(newItemDef) => swapEntry(swapTargetEntry.id, newItemDef)}
          onClose={() => setSwapTargetId(null)}
        />
      )}
    </div>
  );
}

// ─── SWAP ITEM MODAL — change an inventory line for a different item ───
function SwapItemModal({ entry, allItems, cats, onSwap, onClose }) {
  const [search, setSearch] = useState('');
  const [activeCat, setActiveCat] = useState(entry.categoryId);

  const trimmed = search.trim().toLowerCase();
  const filtered = trimmed
    ? allItems.filter(i => i.name.toLowerCase().includes(trimmed)).slice(0, 80)
    : allItems.filter(i => i.categoryId === activeCat);

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.55)', zIndex: 9999, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }}>
      <div onClick={e => e.stopPropagation()} style={{ background: '#fff', borderRadius: 16, width: '100%', maxWidth: 640, maxHeight: '85vh', display: 'flex', flexDirection: 'column', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'hidden' }}>

        {/* Header */}
        <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <div style={{ fontSize: 11, color: 'var(--accent)', fontWeight: 800, textTransform: 'uppercase', letterSpacing: '.08em' }}>Change item</div>
            <div style={{ fontSize: 18, fontWeight: 900, fontFamily: 'Poppins', marginTop: 2 }}>
              Swap <span style={{ color: 'var(--accent-dark)' }}>{entry.name}</span> for…
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 3 }}>Quantity, notes, and room will be preserved.</div>
          </div>
          <button onClick={onClose} style={{ width: 32, height: 32, border: 'none', borderRadius: 8, background: '#f1f5f9', color: '#64748b', cursor: 'pointer', fontSize: 16 }}>×</button>
        </div>

        {/* Search */}
        <div style={{ padding: '12px 22px', borderBottom: '1px solid var(--border)' }}>
          <input
            type="text"
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder="Search the whole catalog…"
            autoFocus
            style={{ width: '100%', boxSizing: 'border-box', padding: '10px 14px', borderRadius: 10, border: '1.5px solid var(--border)', background: 'var(--input-bg)', fontSize: 14, fontFamily: 'inherit', outline: 'none' }}
          />
        </div>

        {/* Category tabs (hidden during search) */}
        {!trimmed && (
          <div style={{ padding: '10px 22px', borderBottom: '1px solid var(--border)', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {cats.map(c => (
              <button key={c.id} onClick={() => setActiveCat(c.id)}
                style={{ padding: '6px 11px', borderRadius: 8, border: 'none', background: activeCat === c.id ? (c.color || 'var(--accent)') : '#f1f5f9', color: activeCat === c.id ? '#fff' : 'var(--text)', fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit', display: 'flex', alignItems: 'center', gap: 5 }}>
                <Icon name={c.icon} size={12} color={activeCat === c.id ? '#fff' : (c.color || 'var(--muted)')}/><span>{c.label}</span>
              </button>
            ))}
          </div>
        )}

        {/* Item grid */}
        <div style={{ padding: 16, overflowY: 'auto', flex: 1 }}>
          {filtered.length === 0 ? (
            <div style={{ textAlign: 'center', padding: 30, color: 'var(--text-muted)', fontSize: 13 }}>
              No items match. Try another search or category.
            </div>
          ) : (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))', gap: 8 }}>
              {filtered.map(item => {
                const cat = cats.find(c => c.id === item.categoryId);
                const isSame = item.name === entry.name && item.categoryId === entry.categoryId;
                return (
                  <button key={item.categoryId + ':' + item.name}
                    disabled={isSame}
                    onClick={() => onSwap(item)}
                    style={{ padding: '10px 12px', borderRadius: 10, border: `1.5px solid ${isSame ? 'var(--accent)' : 'var(--border)'}`, background: isSame ? 'var(--accent-light)' : '#fff', cursor: isSame ? 'default' : 'pointer', textAlign: 'left', fontFamily: 'inherit', display: 'flex', alignItems: 'center', gap: 8, opacity: isSame ? 0.7 : 1 }}>
                    <Icon name={cat?.icon || 'box'} size={18} color={cat?.color || 'var(--muted)'}/>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.name}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-muted)' }}>
                        {isSame ? '(current item)' : `${item.m || item.s || item.l || 0} lbs avg`}
                      </div>
                    </div>
                  </button>
                );
              })}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ─── STEP 4: Pricing ───
function StepPricing({ data, onChange, moveData, inventory }) {
  const u = (field, val) => onChange({ ...data, [field]: val });
  const distance = parseFloat(moveData.distance) || 0;

  // Load company pricing tiers + surcharges + crew roster from Supabase Settings.
  const [pricingTiers, setPricingTiers] = React.useState(window.DEFAULT_PRICING_TIERS || []);
  const [laborOnlyTiers, setLaborOnlyTiers] = React.useState([]);
  const [settingsSurcharges, setSettingsSurcharges] = React.useState(window.DEFAULT_SURCHARGES || []);
  const [crewRoster, setCrewRoster] = React.useState([]);
  const [settingsLoaded, setSettingsLoaded] = React.useState(false);
  React.useEffect(() => {
    if (typeof window.loadSettings !== 'function') return;
    Promise.all([
      window.loadSettings().catch(() => null),
      typeof window.listCrew === 'function' ? window.listCrew({ includeInactive: false }).catch(() => []) : Promise.resolve([]),
    ]).then(([s, crew]) => {
      if (s) {
        setPricingTiers(s.pricingTiers || []);
        setLaborOnlyTiers(s.laborOnlyTiers || []);
        setSettingsSurcharges(s.surcharges || []);
      }
      setCrewRoster(crew || []);
      setSettingsLoaded(true);
    });
  }, []);

  // Service type drives WHICH tier table the wizard reads from for hourly-rate defaults.
  // 'full_service' → pricingTiers, 'labor_only' → laborOnlyTiers.
  const serviceType = data.serviceType || 'full_service';
  const activeTiers = serviceType === 'labor_only' ? laborOnlyTiers : pricingTiers;

  // Specific crew members assigned to this estimate (each: crew_member.id).
  const assignedCrewIds = Array.isArray(data.crewIds) ? data.crewIds : [];
  const assignedCrew = assignedCrewIds.map(id => crewRoster.find(c => c.id === id)).filter(Boolean);
  const toggleCrew = (id) => {
    const next = assignedCrewIds.includes(id)
      ? assignedCrewIds.filter(x => x !== id)
      : [...assignedCrewIds, id];
    // Auto-update mover count to match assigned crew (if any selected)
    const patch = { crewIds: next };
    if (next.length > 0) patch.movers = next.length;
    onChange({ ...data, ...patch });
  };
  // Combined throughput (lbs/hr) from the assigned crew, if any.
  const crewThroughput = assignedCrew.length > 0 && typeof window.calcCrewThroughput === 'function'
    ? window.calcCrewThroughput(assignedCrew, assignedCrew.length)
    : null;

  // Currently-selected surcharges for THIS estimate (from data.surcharges)
  const selectedSurcharges = Array.isArray(data.surcharges) ? data.surcharges : [];
  const isSurchargeOn = (id) => selectedSurcharges.some(s => s.id === id);
  const getSurcharge = (id) => selectedSurcharges.find(s => s.id === id);
  const toggleSurcharge = (settingsItem) => {
    if (isSurchargeOn(settingsItem.id)) {
      u('surcharges', selectedSurcharges.filter(s => s.id !== settingsItem.id));
    } else {
      u('surcharges', [...selectedSurcharges, {
        id: settingsItem.id,
        name: settingsItem.name,
        type: settingsItem.type,
        unit: settingsItem.unit,
        qty: 1,
        price: settingsItem.defaultAmount,
      }]);
    }
  };
  const updateSurcharge = (id, field, val) => {
    u('surcharges', selectedSurcharges.map(s => s.id === id ? { ...s, [field]: val } : s));
  };

  // Auto-update hourly rate to match crew size whenever movers OR serviceType changes
  // (or when settings finish loading). User can still type to override.
  React.useEffect(() => {
    if (!settingsLoaded || !activeTiers.length) return;
    const tier = activeTiers.find(t => t.crewSize === data.movers);
    if (tier && Number(tier.hourlyRate) !== Number(data.hourlyRate)) {
      // Only auto-update if the current rate matches a tier in EITHER table
      // (i.e., the user hasn't manually overridden it for this job).
      const matchesAnyTier = pricingTiers.find(t => Number(t.hourlyRate) === Number(data.hourlyRate))
        || laborOnlyTiers.find(t => Number(t.hourlyRate) === Number(data.hourlyRate));
      if (matchesAnyTier || data.hourlyRate === 125 /* legacy default */) {
        u('hourlyRate', Number(tier.hourlyRate));
      }
    }
  }, [data.movers, serviceType, settingsLoaded, pricingTiers, laborOnlyTiers]);

  const matchedTier = activeTiers.find(t => t.crewSize === data.movers);
  const isCustomRate = matchedTier && Number(matchedTier.hourlyRate) !== Number(data.hourlyRate);
  function resetCrewRate() {
    if (matchedTier) u('hourlyRate', Number(matchedTier.hourlyRate));
  }

  // Use the shared calcTotals (from preview.jsx) so Price Summary, the live deposit
  // calculation, and the final estimate all match exactly. Includes surcharges.
  const _t = (window.calcTotals
    ? window.calcTotals(data, moveData)
    : { laborTotal: 0, truckTotal: 0, fuelTotal: 0, insuranceTotal: 0, packingTotal: 0, surchargeLines: [], surchargesTotal: 0, subtotal: 0, discountAmt: 0, total: 0 });
  const laborTotal = _t.laborTotal;
  const truckTotal = _t.truckTotal;
  const fuelTotal = _t.fuelTotal;
  const insuranceTotal = _t.insuranceTotal;
  const packingTotal = _t.packingTotal;
  const surchargeLines = _t.surchargeLines || [];
  const surchargesTotal = _t.surchargesTotal || 0;
  const subtotal = _t.subtotal;
  const discountAmt = _t.discountAmt;
  const total = _t.total;

  // Auto-suggest hours from inventory weight, crew-aware when specific crew assigned.
  const invWeight = (window.calcInventoryWeight && inventory) ? window.calcInventoryWeight(inventory) : 0;
  const suggestedHours = (invWeight > 0 && window.estimateLaborHours)
    ? window.estimateLaborHours(invWeight, data.movers, {
        stairs: moveData.fromFloor !== 'ground' || moveData.toFloor !== 'ground',
        packing: moveData.packing,
        crewThroughput: crewThroughput,  // sum of assigned members' lbs/hr — overrides generic when set
      })
    : null;

  // Snapshot the SYSTEM estimate the first time auto-calc has a number.
  // Frozen field — stays locked so we can compare your manual quote vs the system later.
  React.useEffect(() => {
    if (suggestedHours == null) return;
    if (data.systemEstimateHours != null) return;
    onChange({ ...data, systemEstimateHours: suggestedHours });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [suggestedHours]);

  // When inventory or crew changes, if you have a saved manual offset,
  // auto-update displayed hours to (newSuggested + your offset).
  React.useEffect(() => {
    if (suggestedHours == null) return;
    if (data.hoursOffset == null) return;
    const newHours = Math.max(0, +(suggestedHours + data.hoursOffset).toFixed(2));
    if (Math.abs(newHours - (parseFloat(data.hours) || 0)) > 0.01) {
      onChange({ ...data, hours: newHours });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [suggestedHours, data.hoursOffset]);

  const PriceRow = ({ label, value, bold }) => (
    <div style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0', borderBottom: '1px solid var(--border)', fontSize: bold ? 16 : 14, fontWeight: bold ? 700 : 400, color: bold ? 'var(--accent-dark)' : 'var(--text)' }}>
      <span>{label}</span><span>${value.toFixed(2)}</span>
    </div>
  );

  return (
    <div>
      <SectionTitle icon="dollar-bill" title="Pricing & Fees" />

      {/* Auto-suggest banner */}
      {suggestedHours !== null && Math.abs(suggestedHours - data.hours) > 0.25 && (
        <div style={{ marginBottom: 18, padding: 14, background: 'linear-gradient(135deg, var(--accent-light), #f0fdf4)', borderRadius: 12, border: '1.5px solid var(--accent)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
          <div style={{ flex: 1, minWidth: 240 }}>
            <div style={{ fontSize: 12, fontWeight: 800, color: 'var(--accent-dark)', textTransform: 'uppercase', letterSpacing: '.08em', marginBottom: 3, display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="bolt" size={12}/> Auto-estimate from inventory</div>
            <div style={{ fontSize: 13, color: 'var(--text)' }}>
              Based on <b>{invWeight.toLocaleString()} lbs</b> of inventory with a <b>{data.movers}-man crew</b>,
              we estimate <b style={{ color: 'var(--accent-dark)' }}>~{suggestedHours} hours</b> of labor (industry avg).
            </div>
          </div>
          <button onClick={() => onChange({ ...data, hours: suggestedHours, hoursOffset: null })}
            style={{ padding: '10px 18px', borderRadius: 10, border: 'none', background: 'var(--accent)', color: '#fff', fontFamily: 'inherit', fontWeight: 800, fontSize: 14, cursor: 'pointer', whiteSpace: 'nowrap' }}>
            Use {suggestedHours} hrs →
          </button>
        </div>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
        <div>
          <div style={{ fontWeight: 700, marginBottom: 12, color: 'var(--text-muted)', fontSize: 12, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Labor</div>

          {/* ── Specific crew assignment (optional, learning-system aware) ── */}
          {crewRoster.length > 0 && (
            <div style={{ marginBottom: 14, padding: 12, background: assignedCrew.length > 0 ? 'var(--accent-light)' : 'var(--bg)', borderRadius: 10, border: `1.5px solid ${assignedCrew.length > 0 ? 'var(--accent)' : 'var(--border)'}` }}>
              <div style={{ fontSize: 11, fontWeight: 800, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.05em', marginBottom: 6 }}>
                Assigned crew (optional — improves estimate accuracy)
              </div>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: assignedCrew.length > 0 ? 8 : 0 }}>
                {crewRoster.map(c => {
                  const on = assignedCrewIds.includes(c.id);
                  const rate = c.lbsPerHourLearned != null ? c.lbsPerHourLearned : c.lbsPerHourBaseline;
                  return (
                    <button key={c.id} type="button" onClick={() => toggleCrew(c.id)}
                      style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '6px 10px', borderRadius: 8, border: 'none', background: on ? 'var(--accent)' : 'var(--card-bg, #fff)', color: on ? '#fff' : 'var(--text)', fontWeight: 700, fontSize: 12, cursor: 'pointer', fontFamily: 'inherit', boxShadow: on ? 'none' : '0 0 0 1px var(--border)' }}>
                      <Icon name={on ? 'check' : 'plus'} size={11} color={on ? '#fff' : 'var(--muted)'}/>
                      <span>{c.name}</span>
                      <span style={{ opacity: 0.75, fontSize: 10, fontWeight: 500 }}>· {rate} lbs/hr</span>
                    </button>
                  );
                })}
              </div>
              {assignedCrew.length > 0 && crewThroughput != null && (
                <div style={{ fontSize: 11, color: 'var(--accent-dark)', fontWeight: 700, paddingTop: 6, borderTop: '1px dashed var(--border)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                  <Icon name="bolt" size={11}/> Combined throughput: <b>{crewThroughput.toLocaleString()} lbs/hr</b> ({assignedCrew.map(c => (c.lbsPerHourLearned != null ? c.lbsPerHourLearned : c.lbsPerHourBaseline)).join(' + ')})
                </div>
              )}
              {assignedCrew.length === 0 && (
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                  Pick specific crew to use their personal lbs/hr rates instead of the generic average.
                </div>
              )}
            </div>
          )}

          <Row>
            <FieldGroup label="Crew size (movers)">
              <Input value={data.movers} onChange={v => u('movers', parseInt(v) || 1)} type="number" placeholder="2" />
            </FieldGroup>
            <FieldGroup label="Hours">
              <Input
                value={data.hours}
                onChange={v => {
                  const n = parseFloat(v) || 0;
                  // If you typed something different from the auto-suggest, lock that as your offset.
                  // Future inventory changes will preserve this offset (e.g., "always 1 hr less than system").
                  const offset = (suggestedHours != null && Math.abs(n - suggestedHours) > 0.01)
                    ? +(n - suggestedHours).toFixed(2)
                    : null;
                  onChange({ ...data, hours: n, hoursOffset: offset });
                }}
                type="number" placeholder="4" />
              {data.hoursOffset != null && data.hoursOffset !== 0 && suggestedHours != null && (
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.5, display: 'flex', alignItems: 'flex-start', gap: 4 }}>
                  <Icon name="pin" size={11} style={{flexShrink:0,marginTop:2}}/>
                  <span>Locked at <b>{data.hoursOffset > 0 ? '+' : ''}{data.hoursOffset} hr</b> from system estimate. New inventory items will preserve this offset.
                  &nbsp;<a href="#" onClick={e => { e.preventDefault(); onChange({ ...data, hours: suggestedHours, hoursOffset: null }); }} style={{ color: 'var(--accent)', fontWeight: 600 }}>Reset to auto</a></span>
                </div>
              )}
            </FieldGroup>
          </Row>

          {/* Not-to-Exceed (NTE) — defaults ON with hours+1; toggle off to hide the guarantee.
              Customer sees this as a price-cap promise alongside the estimated total. */}
          <div style={{ marginBottom: 14, padding: 12, background: data.nteEnabled !== false ? '#f0fdfb' : 'var(--bg)', borderRadius: 10, border: `1.5px solid ${data.nteEnabled !== false ? 'var(--accent)' : 'var(--border)'}` }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, marginBottom: data.nteEnabled !== false ? 8 : 0 }}>
              <label style={{ display: 'flex', alignItems: 'center', gap: 9, cursor: 'pointer', flex: 1 }}>
                <input type="checkbox" checked={data.nteEnabled !== false}
                  onChange={e => u('nteEnabled', e.target.checked)}
                  style={{ width: 16, height: 16, accentColor: '#14C6BF', cursor: 'pointer' }}/>
                <div>
                  <div style={{ fontWeight: 800, fontSize: 13, color: 'var(--text)', display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="lock" size={13}/> Not-to-Exceed Price</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                    {data.nteEnabled !== false
                      ? 'Customer sees a guaranteed price ceiling — closes deals faster.'
                      : 'No price cap shown to customer.'}
                  </div>
                </div>
              </label>
            </div>
            {data.nteEnabled !== false && (() => {
              const autoNte = (parseFloat(data.hours) || 0) + 1;
              const isManual = data.nteHours != null && Number(data.nteHours) > 0;
              const displayValue = isManual ? data.nteHours : autoNte;
              return (
                <div>
                  <div style={{ display: 'grid', gridTemplateColumns: '110px 1fr', gap: 8, alignItems: 'center' }}>
                    <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.05em' }}>NTE hrs</div>
                    <Input value={displayValue}
                      onChange={v => {
                        const n = parseFloat(v) || 0;
                        // If they set it back to auto value, clear manual override
                        if (Math.abs(n - autoNte) < 0.01) u('nteHours', null);
                        else u('nteHours', n);
                      }} type="number" placeholder={String(autoNte)} />
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 6 }}>
                    {isManual
                      ? <span style={{display:'inline-flex',alignItems:'center',gap:4}}><Icon name="pin" size={11}/> Manually set. <a href="#" onClick={e => { e.preventDefault(); u('nteHours', null); }} style={{ color: 'var(--accent)', fontWeight: 600 }}>Reset to auto (hours + 1)</a></span>
                      : <>Auto-tracks estimated hours +1 ({(parseFloat(data.hours) || 0)} + 1 = {autoNte} hrs).</>}
                  </div>
                </div>
              );
            })()}
          </div>
          <FieldGroup label="Crew hourly rate ($ / hour, total for the whole crew)">
            <Input value={data.hourlyRate} onChange={v => u('hourlyRate', parseFloat(v) || 0)} type="number" placeholder="150" />
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.5 }}>
              {matchedTier
                ? <>Default for a {data.movers}-mover crew is <b>${Number(matchedTier.hourlyRate).toFixed(2)}/hr</b>{isCustomRate && <> — you've overridden it. <a href="#" onClick={e => { e.preventDefault(); resetCrewRate(); }} style={{ color: 'var(--accent)', fontWeight: 600 }}>Reset to default</a></>}.</>
                : <>No default rate set for a {data.movers}-mover crew. <a href="#settings" onClick={e => { e.preventDefault(); alert('Open Settings → Pricing to add a rate for this crew size.'); }} style={{ color: 'var(--accent)', fontWeight: 600 }}>Add one in Settings</a>.</>
              }
            </div>
          </FieldGroup>

          <FieldGroup label="Discount">
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 100px', gap: 8 }}>
              <Input value={data.discount} onChange={v => u('discount', v)} type="number" placeholder="0" />
              <Select value={data.discountType} onChange={v => u('discountType', v)}>
                <option value="flat">$ off</option>
                <option value="pct">% off</option>
              </Select>
            </div>
          </FieldGroup>

          {/* ── TRIP FEE (first-class line item, defaults to $50, waivable) ───────── */}
          <div style={{ marginTop: 22, padding: 14, background: data.tripFeeWaived ? 'var(--bg)' : 'var(--accent-light)', borderRadius: 12, border: `1.5px solid ${data.tripFeeWaived ? 'var(--border)' : 'var(--accent)'}` }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, marginBottom: 10 }}>
              <div>
                <div style={{ fontWeight: 800, fontSize: 14, color: 'var(--text)', display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="truck" size={14}/> Trip Fee</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                  {data.tripFeeWaived
                    ? 'Waived for this customer — not billed.'
                    : 'Standard charge. Adjust the price below or waive it if it’s a deal-breaker.'}
                </div>
              </div>
              <button type="button" onClick={() => u('tripFeeWaived', !data.tripFeeWaived)}
                style={{ padding: '7px 13px', borderRadius: 8, border: `1.5px solid ${data.tripFeeWaived ? 'var(--accent)' : '#ef4444'}`, background: '#fff', color: data.tripFeeWaived ? 'var(--accent-dark)' : '#ef4444', fontWeight: 800, fontSize: 12, cursor: 'pointer', fontFamily: 'inherit', whiteSpace: 'nowrap', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                {data.tripFeeWaived ? <><Icon name="arrow-left" size={12}/> Restore</> : <><Icon name="x" size={12}/> Waive</>}
              </button>
            </div>
            {!data.tripFeeWaived && (
              <div style={{ display: 'grid', gridTemplateColumns: '110px 1fr', gap: 8, alignItems: 'center' }}>
                <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.05em' }}>Price ($)</div>
                <Input value={data.tripFee ?? 50} onChange={v => u('tripFee', parseFloat(v) || 0)} type="number" placeholder="50" />
              </div>
            )}
          </div>

          {/* ── ADD-ON SERVICES / SURCHARGES (from Settings, Trip Fee filtered out) ───────────── */}
          <div style={{ fontWeight: 700, marginBottom: 12, marginTop: 22, color: 'var(--text-muted)', fontSize: 12, textTransform: 'uppercase', letterSpacing: '0.08em' }}>
            Add-on Services
          </div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 10, lineHeight: 1.5 }}>
            Toggle services from Settings → Pricing. Adjust price/quantity per estimate as needed.
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {settingsSurcharges.filter(sc => (sc.name || '').trim().toLowerCase() !== 'trip fee').length === 0 && (
              <div style={{ padding: 12, background: 'var(--bg)', borderRadius: 10, fontSize: 12, color: 'var(--text-muted)', textAlign: 'center' }}>
                No surcharges configured. Add them in <b>Settings → Pricing → Surcharges</b>.
              </div>
            )}
            {settingsSurcharges.filter(sc => (sc.name || '').trim().toLowerCase() !== 'trip fee').map(sc => {
              const on = isSurchargeOn(sc.id);
              const sel = getSurcharge(sc.id);
              return (
                <div key={sc.id} style={{ padding: '10px 12px', background: on ? 'var(--accent-light)' : 'var(--bg)', borderRadius: 10, border: `1.5px solid ${on ? 'var(--accent)' : 'var(--border)'}` }}>
                  <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
                    <input type="checkbox" checked={on} onChange={() => toggleSurcharge(sc)}
                      style={{ width: 16, height: 16, accentColor: '#14C6BF', cursor: 'pointer' }} />
                    <div style={{ flex: 1, fontWeight: 700, fontSize: 13, color: 'var(--text)' }}>
                      {sc.name}
                      <span style={{ marginLeft: 8, fontWeight: 500, fontSize: 11, color: 'var(--text-muted)' }}>
                        (default ${sc.defaultAmount}{sc.type === 'percent' ? '%' : ''}{sc.type === 'per_unit' ? ` / ${sc.unit}` : ''}{sc.type === 'per_hour' ? ' / hr' : ''})
                      </span>
                    </div>
                  </label>
                  {on && sel && (
                    <div style={{ marginTop: 8, display: 'grid', gridTemplateColumns: sc.type === 'percent' ? '1fr' : '90px 1fr', gap: 8 }}>
                      {sc.type !== 'percent' && (
                        <div>
                          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-muted)', marginBottom: 3, textTransform: 'uppercase', letterSpacing: '.05em' }}>Qty</div>
                          <Input value={sel.qty} onChange={v => updateSurcharge(sc.id, 'qty', parseFloat(v) || 0)} type="number" placeholder="1" />
                        </div>
                      )}
                      <div>
                        <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-muted)', marginBottom: 3, textTransform: 'uppercase', letterSpacing: '.05em' }}>
                          {sc.type === 'percent' ? '% Rate (override)' : `Price ${sc.type === 'per_unit' ? `/ ${sc.unit}` : sc.type === 'per_hour' ? '/ hr' : 'each'} (override)`}
                        </div>
                        <Input value={sel.price} onChange={v => updateSurcharge(sc.id, 'price', parseFloat(v) || 0)} type="number" placeholder={String(sc.defaultAmount)} />
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>

          {/* ── DEPOSIT SETTINGS (per-estimate override) ─────────────────── */}
          <div style={{ marginTop: 22, padding: 14, background: data.depositRequired ? 'var(--accent-light)' : 'var(--bg)', borderRadius: 12, border: `1.5px solid ${data.depositRequired ? 'var(--accent)' : 'var(--border)'}` }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', marginBottom: data.depositRequired ? 12 : 0 }}>
              <input type="checkbox"
                checked={data.depositRequired !== false}
                onChange={e => u('depositRequired', e.target.checked)}
                style={{ width: 18, height: 18, accentColor: '#14C6BF', cursor: 'pointer' }} />
              <div>
                <div style={{ fontWeight: 800, fontSize: 14, color: 'var(--text)' }}>Require deposit before move</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                  {data.depositRequired !== false
                    ? 'Customer must pay this deposit on the signing page to confirm the booking.'
                    : 'Customer just signs — no payment collected.'}
                </div>
              </div>
            </label>

            {data.depositRequired !== false && (() => {
              const total = (() => {
                try { return window.calcTotals ? window.calcTotals(data, moveData).total : 0; } catch { return 0; }
              })();
              const mode = data.depositMode || 'pct';
              const val = parseFloat(data.depositValue) || 0;
              const calcDollar = mode === 'pct' ? total * val / 100 : val;
              const calcPct = total > 0 ? (calcDollar / total * 100) : 0;
              return (
                <div>
                  <div style={{ display: 'grid', gridTemplateColumns: '110px 1fr', gap: 8, alignItems: 'center', marginBottom: 8 }}>
                    <Select value={mode} onChange={v => u('depositMode', v)} style={{ fontSize: 13 }}>
                      <option value="pct">% of total</option>
                      <option value="flat">$ fixed</option>
                    </Select>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      {mode === 'flat' && <span style={{ fontWeight: 700, fontSize: 16, color: 'var(--text-muted)' }}>$</span>}
                      <Input value={data.depositValue ?? ''} onChange={v => u('depositValue', parseFloat(v) || 0)} type="number" placeholder={mode === 'pct' ? '20' : '500'} />
                      {mode === 'pct' && <span style={{ fontWeight: 700, fontSize: 16, color: 'var(--text-muted)' }}>%</span>}
                    </div>
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--accent-dark)', fontWeight: 700, paddingTop: 6, borderTop: '1px dashed var(--border)' }}>
                    Customer will pay <span style={{ fontSize: 16, fontWeight: 900, fontFamily: 'Poppins' }}>${calcDollar.toFixed(2)}</span>
                    {mode === 'flat' && total > 0 && <span style={{ color: 'var(--text-muted)', fontWeight: 500, fontSize: 12 }}> ({calcPct.toFixed(1)}% of total)</span>}
                  </div>
                </div>
              );
            })()}
          </div>

          {/* ── TENTATIVE RESERVATION TOGGLE — collapsed when OFF (out of the way until needed). */}
          {data.allowTentative ? (
            <div style={{ marginTop: 14, padding: 14, background: '#faf5ff', borderRadius: 12, border: '1.5px solid #a855f7' }}>
              <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
                <input type="checkbox" checked onChange={e => u('allowTentative', e.target.checked)}
                  style={{ width: 18, height: 18, accentColor: '#a855f7', cursor: 'pointer' }} />
                <div>
                  <div style={{ fontWeight: 800, fontSize: 14, color: 'var(--text)', display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="clock" size={14} color="#a855f7"/> Tentative reservation enabled</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.45 }}>
                    Customer sees two buttons: "Save My Date" (soft hold, no deposit) and "Book My Move" (full booking).
                  </div>
                </div>
              </label>
            </div>
          ) : (
            <button type="button" onClick={() => u('allowTentative', true)}
              style={{ marginTop: 14, display: 'flex', alignItems: 'center', gap: 8, padding: '10px 14px', borderRadius: 10, background: 'var(--bg)', border: '1px dashed var(--border)', color: 'var(--text-muted)', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: 600, width: '100%', justifyContent: 'flex-start' }}>
              <Icon name="clock" size={13} color="#a855f7"/><span>Allow tentative reservation</span>
              <span style={{ marginLeft: 'auto', fontSize: 10, color: 'var(--muted)' }}>For soft holds</span>
              <span style={{ fontSize: 14 }}>▸</span>
            </button>
          )}
        </div>

        <div>
          <div style={{ fontWeight: 700, marginBottom: 12, color: 'var(--text-muted)', fontSize: 12, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Price Summary</div>
          <div style={{ background: 'var(--card-bg)', border: '1.5px solid var(--border)', borderRadius: 14, padding: 20, position: 'sticky', top: 20 }}>
            <PriceRow label={`Labor (${data.movers}-mover crew × ${data.hours} hrs @ $${data.hourlyRate}/hr)`} value={laborTotal} />
            {truckTotal > 0 && <PriceRow label={`Truck (${data.truckSize})`} value={truckTotal} />}
            {fuelTotal > 0 && <PriceRow label={`Fuel (${distance} mi × $${data.fuelRate})`} value={fuelTotal} />}
            {insuranceTotal > 0 && <PriceRow label="Insurance / Valuation" value={insuranceTotal} />}
            {packingTotal > 0 && <PriceRow label="Packing Materials" value={packingTotal} />}
            {surchargeLines.map((s, i) => <PriceRow key={s.id || i} label={s.label} value={s.amount} />)}
            {discountAmt > 0 && <PriceRow label={`Discount (${data.discountType === 'pct' ? data.discount + '%' : '$' + data.discount})`} value={-discountAmt} />}
            <div style={{ marginTop: 8, display: 'flex', justifyContent: 'space-between', padding: '12px 0 0', fontSize: 22, fontWeight: 800, color: 'var(--accent-dark)' }}>
              <span>Estimated Total</span><span>${total.toFixed(2)}</span>
            </div>
            {_t.nteEnabled && _t.nteTotal != null && (
              <div style={{ marginTop: 6, display: 'flex', justifyContent: 'space-between', padding: '8px 0 0', fontSize: 13, color: 'var(--text-muted)', borderTop: '1px dashed var(--border)' }}>
                <span style={{display:'inline-flex',alignItems:'center',gap:4}}><Icon name="lock" size={11}/> Not to Exceed ({_t.nteHours} hrs)</span>
                <span style={{ fontWeight: 700, color: 'var(--text)' }}>${_t.nteTotal.toFixed(2)}</span>
              </div>
            )}
            <div style={{ marginTop: 16, padding: 12, background: 'var(--accent-light)', borderRadius: 10, fontSize: 13, color: 'var(--text-muted)' }}>
              * This is an estimate. Final invoice may vary based on actual time and conditions.
            </div>
          </div>

          {/* Internal Notes — collapsed when empty (out of the way until needed).
              Full textarea expands on tap; once filled, stays expanded. */}
          <InternalNotesCollapsible value={data.internalNotes} onChange={v => u('internalNotes', v)} />
        </div>
      </div>
    </div>
  );
}

function SectionTitle({ icon, title }) {
  return (
    <div style={{ marginBottom: 24, display: 'flex', alignItems: 'center', gap: 10 }}>
      <Icon name={icon} size={22} color="var(--accent)"/>
      <h2 style={{ margin: 0, fontSize: 22, fontWeight: 800, color: 'var(--text)' }}>{title}</h2>
    </div>
  );
}

// Internal Notes — out of the way until you need it. Empty = small "Add notes" link.
// Once you click or there's existing content, it expands to a full textarea.
function InternalNotesCollapsible({ value, onChange }) {
  const hasContent = !!(value && value.trim());
  const [expanded, setExpanded] = React.useState(hasContent);
  React.useEffect(() => { if (hasContent) setExpanded(true); }, [hasContent]);
  if (!expanded) {
    return (
      <div style={{ marginTop: 20 }}>
        <button type="button" onClick={() => setExpanded(true)}
          style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 14px', borderRadius: 10, background: 'var(--bg)', border: '1px dashed var(--border)', color: 'var(--text-muted)', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: 600, width: '100%', justifyContent: 'flex-start' }}>
          <Icon name="pencil" size={13}/><span>Add internal notes</span><span style={{ marginLeft: 'auto', fontSize: 14 }}>▸</span>
        </button>
      </div>
    );
  }
  return (
    <div style={{ marginTop: 20 }}>
      <div style={{ fontWeight: 700, marginBottom: 12, color: 'var(--text-muted)', fontSize: 12, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Internal Notes</div>
      <textarea
        value={value || ''}
        onChange={e => onChange(e.target.value)}
        placeholder="Notes for the team (not shown on estimate)..."
        rows={4}
        style={{ width: '100%', boxSizing: 'border-box', padding: '11px 14px', borderRadius: 10, border: '1.5px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text)', fontSize: 15, fontFamily: 'inherit', outline: 'none', resize: 'vertical' }}
      />
    </div>
  );
}

Object.assign(window, { StepCustomer, StepMove, StepInventory, StepPricing });
