// csr-booking.jsx — CE take-a-booking flow (phone operator).
// Flow order: account (selected) → reference → pickup/delivery → items → services → time → quote.
const { useState: useStateBkg, useMemo: useMemoBkg } = React;

const FUEL_LEVY_PCT = 0.125;                                   // shown as a separate line (item 36)
const TAXI_TRUCK = { minHours: 4, hourly: 145, label: "Taxi truck · hourly hire" };
const ITEM_TYPES = ["Carton", "Satchel", "Pallet", "Skid", "Crate", "Tube", "Envelope"];
const VEH_CAPS = [
  { id: "courier", kg: 25,   m3: 0.13 },
  { id: "wagon",   kg: 125,  m3: 0.5 },
  { id: "halfvan", kg: 500,  m3: 1.5 },
  { id: "van",     kg: 1000, m3: 3.0 },
];
const EXTRA_SERVICES = [
  { id: "tail-lift",        label: "Tail lift required",  icon: "truck",          charge: 40, note: "Pushes vehicle to Half Van or larger." },
  { id: "authority-leave",  label: "Authority to leave",  icon: "check-circle",   charge: 0,  note: "Deliver without a signature." },
  { id: "hand-unload",      label: "Hand unload",         icon: "package",        charge: 25, note: "" },
  { id: "two-person",       label: "Two-person lift",     icon: "users",          charge: 55, note: "" },
  { id: "transit-insurance",label: "Transit insurance",   icon: "shield",         charge: 9,  note: "per $1,000 value" },
];
const METRO = new Set(["Sydney CBD","Surry Hills","Newtown","Bondi Junction","North Sydney","Alexandria","Mascot","Botany","Marrickville","Rhodes","Manly","Melbourne CBD","Richmond (VIC)","Brisbane CBD","South Brisbane","Perth CBD","Adelaide CBD","Canberra"]);

const num = x => { const n = parseFloat(x); return isNaN(n) ? 0 : n; };
function emptyItem() { return { qty: "1", type: "Carton", ...window.FX.typeDefaults("Carton") }; }
function itemTotals(items) {
  let kg = 0, m3 = 0, count = 0;
  (items || []).forEach(it => { const q = Math.max(1, parseInt(it.qty, 10) || 1); count += q; kg += num(it.weight) * q; m3 += (num(it.l) * num(it.w) * num(it.h)) / 1e6 * q; });
  return { kg: Math.round(kg * 10) / 10, m3: Math.round(m3 * 1000) / 1000, count };
}
// Auto vehicle from item totals (item 9–10) + tail-lift floor.
function autoVehicle(items, tailLift) {
  const { kg, m3 } = itemTotals(items);
  let fit = VEH_CAPS.find(c => kg <= c.kg && m3 <= c.m3);
  let over = !fit;
  let id = fit ? fit.id : "van";
  if (tailLift && (id === "courier" || id === "wagon")) id = "halfvan";
  return { vehicleId: id, kg, m3, taxiTruck: over };  // over van capacity → taxi truck / hourly
}
function zoneOf(suburb) { return METRO.has(suburb) ? "metro" : "outer"; }
// Which service tiers are valid for this route/zone (item 10, 33).
function serviceAvailability(pickup, dropoff) {
  const ps = pickup && window.FX.suburbState(pickup.suburb), ds = dropoff && window.FX.suburbState(dropoff.suburb);
  if (ps && ds && ps !== ds) return { available: ["standard"], reason: "Interstate route — Next Flight or DC rate only (SCPC unavailable)." };
  if (pickup && dropoff && pickup.suburb && dropoff.suburb && (zoneOf(pickup.suburb) === "outer" || zoneOf(dropoff.suburb) === "outer"))
    return { available: ["standard"], reason: "Out-of-area — DC rate only (SCPC unavailable for this zone)." };
  return { available: ["standard", "premium", "direct"], reason: null };
}

function csrTotal({ vehicleId, km, serviceId, bookingType, extras, rateMult, isReturn, taxiTruck }) {
  const bt = bookingType;
  let baseEx, typeEx, returnEx;
  if (taxiTruck && taxiTruck.on) {
    baseEx = TAXI_TRUCK.minHours * TAXI_TRUCK.hourly * (rateMult || 1);
    typeEx = baseEx; returnEx = 0;
  } else {
    const base = window.FX.quote({ vehicleId, km: km || 0, serviceId, isReturn: false, rateMult });
    baseEx = base.oneWay;
    typeEx = base.oneWay * (bt ? bt.mult : 1) + (bt && bt.surcharge ? bt.surcharge : 0);
    returnEx = isReturn ? typeEx * 0.85 : 0;
  }
  const extrasEx = (extras || []).reduce((s, e) => s + (e.charge || 0) * (e.qty || 1), 0);
  const preFuel = typeEx + returnEx;
  const fuelEx = (taxiTruck && taxiTruck.on) ? 0 : preFuel * FUEL_LEVY_PCT;
  const subtotal = preFuel + fuelEx + extrasEx;
  const gst = subtotal * 0.1;
  return { baseEx, typeEx, returnEx, fuelEx, extrasEx, subtotal, gst, total: subtotal + gst, taxi: !!(taxiTruck && taxiTruck.on) };
}

/* 15-minute time picker — hour pills (24 h) + :00/:15/:30/:45 (item 32). */
function TimePicker15({ value, onChange, accent = "var(--accent)" }) {
  const parts = (value && /^\d{2}:\d{2}$/.test(value)) ? value.split(":") : ["", ""];
  const h = parts[0], m = parts[1];
  const setH = nh => onChange(nh + ":" + (m || "00"));
  const setM = nm => onChange((h || "09") + ":" + nm);
  const hourOpts = Array.from({ length: 24 }, (_, i) => ({ value: String(i).padStart(2, "0"), label: (((i % 12) || 12) + ":00 " + (i < 12 ? "AM" : "PM")) }));
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
      <div style={{ minWidth: 150 }}><Select value={h} onChange={setH} placeholder="Select hour" options={hourOpts} /></div>
      <div style={{ display: "flex", gap: 5 }}>
        {["00", "15", "30", "45"].map(x => {
          const on = m === x;
          return <button key={x} onClick={() => setM(x)} style={{ padding: "9px 13px", borderRadius: "var(--r-sm)", fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 600, border: "1.5px solid " + (on ? accent : "var(--border)"), background: on ? "var(--accent-soft)" : "var(--surface)", color: on ? "var(--accent-700)" : "var(--fg-body)" }}>:{x}</button>;
        })}
      </div>
    </div>
  );
}

