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

function useIsMobile() {
  const [mobile, setMobile] = useState(window.innerWidth < 640);
  useEffect(() => {
    const h = () => setMobile(window.innerWidth < 640);
    window.addEventListener("resize", h);
    return () => window.removeEventListener("resize", h);
  }, []);
  return mobile;
}

const FUNCTIONS_BASE = "https://us-central1-medusa-music-booking-portal.cloudfunctions.net";

// Ensure external URLs always have a protocol so they open correctly
function extUrl(url) {
  if (!url) return url;
  return /^https?:\/\//i.test(url) ? url : `https://${url}`;
}

async function callFn(path, body) {
  const res = await fetch(`${FUNCTIONS_BASE}/${path}`, {
    method:  "POST",
    headers: { "Content-Type": "application/json" },
    body:    JSON.stringify(body),
  });
  return res.json();
}

// All configurable defaults — overridden by config/settings in Firestore
const DEFAULT_SETTINGS = {
  venueName:       "Medusa Brewing Company",
  contactEmail:    "booking@medusabrewing.com",
  baseUrl:         "https://medusa-music-booking-portal.web.app",
  welcomeMessage:  "Browse open dates, pick a time slot, and submit your artist profile. We'll be in touch to confirm.",
  soundSystem:     "Bose L1 Pro PA system and a 4-channel mixer",
  timeSlots: [
    "12:00 PM","12:30 PM","1:00 PM","1:30 PM","2:00 PM","2:30 PM",
    "3:00 PM","3:30 PM","4:00 PM","4:30 PM","5:00 PM","5:30 PM",
    "6:00 PM","6:30 PM","7:00 PM","7:30 PM","8:00 PM",
  ],
  setLengthOptions: ["1 hour","1.5 hours","2 hours","2.5 hours","3 hours","3.5 hours","4 hours"],
  defaultSetLength: "3 hours",
  venues: [
    { id: "taproom",    label: "Taproom",     description: "Indoor ~120-seat space, climate controlled" },
    { id: "beergarden", label: "Beer garden", description: "Outdoor space, weather permitting" },
  ],
  contractTerms: "Artist agrees to perform for the full agreed set length. For every 3-hour booking, the Artist is entitled to one 30-minute break or two 15-minute breaks. Venue provides sound and front-of-house support. Payment made in full night of performance. 14-day cancellation notice required.",
  notifications: {
    artistApproval:      true,
    artistDecline:       true,
    artistCountered:     true,
    artistCancellation:  true,
    adminNewSubmission:  true,
    adminContractSigned: true,
    adminCancelRequest:  true,
  },
};

// Full possible time slot range shown in Settings (admin can enable/disable)
const ALL_POSSIBLE_SLOTS = [
  "12:00 PM","12:30 PM","1:00 PM","1:30 PM","2:00 PM","2:30 PM",
  "3:00 PM","3:30 PM","4:00 PM","4:30 PM","5:00 PM","5:30 PM",
  "6:00 PM","6:30 PM","7:00 PM","7:30 PM","8:00 PM","8:30 PM",
  "9:00 PM","9:30 PM","10:00 PM","10:30 PM","11:00 PM","11:30 PM",
];

const PALETTE = {
  amber:    { bg: "#FAEEDA", border: "#BA7517", text: "#633806" },
  teal:     { bg: "#E1F5EE", border: "#0F6E56", text: "#085041" },
  coral:    { bg: "#FAECE7", border: "#993C1D", text: "#4A1B0C" },
  purple:   { bg: "#EEEDFE", border: "#534AB7", text: "#26215C" },
  gray:     { bg: "#F1EFE8", border: "#5F5E5A", text: "#2C2C2A" },
  blue:     { bg: "#EFF6FF", border: "#2563EB", text: "#1E40AF" },
};

const steps = ["Date & time", "Profile", "Assets", "Review"];

function Badge({ color, children }) {
  return (
    <span style={{ background: PALETTE[color]?.bg || "#F1EFE8", color: PALETTE[color]?.text || "#2C2C2A", border: `0.5px solid ${PALETTE[color]?.border || "#5F5E5A"}`, fontSize: 12, padding: "2px 10px", borderRadius: 20, fontWeight: 500, whiteSpace: "nowrap" }}>
      {children}
    </span>
  );
}

function statusBadge(status) {
  const map = { approved: "teal", pending: "amber", declined: "coral", countered: "blue", available: "purple", booked: "gray", cancelled: "gray" };
  return map[status] ? <Badge color={map[status]}>{status.charAt(0).toUpperCase() + status.slice(1)}</Badge> : null;
}

function SlotPill({ time, selected, onClick, disabled }) {
  return (
    <button onClick={onClick} disabled={disabled} style={{ padding: "6px 14px", borderRadius: 20, border: `0.5px solid ${selected ? PALETTE.amber.border : disabled ? "var(--color-border-tertiary)" : "var(--color-border-secondary)"}`, background: selected ? PALETTE.amber.bg : disabled ? "var(--color-background-tertiary)" : "var(--color-background-primary)", color: selected ? PALETTE.amber.text : disabled ? "var(--color-text-secondary)" : "var(--color-text-primary)", fontSize: 13, fontWeight: selected ? 500 : 400, cursor: disabled ? "default" : "pointer", opacity: disabled ? 0.5 : 1 }}>
      {time}
    </button>
  );
}

function Nav({ view, setView }) {
  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 24px", borderBottom: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ fontSize: 18, fontWeight: 500, color: "var(--color-text-primary)", letterSpacing: "-0.3px" }}>Medusa Brewing</span>
        <span style={{ fontSize: 13, color: "var(--color-text-secondary)", marginTop: 1 }}>Artist Booking</span>
      </div>
      {view !== "admin" && view !== "artist" && (
        <button onClick={() => setView("artist")} style={{ fontSize: 13, padding: "5px 14px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", color: "var(--color-text-primary)" }}>Artist Portal</button>
      )}
    </div>
  );
}

function AdminAuthModal({ onSuccess, onClose }) {
  const [input, setInput]       = useState("");
  const [error, setError]       = useState(false);
  const [checking, setChecking] = useState(false);

  const attempt = async () => {
    if (!input || checking) return;
    setChecking(true);
    try {
      const result = await callFn("verifyAdmin", { password: input });
      if (result.success) {
        localStorage.setItem("adminAuthed", "true");
        onSuccess();
      } else {
        setError(true);
        setInput("");
      }
    } catch {
      setError(true);
      setInput("");
    }
    setChecking(false);
  };

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 360, width: "90%" }}>
        <div style={{ fontSize: 18, fontWeight: 500, marginBottom: 6 }}>Admin access</div>
        <p style={{ fontSize: 14, color: "var(--color-text-secondary)", marginBottom: 20 }}>Enter the admin password to continue.</p>
        <input
          type="password" value={input} autoFocus
          onChange={e => { setInput(e.target.value); setError(false); }}
          onKeyDown={e => e.key === "Enter" && attempt()}
          placeholder="Password"
          style={{ width: "100%", boxSizing: "border-box", marginBottom: error ? 8 : 16 }}
        />
        {error && <p style={{ fontSize: 13, color: PALETTE.coral.text, marginBottom: 12 }}>Incorrect password.</p>}
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button onClick={attempt} disabled={checking} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${PALETTE.amber.border}`, background: PALETTE.amber.bg, cursor: checking ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.amber.text, fontWeight: 500, opacity: checking ? 0.7 : 1 }}>{checking ? "Checking…" : "Enter"}</button>
        </div>
      </div>
    </div>
  );
}

function CounterOfferModal({ sub, onSubmit, onClose }) {
  const [counterPay, setCounterPay] = useState(sub.pay || "");
  const [message, setMessage] = useState("");
  const [sending, setSending] = useState(false);

  const canSend = counterPay.trim() && !sending;

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 440, width: "90%" }}>
        <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 4 }}>Counter offer</div>
        <div style={{ fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 20 }}>
          {sub.name} requested <strong style={{ color: "var(--color-text-primary)" }}>{sub.pay}</strong> for {sub.date}{sub.slot ? ` at ${sub.slot}` : ""}
        </div>
        <div style={{ marginBottom: 14 }}>
          <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Your offer</label>
          <input value={counterPay} onChange={e => setCounterPay(e.target.value)} placeholder="e.g. $350" style={{ width: "100%", boxSizing: "border-box" }} />
        </div>
        <div style={{ marginBottom: 20 }}>
          <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Message to artist (optional)</label>
          <textarea value={message} onChange={e => setMessage(e.target.value)} rows={3} placeholder="Add any context or conditions…" style={{ width: "100%", boxSizing: "border-box", padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
        </div>
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button disabled={!canSend} onClick={async () => {
            setSending(true);
            await onSubmit(sub.id, counterPay.trim(), message.trim());
            setSending(false);
            onClose();
          }} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${canSend ? PALETTE.blue.border : "var(--color-border-tertiary)"}`, background: canSend ? PALETTE.blue.bg : "transparent", cursor: canSend ? "pointer" : "not-allowed", fontSize: 14, color: canSend ? PALETTE.blue.text : "var(--color-text-secondary)", fontWeight: 500 }}>
            {sending ? "Sending…" : "Send counter offer"}
          </button>
        </div>
      </div>
    </div>
  );
}

function ApproveConfirmModal({ subs: subsToApprove, onConfirm, onClose }) {
  const [approving, setApproving] = useState(false);
  const multi = subsToApprove.length > 1;
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 440, width: "90%" }}>
        <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 8 }}>Confirm approval</div>
        <div style={{ fontSize: 14, color: "var(--color-text-secondary)", marginBottom: 20, lineHeight: 1.6 }}>
          {multi
            ? `Approve ${subsToApprove.length} selected submissions? Each artist will receive a confirmation email with their contract link.`
            : <>Approve <strong style={{ color: "var(--color-text-primary)" }}>{subsToApprove[0].name}</strong> for <strong style={{ color: "var(--color-text-primary)" }}>{subsToApprove[0].date}{subsToApprove[0].slot ? ` at ${subsToApprove[0].slot}` : ""}</strong>? They'll receive a confirmation email with their contract link.</>
          }
        </div>
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button disabled={approving} onClick={async () => {
            setApproving(true);
            for (const sub of subsToApprove) await onConfirm(sub.id);
            setApproving(false); onClose();
          }} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: approving ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.teal.text, fontWeight: 500 }}>
            {approving ? "Approving…" : multi ? `Approve ${subsToApprove.length}` : "Approve"}
          </button>
        </div>
      </div>
    </div>
  );
}

function DeclineModal({ subs: subsToDecline, onSubmit, onClose }) {
  const [message, setMessage] = useState("");
  const [sending, setSending]  = useState(false);
  const multi = subsToDecline.length > 1;
  const sub   = subsToDecline[0];
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 440, width: "90%" }}>
        <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 8 }}>Confirm decline</div>
        <div style={{ fontSize: 14, color: "var(--color-text-secondary)", marginBottom: 20, lineHeight: 1.6 }}>
          {multi
            ? `Decline ${subsToDecline.length} selected submissions?`
            : <>Decline <strong style={{ color: "var(--color-text-primary)" }}>{sub.name}</strong> for <strong style={{ color: "var(--color-text-primary)" }}>{sub.date}{sub.slot ? ` at ${sub.slot}` : ""}</strong>?</>
          }
        </div>
        <div style={{ marginBottom: 20 }}>
          <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>
            Message to artist{multi ? "s" : ""} <span style={{ opacity: 0.6 }}>(optional — leave blank for silent decline)</span>
          </label>
          <textarea value={message} onChange={e => setMessage(e.target.value)} rows={3}
            placeholder="e.g. We're fully booked for that period, but please apply again for future dates…"
            style={{ width: "100%", boxSizing: "border-box", padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
        </div>
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button disabled={sending} onClick={async () => {
            setSending(true);
            for (const s of subsToDecline) await onSubmit(s.id, message.trim() || null);
            setSending(false); onClose();
          }} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg, cursor: sending ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.coral.text, fontWeight: 500 }}>
            {sending ? "Declining…" : multi ? `Decline ${subsToDecline.length}` : "Decline"}
          </button>
        </div>
      </div>
    </div>
  );
}

function EditContactModal({ sub, onSave, onClose }) {
  const [form, setForm]   = useState({ name: sub.name || "", contactName: sub.contactName || "", email: sub.email || "", phone: sub.phone || "", payableTo: sub.payableTo || "" });
  const [saving, setSaving] = useState(false);
  const upd = (k, v) => setForm(f => ({ ...f, [k]: v }));

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 440, width: "90%" }}>
        <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 4 }}>Edit contact info</div>
        <div style={{ fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 20 }}>{sub.date}{sub.slot ? ` at ${sub.slot}` : ""}</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12, marginBottom: 20 }}>
          {[["Artist / Band name", "name", "text"], ["Contact person", "contactName", "text"], ["Email address", "email", "email"], ["Phone", "phone", "tel"], ["Payment payable to", "payableTo", "text"]].map(([label, key, type]) => (
            <div key={key}>
              <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
              <input type={type} value={form[key]} onChange={e => upd(key, e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
            </div>
          ))}
        </div>
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button disabled={saving} onClick={async () => {
            setSaving(true);
            await onSave(sub.id, form);
            setSaving(false);
            onClose();
          }} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: saving ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.teal.text, fontWeight: 500 }}>
            {saving ? "Saving…" : "Save changes"}
          </button>
        </div>
      </div>
    </div>
  );
}