function CsrBooking({ customer, currency, rateMult, onPlace, editing, onClear, caller = { name: "", phone: "" }, setCaller = () => {}, seedBooking = null, onQuote }) {
  const seed = editing || seedBooking || {};
  const initStops = seed.stops || (seed.pickup ? [seed.pickup, seed.dropoff] : [window.FX.emptyAddr(), window.FX.emptyAddr()]);
  const [typeId, setTypeId] = useStateBkg(seed.typeId || "standard");
  const [stops, setStops] = useStateBkg(initStops);
  const [sameLocation, setSameLocation] = useStateBkg(!!seed.sameLocation);
  const [isReturn, setIsReturn] = useStateBkg(!!seed.isReturn);
  const [manualVehicle, setManualVehicle] = useStateBkg(seed.vehicleId || null);
  const [serviceId, setServiceId] = useStateBkg(seed.serviceId || "standard");
  const [date, setDate] = useStateBkg(seed.date || window.FX.todayISO());
  const [time, setTime] = useStateBkg(seed.time || "");
  const [deliveryTime, setDeliveryTime] = useStateBkg(seed.deliveryTime || "");
  const [ref1, setRef1] = useStateBkg(seed.ref1 || "");
  const [ref2, setRef2] = useStateBkg(seed.ref2 || "");
  const [items, setItems] = useStateBkg(seed.lineItems && seed.lineItems.length ? seed.lineItems : [emptyItem()]);
  const [extras, setExtras] = useStateBkg(seed.extras || []);
  const [dg, setDg] = useStateBkg(seed.dg || { type: "", qty: "1" });
  const [dgAnswer, setDgAnswer] = useStateBkg(seed.dg ? "yes" : "no");
  const [dgAck, setDgAck] = useStateBkg(!!seed.dgAck || (!!editing && !seed.dg));
  const [notes, setNotes] = useStateBkg(seed.notes || "");
  const [alertAck, setAlertAck] = useStateBkg(!(customer && customer.bookingAlert));
  const [transport, setTransport] = useStateBkg(seed.transport || "air");
  const [callerNote, setCallerNote] = useStateBkg("");
  const [notifyExtra, setNotifyExtra] = useStateBkg(seed.notifyExtra || []);
  const [npName, setNpName] = useStateBkg("");
  const [npEmail, setNpEmail] = useStateBkg("");
  const [npPhone, setNpPhone] = useStateBkg("");
  const npValid = (npEmail.trim() && /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(npEmail.trim())) || npPhone.trim();
  const addNotify = () => { if (!npValid) return; setNotifyExtra(prev => [...prev, { name: npName.trim(), email: npEmail.trim(), phone: npPhone.trim() }]); setNpName(""); setNpEmail(""); setNpPhone(""); };
  const rmNotify = (i) => setNotifyExtra(prev => prev.filter((_, idx) => idx !== i));

  const bookingType = window.FX.BOOKING_TYPES.find(t => t.id === typeId);
  const rc = (customer && customer.refConfig) || {};
  const r1c = { label: "Customer reference (PO / order no.)", required: false, prefix: "", ...(rc.ref1 || {}) };
  const r2c = { label: "Second reference (optional)", required: false, prefix: "", ...(rc.ref2 || {}) };
  const refOk = (val, cfg) => !((cfg.required && !val.trim()) || (cfg.prefix && (cfg.required || val.trim()) && !val.trim().startsWith(cfg.prefix)));
  const refsOk = refOk(ref1, r1c) && refOk(ref2, r2c);
  const setStop = (i, val) => setStops(prev => prev.map((s, idx) => idx === i ? val : s));
  const addStop = () => setStops(prev => [...prev, window.FX.emptyAddr()]);
  const removeStop = (i) => setStops(prev => prev.filter((_, idx) => idx !== i));
  const stopComplete = (s) => !!(s && s.suburb);
  const effStops = sameLocation ? [stops[0], stops[0]] : stops;
  const allStopsComplete = (sameLocation ? [stops[0]] : stops).every(stopComplete);

  const setItem = (i, k, v) => setItems(prev => prev.map((it, idx) => idx === i ? { ...it, [k]: v } : it));
  const addItem = () => setItems(prev => [...prev, emptyItem()]);
  const rmItem = (i) => setItems(prev => prev.length > 1 ? prev.filter((_, idx) => idx !== i) : prev);
  const totals = useMemoBkg(() => itemTotals(items), [items]);
  const auto = useMemoBkg(() => autoVehicle(items, extras.includes("tail-lift")), [items, extras]);
  const vehicleId = manualVehicle || auto.vehicleId;
  const taxiTruck = { on: auto.taxiTruck && !manualVehicle };

  const km = useMemoBkg(() => {
    const s = effStops;
    if (s.some(x => !x.suburb)) return null;
    let total = 0;
    for (let i = 0; i < s.length - 1; i++) { const d = window.FX.distanceKm(s[i].suburb, s[i + 1].suburb); if (d == null) return null; total += d; }
    return total;
  }, [effStops]);

  const avail = useMemoBkg(() => serviceAvailability(effStops[0], effStops[effStops.length - 1]), [effStops]);
  React.useEffect(() => { if (!avail.available.includes(serviceId)) setServiceId(avail.available[0]); }, [avail.available.join(",")]);

  const extraObjs = extras.map(id => EXTRA_SERVICES.find(e => e.id === id)).filter(Boolean);
  const dgOn = dgAnswer === "yes";
  const extraObjsAll = dgOn ? [...extraObjs, { id: "dg", label: "Dangerous goods handling", charge: 65 }] : extraObjs;
  const dgResult = useMemoBkg(() => dgOn ? window.FX.dgAssess(dg.type, dg.qty) : { status: "none" }, [dgOn, dg.type, dg.qty]);
  const dgBlocked = dgOn && dgResult.status === "blocked";
  const dgReady = dgAnswer === "no" ? dgAck : (dgAnswer === "yes" && !!dg.type && !dgBlocked);

  /* Interstate: air (Next Flight) vs road line-haul, with DG-approved outbound port enforcement (items 50, 64–65). */
  const puStateB = effStops[0] && effStops[0].suburb ? window.FX.suburbState(effStops[0].suburb) : null;
  const doStateB = effStops[effStops.length - 1] && effStops[effStops.length - 1].suburb ? window.FX.suburbState(effStops[effStops.length - 1].suburb) : null;
  const interstate = !!(puStateB && doStateB && puStateB !== doStateB);
  const depAp = interstate ? window.FX.AIRPORTS[puStateB] : null;
  const arrAp = interstate ? window.FX.AIRPORTS[doStateB] : null;
  const dgAirBlocked = interstate && dgOn && depAp && depAp.dgOutbound === false;
  const effTransport = !interstate ? null : (dgAirBlocked ? "road" : transport);

  const calc = useMemoBkg(() => csrTotal({ vehicleId, km, serviceId, bookingType, extras: extraObjsAll, rateMult, isReturn, taxiTruck }), [vehicleId, km, serviceId, bookingType, extras.join(","), dgOn, rateMult, isReturn, taxiTruck.on]);
  const ready = allStopsComplete && time && totals.count > 0 && totals.kg > 0 && refsOk && dgReady;

  function toggleExtra(id) { setExtras(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]); }
  function setNow() { const d = new Date(); setDate(window.FX.todayISO()); setTime(d.toTimeString().slice(0, 5)); }
  function saveAsQuote() {
    const pu = effStops[0], dr = effStops[effStops.length - 1];
    const ps = window.FX.suburbState(pu.suburb), ds = window.FX.suburbState(dr.suburb);
    onQuote && onQuote({ from: pu.suburb, fromPc: pu.postcode || "", to: dr.suburb, toPc: dr.postcode || "", serviceId, vehicleId, isReturn, isInterstate: !!(ps && ds && ps !== ds), items, total: calc.total, km: km || 0 });
  }

  function place() {
    if (!ready) return;
    const pickup = effStops[0], dropoff = effStops[effStops.length - 1];
    const b = {
      tracking: editing ? editing.tracking : window.FX.genTracking(),
      customerId: customer.id, customerName: customer.name, customerRef: customer.ref,
      typeId, stops: effStops, pickup, dropoff, isReturn, sameLocation, vehicleId, serviceId, date, time, deliveryTime, ref1, ref2, notes,
      notifyExtra, callerNote: callerNote.trim(),
      lineItems: items, extras, dg: dgOn ? dg : null, dgDeclaredNone: dgAnswer === "no", dgAck,
      charges: extraObjsAll.map(e => ({ id: e.id, label: e.label, amount: e.charge, qty: 1 })),
      state: window.FX.suburbState(dropoff.suburb), km: km || 0,
      transport: effTransport, interstate,
      total: calc.total, subtotal: calc.subtotal, gst: calc.gst, taxiTruck: taxiTruck.on,
      status: editing ? editing.status : "Booked", placedAt: editing ? editing.placedAt : new Date().toISOString(),
    };
    onPlace(b);
  }

  return (
    <div className="fade-up" style={{ display: "grid", gridTemplateColumns: "minmax(0,1fr) 312px", gap: 20, alignItems: "start" }}>
      {customer && customer.bookingAlert && !alertAck && (
        <Modal open={true} onClose={() => setAlertAck(true)} title="Before you book — customer requirement" width={500} top>
          <div style={{ display: "flex", gap: 12, alignItems: "flex-start", padding: "14px 16px", background: "color-mix(in srgb, var(--danger), white 93%)", border: "1px solid var(--danger)", borderRadius: "var(--r-md)", marginBottom: 16 }}>
            <Icon name="megaphone" size={19} color="var(--danger)" style={{ flex: "none", marginTop: 2 }} />
            <span style={{ fontSize: 14, color: "var(--fg-strong)", lineHeight: 1.55 }}>{customer.bookingAlert}</span>
          </div>
          <div style={{ fontSize: 12.5, color: "var(--fg-mute)", marginBottom: 16 }}>This notice is set on {customer.name}'s file and shows on every new booking.</div>
          <Button variant="primary" full icon="check" onClick={() => setAlertAck(true)}>Acknowledged — continue to booking</Button>
        </Modal>
      )}
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        {/* Reference (flow: account → reference → addresses) */}
        <Card pad={20}>
          <SecTitle n="1" title="Caller & reference" />
          <div style={{ display: "grid", gridTemplateColumns: "1.3fr 1fr", gap: 12, marginBottom: 14 }}>
            <Field label="Caller name"><TextInput value={caller.name} onChange={v => setCaller({ ...caller, name: v })} placeholder="Who are you speaking with?" /></Field>
            <Field label="Callback number"><TextInput value={caller.phone} onChange={v => setCaller({ ...caller, phone: v })} placeholder="+61 4XX XXX XXX" mono /></Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            {[[r1c, ref1, setRef1], [r2c, ref2, setRef2]].map(([cfg, val, setVal], i) => {
              const bad = !refOk(val, cfg);
              return (
                <Field key={i} label={<span>{cfg.label}{cfg.required && <span style={{ color: "var(--danger)" }}> *</span>}</span>} hint={cfg.prefix ? `Must start with “${cfg.prefix}”` : null}>
                  <TextInput value={val} onChange={setVal} placeholder={cfg.prefix ? cfg.prefix + "…" : (cfg.required ? "Required" : "Optional")} mono style={bad && val.trim() ? { borderColor: "var(--danger)" } : {}} />
                </Field>
              );
            })}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 9, marginTop: 14 }}>
            {window.FX.BOOKING_TYPES.map(t => {
              const active = t.id === typeId;
              const tn = { brand: "var(--brand)", accent: "var(--accent)", warn: "var(--warn)", danger: "var(--danger)" }[t.tone] || "var(--brand)";
              return (
                <button key={t.id} onClick={() => setTypeId(t.id)} style={{ textAlign: "left", padding: "11px 12px", borderRadius: "var(--r-md)", transition: "all 140ms ease", border: "1.5px solid " + (active ? tn : "var(--border)"), background: active ? "color-mix(in srgb, " + tn + ", white 90%)" : "var(--surface)" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
                    <span style={{ width: 26, height: 26, borderRadius: 7, flex: "none", display: "inline-flex", alignItems: "center", justifyContent: "center", background: active ? tn : "var(--bg-mist)", color: active ? "#fff" : "var(--fg-mute)" }}><Icon name={t.icon} size={15} /></span>
                    <span style={{ fontWeight: 600, fontSize: 13, color: "var(--fg-strong)", lineHeight: 1.15 }}>{t.short}</span>
                  </div>
                  <div style={{ fontSize: 11, color: "var(--fg-mute)", lineHeight: 1.35 }}>{t.blurb}</div>
                </button>
              );
            })}
          </div>
          <div style={{ marginTop: 14, padding: "13px 15px", borderRadius: "var(--r-md)", background: "var(--brand)", color: "#fff" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
              <Icon name="info" size={15} /><span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "1px", textTransform: "uppercase", opacity: 0.85 }}>Operator instructions · {bookingType.short}</span>
            </div>
            <ul style={{ margin: 0, paddingLeft: 18, display: "flex", flexDirection: "column", gap: 5 }}>
              {bookingType.instructions.map((ins, i) => <li key={i} style={{ fontSize: 13, lineHeight: 1.4 }}>{ins}</li>)}
            </ul>
          </div>
        </Card>

        {/* Addresses — multi-leg + same-location toggle */}
        <Card pad={20}>
          <SecTitle n="2" title="Pickup & delivery" hint={km != null ? km + " km" : null} />
          <button onClick={() => setSameLocation(!sameLocation)} style={{ display: "inline-flex", alignItems: "center", gap: 9, marginBottom: 12, padding: "8px 13px", borderRadius: "var(--r-pill)", border: "1.5px solid " + (sameLocation ? "var(--accent)" : "var(--border-strong)"), background: sameLocation ? "var(--accent-soft)" : "var(--surface)", color: sameLocation ? "var(--accent-700)" : "var(--fg-body)", fontSize: 13, fontWeight: 500 }}>
            <Icon name="map-pin" size={15} /> Same location (wait & return to pickup) {sameLocation && <Icon name="check" size={15} />}
          </button>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {(sameLocation ? [stops[0]] : stops).map((s, i) => {
              const isFirst = i === 0, isLast = i === (sameLocation ? 0 : stops.length - 1);
              const role = sameLocation ? "Pickup & return" : (isFirst ? "Pickup from" : (stops.length > 2 ? `Drop-off ${i}` : "Deliver to"));
              const accent = isFirst ? "var(--brand)" : "var(--accent)";
              const removable = !sameLocation && i > 0 && stops.length > 2;
              const legKm = (!sameLocation && !isLast && s.suburb && stops[i + 1].suburb) ? window.FX.distanceKm(s.suburb, stops[i + 1].suburb) : null;
              return (
                <React.Fragment key={i}>
                  <AddressField value={s} onChange={v => setStop(i, v)} addressBook={window.FX.ADDRESS_BOOK} role={role} accent={accent} index={i} compact onRemove={removable ? () => removeStop(i) : undefined} />
                  {!isLast && (
                    <div style={{ display: "flex", justifyContent: "center", alignItems: "center", gap: 8, margin: "-2px 0" }}>
                      <span style={{ width: 2, height: 14, background: "var(--border-strong)", borderRadius: 2 }} />
                      {legKm != null && <Badge tone="brand"><Icon name="navigation" size={11} /> {legKm} km</Badge>}
                      <span style={{ width: 2, height: 14, background: "var(--border-strong)", borderRadius: 2 }} />
                    </div>
                  )}
                </React.Fragment>
              );
            })}
          </div>
          {!sameLocation && (
            <div style={{ display: "flex", gap: 10, marginTop: 12, flexWrap: "wrap" }}>
              <button onClick={addStop} style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8, flex: 1, minWidth: 160, padding: "11px", background: "var(--surface)", border: "1px dashed var(--border-strong)", borderRadius: "var(--r-md)", color: "var(--brand)", fontSize: 13.5, fontWeight: 500 }}>
                <Icon name="plus" size={16} /> Add another leg
              </button>
              <button onClick={() => setIsReturn(!isReturn)} style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 9, flex: 1, minWidth: 160, padding: "11px", borderRadius: "var(--r-md)", border: "1.5px solid " + (isReturn ? "var(--accent)" : "var(--border-strong)"), background: isReturn ? "var(--accent-soft)" : "var(--surface)", color: isReturn ? "var(--accent-700)" : "var(--fg-body)", fontSize: 13.5, fontWeight: 500 }}>
                <Icon name="repeat" size={16} /> Return booking {isReturn && <Icon name="check" size={15} />}
              </button>
            </div>
          )}

          {/* Interstate transport: Next Flight (air) vs road line-haul */}
          {interstate && (
            <div className="fade-up" style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--border)" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
                <Icon name="plane" size={15} color="var(--brand)" />
                <span style={{ fontSize: 13.5, fontWeight: 700, color: "var(--fg-strong)" }}>Interstate · {puStateB} → {doStateB}</span>
                <span style={{ marginLeft: "auto", fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--fg-mute)" }}>{depAp.code} → {arrAp.code}</span>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 9 }}>
                {[
                  { id: "air", icon: "plane", title: "Next Flight · air", sub: `Flies ${depAp.code} → ${arrAp.code} · same day`, disabled: dgAirBlocked },
                  { id: "road", icon: "truck-big", title: "Road line-haul", sub: "Doesn't fly · next business day", disabled: false },
                ].map(m => {
                  const on = effTransport === m.id;
                  return (
                    <button key={m.id} disabled={m.disabled} onClick={() => !m.disabled && setTransport(m.id)} style={{ display: "flex", alignItems: "flex-start", gap: 10, textAlign: "left", padding: "11px 13px", borderRadius: "var(--r-md)", border: "1.5px solid " + (on ? "var(--brand)" : "var(--border)"), background: on ? "var(--brand-soft)" : "var(--surface)", opacity: m.disabled ? 0.45 : 1, cursor: m.disabled ? "not-allowed" : "pointer" }}>
                      <span style={{ width: 30, height: 30, borderRadius: 8, flex: "none", display: "inline-flex", alignItems: "center", justifyContent: "center", background: on ? "var(--brand)" : "var(--bg-mist)", color: on ? "#fff" : "var(--fg-mute)" }}><Icon name={m.icon} size={16} /></span>
                      <span>
                        <span style={{ display: "block", fontSize: 13, fontWeight: 700, color: "var(--fg-strong)" }}>{m.title}</span>
                        <span style={{ display: "block", fontSize: 11.5, color: "var(--fg-mute)", marginTop: 2 }}>{m.sub}</span>
                      </span>
                    </button>
                  );
                })}
              </div>
              {dgAirBlocked ? (
                <div style={{ display: "flex", gap: 9, marginTop: 10, padding: "11px 13px", background: "var(--warn-soft)", borderRadius: "var(--r-sm)", lineHeight: 1.45 }}>
                  <Icon name="alert-triangle" size={15} color="#a36a00" style={{ flex: "none", marginTop: 1 }} />
                  <span style={{ fontSize: 12.5, color: "#8a5a00" }}><strong>This shipment isn't flying.</strong> {depAp.code} ({depAp.city}) is not a DG-approved outbound port, so dangerous goods can't be accepted for air from here. It will travel by road line-haul and arrive next business day.</span>
                </div>
              ) : effTransport === "road" ? (
                <div style={{ display: "flex", gap: 9, marginTop: 10, padding: "11px 13px", background: "var(--bg-mist)", borderRadius: "var(--r-sm)", lineHeight: 1.45 }}>
                  <Icon name="info" size={15} color="var(--fg-mute)" style={{ flex: "none", marginTop: 1 }} />
                  <span style={{ fontSize: 12.5, color: "var(--fg-body)" }}><strong>This shipment isn't flying.</strong> It travels by road line-haul — tell the caller to expect delivery next business day, not same-day.</span>
                </div>
              ) : (
                <div style={{ display: "flex", gap: 9, marginTop: 10, padding: "11px 13px", background: "var(--brand-soft)", borderRadius: "var(--r-sm)", lineHeight: 1.45 }}>
                  <Icon name="plane" size={15} color="var(--brand)" style={{ flex: "none", marginTop: 1 }} />
                  <span style={{ fontSize: 12.5, color: "var(--fg-body)" }}>Books onto the next available flight {depAp.code} → {arrAp.code}, with a courier at each end. Same-day delivery.</span>
                </div>
              )}
            </div>
          )}
        </Card>

        {/* Items — line items + auto vehicle */}
        <Card pad={20}>
          <SecTitle n="3" title="Items" hint={totals.count ? `${totals.count} item${totals.count === 1 ? "" : "s"} · ${totals.kg} kg` : null} />
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {items.map((it, i) => (
              <div key={i} style={{ display: "grid", gridTemplateColumns: "56px 1.15fr 1.05fr 84px 30px", gap: 8, alignItems: "end", padding: "10px", background: "var(--bg-mist)", borderRadius: "var(--r-md)" }}>
                <Field label={i === 0 ? "Qty" : ""}><TextInput type="number" value={it.qty} onChange={v => setItem(i, "qty", v)} mono /></Field>
                <Field label={i === 0 ? "Type" : ""}><Select value={it.type} onChange={v => setItems(prev => prev.map((x, idx) => idx === i ? { ...x, type: v, ...window.FX.typeDefaults(v) } : x))} options={ITEM_TYPES} /></Field>
                <Field label={i === 0 ? "L × W × H (cm)" : ""}>
                  <div style={{ display: "flex", alignItems: "center", gap: 3 }}>
                    <TextInput type="number" value={it.l} onChange={v => setItem(i, "l", v)} placeholder="L" mono />
                    <TextInput type="number" value={it.w} onChange={v => setItem(i, "w", v)} placeholder="W" mono />
                    <TextInput type="number" value={it.h} onChange={v => setItem(i, "h", v)} placeholder="H" mono />
                  </div>
                </Field>
                <Field label={i === 0 ? "kg" : ""}><TextInput type="number" value={it.weight} onChange={v => setItem(i, "weight", v)} placeholder="kg" mono /></Field>
                {items.length > 1 ? <button onClick={() => rmItem(i)} style={{ justifySelf: "end", background: "var(--surface)", border: "none", borderRadius: 7, width: 28, height: 34, display: "inline-flex", alignItems: "center", justifyContent: "center", color: "var(--fg-mute)" }}><Icon name="x" size={14} /></button> : <span />}
              </div>
            ))}
          </div>
          <button onClick={addItem} style={{ display: "inline-flex", alignItems: "center", gap: 8, marginTop: 10, padding: "9px 14px", background: "var(--surface)", border: "1px dashed var(--border-strong)", borderRadius: "var(--r-md)", color: "var(--brand)", fontSize: 13, fontWeight: 500 }}>
            <Icon name="plus" size={15} /> Add line item
          </button>
          {/* Auto vehicle result */}
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginTop: 14, padding: "12px 14px", borderRadius: "var(--r-md)", background: taxiTruck.on ? "var(--warn-soft)" : "var(--brand-soft)", border: "1px solid " + (taxiTruck.on ? "var(--warn)" : "transparent") }}>
            <span style={{ width: 38, height: 38, borderRadius: 10, flex: "none", background: taxiTruck.on ? "var(--warn)" : "var(--brand)", color: "#fff", display: "inline-flex", alignItems: "center", justifyContent: "center" }}><Icon name={taxiTruck.on ? "truck-big" : (window.FX.VEHICLES.find(v => v.id === vehicleId) || {}).icon || "package"} size={19} /></span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 10.5, fontFamily: "var(--font-mono)", letterSpacing: "0.6px", textTransform: "uppercase", color: taxiTruck.on ? "#8a5a00" : "var(--brand)" }}>Recommended vehicle · auto</div>
              <div style={{ fontSize: 14, fontWeight: 700, color: "var(--fg-strong)" }}>{taxiTruck.on ? TAXI_TRUCK.label : (window.FX.VEHICLES.find(v => v.id === vehicleId) || {}).name}{" "}<span style={{ fontWeight: 400, color: "var(--fg-mute)", fontSize: 12.5 }}>· {totals.kg} kg · {totals.m3} m³</span></div>
            </div>
            <Select value={manualVehicle || "auto"} onChange={v => setManualVehicle(v === "auto" ? null : v)} options={[{ value: "auto", label: "Auto" }, ...window.FX.VEHICLES.map(v => ({ value: v.id, label: v.name }))]} style={{ width: 120, paddingTop: 7, paddingBottom: 7, fontSize: 12.5 }} />
          </div>
        </Card>

        {/* Extra services (tick boxes) + DG */}
        <Card pad={20}>
          <SecTitle n="4" title="Extra services & requirements" hint={extras.length ? extras.length + " selected" : null} />
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
            {EXTRA_SERVICES.map(e => {
              const on = extras.includes(e.id);
              return (
                <button key={e.id} onClick={() => toggleExtra(e.id)} style={{ display: "flex", alignItems: "flex-start", gap: 10, textAlign: "left", padding: "10px 12px", borderRadius: "var(--r-md)", border: "1.5px solid " + (on ? "var(--accent)" : "var(--border)"), background: on ? "var(--accent-soft)" : "var(--surface)" }}>
                  <span style={{ width: 18, height: 18, borderRadius: 5, flex: "none", marginTop: 1, border: "1.5px solid " + (on ? "var(--accent)" : "var(--border-strong)"), background: on ? "var(--accent)" : "transparent", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>{on && <Icon name="check" size={12} color="#fff" />}</span>
                  <span style={{ minWidth: 0 }}>
                    <span style={{ display: "flex", alignItems: "center", gap: 6 }}><Icon name={e.icon} size={14} color={on ? "var(--accent-700)" : "var(--fg-mute)"} /><span style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-strong)" }}>{e.label}</span></span>
                    <span style={{ display: "block", fontSize: 11, color: "var(--fg-mute)", marginTop: 2 }}>{e.charge ? window.FX.money(e.charge, currency) : "No charge"}{e.note ? " · " + e.note : ""}</span>
                  </span>
                </button>
              );
            })}
          </div>

          {/* Dangerous goods — declared on every booking */}
          <div style={{ marginTop: 16, borderTop: "1px solid var(--border)", paddingTop: 16 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
              <Icon name="alert-triangle" size={16} color="var(--accent-700)" />
              <span style={{ fontSize: 14, fontWeight: 700, color: "var(--fg-strong)" }}>Dangerous goods declaration</span>
              <span style={{ color: "var(--danger)" }}>*</span>
            </div>
            <div style={{ fontSize: 12.5, color: "var(--fg-mute)", marginBottom: 11 }}>Does this shipment contain any dangerous goods?</div>
            <div style={{ display: "flex", gap: 8, maxWidth: 220 }}>
              {[["no", "No"], ["yes", "Yes"]].map(([v, l]) => {
                const on = dgAnswer === v;
                return <button key={v} onClick={() => setDgAnswer(v)} style={{ flex: 1, padding: "9px 0", borderRadius: "var(--r-md)", border: "1.5px solid " + (on ? "var(--accent)" : "var(--border-strong)"), background: on ? "var(--accent-soft)" : "var(--surface)", color: on ? "var(--accent-700)" : "var(--fg-body)", fontSize: 13.5, fontWeight: 600 }}>{l}</button>;
              })}
            </div>
            {dgAnswer === "no" && (
              <button onClick={() => setDgAck(!dgAck)} style={{ display: "flex", gap: 11, alignItems: "flex-start", marginTop: 12, width: "100%", textAlign: "left", background: dgAck ? "var(--brand-soft)" : "var(--surface)", border: "1.5px solid " + (dgAck ? "var(--brand)" : "var(--border)"), borderRadius: "var(--r-md)", padding: "12px 13px" }}>
                <span style={{ width: 20, height: 20, borderRadius: 5, flex: "none", marginTop: 1, border: "1.5px solid " + (dgAck ? "var(--brand)" : "var(--border-strong)"), background: dgAck ? "var(--brand)" : "transparent", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>{dgAck && <Icon name="check" size={12} color="#fff" />}</span>
                <span style={{ fontSize: 12.5, color: "var(--fg-body)", lineHeight: 1.5 }}>Caller declares this shipment contains <strong>no dangerous or prohibited goods</strong> — including hidden DG such as aerosols, lithium batteries or dry ice.</span>
              </button>
            )}
            {dgAnswer === "yes" && (
              <div className="fade-up" style={{ marginTop: 12, padding: 14, borderRadius: "var(--r-md)", border: "1px solid " + (dgBlocked ? "var(--danger)" : dgResult.status === "accept" ? "var(--success, #1f8a5b)" : "var(--border)"), background: dgBlocked ? "color-mix(in srgb, var(--danger), white 94%)" : dgResult.status === "accept" ? "color-mix(in srgb, var(--success, #1f8a5b), white 92%)" : "var(--bg-mist)" }}>
                <div style={{ display: "grid", gridTemplateColumns: "2fr 70px", gap: 10 }}>
                  <Field label="Type"><Select value={dg.type} onChange={v => setDg({ ...dg, type: v })} placeholder="Select DG type" options={window.FX.DANGEROUS_GOODS} /></Field>
                  <Field label="Qty"><TextInput type="number" value={dg.qty} onChange={v => setDg({ ...dg, qty: v })} mono /></Field>
                </div>
                {dg.type && (
                  <div style={{ display: "flex", gap: 9, marginTop: 12, alignItems: "flex-start" }}>
                    <Icon name={dgResult.status === "accept" ? "check-circle" : "alert-triangle"} size={16} color={dgResult.status === "accept" ? "var(--success, #1f8a5b)" : "var(--danger)"} style={{ flex: "none", marginTop: 1 }} />
                    <div>
                      <div style={{ fontSize: 13, fontWeight: 700, color: dgResult.status === "accept" ? "var(--success, #1f8a5b)" : "var(--danger)" }}>{dgResult.status === "accept" ? "Within limited quantity — auto-accepted" : "Blocked — must go through Customer Service"}</div>
                      <div style={{ fontSize: 12.5, color: "var(--fg-body)", marginTop: 2, lineHeight: 1.45 }}>{dgResult.reason}</div>
                    </div>
                  </div>
                )}
              </div>
            )}
          </div>
        </Card>

        {/* Service tier + times */}
        <Card pad={20}>
          <SecTitle n="5" title="Service & timing" />
          {avail.reason && (
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12, padding: "9px 12px", background: "var(--warn-soft)", borderRadius: "var(--r-sm)", fontSize: 12.5, color: "#8a5a00" }}>
              <Icon name="info" size={14} color="#a36a00" /> {avail.reason}
            </div>
          )}
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 16 }}>
            {window.FX.SERVICES.map(s => {
              const ok = avail.available.includes(s.id);
              const on = serviceId === s.id && ok;
              return (
                <button key={s.id} disabled={!ok} onClick={() => ok && setServiceId(s.id)} title={ok ? "" : "Not available for this route/zone"} style={{ flex: 1, minWidth: 120, textAlign: "left", padding: "11px 13px", borderRadius: "var(--r-md)", border: "1.5px solid " + (on ? "var(--accent)" : "var(--border)"), background: on ? "var(--accent-soft)" : "var(--surface)", opacity: ok ? 1 : 0.4, cursor: ok ? "pointer" : "not-allowed" }}>
                  <div style={{ fontSize: 13.5, fontWeight: 700, color: "var(--fg-strong)" }}>{s.name}</div>
                  <div style={{ fontSize: 11.5, color: "var(--fg-mute)", marginTop: 2 }}>{ok ? s.eta : "Unavailable"}</div>
                </button>
              );
            })}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 14 }}>
            <Field label="Pickup date"><TextInput type="date" value={date} onChange={setDate} min={window.FX.todayISO()} /></Field>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, margin: "14px 0 8px" }}>
            <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-strong)" }}>Ready / pickup time</span>
            <button onClick={setNow} style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: "var(--r-pill)", fontWeight: 600, fontSize: 11.5, border: "none", background: "var(--accent)", color: "#fff" }}><Icon name="zap" size={12} /> Now</button>
            {time && <span style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 700, color: "var(--accent-700)", marginLeft: "auto" }}>{time}</span>}
          </div>
          <TimePicker15 value={time} onChange={setTime} />
        </Card>

        {/* Notifications — default parties + additional recipients */}
        <Card pad={20}>
          <SecTitle n="6" title="Notifications" hint={notifyExtra.length ? notifyExtra.length + " added" : null} />
          <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 13px", background: "var(--bg-mist)", borderRadius: "var(--r-md)" }}>
              <Icon name="map-pin" size={15} color="var(--brand)" />
              <span style={{ fontSize: 13, color: "var(--fg-body)", flex: 1 }}>Pickup contact{effStops[0].contact ? " · " + effStops[0].contact : ""}</span>
              <Badge tone="neutral">Default</Badge>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 13px", background: "var(--bg-mist)", borderRadius: "var(--r-md)" }}>
              <Icon name="map-pin" size={15} color="var(--accent)" />
              <span style={{ fontSize: 13, color: "var(--fg-body)", flex: 1 }}>Recipient{effStops[effStops.length - 1].contact ? " · " + effStops[effStops.length - 1].contact : ""}</span>
              <Badge tone="neutral">Default</Badge>
            </div>
          </div>
          <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-strong)", marginBottom: 9 }}>Also notify someone else</div>
          {notifyExtra.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12 }}>
              {notifyExtra.map((p, i) => (
                <div key={i} style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 12px", border: "1px solid var(--border)", borderRadius: "var(--r-md)" }}>
                  <span style={{ width: 30, height: 30, borderRadius: "50%", flex: "none", background: "var(--brand-soft)", color: "var(--brand)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontWeight: 700, fontSize: 11 }}>{(p.name || "?").slice(0, 2).toUpperCase()}</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    {p.name && <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-strong)" }}>{p.name}</div>}
                    <div style={{ display: "flex", gap: 12, fontSize: 12, color: "var(--fg-mute)" }}>{p.email && <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><Icon name="mail" size={12} /> {p.email}</span>}{p.phone && <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontFamily: "var(--font-mono)" }}><Icon name="message-square" size={12} /> {p.phone}</span>}</div>
                  </div>
                  <button onClick={() => rmNotify(i)} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--fg-mute)", padding: 4 }}><Icon name="x" size={15} /></button>
                </div>
              ))}
            </div>
          )}
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1.3fr 1fr auto", gap: 8, alignItems: "end" }}>
            <Field label="Name"><TextInput value={npName} onChange={setNpName} placeholder="Optional" /></Field>
            <Field label="Email"><TextInput value={npEmail} onChange={setNpEmail} placeholder="name@company.com" type="email" /></Field>
            <Field label="Mobile (SMS)"><TextInput value={npPhone} onChange={setNpPhone} placeholder="+61 4XX" mono /></Field>
            <Button variant="secondary" icon="plus" onClick={addNotify} disabled={!npValid}>Add</Button>
          </div>
        </Card>

        {/* Notes — anything that didn't fit a field above (bottom of form) */}
        <Card pad={20}>
          <SecTitle n="7" title="Notes" />
          <div style={{ fontSize: 12.5, color: "var(--fg-mute)", marginBottom: 10 }}>Anything that didn't fit a field above — e.g. a site's closing time, dock access, or a caller request. Saved to the booking's note log with your name and the time.</div>
          <textarea value={callerNote} onChange={e => setCallerNote(e.target.value)} rows={3} placeholder="e.g. Dock closes 4:00 PM · ask for Sam on arrival · caller wants a text before pickup" style={{ ...window.inputStyle, resize: "vertical", fontSize: 13.5, lineHeight: 1.45 }} />
        </Card>
      </div>

      {/* Sticky total rail */}
      <div style={{ position: "sticky", top: 16 }}>
        <Card pad={0} style={{ overflow: "hidden" }}>
          <div style={{ background: "var(--brand)", color: "#fff", padding: "16px 18px" }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "1.2px", opacity: 0.7, textTransform: "uppercase" }}>{editing ? "Updating booking" : "Quote"}</div>
            {ready ? (
              <React.Fragment>
                <div style={{ fontSize: 34, fontWeight: 900, letterSpacing: "-1.4px", marginTop: 4 }}>{window.FX.money(calc.total, currency)}</div>
                <div style={{ fontSize: 12, opacity: 0.7 }}>incl. GST · {calc.taxi ? "hourly hire" : bookingType.short}{isReturn ? " · return" : ""}</div>
              </React.Fragment>
            ) : (
              <div style={{ display: "flex", gap: 10, alignItems: "flex-start", marginTop: 8 }}>
                <Icon name="calculator" size={18} color="#fff" style={{ flex: "none", marginTop: 2, opacity: 0.9 }} />
                <span style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.4, opacity: 0.92 }}>Enter items, both addresses and a pickup time — we'll price it once we know what we're quoting on.</span>
              </div>
            )}
          </div>
          {ready && (
          <div style={{ padding: "14px 18px" }}>
            {calc.taxi ? (
              <React.Fragment>
                <Line label={`Taxi truck · ${TAXI_TRUCK.minHours} hr minimum`} value={window.FX.money(calc.baseEx, currency)} />
                <div style={{ fontSize: 11, color: "var(--fg-mute)", padding: "2px 0 6px", lineHeight: 1.4 }}>Charged at {window.FX.money(TAXI_TRUCK.hourly, currency)}/hr, {TAXI_TRUCK.minHours} hr minimum. Time beyond the minimum is billed per hour; part-hours are rounded up to the next 15 min.</div>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <Line label="Base rate" value={window.FX.money(calc.baseEx, currency)} />
                {bookingType.mult !== 1 && <Line label={`${bookingType.short} (×${bookingType.mult})`} value={window.FX.money(calc.typeEx - calc.baseEx, currency)} accent />}
                {isReturn && <Line label="Return leg (−15%)" value={window.FX.money(calc.returnEx, currency)} />}
                <Line label={`Fuel levy (${Math.round(FUEL_LEVY_PCT * 100)}%)`} value={window.FX.money(calc.fuelEx, currency)} small />
              </React.Fragment>
            )}
            {extraObjsAll.map(e => <Line key={e.id} label={e.label} value={window.FX.money(e.charge, currency)} small />)}
            <div style={{ borderTop: "1px dashed var(--border)", margin: "8px 0" }} />
            <Line label="Subtotal" value={window.FX.money(calc.subtotal, currency)} />
            <Line label="GST (10%)" value={window.FX.money(calc.gst, currency)} small />
          </div>
          )}
          <div style={{ padding: "0 18px 18px" }}>
            {dgBlocked && <div style={{ fontSize: 11.5, color: "var(--danger)", marginBottom: 10, lineHeight: 1.4, display: "flex", gap: 6 }}><Icon name="alert-triangle" size={14} style={{ flex: "none", marginTop: 1 }} /> DG above limited quantity — this booking must be checked for travel by CE before it can be placed.</div>}
            <Button variant="primary" full size="lg" icon={editing ? "check" : "check-circle"} onClick={place} disabled={!ready}>{editing ? "Save changes" : "Place booking"}</Button>
            {!editing && <Button variant="secondary" full icon="calculator" onClick={saveAsQuote} disabled={!allStopsComplete} style={{ marginTop: 8 }}>Save as quote</Button>}
            {editing && <Button variant="ghost" full onClick={onClear} style={{ marginTop: 8 }}>Cancel edit</Button>}
            <div style={{ fontSize: 10.5, color: "var(--fg-faint)", lineHeight: 1.5, marginTop: 10 }}>By placing this booking you accept the Fedex freight <a href="#" onClick={e => e.preventDefault()} style={{ color: "var(--accent-700)" }}>terms &amp; conditions</a>. Prices include GST; final charges may vary with actual weight &amp; dimensions measured at depot.</div>
            {!ready && !dgBlocked && (
              <div style={{ marginTop: 12 }}>
                <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.8px", textTransform: "uppercase", color: "var(--fg-mute)", marginBottom: 7 }}>To place this booking</div>
                <div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
                  {[
                    [allStopsComplete, "Suburb for every stop"],
                    [!!time, "Ready / pickup time"],
                    [totals.count > 0 && totals.kg > 0, "Item details with weight"],
                    ...((r1c.required || r1c.prefix) ? [[refOk(ref1, r1c), r1c.label + (r1c.prefix ? ` — starts with “${r1c.prefix}”` : "")]] : []),
                    ...((r2c.required || r2c.prefix) ? [[refOk(ref2, r2c), r2c.label + (r2c.prefix ? ` — starts with “${r2c.prefix}”` : "")]] : []),
                    ...(dgOn ? [[!dgBlocked && !!dg.type, "Dangerous goods type"]] : [[dgAck, "Confirm the no-dangerous-goods declaration"]]),
                  ].map(([done, label], ci) => (
                    <div key={ci} style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <span style={{ width: 16, height: 16, borderRadius: "50%", flex: "none", display: "inline-flex", alignItems: "center", justifyContent: "center", background: done ? "var(--success, #1f8a5b)" : "var(--bg-mist-2)", color: "#fff" }}>{done ? <Icon name="check" size={10} /> : <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--fg-faint)" }} />}</span>
                      <span style={{ fontSize: 12, color: done ? "var(--fg-mute)" : "var(--fg-strong)", fontWeight: done ? 400 : 600 }}>{label}</span>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>
        </Card>
      </div>
    </div>
  );
}

function SecTitle({ n, title, hint }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
      <span style={{ width: 22, height: 22, borderRadius: "50%", background: "var(--brand)", color: "#fff", display: "inline-flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 700, flex: "none" }}>{n}</span>
      <span style={{ fontSize: 15.5, fontWeight: 700, color: "var(--fg-strong)", flex: 1 }}>{title}</span>
      {hint && <Badge tone="brand"><Icon name="navigation" size={11} /> {hint}</Badge>}
    </div>
  );
}
function Line({ label, value, accent, small }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", gap: 12, padding: small ? "3px 0" : "4px 0" }}>
      <span style={{ fontSize: small ? 12 : 13, color: accent ? "var(--accent-700)" : "var(--fg-mute)", minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{label}</span>
      <span style={{ fontSize: small ? 12 : 13, fontWeight: 600, color: "var(--fg-strong)", flex: "none" }}>{value}</span>
    </div>
  );
}

Object.assign(window, { CsrBooking, csrTotal });