function ArtistPortal({ dates, settings = DEFAULT_SETTINGS }) {
  const [step, setStep]           = useState(0);
  const [selections, setSelections] = useState([]); // [{date: dateObj, slot: "5:00 PM"}]
  const [form, setForm]             = useState({ name: "", contactName: "", genre: "", bio: "", email: "", emailConfirm: "", phone: "", draw: "", performers: "", pay: "", payableTo: "", links: "", sound: "" });
  const [assets, setAssets]         = useState({ logo: null, photo: null, instagram: "", spotify: "", website: "" });
  const [submitted, setSubmitted]     = useState(false);
  const [agreed, setAgreed]           = useState(false);
  const [submitting, setSubmitting]   = useState(false);
  const [profileFound, setProfileFound] = useState(null);  // profile data if found
  const [prefilled, setPrefilled]     = useState(false);

  const upd  = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const updA = (k, v) => setAssets(a => ({ ...a, [k]: v }));

  const checkEmailForProfile = async () => {
    if (!form.email || prefilled) return;
    const result = await callFn("getArtistProfile", { email: form.email }).catch(() => null);
    if (result?.profile) setProfileFound(result.profile);
  };

  const applyProfile = () => {
    const p = profileFound;
    setForm(f => ({
      ...f,
      name:        p.name        || f.name,
      contactName: p.contactName || f.contactName,
      phone:       p.phone       || f.phone,
      payableTo:   p.payableTo   || f.payableTo,
      genre:       p.genre       || f.genre,
      bio:         p.bio         || f.bio,
      links:       p.links       || f.links,
    }));
    setAssets(a => ({
      ...a,
      instagram: p.instagram || a.instagram,
      spotify:   p.spotify   || a.spotify,
      website:   p.website   || a.website,
    }));
    setProfileFound(null);
    setPrefilled(true);
  };

  const isDateSelected = id  => selections.some(s => s.date.id === id);
  const getSlotForDate = id  => selections.find(s => s.date.id === id)?.slot || null;
  const toggleDate     = d   => {
    if (isDateSelected(d.id)) setSelections(prev => prev.filter(s => s.date.id !== d.id));
    else                       setSelections(prev => [...prev, { date: d, slot: null }]);
  };
  const setSlotForDate = (dateId, slot) =>
    setSelections(prev => prev.map(s => s.date.id === dateId ? { ...s, slot } : s));

  const canProceed0 = selections.length > 0 && selections.every(s => s.slot);

  const reset = () => {
    setSubmitted(false); setStep(0); setSelections([]);
    setForm({ name: "", contactName: "", genre: "", bio: "", email: "", emailConfirm: "", phone: "", draw: "", performers: "", pay: "", payableTo: "", links: "", sound: "" });
    setAssets({ logo: null, photo: null, instagram: "", spotify: "", website: "" });
    setAgreed(false); setSubmitting(false);
  };

  if (submitted) return (
    <div style={{ maxWidth: 560, margin: "60px auto", textAlign: "center", padding: "0 24px" }}>
      <div style={{ width: 56, height: 56, borderRadius: "50%", background: PALETTE.teal.bg, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 20px", border: `0.5px solid ${PALETTE.teal.border}` }}>
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 12l5 5L19 7" stroke={PALETTE.teal.text} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
      </div>
      <h2 style={{ fontSize: 22, fontWeight: 500, margin: "0 0 8px" }}>Request submitted</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15, lineHeight: 1.6 }}>
        We'll review your application for <strong>{selections.length} date{selections.length !== 1 ? "s" : ""}</strong> and be in touch at <strong>{form.email}</strong>. If approved, you'll receive a contract to sign electronically.
      </p>
      <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 6 }}>
        {selections.map(s => (
          <div key={s.date.id} style={{ display: "flex", gap: 8, justifyContent: "center" }}>
            <Badge color="purple">{s.date.label}</Badge>
            <Badge color="amber">{s.slot}</Badge>
          </div>
        ))}
      </div>
      <button onClick={reset} style={{ marginTop: 24, padding: "8px 20px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-primary)" }}>Submit another</button>
    </div>
  );

  return (
    <div style={{ maxWidth: 680, margin: "0 auto", padding: "32px 24px" }}>
      <div style={{ marginBottom: 28 }}>
        <h2 style={{ fontSize: 22, fontWeight: 500, margin: "0 0 6px" }}>Book a performance at {settings.venueName}</h2>
        <p style={{ color: "var(--color-text-secondary)", fontSize: 15, margin: "0 0 12px" }}>{settings.welcomeMessage}</p>
        <p style={{ fontSize: 13, color: PALETTE.amber.text, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, borderRadius: 8, padding: "10px 14px", margin: 0, lineHeight: 1.6 }}>
          <strong>Please complete all fields as thoroughly as possible.</strong> Submissions with missing or incomplete information are likely to be declined.
        </p>
      </div>

      <div style={{ display: "flex", gap: 8, marginBottom: 28, alignItems: "center", flexWrap: "wrap" }}>
        {steps.map((s, i) => (
          <div key={s} style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
              <div style={{ width: 24, height: 24, borderRadius: "50%", background: i <= step ? PALETTE.amber.bg : "var(--color-background-secondary)", border: `0.5px solid ${i <= step ? PALETTE.amber.border : "var(--color-border-tertiary)"}`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12, fontWeight: 500, color: i <= step ? PALETTE.amber.text : "var(--color-text-secondary)" }}>{i + 1}</div>
              <span style={{ fontSize: 13, color: i === step ? "var(--color-text-primary)" : "var(--color-text-secondary)", fontWeight: i === step ? 500 : 400 }}>{s}</span>
            </div>
            {i < steps.length - 1 && <div style={{ width: 20, height: 0.5, background: "var(--color-border-tertiary)" }} />}
          </div>
        ))}
      </div>

      {step === 0 && (
        <div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
            <p style={{ fontSize: 14, color: "var(--color-text-secondary)", margin: 0 }}>Select one or more dates and a time slot for each. You can apply for multiple dates in a single submission.</p>
            <button disabled={!canProceed0} onClick={() => setStep(1)} style={{ marginLeft: 16, flexShrink: 0, padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: canProceed0 ? PALETTE.amber.bg : "transparent", cursor: canProceed0 ? "pointer" : "not-allowed", fontSize: 14, color: canProceed0 ? PALETTE.amber.text : "var(--color-text-secondary)", fontWeight: 500 }}>Continue</button>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {dates.filter(d => d.status === "available").map(d => {
              const isAvail    = true;
              const isSelected = isDateSelected(d.id);
              const chosenSlot = getSlotForDate(d.id);
              return (
                <div key={d.id} onClick={() => { if (isAvail) toggleDate(d); }}
                  style={{ padding: "14px 16px", borderRadius: 12, border: `0.5px solid ${isSelected ? PALETTE.amber.border : "var(--color-border-tertiary)"}`, background: isSelected ? PALETTE.amber.bg : !isAvail ? "var(--color-background-tertiary)" : "var(--color-background-primary)", cursor: isAvail ? "pointer" : "default", opacity: !isAvail ? 0.55 : 1 }}>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: isAvail ? 10 : 0 }}>
                    <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
                      <span style={{ fontSize: 15, fontWeight: 500, color: "var(--color-text-primary)" }}>{d.label}</span>
                      {statusBadge(d.status)}
                    </div>
                    <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                      {isSelected && chosenSlot && <Badge color="teal">{chosenSlot} ✓</Badge>}
                      {isSelected && !chosenSlot && <span style={{ fontSize: 12, color: PALETTE.amber.text }}>Pick a time →</span>}
                      {isAvail && !isSelected && d.setLength && <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{d.setLength} set</span>}
                    </div>
                  </div>
                  {isAvail && (
                    <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                      {(d.slots || []).map(slot => (
                        <SlotPill key={slot} time={slot} selected={chosenSlot === slot}
                          onClick={e => {
                            e.stopPropagation();
                            if (!isDateSelected(d.id)) setSelections(prev => [...prev, { date: d, slot }]);
                            else setSlotForDate(d.id, slot);
                          }} />
                      ))}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          {selections.length > 0 && (
            <div style={{ marginTop: 14, padding: "10px 14px", borderRadius: 8, background: PALETTE.teal.bg, border: `0.5px solid ${PALETTE.teal.border}`, fontSize: 13, color: PALETTE.teal.text, display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
              <span style={{ fontWeight: 500 }}>{selections.length} date{selections.length !== 1 ? "s" : ""} selected:</span>
              {selections.map(s => (
                <span key={s.date.id}>{s.date.label}{s.slot ? ` at ${s.slot}` : " (no time yet)"}</span>
              ))}
            </div>
          )}
          <div style={{ marginTop: 16, display: "flex", justifyContent: "flex-end" }}>
            <button disabled={!canProceed0} onClick={() => setStep(1)} style={{ padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: canProceed0 ? PALETTE.amber.bg : "transparent", cursor: canProceed0 ? "pointer" : "not-allowed", fontSize: 14, color: canProceed0 ? PALETTE.amber.text : "var(--color-text-secondary)", fontWeight: 500 }}>Continue</button>
          </div>
        </div>
      )}

      {step === 1 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div style={{ padding: "10px 14px", borderRadius: 8, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, fontSize: 13, color: PALETTE.amber.text, display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center" }}>
            <span style={{ fontWeight: 500 }}>Requesting {selections.length} date{selections.length !== 1 ? "s" : ""}:</span>
            {selections.map((s, i) => (
              <span key={s.date.id}>{s.date.label} at {s.slot}{i < selections.length - 1 ? " ·" : ""}</span>
            ))}
          </div>
          {profileFound && (
            <div style={{ padding: "12px 14px", borderRadius: 8, background: PALETTE.teal.bg, border: `0.5px solid ${PALETTE.teal.border}`, fontSize: 13, color: PALETTE.teal.text, display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 }}>
              <span>👋 Welcome back, <strong>{profileFound.name}</strong>! Pre-fill your info from your saved profile?</span>
              <div style={{ display: "flex", gap: 8, flexShrink: 0 }}>
                <button onClick={applyProfile} style={{ padding: "5px 12px", borderRadius: 6, border: `0.5px solid ${PALETTE.teal.border}`, background: "var(--color-background-primary)", cursor: "pointer", fontSize: 12, color: PALETTE.teal.text, fontWeight: 500 }}>Yes, pre-fill</button>
                <button onClick={() => setProfileFound(null)} style={{ padding: "5px 12px", borderRadius: 6, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 12, color: "var(--color-text-secondary)" }}>No thanks</button>
              </div>
            </div>
          )}
          {(() => {
            const lengths = [...new Set(selections.map(s => s.date.setLength).filter(Boolean))];
            const payLabel = lengths.length === 1
              ? `Requested pay for a ${lengths[0]} set`
              : lengths.length > 1
                ? `Requested pay (your dates have varying set lengths: ${lengths.join(", ")})`
                : "Requested pay";
            return [
              ["Artist / Band name", "name", "text", null],
              ["Contact person (authorized representative)", "contactName", "text", null],
              ["Genre", "genre", "text", null],
              ["Contact email", "email", "email", null],
              ["Confirm email", "emailConfirm", "email", null],
              ["Phone number", "phone", "tel", null],
              ["Estimated draw (attendees)", "draw", "text", null],
              ["Number of performers", "performers", "number", null],
              [payLabel, "pay", "text", "e.g. $200 — enter a single amount"],
              ["Make payment payable to", "payableTo", "text", null],
            ].map(([label, key, type, hint]) => (
              <div key={key}>
                <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
                <input type={type} value={form[key]} onChange={e => upd(key, e.target.value)}
                  onBlur={key === "email" ? checkEmailForProfile : undefined}
                  placeholder={hint || ""}
                  style={{ width: "100%", boxSizing: "border-box", borderColor: key === "emailConfirm" && form.emailConfirm && form.email !== form.emailConfirm ? PALETTE.coral.border : undefined }} />
                {key === "emailConfirm" && form.emailConfirm && form.email !== form.emailConfirm && (
                  <p style={{ fontSize: 12, color: PALETTE.coral.text, margin: "4px 0 0" }}>Email addresses don't match.</p>
                )}
                {hint && <p style={{ fontSize: 12, color: "var(--color-text-secondary)", margin: "4px 0 0", opacity: 0.7 }}>Please enter one amount — not multiple rates for different set lengths.</p>}
              </div>
            ));
          })()}
          <div>
            <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Bio / description</label>
            <textarea value={form.bio} onChange={e => upd("bio", e.target.value)} rows={4} style={{ width: "100%", boxSizing: "border-box", padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
          </div>
          <div>
            <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Link to live performance video</label>
            <input value={form.links} onChange={e => upd("links", e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
          </div>
          <div style={{ padding: "14px 16px", borderRadius: 10, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-secondary)" }}>
            <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 4 }}>House sound system</div>
            <div style={{ fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 12, lineHeight: 1.5 }}>We provide a <strong style={{ color: "var(--color-text-primary)" }}>{settings.soundSystem}</strong> at no charge. Will you be using our system or bringing your own?</div>
            <div style={{ display: "flex", gap: 8 }}>
              {[["house", "Use house system"], ["own", "Bringing my own sound"]].map(([val, label]) => (
                <button key={val} onClick={() => upd("sound", val)}
                  style={{ flex: 1, padding: "8px 12px", borderRadius: 8, border: `0.5px solid ${form.sound === val ? PALETTE.teal.border : "var(--color-border-secondary)"}`, background: form.sound === val ? PALETTE.teal.bg : "var(--color-background-primary)", color: form.sound === val ? PALETTE.teal.text : "var(--color-text-primary)", fontSize: 13, fontWeight: form.sound === val ? 500 : 400, cursor: "pointer" }}>
                  {label}
                </button>
              ))}
            </div>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}>
            <button onClick={() => setStep(0)} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Back</button>
            {(() => {
              const ok = form.name && form.contactName && form.email && form.emailConfirm && form.email === form.emailConfirm && form.sound;
              return <button disabled={!ok} onClick={() => setStep(2)} style={{ padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: ok ? PALETTE.amber.bg : "transparent", cursor: ok ? "pointer" : "not-allowed", fontSize: 14, color: ok ? PALETTE.amber.text : "var(--color-text-secondary)", fontWeight: 500 }}>Continue</button>;
            })()}
          </div>
        </div>
      )}

      {step === 2 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <p style={{ fontSize: 14, color: "var(--color-text-secondary)", margin: "0 0 4px" }}>Upload your press kit assets. These are used for promotion once confirmed.</p>
          {[["Logo (PNG or SVG)", "logo", 2], ["Press photo", "photo", 5]].map(([label, key, maxMB]) => (
            <div key={key} style={{ padding: "20px", borderRadius: 10, border: "0.5px dashed var(--color-border-secondary)", textAlign: "center", background: "var(--color-background-secondary)" }}>
              <div style={{ fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 8 }}>{label} <span style={{ opacity: 0.6 }}>(max {maxMB}MB)</span></div>
              <input type="file" accept="image/*" onChange={e => {
                const file = e.target.files[0];
                if (file && file.size > maxMB * 1024 * 1024) {
                  alert(`${label} must be under ${maxMB}MB. Your file is ${(file.size / 1024 / 1024).toFixed(1)}MB.`);
                  e.target.value = "";
                  return;
                }
                updA(key, file || null);
              }} style={{ fontSize: 13 }} />
              {assets[key] && <div style={{ fontSize: 12, color: PALETTE.teal.text, marginTop: 6 }}>Selected: {assets[key].name}</div>}
            </div>
          ))}
          {[["Instagram handle", "instagram"], ["Spotify / streaming link", "spotify"], ["Website", "website"]].map(([label, key]) => (
            <div key={key}>
              <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
              <input value={assets[key]} onChange={e => updA(key, e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
            </div>
          ))}
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}>
            <button onClick={() => setStep(1)} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Back</button>
            <button onClick={() => setStep(3)} style={{ padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: PALETTE.amber.bg, cursor: "pointer", fontSize: 14, color: PALETTE.amber.text, fontWeight: 500 }}>Review</button>
          </div>
        </div>
      )}

      {step === 3 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 12, padding: "18px 20px" }}>
            <div style={{ fontSize: 13, fontWeight: 500, color: "var(--color-text-secondary)", marginBottom: 12, textTransform: "uppercase", letterSpacing: 0.5 }}>Review your submission</div>
            <div style={{ padding: "6px 0", borderBottom: "0.5px solid var(--color-border-tertiary)", marginBottom: 4 }}>
              <span style={{ fontSize: 13, color: "var(--color-text-secondary)" }}>Dates requested</span>
              <div style={{ display: "flex", flexDirection: "column", gap: 4, marginTop: 6 }}>
                {selections.map(s => (
                  <div key={s.date.id} style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                    <Badge color="purple">{s.date.label}</Badge>
                    <Badge color="amber">{s.slot}</Badge>
                    {s.date.setLength && <span style={{ fontSize: 12, color: "var(--color-text-secondary)", alignSelf: "center" }}>{s.date.setLength} set</span>}
                  </div>
                ))}
              </div>
            </div>
            {[["Artist / Band", form.name], ["Contact person", form.contactName], ["Genre", form.genre], ["Email", form.email], ["Phone", form.phone], ["Estimated draw", form.draw], ["Number of performers", form.performers], ["Requested pay", form.pay], ["Payment payable to", form.payableTo], ["Sound", form.sound === "house" ? "Using house system (Bose L1 Pro + 4-ch mixer)" : "Bringing own sound"]].map(([k, v]) => v && (
              <div key={k} style={{ display: "flex", justifyContent: "space-between", padding: "6px 0", borderBottom: "0.5px solid var(--color-border-tertiary)", fontSize: 14 }}>
                <span style={{ color: "var(--color-text-secondary)" }}>{k}</span>
                <span style={{ fontWeight: 500 }}>{v}</span>
              </div>
            ))}
          </div>
          <div style={{ padding: "14px 16px", borderRadius: 10, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-secondary)", fontSize: 13, color: "var(--color-text-secondary)", lineHeight: 1.6 }}>
            <strong style={{ color: "var(--color-text-primary)" }}>What happens next:</strong> We'll review within a few days. If approved, you'll receive an auto-filled contract for electronic signature confirming your date, time, and agreed pay.
          </div>
          <label style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: 14, cursor: "pointer" }}>
            <input type="checkbox" checked={agreed} onChange={e => setAgreed(e.target.checked)} style={{ marginTop: 2 }} />
            <span style={{ color: "var(--color-text-secondary)", lineHeight: 1.5 }}>I confirm all information is accurate and agree to be contacted by Medusa Brewing regarding this booking request.</span>
          </label>
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 4 }}>
            <button onClick={() => setStep(2)} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Back</button>
            <button disabled={!agreed || submitting} onClick={async () => {
              setSubmitting(true);
              try {
                const { storage, ref, uploadBytes, getDownloadURL } = window.__firebase;
                let logoUrl = null, photoUrl = null;
                if (assets.logo) {
                  const r = ref(storage, `press-kits/${Date.now()}-logo-${assets.logo.name}`);
                  await uploadBytes(r, assets.logo);
                  logoUrl = await getDownloadURL(r);
                }
                if (assets.photo) {
                  const r = ref(storage, `press-kits/${Date.now()}-photo-${assets.photo.name}`);
                  await uploadBytes(r, assets.photo);
                  photoUrl = await getDownloadURL(r);
                }
                const { emailConfirm: _ec, ...formData } = form;
                const result = await callFn("submitBookingBatch", {
                  formData,
                  dates:     selections.map(sel => ({
                    date:      sel.date.label,
                    dateRaw:   sel.date.date,
                    dateId:    sel.date.id,
                    slot:      sel.slot,
                    setLength: sel.date.setLength,
                  })),
                  instagram: assets.instagram,
                  spotify:   assets.spotify,
                  website:   assets.website,
                  logoUrl,
                  photoUrl,
                });
                if (result.success) setSubmitted(true);
              } catch (err) {
                console.error("Submission failed:", err);
              } finally {
                setSubmitting(false);
              }
            }} style={{ padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: agreed && !submitting ? PALETTE.teal.bg : "transparent", cursor: agreed && !submitting ? "pointer" : "not-allowed", fontSize: 14, color: agreed && !submitting ? PALETTE.teal.text : "var(--color-text-secondary)", fontWeight: 500 }}>
              {submitting ? "Submitting…" : "Submit request"}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function ContractModal({ sub, onClose, settings = DEFAULT_SETTINGS }) {
  const BASE_URL    = "https://booking.medusabrewing.com";
  const contractUrl = `${BASE_URL}?sign=true&id=${sub.id}`;
  const today       = new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
  const signedDate  = sub.contractSignedAt?.toDate?.()?.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 520, width: "90%", maxHeight: "85vh", overflowY: "auto" }}>
        <div style={{ fontSize: 18, fontWeight: 500, marginBottom: 6 }}>Performance agreement</div>
        <div style={{ fontSize: 13, marginBottom: 20 }}>
          {sub.contractSigned
            ? <span style={{ color: PALETTE.teal.text, fontWeight: 500 }}>Signed ✓ by {sub.contractSignedBy}{signedDate ? ` on ${signedDate}` : ""}</span>
            : <span style={{ color: PALETTE.amber.text }}>Awaiting artist signature</span>
          }
        </div>
        <div style={{ fontSize: 14, lineHeight: 1.8, color: "var(--color-text-primary)", background: "var(--color-background-secondary)", padding: "16px 18px", borderRadius: 10, border: "0.5px solid var(--color-border-tertiary)", marginBottom: 20 }}>
          <p style={{ margin: "0 0 10px" }}>This Performance Agreement is entered into as of <strong>{today}</strong> between <strong>{settings.venueName}</strong> ("Venue") and <strong>{sub.name}</strong> ("Artist"), represented by <strong>{sub.contactName || "authorized representative"}</strong>.</p>
          {sub.venue && <p style={{ margin: "0 0 8px" }}><strong>Venue:</strong> {settings.venues.find(v => v.id === sub.venue)?.label || sub.venue}</p>}
          <p style={{ margin: "0 0 8px" }}><strong>Set time:</strong> {sub.slot}</p>
          {sub.setLength && <p style={{ margin: "0 0 8px" }}><strong>Set length:</strong> {sub.setLength}</p>}
          <p style={{ margin: "0 0 8px" }}><strong>Performance fee:</strong> {sub.counterPay || sub.pay}</p>
          {sub.payableTo && <p style={{ margin: "0 0 8px" }}><strong>Payment payable to:</strong> {sub.payableTo}</p>}
          <p style={{ margin: "0 0 8px" }}><strong>Sound:</strong> {sub.sound === "house" ? "Artist will use house system (Bose L1 Pro + 4-channel mixer)" : "Artist will provide own sound system"}</p>
          <p style={{ margin: "12px 0 0", fontSize: 13, color: "var(--color-text-secondary)" }}>{settings.contractTerms}</p>
        </div>
        {!sub.contractSigned && (
          <div style={{ marginBottom: 20, padding: "12px 14px", borderRadius: 8, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}` }}>
            <div style={{ fontSize: 12, color: PALETTE.amber.text, fontWeight: 500, marginBottom: 4 }}>Signing link (send to artist)</div>
            <div style={{ fontSize: 12, color: PALETTE.amber.text, wordBreak: "break-all", fontFamily: "monospace" }}>{contractUrl}</div>
          </div>
        )}
        <div style={{ display: "flex", justifyContent: "flex-end" }}>
          <button onClick={onClose} style={{ padding: "8px 22px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-primary)" }}>Close</button>
        </div>
      </div>
    </div>
  );
}

function ContractSign({ submissionId, settings = DEFAULT_SETTINGS }) {
  const [sub, setSub] = useState(null);
  const [loading, setLoading] = useState(true);
  const [sig, setSig] = useState("");
  const [signing, setSigning] = useState(false);
  const [done, setDone] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const { db, doc, onSnapshot } = window.__firebase;
    return onSnapshot(
      doc(db, "submissions", submissionId),
      snap => { if (snap.exists()) setSub({ id: snap.id, ...snap.data() }); setLoading(false); },
      err  => { console.error(err); setLoading(false); }
    );
  }, [submissionId]);

  const today = new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });

  if (loading) return (
    <div style={{ textAlign: "center", padding: "80px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>Loading your agreement…</div>
  );

  if (!sub || sub.status !== "approved") return (
    <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15 }}>This contract link is no longer valid.</p>
    </div>
  );

  if (sub.contractSigned || done) return (
    <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
      <div style={{ width: 56, height: 56, borderRadius: "50%", background: PALETTE.teal.bg, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 20px", border: `0.5px solid ${PALETTE.teal.border}` }}>
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 12l5 5L19 7" stroke={PALETTE.teal.text} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
      </div>
      <h2 style={{ fontSize: 20, fontWeight: 500, margin: "0 0 10px" }}>Agreement signed</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15, lineHeight: 1.6 }}>
        Your performance agreement for <strong>{sub.date}</strong> at <strong>{sub.slot}</strong> has been signed. See you there!
      </p>
    </div>
  );

  // Normalize stored name and input — collapse internal spaces, trim edges
  const normalize = s => (s || "").trim().replace(/\s+/g, " ");
  const signAs  = normalize(sub.contactName || sub.name);
  const canSign = normalize(sig).toLowerCase() === signAs.toLowerCase() && !signing;

  return (
    <div style={{ maxWidth: 560, margin: "40px auto", padding: "0 24px" }}>
      <h2 style={{ fontSize: 22, fontWeight: 500, margin: "0 0 8px" }}>Performance agreement</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 14, margin: "0 0 24px" }}>Review and sign your agreement with Medusa Brewing.</p>
      <div style={{ fontSize: 14, lineHeight: 1.8, color: "var(--color-text-primary)", background: "var(--color-background-secondary)", padding: "16px 18px", borderRadius: 10, border: "0.5px solid var(--color-border-tertiary)", marginBottom: 24 }}>
        <p style={{ margin: "0 0 12px" }}>This Performance Agreement is entered into as of <strong>{today}</strong> between <strong>{settings.venueName}</strong> ("Venue") and <strong>{sub.name}</strong> ("Artist"), represented by <strong>{sub.contactName || "authorized representative"}</strong>.</p>
        <p style={{ margin: "0 0 8px" }}><strong>Date:</strong> {sub.date}</p>
        <p style={{ margin: "0 0 8px" }}><strong>Set time:</strong> {sub.slot}</p>
        {sub.setLength && <p style={{ margin: "0 0 8px" }}><strong>Set length:</strong> {sub.setLength}</p>}
        <p style={{ margin: "0 0 8px" }}><strong>Performance fee:</strong> {sub.counterPay || sub.pay}</p>
        {sub.payableTo && <p style={{ margin: "0 0 8px" }}><strong>Payment payable to:</strong> {sub.payableTo}</p>}
        <p style={{ margin: "0 0 8px" }}><strong>Sound:</strong> {sub.sound === "house" ? "Artist will use house system (Bose L1 Pro + 4-channel mixer)" : "Artist will provide own sound system"}</p>
        <p style={{ margin: "12px 0 0", fontSize: 13, color: "var(--color-text-secondary)" }}>{settings.contractTerms}</p>
      </div>
      <div style={{ marginBottom: 20 }}>
        <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 6 }}>
          To sign, type your full name exactly as shown: <strong style={{ color: "var(--color-text-primary)" }}>{signAs}</strong>
        </label>
        <input
          value={sig}
          onChange={e => { setSig(e.target.value); setError(null); }}
          placeholder={`Type "${signAs}" here`}
          style={{ width: "100%", boxSizing: "border-box", fontStyle: "italic" }}
          autoFocus
        />
        {sig && !canSign && !signing && (
          <p style={{ fontSize: 12, color: PALETTE.amber.text, marginTop: 6 }}>Name doesn't match yet — type it exactly as shown above.</p>
        )}
        {!sig && (
          <p style={{ fontSize: 12, color: "var(--color-text-secondary)", marginTop: 6, opacity: 0.7 }}>👆 Type your name above to activate the Sign button below.</p>
        )}
        {error && <p style={{ fontSize: 13, color: PALETTE.coral.text, marginTop: 6 }}>{error}</p>}
      </div>
      <button disabled={!canSign} onClick={async () => {
        setSigning(true);
        setError(null);
        try {
          const result = await callFn("signContract", { id: submissionId, signedBy: normalize(sig) });
          if (result.success) setDone(true);
          else setError("Something went wrong. Please try again.");
        } catch { setError("Something went wrong. Please try again."); }
        setSigning(false);
      }} style={{ width: "100%", padding: "11px 22px", borderRadius: 8, border: `0.5px solid ${canSign ? PALETTE.teal.border : "var(--color-border-tertiary)"}`, background: canSign ? PALETTE.teal.bg : "transparent", cursor: canSign ? "pointer" : "not-allowed", fontSize: 14, color: canSign ? PALETTE.teal.text : "var(--color-text-secondary)", fontWeight: 500 }}>
        {signing ? "Signing…" : "Sign agreement"}
      </button>
    </div>
  );
}

function EditProfileModal({ profile, onSave, onClose }) {
  const isNew = !profile;
  const [form, setForm] = useState({
    name: profile?.name || "", contactName: profile?.contactName || "",
    email: profile?.email || "", phone: profile?.phone || "",
    payableTo: profile?.payableTo || "", genre: profile?.genre || "",
    bio: profile?.bio || "", instagram: profile?.instagram || "",
    spotify: profile?.spotify || "", website: profile?.website || "",
    links: profile?.links || "",
  });
  const [saving, setSaving] = useState(false);
  const [error, setError]   = useState(null);
  const upd = (k, v) => setForm(f => ({ ...f, [k]: v }));

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100, overflowY: "auto", padding: "24px 0" }}>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 14, padding: "28px 32px", maxWidth: 500, width: "90%" }}>
        <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 20 }}>{isNew ? "Create artist profile" : `Edit profile — ${profile.name}`}</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12, marginBottom: 20 }}>
          {[["Artist / Band name", "name", "text"], ["Contact person", "contactName", "text"], ["Email address", "email", "email"], ["Phone", "phone", "tel"], ["Payment payable to", "payableTo", "text"], ["Genre", "genre", "text"]].map(([label, key, type]) => (
            <div key={key}>
              <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}{key === "email" && isNew ? " *" : ""}</label>
              <input type={type} value={form[key]} onChange={e => upd(key, e.target.value)} disabled={key === "email" && !isNew} style={{ width: "100%", boxSizing: "border-box", opacity: key === "email" && !isNew ? 0.6 : 1 }} />
            </div>
          ))}
          <div>
            <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Bio</label>
            <textarea value={form.bio} onChange={e => upd("bio", e.target.value)} rows={3} style={{ width: "100%", boxSizing: "border-box", padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
          </div>
          {[["Instagram", "instagram"], ["Spotify", "spotify"], ["Website", "website"], ["Performance video link", "links"]].map(([label, key]) => (
            <div key={key}>
              <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
              <input value={form[key]} onChange={e => upd(key, e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
            </div>
          ))}
        </div>
        {error && <p style={{ fontSize: 13, color: PALETTE.coral.text, margin: "0 0 12px" }}>{error}</p>}
        <div style={{ display: "flex", justifyContent: "space-between" }}>
          <button onClick={onClose} style={{ padding: "8px 18px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 14, color: "var(--color-text-secondary)" }}>Cancel</button>
          <button disabled={saving || (!form.name && isNew) || (!form.email && isNew)} onClick={async () => {
            if (isNew && !form.email) { setError("Email is required."); return; }
            setSaving(true); setError(null);
            const { email, ...profileData } = form;
            const result = await callFn("upsertArtistProfile", { email: isNew ? email : profile.email, profileData }).catch(() => null);
            if (result?.success) onSave();
            else setError("Failed to save. Try again.");
            setSaving(false);
          }} style={{ padding: "8px 22px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: saving ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.teal.text, fontWeight: 500 }}>
            {saving ? "Saving…" : isNew ? "Create profile" : "Save changes"}
          </button>
        </div>
      </div>
    </div>
  );
}

function ArtistsTab({ subs }) {
  const [profiles, setProfiles]   = useState([]);
  const [loading, setLoading]     = useState(true);
  const [search, setSearch]       = useState("");
  const [filter, setFilter]       = useState("all"); // all | starred | booked | never-booked
  const [expanded, setExpanded]   = useState(null);
  const [editProfile, setEditProfile] = useState(undefined); // undefined = closed, null = new, obj = edit
  const [migrating, setMigrating] = useState(false);
  const [migrateMsg, setMigrateMsg] = useState(null);

  useEffect(() => {
    const { db, collection, onSnapshot, query, orderBy } = window.__firebase;
    const q = query(collection(db, "profiles"), orderBy("name"));
    return onSnapshot(q, snap => {
      setProfiles(snap.docs.map(d => ({ id: d.id, ...d.data() })));
      setLoading(false);
    }, console.error);
  }, []);

  const toggleStar = p => {
    callFn("upsertArtistProfile", { email: p.email, profileData: { starred: !p.starred } }).catch(console.error);
  };

  // Pre-compute booked emails as a Set → O(1) lookup instead of O(n) per profile
  const bookedEmailSet = useMemo(
    () => new Set(subs.filter(s => s.status === "approved").map(s => (s.email || "").toLowerCase())),
    [subs]
  );
  const hasBooking = p => bookedEmailSet.has(p.email);

  const filtered = profiles
    .filter(p => [p.name, p.email, p.genre, p.contactName].some(v => (v || "").toLowerCase().includes(search.toLowerCase())))
    .filter(p =>
      filter === "starred"      ? !!p.starred :
      filter === "booked"       ? hasBooking(p) :
      filter === "never-booked" ? !hasBooking(p) : true
    )
    .sort((a, b) => {
      if (a.starred && !b.starred) return -1;
      if (!a.starred && b.starred)  return 1;
      return (a.name || "").localeCompare(b.name || "");
    });

  const migrate = async () => {
    if (!window.confirm("Build profiles from all existing submissions? This will create or update a profile for every artist who has submitted a booking.")) return;
    setMigrating(true); setMigrateMsg(null);
    const result = await callFn("migrateProfiles", {}).catch(() => null);
    setMigrateMsg(result?.success ? `Done — ${result.profilesCreated} profile${result.profilesCreated !== 1 ? "s" : ""} created or updated.` : "Migration failed. Check logs.");
    setMigrating(false);
  };

  return (
    <div>
      {editProfile !== undefined && (
        <EditProfileModal profile={editProfile} onSave={() => setEditProfile(undefined)} onClose={() => setEditProfile(undefined)} />
      )}

      {/* Toolbar */}
      <div style={{ display: "flex", gap: 10, marginBottom: 12, flexWrap: "wrap", alignItems: "center" }}>
        <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search by name, email, genre…" style={{ flex: 1, minWidth: 200 }} />
        <button onClick={() => setEditProfile(null)} style={{ padding: "7px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: "pointer", fontSize: 13, color: PALETTE.teal.text, fontWeight: 500 }}>+ Create profile</button>
        <button onClick={migrate} disabled={migrating} style={{ padding: "7px 16px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: "transparent", cursor: migrating ? "not-allowed" : "pointer", fontSize: 13, color: "var(--color-text-secondary)" }}>
          {migrating ? "Importing…" : "Import from submissions"}
        </button>
      </div>
      {/* Filter pills */}
      <div style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" }}>
        {[["all", "All"], ["starred", "⭐ Starred"], ["booked", "Has been booked"], ["never-booked", "Never booked"]].map(([val, label]) => (
          <button key={val} onClick={() => setFilter(val)}
            style={{ padding: "5px 14px", borderRadius: 20, border: `0.5px solid ${filter === val ? "var(--color-border-primary)" : "var(--color-border-tertiary)"}`, background: filter === val ? "var(--color-background-secondary)" : "transparent", fontSize: 13, cursor: "pointer", fontWeight: filter === val ? 500 : 400, color: "var(--color-text-primary)" }}>
            {label}
            <span style={{ marginLeft: 5, fontSize: 11, opacity: 0.6 }}>
              {val === "all" ? profiles.length : val === "starred" ? profiles.filter(p => !!p.starred).length : val === "booked" ? profiles.filter(p => hasBooking(p)).length : profiles.filter(p => !hasBooking(p)).length}
            </span>
          </button>
        ))}
      </div>
      {migrateMsg && <div style={{ padding: "10px 14px", borderRadius: 8, background: PALETTE.teal.bg, border: `0.5px solid ${PALETTE.teal.border}`, fontSize: 13, color: PALETTE.teal.text, marginBottom: 14 }}>{migrateMsg}</div>}

      {loading && <div style={{ textAlign: "center", padding: "40px", color: "var(--color-text-secondary)", fontSize: 14 }}>Loading profiles…</div>}
      {!loading && filtered.length === 0 && (
        <div style={{ textAlign: "center", padding: "40px", color: "var(--color-text-secondary)", fontSize: 14 }}>
          {profiles.length === 0 ? "No profiles yet. Click \"Import from submissions\" to build them from existing bookings." : "No profiles match your search."}
        </div>
      )}

      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {filtered.map(p => {
          const profileSubs = subs.filter(s => (s.email || "").toLowerCase() === p.email);
          const approved    = profileSubs.filter(s => s.status === "approved");
          const isOpen      = expanded === p.id;
          return (
            <div key={p.id} style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 12, overflow: "hidden" }}>
              {/* Header row */}
              <div style={{ display: "flex", alignItems: "center" }}>
                <button onClick={e => { e.stopPropagation(); toggleStar(p); }}
                  style={{ padding: "14px 10px 14px 16px", background: "none", border: "none", cursor: "pointer", fontSize: 18, lineHeight: 1, flexShrink: 0 }}
                  title={p.starred ? "Remove star" : "Star this artist"}>
                  {p.starred ? "⭐" : "☆"}
                </button>
              <div onClick={() => setExpanded(isOpen ? null : p.id)} style={{ flex: 1, display: "flex", justifyContent: "space-between", alignItems: "center", padding: "14px 18px 14px 0", cursor: "pointer" }}>
                <div>
                  <div style={{ fontSize: 15, fontWeight: 500, marginBottom: 4 }}>{p.name || <span style={{ opacity: 0.4 }}>No name</span>}</div>
                  <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
                    {p.genre && <Badge color="gray">{p.genre}</Badge>}
                    <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{p.email}</span>
                  </div>
                </div>
                <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
                  <div style={{ textAlign: "right" }}>
                    <div style={{ fontSize: 13, fontWeight: 500, color: "var(--color-text-primary)" }}>{profileSubs.length} submission{profileSubs.length !== 1 ? "s" : ""}</div>
                    {approved.length > 0 && <div style={{ fontSize: 12, color: PALETTE.teal.text }}>{approved.length} booked</div>}
                  </div>
                  <span style={{ fontSize: 16, color: "var(--color-text-secondary)" }}>{isOpen ? "▲" : "▼"}</span>
                </div>
              </div>
              </div>

              {isOpen && (
                <div style={{ padding: "0 18px 18px", borderTop: "0.5px solid var(--color-border-tertiary)" }}>
                  {/* Profile details */}
                  <div style={{ display: "flex", gap: 24, flexWrap: "wrap", padding: "14px 0 12px", fontSize: 13 }}>
                    {[["Rep", p.contactName], ["Phone", p.phone], ["Payable to", p.payableTo]].map(([k, v]) => v ? (
                      <span key={k}><span style={{ color: "var(--color-text-secondary)" }}>{k}: </span>{v}</span>
                    ) : null)}
                  </div>
                  {p.bio && <p style={{ fontSize: 13, color: "var(--color-text-secondary)", margin: "0 0 12px", lineHeight: 1.5 }}>{p.bio}</p>}
                  <div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginBottom: 14 }}>
                    {p.instagram && <a href={`https://instagram.com/${p.instagram.replace("@","")}`} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.teal.text }}>Instagram</a>}
                    {p.spotify   && <a href={extUrl(p.spotify)}   target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.teal.text }}>Spotify</a>}
                    {p.website   && <a href={extUrl(p.website)}   target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.teal.text }}>Website</a>}
                    {p.links     && <a href={extUrl(p.links)}     target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.teal.text }}>Performance video</a>}
                    {p.logoUrl   && <a href={p.logoUrl}   target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.purple.text, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg, padding: "2px 8px", borderRadius: 6, textDecoration: "none" }}>Logo</a>}
                    {p.photoUrl  && <a href={p.photoUrl}  target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.purple.text, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg, padding: "2px 8px", borderRadius: 6, textDecoration: "none" }}>Press photo</a>}
                  </div>

                  {/* Booking history — split into upcoming and past */}
                  {profileSubs.length > 0 && (() => {
                    const today    = new Date().toISOString().split("T")[0];
                    const upcoming = profileSubs.filter(s => s.status === "approved" && (s.dateRaw || "") >= today).sort((a, b) => (a.dateRaw || "").localeCompare(b.dateRaw || ""));
                    const rest     = profileSubs.filter(s => !(s.status === "approved" && (s.dateRaw || "") >= today)).sort((a, b) => (b.dateRaw || "").localeCompare(a.dateRaw || ""));
                    const row = s => (
                      <div key={s.id} style={{ display: "flex", gap: 8, alignItems: "center", fontSize: 13, flexWrap: "wrap" }}>
                        {statusBadge(s.status)}
                        <span style={{ fontWeight: 500 }}>{s.date}</span>
                        {s.slot && <span style={{ color: "var(--color-text-secondary)" }}>{s.slot}</span>}
                        {(s.counterPay || s.pay) && <span style={{ color: "var(--color-text-secondary)" }}>{s.counterPay || s.pay}</span>}
                      </div>
                    );
                    return (
                      <div style={{ marginBottom: 14 }}>
                        {upcoming.length > 0 && (
                          <>
                            <div style={{ fontSize: 12, fontWeight: 500, color: PALETTE.teal.text, marginBottom: 8, textTransform: "uppercase", letterSpacing: 0.4 }}>Upcoming bookings</div>
                            <div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 12, padding: "10px 12px", background: PALETTE.teal.bg, borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}` }}>
                              {upcoming.map(row)}
                            </div>
                          </>
                        )}
                        {rest.length > 0 && (
                          <>
                            <div style={{ fontSize: 12, fontWeight: 500, color: "var(--color-text-secondary)", marginBottom: 8, textTransform: "uppercase", letterSpacing: 0.4 }}>History</div>
                            <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>{rest.map(row)}</div>
                          </>
                        )}
                      </div>
                    );
                  })()}

                  <div style={{ display: "flex", gap: 8 }}>
                    <button onClick={() => setEditProfile(p)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.amber.border}`, background: PALETTE.amber.bg, cursor: "pointer", fontSize: 13, color: PALETTE.amber.text, fontWeight: 500 }}>Edit profile</button>
                    <button onClick={async () => {
                      if (!window.confirm(`Delete ${p.name || p.email}'s profile? Their submission history will be preserved.`)) return;
                      await callFn("deleteArtistProfile", { email: p.email }).catch(console.error);
                    }} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: "transparent", cursor: "pointer", fontSize: 13, color: PALETTE.coral.text }}>Delete profile</button>
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function OverviewTab({ dates, subs, setTab, resendContract, onReviewDate }) {
  const [filter, setFilter]   = useState("all");
  const [sentId, setSentId]   = useState(null);

  const handleResendContract = id => {
    resendContract(id);
    setSentId(id);
    setTimeout(() => setSentId(s => s === id ? null : s), 3000);
  };

  const today = new Date(); today.setHours(0, 0, 0, 0);

  const enriched = useMemo(() => dates
    .filter(d => new Date(d.date + "T12:00:00") >= today)
    .map(d => {
      const daysUntil    = Math.round((new Date(d.date + "T12:00:00") - today) / 86400000);
      const pending      = subs.filter(s => s.dateId === d.id && s.status === "pending");
      const approvedSub  = subs.find(s => s.dateId === d.id && (s.status === "approved" || s.status === "countered"));
      const isBooked     = d.status === "booked" || !!approvedSub;
      const tier         = isBooked ? "booked" : daysUntil <= 14 ? "urgent" : daysUntil <= 30 ? "soon" : "later";
      return { ...d, daysUntil, pending, approvedSub, isBooked, tier };
    })
    .sort((a, b) => a.date.localeCompare(b.date))
  , [dates, subs]);

  const filtered = enriched.filter(d =>
    filter === "needs-booking" ? !d.isBooked :
    filter === "has-pending"   ? d.pending.length > 0 :
    filter === "booked"        ? d.isBooked : true
  );

  const unsignedContracts = subs
    .filter(s => s.status === "approved" && !s.contractSigned)
    .map(s => ({
      ...s,
      daysUntil: s.dateRaw ? Math.round((new Date(s.dateRaw + "T12:00:00") - today) / 86400000) : null,
    }))
    .sort((a, b) => (a.dateRaw || "").localeCompare(b.dateRaw || ""));

  const urgentCount  = enriched.filter(d => d.tier === "urgent").length;
  const soonCount    = enriched.filter(d => d.tier === "soon").length;
  const pendingDates = enriched.filter(d => d.pending.length > 0 && !d.isBooked).length;

  const TIERS = [
    { key: "urgent", label: "Needs booking soon", sub: "less than 2 weeks away", palette: PALETTE.coral },
    { key: "soon",   label: "Coming up",          sub: "2–4 weeks away",         palette: PALETTE.amber },
    { key: "later",  label: "Further out",        sub: "4+ weeks away",          palette: { bg: "#F0FAF5", border: "#2D9B6F", text: "#1A5C3E" } },
    { key: "booked", label: "Booked",             sub: null,                     palette: PALETTE.teal },
  ];

  const dayName = dateStr => new Date(dateStr + "T12:00:00").toLocaleDateString("en-US", { weekday: "short" });
  const dateFmt = dateStr => new Date(dateStr + "T12:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric" });

  return (
    <div>
      {/* Outstanding agreements */}
      {unsignedContracts.length > 0 && (
        <div style={{ marginBottom: 24 }}>
          <div style={{ fontSize: 13, fontWeight: 500, color: PALETTE.amber.text, marginBottom: 10, display: "flex", alignItems: "center", gap: 6 }}>
            ✍️ Outstanding agreements
            <span style={{ fontSize: 12, fontWeight: 400, opacity: 0.8 }}>— {unsignedContracts.length} booking{unsignedContracts.length !== 1 ? "s" : ""} awaiting signature</span>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {unsignedContracts.map(s => (
              <div key={s.id} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 16px", borderRadius: 10, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, flexWrap: "wrap", gap: 10 }}>
                <div>
                  <span style={{ fontSize: 14, fontWeight: 500, color: PALETTE.amber.text }}>{s.name}</span>
                  <span style={{ fontSize: 13, color: PALETTE.amber.text, opacity: 0.85, marginLeft: 10 }}>{s.date}{s.slot ? ` at ${s.slot}` : ""}</span>
                  {s.daysUntil !== null && (
                    <span style={{ fontSize: 12, color: PALETTE.amber.text, opacity: 0.7, marginLeft: 8 }}>({s.daysUntil === 0 ? "today" : s.daysUntil === 1 ? "tomorrow" : `${s.daysUntil} days`})</span>
                  )}
                </div>
                {(() => {
                  const sent = sentId === s.id;
                  return (
                    <button onClick={() => handleResendContract(s.id)} style={{ padding: "5px 14px", borderRadius: 8, border: `0.5px solid ${sent ? PALETTE.teal.border : PALETTE.amber.border}`, background: sent ? PALETTE.teal.bg : "var(--color-background-primary)", cursor: "pointer", fontSize: 12, color: sent ? PALETTE.teal.text : PALETTE.amber.text, fontWeight: 500, whiteSpace: "nowrap" }}>
                      {sent ? "Sent ✓" : "Resend contract →"}
                    </button>
                  );
                })()}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Summary bar */}
      {(urgentCount > 0 || pendingDates > 0) && (
        <div style={{ padding: "12px 16px", borderRadius: 10, background: PALETTE.coral.bg, border: `0.5px solid ${PALETTE.coral.border}`, marginBottom: 20, fontSize: 14, color: PALETTE.coral.text, display: "flex", flexWrap: "wrap", gap: 16, alignItems: "center" }}>
          {urgentCount > 0 && <span>⚠ <strong>{urgentCount}</strong> open date{urgentCount !== 1 ? "s" : ""} need{urgentCount === 1 ? "s" : ""} booking within 2 weeks</span>}
          {soonCount  > 0 && <span>· <strong>{soonCount}</strong> more in the next month</span>}
          {pendingDates > 0 && <span>· <strong>{pendingDates}</strong> date{pendingDates !== 1 ? "s" : ""} with pending requests</span>}
        </div>
      )}

      {/* Filter pills */}
      <div style={{ display: "flex", gap: 8, marginBottom: 20, flexWrap: "wrap" }}>
        {[["all", "All upcoming"], ["needs-booking", "Needs booking"], ["has-pending", "Has pending"], ["booked", "Booked"]].map(([val, label]) => (
          <button key={val} onClick={() => setFilter(val)}
            style={{ padding: "5px 14px", borderRadius: 20, border: `0.5px solid ${filter === val ? "var(--color-border-primary)" : "var(--color-border-tertiary)"}`, background: filter === val ? "var(--color-background-secondary)" : "transparent", fontSize: 13, cursor: "pointer", fontWeight: filter === val ? 500 : 400, color: "var(--color-text-primary)" }}>
            {label}
            <span style={{ marginLeft: 6, fontSize: 11, opacity: 0.6 }}>
              {val === "all" ? enriched.length : val === "needs-booking" ? enriched.filter(d => !d.isBooked).length : val === "has-pending" ? enriched.filter(d => d.pending.length > 0).length : enriched.filter(d => d.isBooked).length}
            </span>
          </button>
        ))}
      </div>

      {filtered.length === 0 && (
        <div style={{ textAlign: "center", padding: "48px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>No dates match this filter.</div>
      )}

      {/* Grouped tiers */}
      {TIERS.map(({ key, label, sub, palette }) => {
        const items = filtered.filter(d => d.tier === key);
        if (!items.length) return null;
        return (
          <div key={key} style={{ marginBottom: 28 }}>
            <div style={{ display: "flex", alignItems: "baseline", gap: 8, marginBottom: 12 }}>
              <span style={{ fontSize: 13, fontWeight: 500, color: palette.text }}>{label}</span>
              {sub && <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{sub}</span>}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(170px, 1fr))", gap: 10 }}>
              {items.map(d => (
                <div key={d.id} style={{ borderRadius: 12, border: `0.5px solid ${palette.border}`, background: "var(--color-background-primary)", overflow: "hidden" }}>
                  {/* Coloured top bar */}
                  <div style={{ background: palette.bg, padding: "8px 12px", borderBottom: `0.5px solid ${palette.border}` }}>
                    <div style={{ fontSize: 11, fontWeight: 600, color: palette.text, textTransform: "uppercase", letterSpacing: 0.5 }}>
                      {d.isBooked ? "✓ Booked" : d.daysUntil === 0 ? "Today" : d.daysUntil === 1 ? "Tomorrow" : `${d.daysUntil} days`}
                    </div>
                  </div>
                  {/* Card body */}
                  <div style={{ padding: "10px 12px" }}>
                    <div style={{ fontSize: 11, color: "var(--color-text-secondary)", marginBottom: 2 }}>{dayName(d.date)}</div>
                    <div style={{ fontSize: 16, fontWeight: 500, color: "var(--color-text-primary)", marginBottom: 8 }}>{dateFmt(d.date)}</div>
                    {d.isBooked && d.approvedSub ? (
                      <div>
                        <div style={{ fontSize: 13, fontWeight: 500, color: "var(--color-text-primary)" }}>{d.approvedSub.name}</div>
                        <div style={{ fontSize: 12, color: "var(--color-text-secondary)", marginTop: 2 }}>
                          {d.approvedSub.slot}{d.approvedSub.counterPay || d.approvedSub.pay ? ` · ${d.approvedSub.counterPay || d.approvedSub.pay}` : ""}
                        </div>
                      </div>
                    ) : d.pending.length > 0 ? (
                      <div>
                        <div style={{ fontSize: 12, color: PALETTE.blue.text, fontWeight: 500 }}>{d.pending.length} pending request{d.pending.length !== 1 ? "s" : ""}</div>
                        <button onClick={() => onReviewDate(d.id, d.label)} style={{ marginTop: 6, fontSize: 11, padding: "3px 8px", borderRadius: 6, border: `0.5px solid ${PALETTE.blue.border}`, background: PALETTE.blue.bg, cursor: "pointer", color: PALETTE.blue.text }}>Review →</button>
                      </div>
                    ) : (
                      <div style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>No requests yet</div>
                    )}
                  </div>
                </div>
              ))}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function AdminDashboard({ dates, setDates, onSignOut, settings = DEFAULT_SETTINGS }) {
  const [subs, setSubs] = useState([]);
  const [tab, setTab] = useState("submissions");
  const [activeFilter, setActiveFilter] = useState(null);
  const [dateIdFilter, setDateIdFilter] = useState(null); // { dateId, label } — set from Overview "Review" button
  const [searchQuery, setSearchQuery]   = useState("");
  const [sortBy, setSortBy]             = useState("newest");
  const [contract, setContract] = useState(null);
  const [counterOfferSub, setCounterOfferSub] = useState(null);
  const [approveSubs, setApproveSubs]         = useState(null); // array of subs pending approval confirm
  const [declineSubs, setDeclineSubs]         = useState(null); // array of subs pending decline confirm
  const [editSub, setEditSub]                 = useState(null);
  const [selectedSubIds, setSelectedSubIds]   = useState(new Set());
  const [sentFeedback, setSentFeedback]       = useState(null); // { id, type }
  const [newDateY, setNewDateY] = useState("");
  const [newDateM, setNewDateM] = useState("");
  const [newDateD, setNewDateD] = useState("");
  const [bulkMonth, setBulkMonth]   = useState(() => { const d = new Date(); d.setMonth(d.getMonth() + 1); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`; });
  const [bulkDays, setBulkDays]     = useState([5, 6]); // Fri, Sat default
  const [bulkAdding, setBulkAdding] = useState(false);
  const [bulkConfirm, setBulkConfirm] = useState(false);
  const [expandedDate, setExpandedDate] = useState(null);
  const [defaultSlots, setDefaultSlots] = useState(["5:00 PM", "8:00 PM"]);
  const [defaultVenues, setDefaultVenues] = useState(["taproom"]);
  const [defaultSetLength, setDefaultSetLength] = useState("3 hours");
  const [applyConfirm, setApplyConfirm]         = useState(false);
  const [selectedDateIds, setSelectedDateIds]   = useState(new Set());
  const [calendarFilter, setCalendarFilter]     = useState("all");

  useEffect(() => {
    const { db, collection, onSnapshot, query, orderBy } = window.__firebase;
    const q = query(collection(db, "submissions"), orderBy("createdAt", "desc"));
    return onSnapshot(
      q,
      snap => { setSubs(snap.docs.map(d => ({ id: d.id, ...d.data() }))); },
      err  => { console.error("Submissions listener error:", err); }
    );
  }, []);

  const approve = async id => {
    const sub = subs.find(s => s.id === id);
    if (sub?.dateId && isDateEffectivelyBooked(sub.dateId, id)) {
      if (!window.confirm("⚠ This date already has an approved booking. Approving this will create a double-booking on the calendar. Continue anyway?")) return;
    }
    setSubs(s => s.map(x => x.id === id ? { ...x, status: "approved" } : x));
    await callFn("updateSubmission", { id, status: "approved" });
    // Update Google Calendar
    if (sub?.dateId) {
      setDates(prev => prev.map(d => {
        if (d.id !== sub.dateId) return d;
        const remaining = (d.slots || []).filter(s => s !== sub.slot);
        // If other slots remain, keep the date available with those slots
        if (remaining.length > 0) return { ...d, slots: remaining };
        // All slots taken — mark as fully booked
        return { ...d, status: "booked", artist: sub.name };
      }));
      callFn("blockDate", {
        eventId:     sub.dateId,
        artistName:  sub.name,
        pay:         sub.counterPay || sub.pay,
        slot:        sub.slot,
        setLength:   sub.setLength,
        dateRaw:     sub.dateRaw,
        contactName: sub.contactName,
        phone:       sub.phone,
        email:       sub.email,
        payableTo:   sub.payableTo,
        genre:       sub.genre,
        draw:        sub.draw,
        sound:       sub.sound,
        bio:         sub.bio,
      }).catch(console.error);
    }
    // Email artist (fire-and-forget, respects notification settings)
    if (sub?.email && settings.notifications.artistApproval) {
      callFn("sendArtistEmail", {
        type: "approved", to: sub.email, name: sub.name,
        date: sub.date, slot: sub.slot, pay: sub.counterPay || sub.pay,
        sound: sub.sound, setLength: sub.setLength,
        submissionId: id,
        dateRaw: sub.dateRaw,
        venue:   sub.venue,
      }).catch(console.error);
    }
  };

  const decline = async (id, message = null) => {
    const sub = subs.find(s => s.id === id);
    setSubs(s => s.map(x => x.id === id ? { ...x, status: "declined" } : x));
    await callFn("updateSubmission", { id, status: "declined" });
    if (message !== null && sub?.email && settings.notifications.artistDecline) {
      callFn("sendArtistEmail", {
        type: "declined", to: sub.email, name: sub.name, date: sub.date,
        declineMessage: message,
      }).catch(console.error);
    }
  };

  const saveContactEdit = async (id, fields) => {
    setSubs(s => s.map(x => x.id === id ? { ...x, ...fields } : x));
    await callFn("updateSubmission", { id, ...fields });
  };

  const showSent = (id, type) => {
    setSentFeedback({ id, type });
    setTimeout(() => setSentFeedback(f => f?.id === id && f?.type === type ? null : f), 3000);
  };

  const resendContract = async id => {
    const sub = subs.find(s => s.id === id);
    if (!sub?.email) return;
    callFn("sendArtistEmail", {
      type: "contract_reminder", to: sub.email, name: sub.name,
      date: sub.date, slot: sub.slot, submissionId: id,
    }).catch(console.error);
    showSent(id, "contract");
  };

  const resendConfirmation = async id => {
    const sub = subs.find(s => s.id === id);
    if (!sub?.email) return;
    callFn("sendArtistEmail", {
      type: "approved", to: sub.email, name: sub.name,
      date: sub.date, slot: sub.slot, pay: sub.counterPay || sub.pay,
      sound: sub.sound, setLength: sub.setLength,
      submissionId: id, dateRaw: sub.dateRaw, venue: sub.venue,
    }).catch(console.error);
    showSent(id, "confirmation");
  };

  const submitCounterOffer = async (id, counterPay, counterMessage) => {
    const sub = subs.find(s => s.id === id);
    setSubs(s => s.map(x => x.id === id ? { ...x, status: "countered", counterPay, counterMessage } : x));
    await callFn("updateSubmission", { id, status: "countered", counterPay, counterMessage });
    if (sub?.email && settings.notifications.artistCountered) {
      callFn("sendArtistEmail", {
        type: "countered", to: sub.email, name: sub.name,
        date: sub.date, slot: sub.slot, counterPay, counterMessage,
        submissionId: id,
      }).catch(console.error);
    }
  };

  const deleteSubmission = async id => {
    if (!window.confirm("Permanently delete this submission? This cannot be undone.")) return;
    setSubs(prev => prev.filter(s => s.id !== id));
    callFn("deleteSubmission", { id }).catch(console.error);
  };

  const reopen = async id => {
    setSubs(s => s.map(x => x.id === id ? { ...x, status: "pending" } : x));
    await callFn("updateSubmission", { id, status: "pending" });
  };

  const cancel = async id => {
    if (!window.confirm("Cancel this booking? The artist will be notified and the calendar date will reopen.")) return;
    const sub = subs.find(s => s.id === id);
    setSubs(s => s.map(x => x.id === id ? { ...x, status: "cancelled" } : x));
    await callFn("updateSubmission", { id, status: "cancelled" });
    if (sub?.dateId) {
      setDates(prev => prev.map(d => d.id === sub.dateId ? { ...d, status: "available", artist: undefined } : d));
      callFn("unblockDate", { eventId: sub.dateId, slot: sub.slot }).catch(console.error);
    }
    if (sub?.email && settings.notifications.artistCancellation) {
      callFn("sendArtistEmail", {
        type: "cancelled", to: sub.email, name: sub.name, date: sub.date, slot: sub.slot,
      }).catch(console.error);
    }
  };

  const handleDeleteDate = async dateId => {
    const date = dates.find(d => d.id === dateId);
    const msg  = date?.status === "booked"
      ? `⚠ This date is currently booked${date.artist && date.artist !== "Blocked" ? ` (${date.artist})` : ""}. Deleting it will permanently remove it from the calendar. Continue?`
      : "Permanently remove this date from the calendar? This cannot be undone.";
    if (!window.confirm(msg)) return;
    setDates(prev => prev.filter(d => d.id !== dateId));
    callFn("deleteCalendarDate", { eventId: dateId }).catch(console.error);
  };

  const toggleSelectDate = id => setSelectedDateIds(prev => {
    const next = new Set(prev);
    next.has(id) ? next.delete(id) : next.add(id);
    return next;
  });

  const handleBulkDelete = async () => {
    const selected     = dates.filter(d => selectedDateIds.has(d.id));
    const bookedCount  = selected.filter(d => d.status === "booked").length;
    const msg = bookedCount > 0
      ? `⚠ ${bookedCount} of the selected date${bookedCount > 1 ? "s are" : " is"} currently booked. Deleting will permanently remove ${bookedCount > 1 ? "them" : "it"} from the calendar. Continue?`
      : `Permanently remove ${selectedDateIds.size} date${selectedDateIds.size > 1 ? "s" : ""} from the calendar? This cannot be undone.`;
    if (!window.confirm(msg)) return;
    const ids = [...selectedDateIds];
    setDates(prev => prev.filter(d => !ids.includes(d.id)));
    setSelectedDateIds(new Set());
    ids.forEach(id => callFn("deleteCalendarDate", { eventId: id }).catch(console.error));
  };

  const handleBulkOpen = async () => {
    const ids = [...selectedDateIds].filter(id => dates.find(d => d.id === id)?.status === "booked");
    if (!ids.length) return;
    if (!window.confirm(`Re-open ${ids.length} booked date${ids.length > 1 ? "s" : ""}?`)) return;
    setDates(prev => prev.map(d => ids.includes(d.id) ? { ...d, status: "available", artist: undefined } : d));
    setSelectedDateIds(new Set());
    ids.forEach(id => callFn("unblockDate", { eventId: id }).catch(console.error));
  };

  const handleBulkBlock = async () => {
    const ids = [...selectedDateIds].filter(id => dates.find(d => d.id === id)?.status === "available");
    if (!ids.length) return;
    if (!window.confirm(`Block ${ids.length} available date${ids.length > 1 ? "s" : ""}?`)) return;
    setDates(prev => prev.map(d => ids.includes(d.id) ? { ...d, status: "booked" } : d));
    setSelectedDateIds(new Set());
    ids.forEach(id => callFn("blockDate", { eventId: id, artistName: "Blocked" }).catch(console.error));
  };

  const toggleDefaultSlot  = slot => setDefaultSlots(prev => prev.includes(slot) ? prev.filter(s => s !== slot) : [...prev, slot].sort());
  const toggleDefaultVenue = vid  => setDefaultVenues(prev => prev.includes(vid)  ? prev.filter(v => v !== vid)  : [...prev, vid]);

  const applyToAll = async () => {
    setDates(prev => prev.map(d => d.status !== "booked" ? { ...d, slots: [...defaultSlots], venues: [...defaultVenues], setLength: defaultSetLength } : d));
    await callFn("applyDefaultsToAllDates", { slots: defaultSlots, venues: defaultVenues, setLength: defaultSetLength });
    setApplyConfirm(true);
    setTimeout(() => setApplyConfirm(false), 2500);
  };

  const toggleSlot = async (dateId, slot) => {
    const date = dates.find(d => d.id === dateId);
    if (!date) return;
    const isRemoving = (date.slots || []).includes(slot);
    if (isRemoving && (date.slots || []).length <= 1) return; // at least one slot required
    const newSlots = isRemoving
      ? date.slots.filter(s => s !== slot)
      : [...(date.slots || []), slot].sort();
    setDates(prev => prev.map(d => d.id === dateId ? { ...d, slots: newSlots } : d));
    await callFn("updateCalendarDate", { eventId: dateId, slots: newSlots, venues: date.venues || [], setLength: date.setLength || "3 hours" });
  };

  const toggleVenue = async (dateId, venueId) => {
    const date = dates.find(d => d.id === dateId);
    if (!date) return;
    const cur = date.venues || [];
    const newVenues = cur.includes(venueId) ? cur.filter(v => v !== venueId) : [...cur, venueId];
    setDates(prev => prev.map(d => d.id === dateId ? { ...d, venues: newVenues } : d));
    await callFn("updateCalendarDate", { eventId: dateId, slots: date.slots || [], venues: newVenues, setLength: date.setLength || "3 hours" });
  };

  const updateSetLength = async (dateId, setLength) => {
    const date = dates.find(d => d.id === dateId);
    if (!date) return;
    setDates(prev => prev.map(d => d.id === dateId ? { ...d, setLength } : d));
    await callFn("updateCalendarDate", { eventId: dateId, slots: date.slots || [], venues: date.venues || [], setLength });
  };

  const handleBlockDate = async dateId => {
    setDates(prev => prev.map(d => d.id === dateId ? { ...d, status: "booked" } : d));
    await callFn("blockDate", { eventId: dateId, artistName: "Blocked" });
  };

  const handleUnblockDate = async dateId => {
    setDates(prev => prev.map(d => d.id === dateId ? { ...d, status: "available", artist: undefined } : d));
    await callFn("unblockDate", { eventId: dateId });
  };

  const newDate = newDateY && newDateM && newDateD ? `${newDateY}-${newDateM}-${newDateD}` : "";

  const handleAddDate = async () => {
    if (!newDate || defaultSlots.length === 0 || defaultVenues.length === 0) return;
    const label  = new Date(newDate + "T12:00:00").toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" });
    const result = await callFn("addCalendarDate", { date: newDate, slots: defaultSlots, venues: defaultVenues, setLength: defaultSetLength });
    if (result.eventId) {
      setDates(prev => [...prev, { id: result.eventId, date: newDate, label, status: "available", slots: [...defaultSlots], venues: [...defaultVenues], setLength: defaultSetLength }].sort((a, b) => a.date.localeCompare(b.date)));
    }
    setNewDateY(""); setNewDateM(""); setNewDateD("");
  };

  const getBulkPreviewDates = () => {
    if (!bulkMonth || bulkDays.length === 0) return [];
    const [year, month] = bulkMonth.split("-").map(Number);
    const daysInMonth   = new Date(year, month, 0).getDate();
    const result = [];
    for (let day = 1; day <= daysInMonth; day++) {
      const d = new Date(year, month - 1, day);
      if (bulkDays.includes(d.getDay())) {
        const dateStr = `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
        if (!dates.some(existing => existing.date === dateStr)) result.push(dateStr);
      }
    }
    return result;
  };

  const handleBulkAddDates = async () => {
    const newDates = getBulkPreviewDates();
    if (!newDates.length) return;
    setBulkAdding(true);
    try {
      const result = await callFn("addCalendarDatesBatch", { dates: newDates, slots: defaultSlots, venues: defaultVenues, setLength: defaultSetLength });
      if (result.eventIds) {
        const objs = newDates.map((dateStr, i) => ({
          id:       result.eventIds[i],
          date:     dateStr,
          label:    new Date(dateStr + "T12:00:00").toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }),
          status:   "available",
          slots:    [...defaultSlots],
          venues:   [...defaultVenues],
          setLength: defaultSetLength,
        }));
        setDates(prev => [...prev, ...objs].sort((a, b) => a.date.localeCompare(b.date)));
        setBulkConfirm(true);
        setTimeout(() => setBulkConfirm(false), 3000);
      }
    } catch (err) { console.error(err); }
    setBulkAdding(false);
  };

  const pending   = subs.filter(s => s.status === "pending");
  const approved  = subs.filter(s => s.status === "approved");
  const countered = subs.filter(s => s.status === "countered");
  const declined  = subs.filter(s => s.status === "declined");
  const cancelled = subs.filter(s => s.status === "cancelled");

  const matchesSearch = s => {
    if (!searchQuery.trim()) return true;
    const q = searchQuery.toLowerCase();
    return [s.name, s.contactName, s.email, s.genre, s.date, s.phone, s.payableTo]
      .some(v => (v || "").toLowerCase().includes(q));
  };

  const visibleSubs = subs
    .filter(s => (!activeFilter || s.status === activeFilter) && matchesSearch(s) && (!dateIdFilter || s.dateId === dateIdFilter.dateId))
    .sort((a, b) => {
      if (sortBy === "oldest")           return (a.submitted || "").localeCompare(b.submitted || "");
      if (sortBy === "performance-date") return (a.dateRaw  || "").localeCompare(b.dateRaw  || "");
      if (sortBy === "name-az")  return (a.name || "").toLowerCase().localeCompare((b.name || "").toLowerCase());
      if (sortBy === "name-za")  return (b.name || "").toLowerCase().localeCompare((a.name || "").toLowerCase());
      return (b.submitted || "").localeCompare(a.submitted || ""); // newest first (default)
    });

  // A date is effectively booked if another submission (not this one) is approved or countered for it.
  // Uses live Firestore submissions data — reliable even after page refresh.
  const isDateEffectivelyBooked = (dateId, excludeId = null) =>
    !!dateId && subs.some(s => s.dateId === dateId && s.id !== excludeId && (s.status === "approved" || s.status === "countered"));

  const visibleCalendarDates = dates.filter(d =>
    calendarFilter === "available" ? d.status === "available" :
    calendarFilter === "booked"    ? d.status === "booked"    : true
  );
  const allVisibleSelected = visibleCalendarDates.length > 0 && visibleCalendarDates.every(d => selectedDateIds.has(d.id));
  const someSelected       = selectedDateIds.size > 0;
  const selectedHasBooked  = [...selectedDateIds].some(id => dates.find(d => d.id === id)?.status === "booked");
  const selectedHasAvail   = [...selectedDateIds].some(id => dates.find(d => d.id === id)?.status === "available");

  return (
    <div style={{ maxWidth: 720, margin: "0 auto", padding: "32px 24px" }}>
      {contract        && <ContractModal       sub={contract}         onClose={() => setContract(null)} settings={settings} />}
      {counterOfferSub && <CounterOfferModal   sub={counterOfferSub}  onSubmit={submitCounterOffer} onClose={() => setCounterOfferSub(null)} />}
      {approveSubs     && <ApproveConfirmModal  subs={approveSubs}     onConfirm={approve} onClose={() => { setApproveSubs(null); setSelectedSubIds(new Set()); }} />}
      {declineSubs     && <DeclineModal         subs={declineSubs}     onSubmit={decline}  onClose={() => { setDeclineSubs(null); setSelectedSubIds(new Set()); }} />}
      {editSub         && <EditContactModal     sub={editSub}          onSave={saveContactEdit} onClose={() => setEditSub(null)} />}

      <div className="mb-pad" style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 24, flexWrap: "wrap", gap: 16 }}>
        <h2 style={{ fontSize: 22, fontWeight: 500, margin: 0 }}>Booking dashboard</h2>
        <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
          <div className="mb-grid-3" style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 10 }}>
            {[["Pending", pending.length, "amber", "pending"], ["Approved", approved.length, "teal", "approved"], ["Countered", countered.length, "blue", "countered"], ["Declined", declined.length, "coral", "declined"], ["Cancelled", cancelled.length, "gray", "cancelled"]].map(([label, count, c, status]) => {
              const active = activeFilter === status;
              return (
                <button key={label} onClick={() => setActiveFilter(active ? null : status)}
                  style={{ textAlign: "center", padding: "10px 16px", borderRadius: 10, background: PALETTE[c].bg, border: `${active ? "2px" : "0.5px"} solid ${PALETTE[c].border}`, cursor: "pointer", boxShadow: active ? `0 0 0 2px ${PALETTE[c].border}22` : "none" }}>
                  <div style={{ fontSize: 22, fontWeight: 500, color: PALETTE[c].text }}>{count}</div>
                  <div style={{ fontSize: 12, color: PALETTE[c].text, opacity: 0.8 }}>{label}</div>
                </button>
              );
            })}
          </div>
          <button onClick={onSignOut} style={{ padding: "6px 14px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 12, color: "var(--color-text-secondary)" }}>Sign out</button>
        </div>
      </div>

      <div style={{ display: "flex", gap: 4, marginBottom: 20, borderBottom: "0.5px solid var(--color-border-tertiary)" }}>
        {["overview", "submissions", "artists", "calendar", "settings"].map(t => (
          <button key={t} onClick={() => setTab(t)} style={{ padding: "8px 16px", borderRadius: "8px 8px 0 0", border: "none", borderBottom: tab === t ? "2px solid var(--color-text-primary)" : "2px solid transparent", background: "transparent", cursor: "pointer", fontSize: 14, fontWeight: tab === t ? 500 : 400, color: tab === t ? "var(--color-text-primary)" : "var(--color-text-secondary)" }}>
            {t.charAt(0).toUpperCase() + t.slice(1)}
          </button>
        ))}
      </div>

      {tab === "overview" && (
        <OverviewTab dates={dates} subs={subs} setTab={setTab} resendContract={resendContract}
          onReviewDate={(dateId, label) => { setDateIdFilter({ dateId, label }); setActiveFilter("pending"); setTab("submissions"); }} />
      )}

      {tab === "artists" && (
        <ArtistsTab subs={subs} />
      )}

      {tab === "submissions" && (
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {/* Date filter banner — set from Overview "Review" button */}
          {dateIdFilter && (
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "10px 14px", borderRadius: 10, background: PALETTE.blue.bg, border: `0.5px solid ${PALETTE.blue.border}`, marginBottom: 12 }}>
              <span style={{ fontSize: 13, color: PALETTE.blue.text }}>
                Showing requests for <strong>{dateIdFilter.label}</strong>
              </span>
              <button onClick={() => { setDateIdFilter(null); setActiveFilter(null); }} style={{ fontSize: 12, padding: "3px 10px", borderRadius: 6, border: `0.5px solid ${PALETTE.blue.border}`, background: "transparent", cursor: "pointer", color: PALETTE.blue.text }}>
                Show all
              </button>
            </div>
          )}

          {/* Search + sort toolbar */}
          <div style={{ display: "flex", gap: 10, marginBottom: 4 }}>
            <div style={{ flex: 1, position: "relative" }}>
              <input
                value={searchQuery}
                onChange={e => setSearchQuery(e.target.value)}
                placeholder="Search by name, email, date, genre…"
                style={{ width: "100%", boxSizing: "border-box", paddingRight: searchQuery ? 32 : 12 }}
              />
              {searchQuery && (
                <button onClick={() => setSearchQuery("")} style={{ position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", background: "none", border: "none", cursor: "pointer", fontSize: 16, color: "var(--color-text-secondary)", lineHeight: 1 }}>×</button>
              )}
            </div>
            <select value={sortBy} onChange={e => setSortBy(e.target.value)}
              style={{ padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 13, cursor: "pointer" }}>
              <option value="newest">Newest first</option>
              <option value="oldest">Oldest first</option>
              <option value="performance-date">Performance date</option>
              <option value="name-az">Name A–Z</option>
              <option value="name-za">Name Z–A</option>
            </select>
          </div>

          {/* Active filter + result count */}
          {(activeFilter || searchQuery) && (
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: 13, color: "var(--color-text-secondary)" }}>
              <span>{visibleSubs.length} result{visibleSubs.length !== 1 ? "s" : ""}{activeFilter ? ` · ${activeFilter}` : ""}{searchQuery ? ` · "${searchQuery}"` : ""}</span>
              <button onClick={() => { setActiveFilter(null); setSearchQuery(""); }} style={{ fontSize: 12, padding: "2px 8px", borderRadius: 6, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", color: "var(--color-text-secondary)" }}>Clear</button>
            </div>
          )}

          {/* Multi-select bulk action bar */}
          {selectedSubIds.size > 0 && (() => {
            const selSubs = visibleSubs.filter(s => selectedSubIds.has(s.id));
            const actionable = selSubs.filter(s => s.status === "pending" || s.status === "countered");
            return (
              <div style={{ display: "flex", gap: 8, alignItems: "center", padding: "10px 14px", borderRadius: 10, background: PALETTE.blue.bg, border: `0.5px solid ${PALETTE.blue.border}`, flexWrap: "wrap" }}>
                <span style={{ fontSize: 13, color: PALETTE.blue.text, fontWeight: 500 }}>{selectedSubIds.size} selected</span>
                {actionable.length > 0 && <>
                  <button onClick={() => setApproveSubs(actionable)} style={{ padding: "5px 14px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: "pointer", fontSize: 12, color: PALETTE.teal.text, fontWeight: 500 }}>Approve {actionable.length}</button>
                  <button onClick={() => setDeclineSubs(actionable)} style={{ padding: "5px 14px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg, cursor: "pointer", fontSize: 12, color: PALETTE.coral.text, fontWeight: 500 }}>Decline {actionable.length}</button>
                </>}
                <button onClick={() => setSelectedSubIds(new Set())} style={{ padding: "5px 8px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 12, color: "var(--color-text-secondary)", marginLeft: "auto" }}>✕ Clear</button>
              </div>
            );
          })()}

          {subs.length === 0 && (
            <div style={{ textAlign: "center", padding: "40px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>No submissions yet.</div>
          )}
          {subs.length > 0 && visibleSubs.length === 0 && (
            <div style={{ textAlign: "center", padding: "40px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>No submissions match your search or filter.</div>
          )}
          {visibleSubs.map(s => (
            <div key={s.id} style={{ background: "var(--color-background-primary)", border: `0.5px solid ${selectedSubIds.has(s.id) ? "var(--color-border-primary)" : "var(--color-border-tertiary)"}`, borderRadius: 12, padding: "16px 18px" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 10 }}>
                <div style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
                  <input type="checkbox" checked={selectedSubIds.has(s.id)}
                    onChange={() => setSelectedSubIds(prev => { const n = new Set(prev); n.has(s.id) ? n.delete(s.id) : n.add(s.id); return n; })}
                    style={{ marginTop: 3, cursor: "pointer", width: 15, height: 15, flexShrink: 0 }} />
                <div>
                  <div style={{ fontSize: 16, fontWeight: 500, marginBottom: 6 }}>{s.name}</div>
                  <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
                    {s.genre  && <Badge color="gray">{s.genre}</Badge>}
                    {s.date   && <Badge color="purple">{s.date}</Badge>}
                    {s.slot   && <Badge color="amber">{s.slot}</Badge>}
                    {s.venue  && <Badge color="teal">{settings.venues.find(v => v.id === s.venue)?.label || s.venue}</Badge>}
                    {statusBadge(s.status)}
                  </div>
                  </div>
                </div>
                <div style={{ fontSize: 12, color: "var(--color-text-secondary)", whiteSpace: "nowrap" }}>Submitted {s.submitted}</div>
              </div>
              {/* Other upcoming bookings for this artist */}
              {(() => {
                const today = new Date().toISOString().split("T")[0];
                const others = subs.filter(o =>
                  o.email?.toLowerCase() === s.email?.toLowerCase() &&
                  o.status === "approved" && o.id !== s.id &&
                  (o.dateRaw || "") >= today
                ).sort((a, b) => (a.dateRaw || "").localeCompare(b.dateRaw || ""));
                if (!others.length) return null;
                const sameMonth = others.find(o => o.dateRaw?.slice(0, 7) === s.dateRaw?.slice(0, 7));
                const palette   = sameMonth ? PALETTE.amber : PALETTE.blue;
                return (
                  <div style={{ padding: "8px 12px", borderRadius: 8, background: palette.bg, border: `0.5px solid ${palette.border}`, fontSize: 12, color: palette.text, marginBottom: 10 }}>
                    {sameMonth ? "⚠ Already booked this month — " : "Also booked: "}
                    {others.map(o => `${o.date}${o.slot ? ` at ${o.slot}` : ""}`).join(" · ")}
                  </div>
                );
              })()}
              {s.bio && <p style={{ fontSize: 13, color: "var(--color-text-secondary)", margin: "0 0 10px", lineHeight: 1.5 }}>{s.bio}</p>}
              <div style={{ display: "flex", gap: 16, fontSize: 13, marginBottom: 10, flexWrap: "wrap" }}>
                {s.contactName && <span><span style={{ color: "var(--color-text-secondary)" }}>Rep: </span>{s.contactName}</span>}
                {s.email       && <span><span style={{ color: "var(--color-text-secondary)" }}>Email: </span>{s.email}</span>}
                {s.phone       && <span><span style={{ color: "var(--color-text-secondary)" }}>Phone: </span>{s.phone}</span>}
                {s.payableTo   && <span><span style={{ color: "var(--color-text-secondary)" }}>Payable to: </span>{s.payableTo}</span>}
              </div>
              <div style={{ display: "flex", gap: 16, fontSize: 13, marginBottom: 10, flexWrap: "wrap" }}>
                {s.draw       && <span><span style={{ color: "var(--color-text-secondary)" }}>Draw: </span>{s.draw}</span>}
                {s.performers && <span><span style={{ color: "var(--color-text-secondary)" }}>Performers: </span>{s.performers}</span>}
                {s.pay        && <span><span style={{ color: "var(--color-text-secondary)" }}>Pay: </span>{s.pay}</span>}
                {s.setLength  && <span><span style={{ color: "var(--color-text-secondary)" }}>Set: </span>{s.setLength}</span>}
                {s.sound      && <span><span style={{ color: "var(--color-text-secondary)" }}>Sound: </span>{s.sound === "house" ? "House system" : "Own sound"}</span>}
              </div>
              {(s.instagram || s.spotify || s.website || s.links) && (
                <div style={{ display: "flex", gap: 12, fontSize: 13, marginBottom: 10, flexWrap: "wrap" }}>
                  {s.instagram && <span><span style={{ color: "var(--color-text-secondary)" }}>IG: </span>{s.instagram}</span>}
                  {s.spotify   && <span><span style={{ color: "var(--color-text-secondary)" }}>Spotify: </span><a href={extUrl(s.spotify)} target="_blank" rel="noopener noreferrer" style={{ color: PALETTE.teal.text }}>{s.spotify}</a></span>}
                  {s.website   && <span><span style={{ color: "var(--color-text-secondary)" }}>Web: </span><a href={extUrl(s.website)} target="_blank" rel="noopener noreferrer" style={{ color: PALETTE.teal.text }}>{s.website}</a></span>}
                  {s.links && !s.website && <span><span style={{ color: "var(--color-text-secondary)" }}>Performance video: </span><a href={extUrl(s.links)} target="_blank" rel="noopener noreferrer" style={{ color: PALETTE.teal.text }}>{s.links}</a></span>}
                </div>
              )}
              {(s.logoUrl || s.photoUrl) && (
                <div style={{ display: "flex", gap: 8, marginBottom: 12 }}>
                  {s.logoUrl  && <a href={s.logoUrl}  target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.purple.text, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg, padding: "3px 10px", borderRadius: 6, textDecoration: "none" }}>View logo</a>}
                  {s.photoUrl && <a href={s.photoUrl} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: PALETTE.purple.text, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg, padding: "3px 10px", borderRadius: 6, textDecoration: "none" }}>View press photo</a>}
                </div>
              )}
              {s.status === "countered" && (
                <div style={{ padding: "10px 12px", borderRadius: 8, background: PALETTE.blue.bg, border: `0.5px solid ${PALETTE.blue.border}`, fontSize: 13, color: PALETTE.blue.text, marginBottom: 10 }}>
                  Counter offer sent: <strong>{s.counterPay}</strong>
                  {s.counterMessage && <span> — {s.counterMessage}</span>}
                </div>
              )}
              {s.status === "pending" && isDateEffectivelyBooked(s.dateId, s.id) && (
                <div style={{ padding: "8px 12px", borderRadius: 8, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, fontSize: 13, color: PALETTE.amber.text, marginBottom: 10 }}>
                  ⚠ Requested date is no longer available — another booking for this date is in progress.
                </div>
              )}
              {(s.status === "pending" || s.status === "countered") && (
                <div className="mb-wrap" style={{ display: "flex", gap: 8 }}>
                  <button onClick={() => setApproveSubs([s])} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: "pointer", fontSize: 13, color: PALETTE.teal.text, fontWeight: 500 }}>Approve</button>
                  {s.status === "pending" && (
                    <button onClick={() => setCounterOfferSub(s)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.blue.border}`, background: PALETTE.blue.bg, cursor: "pointer", fontSize: 13, color: PALETTE.blue.text, fontWeight: 500 }}>Counter</button>
                  )}
                  <button onClick={() => setDeclineSubs([s])} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg, cursor: "pointer", fontSize: 13, color: PALETTE.coral.text, fontWeight: 500 }}>Decline</button>
                </div>
              )}
              <div style={{ display: "flex", justifyContent: "flex-end", gap: 6, marginBottom: 6 }}>
                <button onClick={() => setEditSub(s)} style={{ fontSize: 11, padding: "2px 10px", borderRadius: 6, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", color: "var(--color-text-secondary)" }}>Edit</button>
                <button onClick={() => deleteSubmission(s.id)} style={{ fontSize: 11, padding: "2px 10px", borderRadius: 6, border: `0.5px solid ${PALETTE.coral.border}`, background: "transparent", cursor: "pointer", color: PALETTE.coral.text, opacity: 0.6 }}>Delete</button>
              </div>
              {s.status === "approved" && s.cancelRequested && (
                <div style={{ padding: "10px 12px", borderRadius: 8, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, fontSize: 13, color: PALETTE.amber.text, marginBottom: 10, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <span>⚠ Artist has requested cancellation</span>
                  <button onClick={() => callFn("updateSubmission", { id: s.id, cancelRequested: false })} style={{ fontSize: 12, padding: "3px 10px", borderRadius: 6, border: `0.5px solid ${PALETTE.amber.border}`, background: "transparent", cursor: "pointer", color: PALETTE.amber.text }}>Dismiss</button>
                </div>
              )}
              {s.status === "approved" && (
                <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                  <button onClick={() => setContract(s)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${s.contractSigned ? PALETTE.teal.border : PALETTE.purple.border}`, background: s.contractSigned ? PALETTE.teal.bg : PALETTE.purple.bg, cursor: "pointer", fontSize: 13, color: s.contractSigned ? PALETTE.teal.text : PALETTE.purple.text, fontWeight: 500 }}>
                    {s.contractSigned ? "Contract signed ✓" : "Contract — awaiting signature"}
                  </button>
                  {!s.contractSigned && (() => {
                    const sent = sentFeedback?.id === s.id && sentFeedback?.type === "contract";
                    return <button onClick={() => resendContract(s.id)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${sent ? PALETTE.teal.border : PALETTE.amber.border}`, background: sent ? PALETTE.teal.bg : PALETTE.amber.bg, cursor: "pointer", fontSize: 13, color: sent ? PALETTE.teal.text : PALETTE.amber.text, fontWeight: 500 }}>{sent ? "Sent ✓" : "Resend contract"}</button>;
                  })()}
                  {(() => {
                    const sent = sentFeedback?.id === s.id && sentFeedback?.type === "confirmation";
                    return <button onClick={() => resendConfirmation(s.id)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${sent ? PALETTE.teal.border : PALETTE.blue.border}`, background: sent ? PALETTE.teal.bg : PALETTE.blue.bg, cursor: "pointer", fontSize: 13, color: sent ? PALETTE.teal.text : PALETTE.blue.text }}>{sent ? "Sent ✓" : "Resend confirmation"}</button>;
                  })()}
                  <button onClick={() => cancel(s.id)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg, cursor: "pointer", fontSize: 13, color: PALETTE.coral.text }}>Cancel booking</button>
                </div>
              )}
              {s.status === "cancelled" && (
                <button onClick={() => reopen(s.id)} style={{ padding: "6px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.amber.border}`, background: PALETTE.amber.bg, cursor: "pointer", fontSize: 13, color: PALETTE.amber.text, fontWeight: 500 }}>Re-open</button>
              )}
            </div>
          ))}
        </div>
      )}

      {tab === "calendar" && (
        <div style={{ paddingBottom: 400 }}>
          <div style={{ padding: "16px 18px", borderRadius: 12, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg, marginBottom: 20 }}>
            <div style={{ fontSize: 13, fontWeight: 500, color: PALETTE.purple.text, marginBottom: 10 }}>Default settings</div>
            <div style={{ fontSize: 13, color: PALETTE.purple.text, opacity: 0.8, marginBottom: 12 }}>Applied automatically to new dates. Use "Apply to all" to push to existing open dates.</div>
            <div style={{ fontSize: 12, color: PALETTE.purple.text, opacity: 0.7, marginBottom: 6 }}>Time slots:</div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12 }}>
              {settings.timeSlots.map(t => (
                <SlotPill key={t} time={t} selected={defaultSlots.includes(t)} onClick={() => toggleDefaultSlot(t)} />
              ))}
            </div>
            <div style={{ fontSize: 12, color: PALETTE.purple.text, opacity: 0.7, marginBottom: 6 }}>Venues:</div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12 }}>
              {settings.venues.map(v => {
                const active = defaultVenues.includes(v.id);
                return (
                  <button key={v.id} onClick={() => toggleDefaultVenue(v.id)}
                    style={{ padding: "6px 14px", borderRadius: 20, border: `0.5px solid ${active ? PALETTE.amber.border : "var(--color-border-secondary)"}`, background: active ? PALETTE.amber.bg : "var(--color-background-primary)", color: active ? PALETTE.amber.text : "var(--color-text-primary)", fontSize: 13, fontWeight: active ? 500 : 400, cursor: "pointer" }}>
                    {v.label}
                  </button>
                );
              })}
            </div>
            <div style={{ fontSize: 12, color: PALETTE.purple.text, opacity: 0.7, marginBottom: 6 }}>Default set length:</div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 14 }}>
              {settings.setLengthOptions.map(opt => (
                <button key={opt} onClick={() => setDefaultSetLength(opt)}
                  style={{ padding: "6px 14px", borderRadius: 20, border: `0.5px solid ${defaultSetLength === opt ? PALETTE.teal.border : "var(--color-border-secondary)"}`, background: defaultSetLength === opt ? PALETTE.teal.bg : "var(--color-background-primary)", color: defaultSetLength === opt ? PALETTE.teal.text : "var(--color-text-primary)", fontSize: 13, fontWeight: defaultSetLength === opt ? 500 : 400, cursor: "pointer" }}>
                  {opt}
                </button>
              ))}
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <button onClick={applyToAll} style={{ padding: "7px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.purple.border}`, background: "var(--color-background-primary)", cursor: "pointer", fontSize: 13, color: PALETTE.purple.text, fontWeight: 500 }}>Apply to all open dates</button>
              {applyConfirm && <span style={{ fontSize: 13, color: PALETTE.teal.text, fontWeight: 500 }}>Done — all open dates updated</span>}
            </div>
          </div>

          {/* Status filter + select/action bar */}
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12, flexWrap: "wrap", gap: 10 }}>
            <div style={{ display: "flex", gap: 4 }}>
              {[["All", "all"], ["Open", "available"], ["Booked", "booked"]].map(([label, val]) => (
                <button key={val} onClick={() => { setCalendarFilter(val); setSelectedDateIds(new Set()); }}
                  style={{ padding: "5px 14px", borderRadius: 20, border: `0.5px solid ${calendarFilter === val ? "var(--color-border-primary)" : "var(--color-border-tertiary)"}`, background: calendarFilter === val ? "var(--color-background-secondary)" : "transparent", fontSize: 13, cursor: "pointer", fontWeight: calendarFilter === val ? 500 : 400, color: "var(--color-text-primary)" }}>
                  {label}
                  <span style={{ marginLeft: 5, opacity: 0.6, fontSize: 12 }}>
                    {val === "all" ? dates.length : dates.filter(d => d.status === val).length}
                  </span>
                </button>
              ))}
            </div>
            {someSelected && (
              <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
                <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{selectedDateIds.size} selected</span>
                {selectedHasBooked  && <button onClick={handleBulkOpen}  style={{ padding: "5px 12px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`,  background: PALETTE.teal.bg,  cursor: "pointer", fontSize: 12, color: PALETTE.teal.text,  fontWeight: 500 }}>Open</button>}
                {selectedHasAvail   && <button onClick={handleBulkBlock} style={{ padding: "5px 12px", borderRadius: 8, border: `0.5px solid ${PALETTE.gray.border}`,  background: PALETTE.gray.bg,  cursor: "pointer", fontSize: 12, color: PALETTE.gray.text              }}>Block</button>}
                <button onClick={handleBulkDelete} style={{ padding: "5px 12px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg, cursor: "pointer", fontSize: 12, color: PALETTE.coral.text, fontWeight: 500 }}>Delete</button>
                <button onClick={() => setSelectedDateIds(new Set())} style={{ padding: "5px 8px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "transparent", cursor: "pointer", fontSize: 12, color: "var(--color-text-secondary)" }}>✕</button>
              </div>
            )}
          </div>

          <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 20 }}>
            {/* Select-all row */}
            {visibleCalendarDates.length > 0 && (
              <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "4px 16px" }}>
                <input type="checkbox" checked={allVisibleSelected} onChange={() => {
                  if (allVisibleSelected) setSelectedDateIds(new Set());
                  else setSelectedDateIds(new Set(visibleCalendarDates.map(d => d.id)));
                }} style={{ cursor: "pointer", width: 15, height: 15 }} />
                <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{allVisibleSelected ? "Deselect all" : `Select all ${visibleCalendarDates.length}`}</span>
              </div>
            )}
            {visibleCalendarDates.map(d => (
              <div key={d.id} style={{ borderRadius: 12, border: `0.5px solid ${selectedDateIds.has(d.id) ? "var(--color-border-primary)" : expandedDate === d.id ? "var(--color-border-primary)" : "var(--color-border-tertiary)"}`, background: selectedDateIds.has(d.id) ? "var(--color-background-secondary)" : "var(--color-background-primary)", overflow: "hidden" }}>
                <div style={{ display: "flex", alignItems: "center" }}>
                  <div onClick={e => e.stopPropagation()} style={{ padding: "0 0 0 16px", display: "flex", alignItems: "center" }}>
                    <input type="checkbox" checked={selectedDateIds.has(d.id)} onChange={() => toggleSelectDate(d.id)} style={{ cursor: "pointer", width: 15, height: 15 }} />
                  </div>
                  <div onClick={() => setExpandedDate(expandedDate === d.id ? null : d.id)}
                    style={{ flex: 1, display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 16px 12px 10px", cursor: "pointer" }}>
                  <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
                    <span style={{ fontSize: 15, fontWeight: 500 }}>{d.label}</span>
                    {statusBadge(d.status)}
                    {d.artist && d.artist !== "Blocked" && (
                      <button onClick={e => { e.stopPropagation(); setTab("submissions"); setSearchQuery(d.artist); }}
                        style={{ fontSize: 12, color: PALETTE.teal.text, background: "none", border: "none", cursor: "pointer", padding: 0, textDecoration: "underline" }}
                        title="View booking in Submissions tab">
                        {d.artist}
                      </button>
                    )}
                    {d.artist === "Blocked" && <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>Blocked</span>}
                  </div>
                  <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
                    {d.setLength && <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>{d.setLength}</span>}
                    <div style={{ display: "flex", gap: 4, flexWrap: "wrap", justifyContent: "flex-end" }}>
                      {(d.slots || []).map(s => <SlotPill key={s} time={s} selected={false} disabled={true} />)}
                      {(!d.slots || d.slots.length === 0) && <span style={{ fontSize: 12, color: "var(--color-text-secondary)" }}>No slots set</span>}
                    </div>
                    <span style={{ fontSize: 18, color: "var(--color-text-secondary)", marginLeft: 8 }}>{expandedDate === d.id ? "▲" : "▼"}</span>
                  </div>
                  </div>
                </div>
                {expandedDate === d.id && (
                  <div style={{ padding: "12px 16px 16px", borderTop: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-secondary)" }}>
                    <div style={{ fontSize: 12, color: "var(--color-text-secondary)", marginBottom: 6 }}>Time slots:</div>
                    <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12 }}>
                      {settings.timeSlots.map(t => (
                        <SlotPill key={t} time={t}
                          selected={(d.slots || []).includes(t)}
                          disabled={(d.slots || []).includes(t) && (d.slots || []).length <= 1}
                          onClick={() => toggleSlot(d.id, t)} />
                      ))}
                    </div>
                    <div style={{ fontSize: 12, color: "var(--color-text-secondary)", marginBottom: 6 }}>Venues:</div>
                    <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12 }}>
                      {settings.venues.map(v => {
                        const active = (d.venues || []).includes(v.id);
                        return (
                          <button key={v.id} onClick={() => toggleVenue(d.id, v.id)}
                            style={{ padding: "6px 14px", borderRadius: 20, border: `0.5px solid ${active ? PALETTE.teal.border : "var(--color-border-secondary)"}`, background: active ? PALETTE.teal.bg : "var(--color-background-primary)", color: active ? PALETTE.teal.text : "var(--color-text-primary)", fontSize: 13, fontWeight: active ? 500 : 400, cursor: "pointer" }}>
                            {v.label}
                          </button>
                        );
                      })}
                    </div>
                    <div style={{ fontSize: 12, color: "var(--color-text-secondary)", marginBottom: 6 }}>Set length:</div>
                    <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 14 }}>
                      {settings.setLengthOptions.map(opt => (
                        <button key={opt} onClick={() => updateSetLength(d.id, opt)}
                          style={{ padding: "6px 14px", borderRadius: 20, border: `0.5px solid ${(d.setLength || settings.defaultSetLength) === opt ? PALETTE.teal.border : "var(--color-border-secondary)"}`, background: (d.setLength || settings.defaultSetLength) === opt ? PALETTE.teal.bg : "var(--color-background-primary)", color: (d.setLength || settings.defaultSetLength) === opt ? PALETTE.teal.text : "var(--color-text-primary)", fontSize: 13, fontWeight: (d.setLength || settings.defaultSetLength) === opt ? 500 : 400, cursor: "pointer" }}>
                          {opt}
                        </button>
                      ))}
                    </div>
                    <div style={{ display: "flex", gap: 10 }}>
                      {d.status === "available" && (
                        <button onClick={() => handleBlockDate(d.id)} style={{ fontSize: 12, padding: "5px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: "transparent", cursor: "pointer", color: "var(--color-text-secondary)" }}>Block date</button>
                      )}
                      {d.status === "booked" && (
                        <button onClick={() => handleUnblockDate(d.id)} style={{ fontSize: 12, padding: "5px 12px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: "pointer", color: PALETTE.teal.text }}>Open date</button>
                      )}
                      <button onClick={() => handleDeleteDate(d.id)} style={{ fontSize: 12, padding: "5px 12px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: "transparent", cursor: "pointer", color: PALETTE.coral.text }}>Delete date</button>
                    </div>
                  </div>
                )}
              </div>
            ))}
          </div>

          {/* Add by month */}
          <div style={{ padding: "18px 20px", borderRadius: 10, border: `0.5px solid ${PALETTE.purple.border}`, background: PALETTE.purple.bg }}>
            <div style={{ fontSize: 13, fontWeight: 500, color: PALETTE.purple.text, marginBottom: 14 }}>Add dates by month</div>
            <div style={{ display: "flex", gap: 12, alignItems: "center", marginBottom: 14, flexWrap: "wrap" }}>
              <div>
                <div style={{ fontSize: 12, color: PALETTE.purple.text, opacity: 0.7, marginBottom: 4 }}>Month</div>
                <input type="month" value={bulkMonth} onChange={e => setBulkMonth(e.target.value)}
                  style={{ padding: "6px 10px", borderRadius: 8, border: `0.5px solid ${PALETTE.purple.border}`, background: "var(--color-background-primary)", fontSize: 13 }} />
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 12, color: PALETTE.purple.text, opacity: 0.7, marginBottom: 6 }}>Days of week</div>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                  {["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].map((day, i) => {
                    const active = bulkDays.includes(i);
                    return (
                      <button key={day} onClick={() => setBulkDays(prev => active ? prev.filter(d => d !== i) : [...prev, i].sort())}
                        style={{ padding: "5px 11px", borderRadius: 20, border: `0.5px solid ${active ? PALETTE.amber.border : "var(--color-border-secondary)"}`, background: active ? PALETTE.amber.bg : "var(--color-background-primary)", color: active ? PALETTE.amber.text : "var(--color-text-primary)", fontSize: 13, fontWeight: active ? 500 : 400, cursor: "pointer" }}>
                        {day}
                      </button>
                    );
                  })}
                </div>
              </div>
            </div>
            {(() => {
              const preview      = getBulkPreviewDates();
              const noSlots      = defaultSlots.length === 0;
              const noVenues     = defaultVenues.length === 0;
              const cantAdd      = noSlots || noVenues;
              const canAdd       = !cantAdd && preview.length > 0 && !bulkAdding;
              return (
                <>
                  <div style={{ fontSize: 13, marginBottom: 12, color: cantAdd ? PALETTE.coral.text : preview.length > 0 ? PALETTE.purple.text : PALETTE.purple.text, opacity: cantAdd ? 1 : preview.length > 0 ? 0.85 : 0.6 }}>
                    {noSlots    ? "⚠ Select at least one time slot in Default Settings above before adding dates."
                     : noVenues ? "⚠ Select at least one venue in Default Settings above before adding dates."
                     : bulkDays.length === 0 ? "Select at least one day."
                     : preview.length > 0 ? `${preview.length} date${preview.length !== 1 ? "s" : ""} to add: ${preview.slice(0, 6).map(d => new Date(d + "T12:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric" })).join(", ")}${preview.length > 6 ? ` +${preview.length - 6} more` : ""}`
                     : "All matching dates are already on the calendar."}
                  </div>
                  <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
                    <button onClick={handleBulkAddDates} disabled={!canAdd}
                      style={{ padding: "7px 18px", borderRadius: 8, border: `0.5px solid ${PALETTE.purple.border}`, background: "var(--color-background-primary)", cursor: canAdd ? "pointer" : "not-allowed", fontSize: 13, color: PALETTE.purple.text, fontWeight: 500, opacity: canAdd ? 1 : 0.4 }}>
                      {bulkAdding ? "Adding…" : `Add ${preview.length} date${preview.length !== 1 ? "s" : ""}`}
                    </button>
                    {bulkConfirm && <span style={{ fontSize: 13, color: PALETTE.teal.text, fontWeight: 500 }}>Done — dates added ✓</span>}
                  </div>
                </>
              );
            })()}
          </div>

          {/* Add single date */}
          <div style={{ padding: "16px 18px", borderRadius: 10, border: "0.5px dashed var(--color-border-secondary)", background: "var(--color-background-secondary)" }}>
            <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 10 }}>Add single date</div>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
              {(() => {
                const cy = new Date().getFullYear();
                const selectStyle = { padding: "7px 10px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 13, cursor: "pointer" };
                return (<>
                  <select value={newDateM} onChange={e => setNewDateM(e.target.value)} style={selectStyle}>
                    <option value="">Month</option>
                    {["01","02","03","04","05","06","07","08","09","10","11","12"].map((m, i) => (
                      <option key={m} value={m}>{["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][i]}</option>
                    ))}
                  </select>
                  <select value={newDateD} onChange={e => setNewDateD(e.target.value)} style={selectStyle}>
                    <option value="">Day</option>
                    {Array.from({length:31},(_,i)=>String(i+1).padStart(2,"0")).map(d => (
                      <option key={d} value={d}>{parseInt(d)}</option>
                    ))}
                  </select>
                  <select value={newDateY} onChange={e => setNewDateY(e.target.value)} style={selectStyle}>
                    <option value="">Year</option>
                    {[cy, cy+1, cy+2].map(y => <option key={y} value={String(y)}>{y}</option>)}
                  </select>
                </>);
              })()}
              <button onClick={handleAddDate} disabled={!newDate || defaultSlots.length === 0 || defaultVenues.length === 0}
                style={{ padding: "7px 16px", borderRadius: 8, border: `0.5px solid ${PALETTE.amber.border}`, background: PALETTE.amber.bg, cursor: newDate && defaultSlots.length > 0 && defaultVenues.length > 0 ? "pointer" : "not-allowed", fontSize: 13, color: PALETTE.amber.text, fontWeight: 500, opacity: !newDate || defaultSlots.length === 0 || defaultVenues.length === 0 ? 0.4 : 1 }}>Add</button>
            </div>
            {(defaultSlots.length === 0 || defaultVenues.length === 0) && (
              <p style={{ fontSize: 12, color: PALETTE.coral.text, margin: "8px 0 0" }}>
                ⚠ {defaultSlots.length === 0 ? "Select at least one time slot" : "Select at least one venue"} in Default Settings above before adding dates.
              </p>
            )}
          </div>
        </div>
      )}

      {tab === "settings" && (
        <SettingsPanel settings={settings} />
      )}
    </div>
  );
}

// ── SETTINGS PANEL ────────────────────────────────────────────

function SettingsPanel({ settings }) {
  const [form, setForm]           = useState({ ...settings, notifications: { ...settings.notifications } });
  const [venues, setVenues]       = useState(settings.venues.map(v => ({ ...v })));
  const [saving, setSaving]       = useState(false);
  const [saved, setSaved]         = useState(false);
  const [saveError, setSaveError] = useState(null);
  const [newPw, setNewPw]         = useState("");
  const [confirmPw, setConfirmPw] = useState("");
  const [pwSaving, setPwSaving]   = useState(false);
  const [pwSaved, setPwSaved]     = useState(false);
  const [pwError, setPwError]     = useState("");

  // Keep form in sync if settings prop updates (e.g. live Firestore change)
  useEffect(() => {
    setForm({ ...settings, notifications: { ...settings.notifications } });
    setVenues(settings.venues.map(v => ({ ...v })));
  }, [settings]);

  const upd  = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const updN = (k, v) => setForm(f => ({ ...f, notifications: { ...f.notifications, [k]: v } }));

  const save = async () => {
    setSaving(true); setSaved(false); setSaveError(null);
    try {
      const result = await callFn("saveSettings", { settings: { ...form, venues } });
      if (result.success) { setSaved(true); setTimeout(() => setSaved(false), 3000); }
      else setSaveError("Failed to save. Please try again.");
    } catch { setSaveError("Failed to save. Please try again."); }
    setSaving(false);
  };

  const savePassword = async () => {
    if (!newPw) return;
    if (newPw !== confirmPw) { setPwError("Passwords don't match."); return; }
    if (newPw.length < 6) { setPwError("Password must be at least 6 characters."); return; }
    setPwSaving(true); setPwError(""); setPwSaved(false);
    try {
      const result = await callFn("saveSettings", { newPassword: newPw });
      if (result.success) { setPwSaved(true); setNewPw(""); setConfirmPw(""); setTimeout(() => setPwSaved(false), 3000); }
    } catch { setPwError("Failed to update password."); }
    setPwSaving(false);
  };

  const sectionStyle = { background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 12, padding: "20px 22px", marginBottom: 16 };
  const sectionTitle = { fontSize: 14, fontWeight: 500, color: "var(--color-text-primary)", marginBottom: 16, paddingBottom: 10, borderBottom: "0.5px solid var(--color-border-tertiary)" };
  const labelStyle   = { fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 };
  const inputStyle   = { width: "100%", boxSizing: "border-box" };

  return (
    <div style={{ maxWidth: 680 }}>

      {/* Venue & Branding */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Venue &amp; Branding</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {[["Venue name", "venueName", "text"], ["Contact email", "contactEmail", "email"], ["Portal URL", "baseUrl", "text"]].map(([label, key, type]) => (
            <div key={key}>
              <label style={labelStyle}>{label}</label>
              <input type={type} value={form[key] || ""} onChange={e => upd(key, e.target.value)} style={inputStyle} />
            </div>
          ))}
          <div>
            <label style={labelStyle}>Artist portal welcome message</label>
            <textarea value={form.welcomeMessage || ""} onChange={e => upd("welcomeMessage", e.target.value)} rows={2} style={{ ...inputStyle, padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
          </div>
          <div>
            <label style={labelStyle}>House sound system description</label>
            <input value={form.soundSystem || ""} onChange={e => upd("soundSystem", e.target.value)} style={inputStyle} placeholder="e.g. Bose L1 Pro PA system and a 4-channel mixer" />
          </div>
        </div>
      </div>

      {/* Time Slots */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Available time slots</div>
        <p style={{ fontSize: 13, color: "var(--color-text-secondary)", margin: "0 0 12px" }}>Toggle which slots artists can request. These also appear in the calendar manager.</p>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
          {ALL_POSSIBLE_SLOTS.map(t => {
            const on = (form.timeSlots || []).includes(t);
            return (
              <button key={t} onClick={() => upd("timeSlots", on ? form.timeSlots.filter(s => s !== t) : [...(form.timeSlots || []), t])}
                style={{ padding: "5px 12px", borderRadius: 20, border: `0.5px solid ${on ? PALETTE.amber.border : "var(--color-border-secondary)"}`, background: on ? PALETTE.amber.bg : "var(--color-background-primary)", color: on ? PALETTE.amber.text : "var(--color-text-primary)", fontSize: 13, fontWeight: on ? 500 : 400, cursor: "pointer" }}>
                {t}
              </button>
            );
          })}
        </div>
      </div>

      {/* Set Lengths */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Set length options</div>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 14 }}>
          {["1 hour","1.5 hours","2 hours","2.5 hours","3 hours","3.5 hours","4 hours","4.5 hours","5 hours"].map(opt => {
            const on = (form.setLengthOptions || []).includes(opt);
            return (
              <button key={opt} onClick={() => upd("setLengthOptions", on ? form.setLengthOptions.filter(o => o !== opt) : [...(form.setLengthOptions || []), opt])}
                style={{ padding: "5px 12px", borderRadius: 20, border: `0.5px solid ${on ? PALETTE.teal.border : "var(--color-border-secondary)"}`, background: on ? PALETTE.teal.bg : "var(--color-background-primary)", color: on ? PALETTE.teal.text : "var(--color-text-primary)", fontSize: 13, fontWeight: on ? 500 : 400, cursor: "pointer" }}>
                {opt}
              </button>
            );
          })}
        </div>
        <div>
          <label style={labelStyle}>Default set length</label>
          <select value={form.defaultSetLength || "3 hours"} onChange={e => upd("defaultSetLength", e.target.value)}
            style={{ padding: "7px 10px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", fontSize: 13, cursor: "pointer" }}>
            {(form.setLengthOptions || DEFAULT_SETTINGS.setLengthOptions).map(o => <option key={o} value={o}>{o}</option>)}
          </select>
        </div>
      </div>

      {/* Spaces / Venues */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Spaces / Venues</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 14 }}>
          {venues.map((v, i) => (
            <div key={v.id} style={{ display: "flex", gap: 8, alignItems: "flex-start" }}>
              <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 6 }}>
                <input value={v.label} onChange={e => setVenues(prev => prev.map((x, j) => j === i ? { ...x, label: e.target.value } : x))} placeholder="Space name" style={{ width: "100%", boxSizing: "border-box" }} />
                <input value={v.description} onChange={e => setVenues(prev => prev.map((x, j) => j === i ? { ...x, description: e.target.value } : x))} placeholder="Description" style={{ width: "100%", boxSizing: "border-box" }} />
              </div>
              <button onClick={() => setVenues(prev => prev.filter((_, j) => j !== i))}
                style={{ padding: "6px 10px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: "transparent", cursor: "pointer", fontSize: 12, color: PALETTE.coral.text, marginTop: 2 }}>Remove</button>
            </div>
          ))}
        </div>
        <button onClick={() => setVenues(prev => [...prev, { id: `space_${Date.now()}`, label: "", description: "" }])}
          style={{ padding: "6px 14px", borderRadius: 8, border: "0.5px solid var(--color-border-secondary)", background: "transparent", cursor: "pointer", fontSize: 13, color: "var(--color-text-secondary)" }}>+ Add space</button>
      </div>

      {/* Contract Terms */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Contract terms</div>
        <label style={labelStyle}>These terms appear in the artist performance agreement</label>
        <textarea value={form.contractTerms || ""} onChange={e => upd("contractTerms", e.target.value)} rows={5}
          style={{ ...inputStyle, padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
      </div>

      {/* Email Notifications */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Email notifications</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          {[
            ["artistApproval",      "Notify artist when their booking is approved"],
            ["artistDecline",       "Notify artist when their request is declined (requires a comment in the decline modal)"],
            ["artistCountered",     "Notify artist when a counter offer is sent"],
            ["artistCancellation",  "Notify artist when their booking is cancelled by admin"],
            ["adminNewSubmission",  "Notify admin when a new booking request is submitted"],
            ["adminContractSigned", "Notify admin when an artist signs their contract"],
            ["adminCancelRequest",  "Notify admin when an artist requests cancellation"],
          ].map(([key, label]) => (
            <label key={key} style={{ display: "flex", gap: 12, alignItems: "center", cursor: "pointer", fontSize: 14 }}>
              <input type="checkbox" checked={!!(form.notifications || {})[key]} onChange={e => updN(key, e.target.checked)}
                style={{ width: 16, height: 16, cursor: "pointer" }} />
              <span style={{ color: "var(--color-text-primary)" }}>{label}</span>
            </label>
          ))}
        </div>
      </div>

      {/* Save settings */}
      {saveError && <p style={{ fontSize: 13, color: PALETTE.coral.text, margin: "0 0 10px" }}>{saveError}</p>}
      <button onClick={save} disabled={saving}
        style={{ padding: "10px 28px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: saving ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.teal.text, fontWeight: 500, marginBottom: 32 }}>
        {saving ? "Saving…" : saved ? "Settings saved ✓" : "Save settings"}
      </button>

      {/* Admin Password */}
      <div style={sectionStyle}>
        <div style={sectionTitle}>Admin password</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 360 }}>
          {[["New password", newPw, setNewPw], ["Confirm new password", confirmPw, setConfirmPw]].map(([label, val, set]) => (
            <div key={label}>
              <label style={labelStyle}>{label}</label>
              <input type="password" value={val} onChange={e => { set(e.target.value); setPwError(""); }} style={inputStyle} />
            </div>
          ))}
          {pwError && <p style={{ fontSize: 13, color: PALETTE.coral.text, margin: 0 }}>{pwError}</p>}
          <button onClick={savePassword} disabled={pwSaving || !newPw}
            style={{ padding: "8px 20px", borderRadius: 8, border: `0.5px solid ${PALETTE.amber.border}`, background: PALETTE.amber.bg, cursor: !newPw || pwSaving ? "not-allowed" : "pointer", fontSize: 13, color: PALETTE.amber.text, fontWeight: 500, opacity: !newPw ? 0.5 : 1, alignSelf: "flex-start" }}>
            {pwSaving ? "Updating…" : pwSaved ? "Password updated ✓" : "Update password"}
          </button>
        </div>
      </div>

    </div>
  );
}

function CounterOfferResponse({ action, submissionId }) {
  const [sub, setSub] = useState(null);
  const [loading, setLoading] = useState(true);
  const [selected, setSelected] = useState(action); // "accept" | "decline"
  const [confirming, setConfirming] = useState(false);
  const [done, setDone] = useState(null); // "accepted" | "declined" | "error"

  useEffect(() => {
    const { db, doc, onSnapshot } = window.__firebase;
    return onSnapshot(
      doc(db, "submissions", submissionId),
      snap => { if (snap.exists()) setSub({ id: snap.id, ...snap.data() }); setLoading(false); },
      err  => { console.error(err); setLoading(false); }
    );
  }, [submissionId]);

  if (loading) return (
    <div style={{ textAlign: "center", padding: "80px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>Loading your offer…</div>
  );

  if (!sub) return (
    <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15 }}>This link is no longer valid.</p>
    </div>
  );

  // Already responded
  if (sub.status !== "countered") {
    const accepted = sub.status === "approved";
    return (
      <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
        <div style={{ width: 56, height: 56, borderRadius: "50%", background: accepted ? PALETTE.teal.bg : PALETTE.gray.bg, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 20px", border: `0.5px solid ${accepted ? PALETTE.teal.border : PALETTE.gray.border}` }}>
          {accepted
            ? <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 12l5 5L19 7" stroke={PALETTE.teal.text} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
            : <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M6 18L18 6M6 6l12 12" stroke={PALETTE.gray.text} strokeWidth="2" strokeLinecap="round"/></svg>
          }
        </div>
        <h2 style={{ fontSize: 20, fontWeight: 500, margin: "0 0 10px" }}>{accepted ? "Booking confirmed" : "Offer declined"}</h2>
        <p style={{ color: "var(--color-text-secondary)", fontSize: 15, lineHeight: 1.6 }}>
          {accepted
            ? <>Your booking at Medusa Brewing is confirmed for <strong>{sub.date}</strong> at <strong>{sub.slot}</strong>.{" "}
                {sub.contractSigned
                  ? "You've already signed your performance agreement."
                  : <a href={`?sign=true&id=${submissionId}`} style={{ color: PALETTE.teal.text, fontWeight: 500 }}>Sign your performance agreement →</a>
                }
              </>
            : "You've already declined this offer."
          }
        </p>
      </div>
    );
  }

  if (done) {
    const accepted = done === "accepted";
    return (
      <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
        {done === "error" ? (
          <>
            <h2 style={{ fontSize: 20, fontWeight: 500, margin: "0 0 10px" }}>Something went wrong</h2>
            <p style={{ color: "var(--color-text-secondary)", fontSize: 15 }}>Please try again or contact Medusa Brewing directly.</p>
          </>
        ) : (
          <>
            <div style={{ width: 56, height: 56, borderRadius: "50%", background: accepted ? PALETTE.teal.bg : PALETTE.gray.bg, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 20px", border: `0.5px solid ${accepted ? PALETTE.teal.border : PALETTE.gray.border}` }}>
              {accepted
                ? <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 12l5 5L19 7" stroke={PALETTE.teal.text} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
                : <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M6 18L18 6M6 6l12 12" stroke={PALETTE.gray.text} strokeWidth="2" strokeLinecap="round"/></svg>
              }
            </div>
            <h2 style={{ fontSize: 20, fontWeight: 500, margin: "0 0 10px" }}>{accepted ? "Offer accepted!" : "Offer declined"}</h2>
            <p style={{ color: "var(--color-text-secondary)", fontSize: 15, lineHeight: 1.6 }}>
              {accepted
                ? <>You've accepted the offer for <strong>{sub.date}</strong> at <strong>{sub.slot}</strong>. Please sign your performance agreement to confirm the booking:</>
                : "You've declined the counter offer. Thanks for your interest in performing at Medusa Brewing."
              }
            </p>
            {accepted && (
              <a href={`?sign=true&id=${submissionId}`} style={{ display: "inline-block", marginTop: 16, padding: "10px 24px", background: PALETTE.teal.bg, color: PALETTE.teal.text, border: `0.5px solid ${PALETTE.teal.border}`, borderRadius: 8, textDecoration: "none", fontWeight: 500, fontSize: 14 }}>Sign your agreement →</a>
            )}
          </>
        )}
      </div>
    );
  }

  return (
    <div style={{ maxWidth: 520, margin: "60px auto", padding: "0 24px" }}>
      <h2 style={{ fontSize: 22, fontWeight: 500, margin: "0 0 8px" }}>Counter offer from Medusa Brewing</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15, margin: "0 0 24px" }}>
        Hi <strong style={{ color: "var(--color-text-primary)" }}>{sub.name}</strong>, Medusa Brewing has reviewed your booking request and made a counter offer.
      </p>
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 12, padding: "18px 20px", marginBottom: 20 }}>
        {[["Date", sub.date], ["Time", sub.slot], ["Set length", sub.setLength], ["Your requested pay", sub.pay], ["Counter offer", sub.counterPay]].map(([k, v]) => v && (
          <div key={k} style={{ display: "flex", justifyContent: "space-between", padding: "6px 0", borderBottom: "0.5px solid var(--color-border-tertiary)", fontSize: 14 }}>
            <span style={{ color: "var(--color-text-secondary)" }}>{k}</span>
            <span style={{ fontWeight: 500, color: k === "Counter offer" ? PALETTE.blue.text : "var(--color-text-primary)" }}>{v}</span>
          </div>
        ))}
        {sub.counterMessage && (
          <div style={{ padding: "10px 0 4px", fontSize: 13, color: "var(--color-text-secondary)", lineHeight: 1.5 }}>
            <strong style={{ color: "var(--color-text-primary)" }}>Note: </strong>{sub.counterMessage}
          </div>
        )}
      </div>
      <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
        {[["accept", "Accept offer", "teal"], ["decline", "Decline", "coral"]].map(([val, label, color]) => (
          <button key={val} onClick={() => setSelected(val)}
            style={{ flex: 1, padding: "10px 16px", borderRadius: 8, border: `0.5px solid ${selected === val ? PALETTE[color].border : "var(--color-border-secondary)"}`, background: selected === val ? PALETTE[color].bg : "var(--color-background-primary)", color: selected === val ? PALETTE[color].text : "var(--color-text-primary)", fontSize: 14, fontWeight: selected === val ? 500 : 400, cursor: "pointer" }}>
            {label}
          </button>
        ))}
      </div>
      <button disabled={!selected || confirming} onClick={async () => {
        setConfirming(true);
        try {
          const result = await callFn("respondToCounterOffer", {
            id: submissionId,
            response: selected === "accept" ? "accepted" : "declined",
          });
          if (result.success) setDone(selected === "accept" ? "accepted" : "declined");
          else setDone("error");
        } catch { setDone("error"); }
        setConfirming(false);
      }} style={{ width: "100%", padding: "11px 22px", borderRadius: 8, border: `0.5px solid ${selected && !confirming ? (selected === "accept" ? PALETTE.teal.border : PALETTE.coral.border) : "var(--color-border-tertiary)"}`, background: selected && !confirming ? (selected === "accept" ? PALETTE.teal.bg : PALETTE.coral.bg) : "transparent", cursor: selected && !confirming ? "pointer" : "not-allowed", fontSize: 14, color: selected && !confirming ? (selected === "accept" ? PALETTE.teal.text : PALETTE.coral.text) : "var(--color-text-secondary)", fontWeight: 500 }}>
        {confirming ? "Confirming…" : selected === "accept" ? "Confirm — Accept offer" : selected === "decline" ? "Confirm — Decline" : "Select an option above"}
      </button>
    </div>
  );
}

function ArtistManage({ submissionId, settings = DEFAULT_SETTINGS }) {
  const [sub, setSub]               = useState(null);
  const [loading, setLoading]       = useState(true);
  const [form, setForm]             = useState({ contactName: "", phone: "", payableTo: "", bio: "", links: "", instagram: "", spotify: "", website: "" });
  const [newLogo, setNewLogo]       = useState(null);
  const [newPhoto, setNewPhoto]     = useState(null);
  const [saving, setSaving]         = useState(false);
  const [saved, setSaved]           = useState(false);
  const [saveError, setSaveError]   = useState(null);
  const [requesting, setRequesting] = useState(false);
  const [requested, setRequested]   = useState(false);

  useEffect(() => {
    const { db, doc, onSnapshot } = window.__firebase;
    return onSnapshot(
      doc(db, "submissions", submissionId),
      snap => {
        if (snap.exists()) {
          const d = { id: snap.id, ...snap.data() };
          setSub(d);
          setForm({ contactName: d.contactName || "", phone: d.phone || "", payableTo: d.payableTo || "", bio: d.bio || "", links: d.links || "", instagram: d.instagram || "", spotify: d.spotify || "", website: d.website || "" });
        }
        setLoading(false);
      },
      err => { console.error(err); setLoading(false); }
    );
  }, [submissionId]);

  const upd = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const save = async () => {
    setSaving(true); setSaved(false); setSaveError(null);
    try {
      const { storage, ref, uploadBytes, getDownloadURL } = window.__firebase;
      let logoUrl = sub.logoUrl || null, photoUrl = sub.photoUrl || null;
      if (newLogo) {
        const r = ref(storage, `press-kits/${Date.now()}-logo-${newLogo.name}`);
        await uploadBytes(r, newLogo); logoUrl = await getDownloadURL(r);
      }
      if (newPhoto) {
        const r = ref(storage, `press-kits/${Date.now()}-photo-${newPhoto.name}`);
        await uploadBytes(r, newPhoto); photoUrl = await getDownloadURL(r);
      }
      const result = await callFn("updateBooking", { id: submissionId, ...form, logoUrl, photoUrl });
      if (result.success) { setSaved(true); setNewLogo(null); setNewPhoto(null); setTimeout(() => setSaved(false), 3000); }
      else setSaveError("Failed to save. Please try again.");
    } catch { setSaveError("Failed to save. Please try again."); }
    setSaving(false);
  };

  const requestCancel = async () => {
    if (!window.confirm("Send a cancellation request to Medusa Brewing? They will confirm and you'll receive a follow-up email.")) return;
    setRequesting(true);
    try {
      const result = await callFn("requestCancellation", { id: submissionId });
      if (result.success) setRequested(true);
    } catch { /* silent */ }
    setRequesting(false);
  };

  if (loading) return <div style={{ textAlign: "center", padding: "80px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>Loading your booking…</div>;
  if (!sub || !["approved", "cancelled"].includes(sub.status)) return (
    <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15 }}>This booking management link is no longer valid.</p>
    </div>
  );
  if (sub.status === "cancelled") return (
    <div style={{ maxWidth: 480, margin: "80px auto", textAlign: "center", padding: "0 24px" }}>
      <div style={{ width: 56, height: 56, borderRadius: "50%", background: PALETTE.gray.bg, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 20px", border: `0.5px solid ${PALETTE.gray.border}` }}>
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M6 18L18 6M6 6l12 12" stroke={PALETTE.gray.text} strokeWidth="2" strokeLinecap="round"/></svg>
      </div>
      <h2 style={{ fontSize: 20, fontWeight: 500, margin: "0 0 10px" }}>Booking cancelled</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 15, lineHeight: 1.6, margin: "0 0 24px" }}>Your booking for <strong>{sub.date}</strong> at <strong>{sub.slot}</strong> has been cancelled.</p>
      <a href="https://booking.medusabrewing.com" style={{ fontSize: 14, color: PALETTE.teal.text }}>View available dates →</a>
    </div>
  );

  return (
    <div style={{ maxWidth: 600, margin: "40px auto", padding: "0 24px 60px" }}>
      <h2 style={{ fontSize: 22, fontWeight: 500, margin: "0 0 6px" }}>Manage your booking</h2>
      <p style={{ color: "var(--color-text-secondary)", fontSize: 14, margin: "0 0 24px" }}>Update your contact info, press kit, or request a cancellation.</p>

      {/* Booking summary */}
      <div style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: 12, padding: "16px 20px", marginBottom: 20 }}>
        <div style={{ fontSize: 13, fontWeight: 500, color: "var(--color-text-secondary)", marginBottom: 10, textTransform: "uppercase", letterSpacing: 0.5 }}>Your booking</div>
        {[["Date", sub.date], ["Time", sub.slot], ["Set length", sub.setLength], ["Performance fee", sub.counterPay || sub.pay], ["Sound", sub.sound === "house" ? "House system" : "Bringing own sound"]].map(([k, v]) => v && (
          <div key={k} style={{ display: "flex", justifyContent: "space-between", padding: "5px 0", borderBottom: "0.5px solid var(--color-border-tertiary)", fontSize: 14 }}>
            <span style={{ color: "var(--color-text-secondary)" }}>{k}</span>
            <span style={{ fontWeight: 500 }}>{v}</span>
          </div>
        ))}
        <div style={{ marginTop: 10, display: "flex", gap: 8, alignItems: "center" }}>
          {statusBadge(sub.status)}
          {sub.contractSigned && <Badge color="teal">Contract signed ✓</Badge>}
          {!sub.contractSigned && <a href={`?sign=true&id=${submissionId}`} style={{ fontSize: 12, color: PALETTE.teal.text, textDecoration: "underline" }}>Sign contract →</a>}
        </div>
      </div>

      {/* Cancel requested notice */}
      {(sub.cancelRequested || requested) && (
        <div style={{ padding: "12px 16px", borderRadius: 10, background: PALETTE.amber.bg, border: `0.5px solid ${PALETTE.amber.border}`, fontSize: 14, color: PALETTE.amber.text, marginBottom: 20 }}>
          ⚠ Cancellation request sent — Medusa Brewing has been notified and will be in touch.
        </div>
      )}

      {/* Editable fields */}
      <div style={{ display: "flex", flexDirection: "column", gap: 14, marginBottom: 24 }}>
        <div style={{ fontSize: 14, fontWeight: 500, color: "var(--color-text-primary)", borderBottom: "0.5px solid var(--color-border-tertiary)", paddingBottom: 8 }}>Contact information</div>
        {[["Contact person", "contactName", "text"], ["Phone", "phone", "tel"], ["Make payment payable to", "payableTo", "text"]].map(([label, key, type]) => (
          <div key={key}>
            <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
            <input type={type} value={form[key]} onChange={e => upd(key, e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
          </div>
        ))}
        <div style={{ fontSize: 14, fontWeight: 500, color: "var(--color-text-primary)", borderBottom: "0.5px solid var(--color-border-tertiary)", paddingBottom: 8, marginTop: 8 }}>Press kit</div>
        <div>
          <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>Bio / description</label>
          <textarea value={form.bio} onChange={e => upd("bio", e.target.value)} rows={4} style={{ width: "100%", boxSizing: "border-box", padding: "8px 12px", borderRadius: 8, border: "0.5px solid var(--color-border-tertiary)", background: "var(--color-background-primary)", color: "var(--color-text-primary)", fontSize: 14, resize: "vertical" }} />
        </div>
        {[["Instagram handle", "instagram"], ["Spotify / streaming link", "spotify"], ["Website", "website"], ["Other links", "links"]].map(([label, key]) => (
          <div key={key}>
            <label style={{ fontSize: 13, color: "var(--color-text-secondary)", display: "block", marginBottom: 4 }}>{label}</label>
            <input value={form[key]} onChange={e => upd(key, e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
          </div>
        ))}
        {[["Logo (PNG or SVG)", "logo", setNewLogo, newLogo, sub.logoUrl, 2], ["Press photo", "photo", setNewPhoto, newPhoto, sub.photoUrl, 5]].map(([label, key, setter, file, existing, maxMB]) => (
          <div key={key} style={{ padding: "16px", borderRadius: 10, border: "0.5px dashed var(--color-border-secondary)", background: "var(--color-background-secondary)" }}>
            <div style={{ fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 6 }}>
              {label} <span style={{ opacity: 0.6 }}>(max {maxMB}MB)</span>
              {existing && <span style={{ color: PALETTE.teal.text, fontWeight: 500 }}> — on file</span>}
            </div>
            <input type="file" accept="image/*" onChange={e => {
              const f = e.target.files[0];
              if (f && f.size > maxMB * 1024 * 1024) {
                alert(`${label} must be under ${maxMB}MB. Your file is ${(f.size / 1024 / 1024).toFixed(1)}MB.`);
                e.target.value = "";
                return;
              }
              setter(f || null);
            }} style={{ fontSize: 13 }} />
            {file && <div style={{ fontSize: 12, color: PALETTE.teal.text, marginTop: 4 }}>New file selected: {file.name}</div>}
          </div>
        ))}
        {saveError && <p style={{ fontSize: 13, color: PALETTE.coral.text, margin: 0 }}>{saveError}</p>}
        <button onClick={save} disabled={saving} style={{ padding: "10px 24px", borderRadius: 8, border: `0.5px solid ${PALETTE.teal.border}`, background: PALETTE.teal.bg, cursor: saving ? "not-allowed" : "pointer", fontSize: 14, color: PALETTE.teal.text, fontWeight: 500 }}>
          {saving ? "Saving…" : saved ? "Saved ✓" : "Save changes"}
        </button>
      </div>

      {/* Cancel request */}
      {!sub.cancelRequested && !requested && (
        <div style={{ padding: "20px", borderRadius: 12, border: `0.5px solid ${PALETTE.coral.border}`, background: PALETTE.coral.bg }}>
          <div style={{ fontSize: 14, fontWeight: 500, color: PALETTE.coral.text, marginBottom: 6 }}>Cancel booking</div>
          <p style={{ fontSize: 13, color: PALETTE.coral.text, margin: "0 0 14px", lineHeight: 1.6, opacity: 0.85 }}>This sends a cancellation request to Medusa Brewing. They will confirm and send you a follow-up email. 14-day notice required.</p>
          <button onClick={requestCancel} disabled={requesting} style={{ padding: "8px 20px", borderRadius: 8, border: `0.5px solid ${PALETTE.coral.border}`, background: "var(--color-background-primary)", cursor: requesting ? "not-allowed" : "pointer", fontSize: 13, color: PALETTE.coral.text, fontWeight: 500 }}>
            {requesting ? "Sending…" : "Request cancellation"}
          </button>
        </div>
      )}
    </div>
  );
}

function App() {
  const params       = new URLSearchParams(window.location.search);
  const respondParam = params.get("respond");
  const respondId    = params.get("id");
  const signParam    = params.get("sign");
  const signId       = params.get("id");
  const manageParam  = params.get("manage");
  const manageId     = params.get("id");
  const adminParam   = params.get("admin");
  const isResponse   = (respondParam === "accept" || respondParam === "decline") && !!respondId;
  const isSign       = signParam === "true" && !!signId;
  const isManage     = manageParam === "true" && !!manageId;
  const isAdmin      = adminParam === "true";

  const [view, setView]           = useState(isSign ? "sign" : isManage ? "manage" : isResponse ? "respond" : isAdmin ? "admin" : "artist");
  const [dates, setDates]         = useState([]);
  const [datesLoading, setDatesLoading] = useState(true);
  const [pendingCount, setPendingCount] = useState(0);
  const [adminAuthed, setAdminAuthed]   = useState(() => localStorage.getItem("adminAuthed") === "true");
  const [showAdminAuth, setShowAdminAuth] = useState(isAdmin && localStorage.getItem("adminAuthed") !== "true");
  const [settings, setSettings]   = useState(DEFAULT_SETTINGS);

  useEffect(() => {
    fetch(`${FUNCTIONS_BASE}/getAvailableDates`)
      .then(r => r.json())
      .then(data => { if (data.dates) setDates(data.dates); })
      .catch(err => console.error("Failed to load dates:", err))
      .finally(() => setDatesLoading(false));
  }, []);

  useEffect(() => {
    const { db, onSnapshot, doc } = window.__firebase;
    // Load app settings (live — updates if admin saves changes)
    const unsubSettings = onSnapshot(doc(db, "config/settings"), snap => {
      if (snap.exists()) {
        const d = snap.data();
        setSettings(prev => ({
          ...DEFAULT_SETTINGS, ...d,
          notifications: { ...DEFAULT_SETTINGS.notifications, ...(d.notifications || {}) },
          venues: d.venues || DEFAULT_SETTINGS.venues,
        }));
      }
    }, console.error);
    // Pending count
    const unsubMeta = onSnapshot(doc(db, "meta/notifications"), d => {
      if (d.exists()) setPendingCount(d.data()?.pendingCount || 0);
    });
    return () => { unsubSettings(); unsubMeta(); };
  }, []);

  const handleSignOut = () => {
    localStorage.removeItem("adminAuthed");
    setAdminAuthed(false);
    setView("artist");
  };

  return (
    <div style={{ minHeight: "100vh", background: "var(--color-background-tertiary)", fontFamily: "var(--font-sans)" }}>
      {showAdminAuth && (
        <AdminAuthModal
          onSuccess={() => { setAdminAuthed(true); setShowAdminAuth(false); setView("admin"); }}
          onClose={() => { setShowAdminAuth(false); setView("artist"); }}
        />
      )}
      <Nav view={view} setView={setView} />
      {view === "sign"
        ? <ContractSign submissionId={signId} settings={settings} />
        : view === "manage"
        ? <ArtistManage submissionId={manageId} settings={settings} />
        : view === "respond"
        ? <CounterOfferResponse action={respondParam} submissionId={respondId} />
        : datesLoading
          ? <div style={{ textAlign: "center", padding: "60px 24px", color: "var(--color-text-secondary)", fontSize: 14 }}>Loading available dates…</div>
          : view === "artist"
            ? <ArtistPortal dates={dates} settings={settings} />
            : <AdminDashboard dates={dates} setDates={setDates} onSignOut={handleSignOut} settings={settings} />
      }
      {view !== "admin" && (
        <div style={{ textAlign: "center", padding: "24px", borderTop: "0.5px solid var(--color-border-tertiary)", marginTop: 8 }}>
          <a href="?admin=true" style={{ fontSize: 12, color: "var(--color-text-secondary)", opacity: 0.5, textDecoration: "none" }}>Admin</a>
        </div>
      )}
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
