/* global React, I, S */
/* Pamp — Client (User) portal */

const U_NAV = [
  { key: "dashboard", label: "Home", icon: I.dashboard },
  { key: "discover", label: "Discover", icon: I.sparkle },
  { key: "bookings", label: "My bookings", icon: I.bookings, badge: "3" },
  { key: "favorites", label: "Favorites", icon: I.heart },
  { key: "notifications", label: "Notifications", icon: I.bell, badge: "3" },
  { key: "wallet", label: "Wallet", icon: I.wallet },
  { key: "plan", label: "My plan", icon: I.crown },
  { key: "influencer", label: "Pamp Program", icon: I.gift },
  { key: "reports", label: "Reports", icon: I.chart },
  { section: "Account" },
  { key: "support", label: "Help & support", icon: I.help },
  { key: "settings", label: "Settings", icon: I.settings },
];

function UserApp({ collapsed, onToggle, onTheme, theme, onExit, session, onNavigate, currentPage }) {
  const page = currentPage || "dashboard";
  const setPage = onNavigate;
  const userId = session?.user?.id;
  const profile = session?.profile;

  return (
    <div className="shell" data-sidebar={collapsed ? "collapsed" : "expanded"}>
      <S.Sidebar
        items={U_NAV}
        current={page}
        onNav={setPage}
        collapsed={collapsed}
        footer={
          <button className="nav-item" onClick={onExit} style={{ width: "100%" }} data-tip="Sign out">
            <span className="ni-icon"><I.logout size={18} /></span>
            <span className="ni-label">Sign out</span>
          </button>
        }
      />
      <div className="main-col">
        <S.Topbar
          onToggleSidebar={onToggle}
          onTheme={onTheme}
          theme={theme}
          search="Search vendors, services, locations…"
          right={<>
            <S.IconBtn title="Messages" style={{ position: "relative" }}>
              <I.mail size={18} />
            </S.IconBtn>
            <S.IconBtn title="Calendar" onClick={() => setPage("bookings")}><I.calendar size={18} /></S.IconBtn>
          </>}
        />
        <main className="main-scroll">
          {page === "dashboard"     && <UserHome userId={userId} profile={profile} onNav={setPage} />}
          {page === "discover"      && <UserDiscover userId={userId} />}
          {page === "bookings"      && <UserBookings userId={userId} />}
          {page === "wallet"        && <UserWallet />}
          {page === "plan"          && <UserPlan />}
          {page === "favorites"     && <UserFavorites userId={userId} onNav={setPage} />}
          {page === "influencer"    && <UserInfluencer />}
          {page === "reports"       && <UserReports userId={userId} />}
          {page === "notifications" && <UserNotifications userId={userId} />}
          {page === "support"       && <window.SupportPage kind="client" />}
          {page === "settings"      && <UserSettings userId={userId} profile={profile} />}
        </main>
      </div>
    </div>
  );
}

/* ====================================================================
   USER — HOME (wired)
   ==================================================================== */
function UserHome({ userId, profile, onNav }) {
  const [bookings, setBookings] = React.useState(null);
  const [favorites, setFavorites] = React.useState(null);

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    Promise.all([
      SB.getUserBookings(userId),
      SB.getUserFavorites(userId),
    ]).then(([b, f]) => {
      if (!alive) return;
      setBookings(b || []);
      setFavorites(f || []);
    });
    return () => { alive = false; };
  }, [userId]);

  if (bookings === null || favorites === null) {
    return <div className="page-enter"><window.LoadingState /></div>;
  }

  const now = Date.now();
  const upcoming = bookings
    .filter(b => b.status !== "cancelled" && b.status !== "completed" && b.status !== "no_show")
    .filter(b => {
      const t = new Date(`${b.booking_date}T${b.start_time || "00:00"}`).getTime();
      return t >= now - 60 * 60 * 1000;
    })
    .sort((a, b) => {
      const ta = new Date(`${a.booking_date}T${a.start_time || "00:00"}`).getTime();
      const tb = new Date(`${b.booking_date}T${b.start_time || "00:00"}`).getTime();
      return ta - tb;
    });
  const past = bookings.filter(b => b.status === "completed");
  const next = upcoming[0] || null;
  const totalSpent = past.reduce((s, b) => s + Number(b.total_price || 0), 0);

  const firstName = (profile?.full_name || "").split(" ")[0] || "there";
  const greeting = (() => {
    const h = new Date().getHours();
    if (h < 12) return "Good morning";
    if (h < 18) return "Good afternoon";
    return "Good evening";
  })();
  const today = new Date().toLocaleDateString(undefined, { weekday: "long", month: "long", day: "numeric" });

  let subtitle = "Browse vendors or book a service to get started.";
  if (next) {
    const dt = new Date(`${next.booking_date}T${next.start_time || "00:00"}`);
    const mins = Math.round((dt.getTime() - now) / 60000);
    if (mins < 0)            subtitle = `Your appointment with ${next.vendor_profiles?.business_name || "your vendor"} is happening now.`;
    else if (mins < 60)      subtitle = `Your next appointment starts in ${mins} min. Tea before you go.`;
    else if (mins < 60 * 24) subtitle = `Your next appointment is in ${Math.round(mins / 60)} hours.`;
    else                     subtitle = `Your next appointment is on ${window.fmtDate(next.booking_date)}.`;
  }

  return (
    <div className="page-enter">
      <div className="row between" style={{ marginBottom: 28, alignItems: "flex-end", flexWrap: "wrap", gap: 12 }}>
        <div>
          <div className="eyebrow" style={{ marginBottom: 8 }}>{today}</div>
          <h1 className="h1">{greeting}, {firstName}.</h1>
          <div className="muted" style={{ marginTop: 6, fontSize: 14 }}>{subtitle}</div>
        </div>
        <div className="row" style={{ gap: 8 }}>
          {profile?.city && <S.Btn variant="outline" size="sm" icon={<I.location size={14} />}>{profile.city}</S.Btn>}
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => onNav?.("discover")}>Book a service</S.Btn>
        </div>
      </div>

      <div className="grid-12">
        <div className="card" style={{ gridColumn: "span 7", position: "relative", overflow: "hidden", background: "var(--ink)", color: "var(--bg)", borderColor: "transparent" }}>
          <div style={{
            position: "absolute", inset: 0, opacity: 0.7,
            background: "radial-gradient(circle at 80% 20%, var(--accent) 0%, transparent 50%), radial-gradient(circle at 20% 80%, oklch(50% 0.16 320) 0%, transparent 50%)",
            filter: "blur(40px)",
          }} />
          <div style={{ position: "relative", zIndex: 1, minHeight: 280 }}>
            {next ? <>
              <div className="row between">
                <div className="eyebrow" style={{ color: "oklch(80% 0.04 290)" }}>Next appointment</div>
                <S.Chip tone="accent" icon={<span className="dot" style={{ background: "var(--accent)" }} />}>{window.statusLabel(next.status)}</S.Chip>
              </div>
              <div className="display" style={{ fontSize: 40, letterSpacing: "-0.035em", lineHeight: 1.05, margin: "16px 0 12px", color: "var(--bg)" }}>
                {next.vendor_profiles?.business_name || "Your vendor"}<br />
                <span style={{ opacity: 0.6 }}>{next.services?.name || "Service"}</span>
              </div>
              <div className="row" style={{ gap: 24, marginTop: 20, color: "oklch(80% 0.04 290)", fontSize: 13, flexWrap: "wrap" }}>
                <div className="row-tight"><I.clock size={14} /> {window.fmtTime(next.start_time)} · {next.services?.duration_mins || 60} min</div>
                {next.vendor_profiles?.city && <div className="row-tight"><I.location size={14} /> {next.vendor_profiles.city}</div>}
                <div className="row-tight"><I.calendar size={14} /> {window.fmtDate(next.booking_date)}</div>
              </div>
              <div className="row" style={{ marginTop: 24, gap: 8 }}>
                <S.Btn variant="primary" style={{ background: "white", color: "var(--ink)" }} icon={<I.calendar size={14} />} onClick={() => onNav?.("bookings")}>View details</S.Btn>
                <S.Btn variant="ghost" style={{ color: "var(--bg)", background: "oklch(100% 0 0 / 0.10)" }} onClick={() => onNav?.("bookings")}>All bookings</S.Btn>
              </div>
            </> : <>
              <div className="eyebrow" style={{ color: "oklch(80% 0.04 290)" }}>No upcoming appointments</div>
              <div className="display" style={{ fontSize: 36, letterSpacing: "-0.035em", lineHeight: 1.1, margin: "16px 0 12px", color: "var(--bg)" }}>
                Ready to book your<br />
                <span style={{ opacity: 0.6 }}>next experience?</span>
              </div>
              <div className="muted" style={{ color: "oklch(80% 0.04 290)", fontSize: 14, marginTop: 12 }}>
                Browse top-rated vendors and book in seconds.
              </div>
              <div className="row" style={{ marginTop: 24, gap: 8 }}>
                <S.Btn variant="primary" style={{ background: "white", color: "var(--ink)" }} iconRight={<I.arrowR size={14} />} onClick={() => onNav?.("discover")}>Discover vendors</S.Btn>
              </div>
            </>}
          </div>
        </div>

        <div className="col" style={{ gridColumn: "span 5", gap: 20 }}>
          <div className="grid-2">
            <div className="card" style={{ padding: 20 }}>
              <div className="eyebrow">Bookings</div>
              <div className="display" style={{ fontSize: 32, marginTop: 8 }}>{bookings.length}</div>
              <div className="muted tiny">{upcoming.length} upcoming · {past.length} completed</div>
              <div className="row" style={{ marginTop: 14 }}>
                <S.Btn variant="outline" size="sm" style={{ flex: 1 }} onClick={() => onNav?.("bookings")}>View all</S.Btn>
              </div>
            </div>
            <div className="card" style={{ padding: 20 }}>
              <div className="eyebrow">Favorites</div>
              <div className="display" style={{ fontSize: 32, marginTop: 8 }}>{favorites.length}</div>
              <div className="muted tiny">Saved vendors</div>
              <div className="row" style={{ marginTop: 14 }}>
                <S.Btn variant="outline" size="sm" style={{ flex: 1 }} onClick={() => onNav?.("favorites")}>Browse</S.Btn>
              </div>
            </div>
          </div>

          <div className="card" style={{ padding: 20 }}>
            <div className="row between">
              <div>
                <div className="eyebrow">Total spent</div>
                <div className="display" style={{ fontSize: 28, marginTop: 6 }}>{window.fmtMoney(totalSpent)}</div>
                <div className="muted tiny">Across {past.length} completed booking{past.length === 1 ? "" : "s"}</div>
              </div>
              <span style={{
                width: 48, height: 48, borderRadius: 12,
                background: "var(--accent-soft)", color: "var(--accent-ink)",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
              }}><I.wallet size={20} /></span>
            </div>
          </div>
        </div>

        <div className="card" style={{ gridColumn: "span 12" }}>
          <div className="row between" style={{ marginBottom: 14 }}>
            <div>
              <div className="eyebrow">Recent activity</div>
              <div className="h3" style={{ marginTop: 4 }}>Your bookings</div>
            </div>
            <S.Btn variant="ghost" size="sm" onClick={() => onNav?.("bookings")} iconRight={<I.arrowR size={12} />}>See all</S.Btn>
          </div>
          {bookings.length === 0 ? (
            <window.EmptyState
              icon={<I.bookings size={24} />}
              title="No bookings yet"
              sub="Book your first appointment to see it here."
              action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => onNav?.("discover")}>Discover vendors</S.Btn>}
            />
          ) : (
            <table className="tbl">
              <thead>
                <tr>
                  <th>Vendor</th>
                  <th>Service</th>
                  <th>When</th>
                  <th>Status</th>
                  <th className="col-num">Price</th>
                </tr>
              </thead>
              <tbody>
                {bookings.slice(0, 5).map(b => (
                  <tr key={b.id}>
                    <td><div className="row-tight"><S.Avatar name={b.vendor_profiles?.business_name || "—"} size="sm" />{b.vendor_profiles?.business_name || "—"}</div></td>
                    <td>{b.services?.name || "—"}</td>
                    <td>
                      <div className="mono tiny">{window.fmtDate(b.booking_date)}</div>
                      <div className="muted tiny">{window.fmtTime(b.start_time)}</div>
                    </td>
                    <td><S.Chip tone={window.statusTone(b.status)}>{window.statusLabel(b.status)}</S.Chip></td>
                    <td className="col-num mono">{window.fmtMoney(b.total_price)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  );
}

/* ====================================================================
   USER — DISCOVER
   ==================================================================== */
function UserDiscover({ userId }) {
  const toast = window.useToast();
  const [cat, setCat] = React.useState("All");
  const [searchInput, setSearchInput] = React.useState("");
  const search = window.useDebounce(searchInput, 250);
  const [vendors, setVendors] = React.useState(null);
  const [favorites, setFavorites] = React.useState(new Set());
  const [reloadKey, setReloadKey] = React.useState(0);
  const [flow, setFlow] = React.useState(null);
  const closeFlow = () => setFlow(null);

  React.useEffect(() => {
    let alive = true;
    setVendors(null);
    Promise.all([
      SB.getActiveVendors(),
      userId ? SB.getUserFavorites(userId) : Promise.resolve([]),
    ]).then(([v, f]) => {
      if (!alive) return;
      setVendors(v || []);
      const favSet = new Set();
      (f || []).forEach(item => {
        const id = item.vendor_profiles?.id;
        if (id) favSet.add(id);
      });
      setFavorites(favSet);
    });
    return () => { alive = false; };
  }, [userId, reloadKey]);

  if (vendors === null) return <div className="page-enter"><window.LoadingState /></div>;

  // Build category list from real data
  const catCounts = vendors.reduce((m, v) => {
    const c = v.category || "Other";
    m[c] = (m[c] || 0) + 1;
    return m;
  }, {});
  const cats = ["All", ...Object.keys(catCounts).sort()];

  // Filter
  let visible = vendors;
  if (cat !== "All") visible = visible.filter(v => (v.category || "Other") === cat);
  if (search) {
    const q = search.toLowerCase();
    visible = visible.filter(v =>
      (v.business_name || "").toLowerCase().includes(q) ||
      (v.city || "").toLowerCase().includes(q) ||
      (v.category || "").toLowerCase().includes(q)
    );
  }

  const toggleFavorite = async (e, vendorId) => {
    e.stopPropagation();
    if (!userId) { toast.error("Sign in to save favorites"); return; }
    const isFav = favorites.has(vendorId);
    try {
      if (isFav) {
        const { error } = await SB.client.from("favorites").delete().eq("user_id", userId).eq("vendor_id", vendorId);
        if (error) { toast.error("Couldn't unfavorite"); return; }
        setFavorites(curr => { const n = new Set(curr); n.delete(vendorId); return n; });
      } else {
        const { error } = await SB.client.from("favorites").insert({ user_id: userId, vendor_id: vendorId });
        if (error) { toast.error("Couldn't favorite"); return; }
        setFavorites(curr => { const n = new Set(curr); n.add(vendorId); return n; });
      }
    } catch (err) {
      toast.error(err.message || "Failed");
    }
  };

  // Adapt a Supabase vendor row into the shape the design-pack modals expect.
  // The modals read: vendor.name, vendor.tagline, vendor.dist, vendor.rating,
  // vendor.gallery (array of strings), vendor.services[].duration (string),
  // vendor.services[].price, vendor.staff (array).
  const adaptVendorForModal = (v) => {
    const services = (v.services || []).map(s => ({
      ...s,
      // Preserve real DB id so we can reference it on insert
      _dbId: s.id,
      name: s.name || "Service",
      price: Number(s.price || 0),
      duration: formatMins(s.duration_mins || 60),
      duration_mins: s.duration_mins || 60,
    }));
    const gallery = [v.cover_image_url, v.logo_url].filter(Boolean);
    return {
      ...v,
      name: v.business_name || "Vendor",
      tagline: v.tagline || "",
      dist: v.city || "",
      rating: v.rating != null ? Number(v.rating).toFixed(1) : "—",
      gallery: gallery.length ? gallery : ["vendor photo"],
      services,
      staff: [], // staff feature not yet in DB
      // Keep originals so submitBooking can reference vendor.id, services[i]._dbId
      _vendorRow: v,
    };
  };

  const openBookingFlow = (v) => {
    if (!userId) { toast.error("Sign in to book a service"); return; }
    setFlow({ step: "select", vendor: v, modalVendor: adaptVendorForModal(v) });
  };

  // Convert a calendar Date + "HH:MM AM" time string to ISO date + 24h time.
  const buildDateTime = (date, timeStr) => {
    if (!date || !timeStr) return { booking_date: null, start_time: null };
    const d = new Date(date);
    const yyyy = d.getFullYear();
    const mm = String(d.getMonth() + 1).padStart(2, "0");
    const dd = String(d.getDate()).padStart(2, "0");
    const booking_date = `${yyyy}-${mm}-${dd}`;
    // Parse "10:30 AM" / "2:00 PM" / "14:00"
    const cleaned = String(timeStr).trim();
    let h = 0, m = 0;
    const ampm = cleaned.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
    const h24  = cleaned.match(/^(\d{1,2}):(\d{2})$/);
    if (ampm) {
      h = parseInt(ampm[1], 10) % 12;
      if (/PM/i.test(ampm[3])) h += 12;
      m = parseInt(ampm[2], 10);
    } else if (h24) {
      h = parseInt(h24[1], 10);
      m = parseInt(h24[2], 10);
    }
    const start_time = `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:00`;
    return { booking_date, start_time };
  };

  // Add minutes to "HH:MM:00" and return the new "HH:MM:00"
  const addMinutes = (timeStr, mins) => {
    const [h, m] = timeStr.split(":").map(Number);
    const total = h * 60 + m + mins;
    return `${String(Math.floor(total / 60) % 24).padStart(2, "0")}:${String(total % 60).padStart(2, "0")}:00`;
  };

  const submitBooking = async () => {
    if (!flow) return;
    if (!userId) { toast.error("Sign in to book a service"); return; }
    const vendor = flow.vendor;
    const services = flow.services || [];
    if (services.length === 0) { toast.error("Pick a service first"); return; }
    const { booking_date, start_time } = buildDateTime(flow.date, flow.time);
    if (!booking_date || !start_time) { toast.error("Pick a date and time"); return; }

    // Create one booking row per selected service, staggered by duration.
    // We call the SECURITY DEFINER RPC `create_my_booking` to bypass any
    // RLS friction on the bookings table.
    let cursor = start_time;
    const created = [];
    for (const svc of services) {
      const dur = svc.duration_mins || (svc.duration ? parseDur(svc.duration) : 60);
      const { data, error } = await SB.client.rpc("create_my_booking", {
        p_vendor_id:    vendor.id,
        p_service_id:   svc._dbId || svc.id,
        p_booking_date: booking_date,
        p_start_time:   cursor,
        p_total_price:  Number(svc.price || 0),
        p_status:       "pending",
      });
      if (error) {
        toast.error(`Couldn't create booking: ${error.message}`);
        return;
      }
      created.push(data);
      cursor = addMinutes(cursor, dur);
    }

    // Fire confirmation email (fire-and-forget, won't block on failure)
    SB.emailBookingCreated({
      bookings: created,
      vendor: { id: vendor.id, name: vendor.business_name, email: vendor.contact_email || vendor.owner_email },
      client: { id: userId },
      when: { date: booking_date, time: start_time },
    }).catch(() => {});

    toast.success(`Booked! ${created.length} appointment${created.length === 1 ? "" : "s"} created.`);
    setFlow((f) => ({ ...f, step: "success", bookings: created }));
  };

  // Local helpers - keep self-contained so we don't depend on modal internals.
  const formatMins = (min) => {
    if (!min) return "";
    const h = Math.floor(min / 60), m = min % 60;
    if (h && m) return `${h}h ${m}m`;
    if (h) return `${h}h`;
    return `${m} min`;
  };
  const parseDur = (str = "") => {
    let total = 0;
    const h = str.match(/(\d+)\s*h/i); if (h) total += parseInt(h[1]) * 60;
    const m = str.match(/(\d+)\s*m/i); if (m) total += parseInt(m[1]);
    return total || 60;
  };

  const tonForCat = (c) => {
    if (!c) return "";
    const lower = c.toLowerCase();
    if (lower.includes("hair") || lower.includes("color")) return "accent";
    if (lower.includes("spa") || lower.includes("massage")) return "info";
    if (lower.includes("nail")) return "warn";
    return "pos";
  };

  return (
    <div className="page-enter">
      <S.PageHead eyebrow={`${vendors.length} active vendor${vendors.length === 1 ? "" : "s"}`} title="Discover" sub="Browse and book any vendor on Pamp." />

      <div className="card" style={{ marginBottom: 20, padding: 16 }}>
        <div className="row" style={{ gap: 10, flexWrap: "wrap" }}>
          <S.Input
            icon={<I.search size={15} />}
            placeholder="Search by vendor, city, or service…"
            style={{ flex: 1, minWidth: 240 }}
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
          />
        </div>
      </div>

      <div className="row" style={{ gap: 8, marginBottom: 24, overflowX: "auto", paddingBottom: 4 }}>
        {cats.map((c) => (
          <button key={c} onClick={() => setCat(c)}
            className={cat === c ? "btn btn-primary btn-sm" : "btn btn-outline btn-sm"}
          >{c}{c !== "All" && <span style={{ marginLeft: 4, opacity: 0.7, fontSize: 11 }}>({catCounts[c]})</span>}</button>
        ))}
      </div>

      {visible.length === 0 ? (
        <window.EmptyState
          icon={<I.store size={24} />}
          title={search || cat !== "All" ? "No vendors match" : "No vendors yet"}
          sub={search || cat !== "All" ? "Try a different search or category." : "Vendors will appear here once they sign up."}
        />
      ) : (
        <div className="grid-3">
          {visible.map((v) => {
            const isFav = favorites.has(v.id);
            const fromPrice = v.services?.length
              ? Math.min(...v.services.map(s => Number(s.price || 0)).filter(p => p > 0))
              : null;
            return (
              <div key={v.id} className="card" style={{ padding: 0, overflow: "hidden", cursor: "pointer" }}
                   onClick={() => openBookingFlow(v)}>
                {v.cover_image_url || v.logo_url ? (
                  <img src={v.cover_image_url || v.logo_url} alt={v.business_name}
                       style={{ width: "100%", height: 160, objectFit: "cover", display: "block" }}
                       onError={(e) => { e.target.style.display = "none"; }} />
                ) : (
                  <div className="placeholder-img" style={{ height: 160, borderRadius: 0 }}>{v.business_name}</div>
                )}
                <div style={{ padding: 18 }}>
                  <div className="row between">
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div className="row-tight">
                        {v.category && <S.Chip tone={tonForCat(v.category)}>{v.category}</S.Chip>}
                        {v.city && <span className="tiny muted">· {v.city}</span>}
                      </div>
                      <div style={{ fontWeight: 500, marginTop: 8 }}>{v.business_name}</div>
                      {v.tagline && <div className="muted tiny">{v.tagline}</div>}
                    </div>
                    <S.IconBtn onClick={(e) => toggleFavorite(e, v.id)}>
                      <I.heart size={16} color={isFav ? "var(--neg)" : undefined} style={isFav ? { fill: "var(--neg)" } : undefined} />
                    </S.IconBtn>
                  </div>
                  <div className="divider" style={{ margin: "14px 0" }} />
                  <div className="row between">
                    <div className="row-tight tiny">
                      {v.rating != null && <>
                        <I.star size={12} color="var(--warn)" /> <span className="mono">{Number(v.rating).toFixed(1)}</span>
                      </>}
                      {v.total_reviews ? <span className="muted">({v.total_reviews})</span> : null}
                    </div>
                    <div className="row-tight tiny muted">{v.services?.length || 0} service{v.services?.length === 1 ? "" : "s"}</div>
                  </div>
                  <div className="row between" style={{ marginTop: 14 }}>
                    {fromPrice !== null && fromPrice > 0
                      ? <span className="mono" style={{ fontSize: 14, fontWeight: 500 }}>from {window.fmtMoney(fromPrice)}</span>
                      : <span />}
                    <S.Btn size="sm" iconRight={<I.arrowR size={12} />} onClick={(e) => { e.stopPropagation(); openBookingFlow(v); }}>Book</S.Btn>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}

      <window.M.BookingModal
        open={flow?.step === "select"}
        vendor={flow?.modalVendor}
        onClose={closeFlow}
        onContinue={({ services, serviceIndices, staff }) =>
          setFlow((f) => ({ ...f, step: "calendar", services, serviceIndices, staff }))
        }
      />

      <window.M.BookingCalendarModal
        open={flow?.step === "calendar"}
        vendor={flow?.modalVendor}
        services={flow?.services || []}
        staff={flow?.staff}
        onClose={closeFlow}
        onBack={() => setFlow((f) => ({ ...f, step: "select" }))}
        onContinue={({ date, time }) =>
          setFlow((f) => ({ ...f, step: "details", date, time }))
        }
      />

      <window.M.BookingDetailsModal
        open={flow?.step === "details"}
        vendor={flow?.modalVendor}
        services={flow?.services || []}
        staff={flow?.staff}
        date={flow?.date}
        time={flow?.time}
        onClose={closeFlow}
        onBack={() => setFlow((f) => ({ ...f, step: "calendar" }))}
        onPay={submitBooking}
      />

      <window.M.BookingSuccessModal
        open={flow?.step === "success"}
        vendor={flow?.modalVendor}
        services={flow?.services || []}
        staff={flow?.staff}
        date={flow?.date}
        time={flow?.time}
        onClose={closeFlow}
        onView={closeFlow}
      />
    </div>
  );
}

/* ====================================================================
   USER — BOOKINGS
   ==================================================================== */
function UserBookings({ userId }) {
  const toast = window.useToast();
  const [tab, setTab] = React.useState("upcoming");
  const [bookings, setBookings] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    setBookings(null);
    SB.getUserBookings(userId).then(b => { if (alive) setBookings(b || []); });
    return () => { alive = false; };
  }, [userId, reloadKey]);

  if (bookings === null) return <div className="page-enter"><window.LoadingState /></div>;

  // Categorize
  const now = Date.now();
  const upcoming = bookings.filter(b => {
    if (b.status === "cancelled" || b.status === "completed" || b.status === "no_show") return false;
    const t = new Date(`${b.booking_date}T${b.start_time || "00:00"}`).getTime();
    return t >= now - 60 * 60 * 1000;
  });
  const past = bookings.filter(b => b.status === "completed");
  const cancelled = bookings.filter(b => b.status === "cancelled" || b.status === "no_show");
  const visible = tab === "upcoming" ? upcoming : tab === "past" ? past : cancelled;

  const cancelBooking = async (id) => {
    if (!confirm("Cancel this booking? You may be subject to your vendor's cancellation policy.")) return;
    const ok = await SB.updateBookingStatus(id, "cancelled");
    if (!ok) { toast.error("Could not cancel"); return; }
    toast.success("Booking cancelled");
    setReloadKey(k => k + 1);
  };

  return (
    <div className="page-enter">
      <S.PageHead eyebrow={`${upcoming.length} upcoming · ${past.length} past · ${cancelled.length} cancelled`} title="My bookings" sub="Everything you've scheduled, completed, or cancelled." />

      <div className="row" style={{ gap: 0, borderBottom: "1px solid var(--border)", marginBottom: 20 }}>
        {[
          { k: "upcoming", l: "Upcoming", n: upcoming.length },
          { k: "past", l: "Past", n: past.length },
          { k: "cancelled", l: "Cancelled", n: cancelled.length },
        ].map(t => (
          <button key={t.k} onClick={() => setTab(t.k)}
            style={{
              padding: "12px 18px", fontSize: 13, fontWeight: 500,
              color: tab === t.k ? "var(--ink)" : "var(--ink-3)",
              borderBottom: `2px solid ${tab === t.k ? "var(--ink)" : "transparent"}`,
            }}>
            {t.l} <span className="mono tiny muted">{t.n}</span>
          </button>
        ))}
      </div>

      {visible.length === 0 ? (
        <window.EmptyState
          icon={<I.bookings size={24} />}
          title={tab === "upcoming" ? "No upcoming bookings" : tab === "past" ? "No past bookings yet" : "No cancellations"}
          sub={tab === "upcoming" ? "Book a service to see it here." : tab === "past" ? "Completed bookings will appear here." : "Cancelled bookings show up here."}
        />
      ) : (
        <div className="col" style={{ gap: 14 }}>
          {visible.map((b) => {
            const isUpcoming = tab === "upcoming";
            return (
              <div key={b.id} className="card row" style={{ gap: 16, flexWrap: "wrap" }}>
                <div className="placeholder-img" style={{ width: 80, height: 80, borderRadius: 12, fontSize: 9, flexShrink: 0 }}>
                  {b.vendor_profiles?.business_name?.slice(0, 2).toUpperCase() || "—"}
                </div>
                <div style={{ flex: 1, minWidth: 200 }}>
                  <div className="row-tight">
                    <S.Chip tone={window.statusTone(b.status)}>{window.statusLabel(b.status)}</S.Chip>
                    <span className="muted tiny">{window.fmtDate(b.booking_date)} · {window.fmtTime(b.start_time)}</span>
                  </div>
                  <div style={{ fontSize: 16, fontWeight: 500, marginTop: 8 }}>{b.vendor_profiles?.business_name || "—"}</div>
                  <div className="muted" style={{ fontSize: 13 }}>{b.services?.name || "Service"} · {b.services?.duration_mins || 60} min</div>
                  {b.vendor_profiles?.city && <div className="muted tiny" style={{ marginTop: 4 }}><I.location size={11} /> {b.vendor_profiles.city}</div>}
                </div>
                <div style={{ textAlign: "right" }}>
                  <div className="display" style={{ fontSize: 22 }}>{window.fmtMoney(b.total_price)}</div>
                  <div className="muted tiny">total</div>
                </div>
                <div className="col" style={{ gap: 6 }}>
                  {isUpcoming ? <>
                    <S.Btn variant="ghost" size="sm" onClick={() => cancelBooking(b.id)} style={{ color: "var(--neg)" }}>Cancel</S.Btn>
                  </> : tab === "past" ? <>
                    <S.Btn variant="ghost" size="sm">Details</S.Btn>
                  </> : null}
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

/* ====================================================================
   USER — WALLET
   ==================================================================== */
function UserWallet() {
  return (
    <div className="page-enter">
      <window.DemoBanner feature="client wallet" />
      <S.PageHead eyebrow="Money" title="Wallet" sub="Credit, gift cards, payment methods, and history." />

      <div className="grid-12" style={{ marginBottom: 20 }}>
        <div className="card" style={{ gridColumn: "span 5", background: "var(--ink)", color: "var(--bg)", borderColor: "transparent", position: "relative", overflow: "hidden" }}>
          <div style={{ position: "absolute", inset: 0, background: "radial-gradient(circle at 80% 20%, var(--accent) 0%, transparent 50%)", opacity: 0.5 }} />
          <div style={{ position: "relative" }}>
            <div className="eyebrow" style={{ color: "oklch(75% 0.02 145)" }}>Available balance</div>
            <div className="display" style={{ fontSize: 56, color: "var(--bg)", letterSpacing: "-0.035em", marginTop: 8 }}>$248.40</div>
            <div className="muted tiny" style={{ color: "oklch(75% 0.02 145)" }}>≈ 4 average bookings</div>
            <div className="row" style={{ marginTop: 28, gap: 8 }}>
              <S.Btn variant="primary" icon={<I.plus size={14} />}>Top up</S.Btn>
              <S.Btn variant="ghost" style={{ color: "var(--bg)", background: "oklch(100% 0 0 / 0.10)" }} icon={<I.download size={14} />}>Withdraw</S.Btn>
            </div>
          </div>
        </div>

        <div className="card" style={{ gridColumn: "span 4", padding: 24, display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
          <div>
            <div className="eyebrow">Spent this year</div>
            <div className="display" style={{ fontSize: 36, marginTop: 10 }}>$1,824</div>
            <div className="row-tight" style={{ marginTop: 8 }}>
              <S.Chip tone="pos">+12%</S.Chip>
              <span className="muted tiny">vs last year</span>
            </div>
          </div>
          <div style={{ marginTop: 14 }}>
            <S.Spark data={[2, 3, 4, 3, 5, 4, 6, 5, 7, 8, 9, 8]} width={300} height={56} />
            <div className="row between" style={{ marginTop: 8 }}>
              <span className="muted tiny">Jan</span>
              <span className="muted tiny">Dec</span>
            </div>
          </div>
        </div>

        <div className="card" style={{ gridColumn: "span 3", padding: 22, display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
          <div>
            <div className="eyebrow">Loyalty</div>
            <div className="display" style={{ fontSize: 36, marginTop: 10 }}>Gold</div>
            <div className="muted tiny" style={{ marginTop: 4 }}>3 visits to Platinum</div>
          </div>
          <div className="bar" style={{ marginTop: 18 }}><span style={{ width: "82%" }} /></div>
        </div>
      </div>

      <div className="card card-flush">
        <div className="row between" style={{ padding: "22px 22px 14px" }}>
          <div className="h3">Recent activity</div>
          <S.Btn variant="outline" size="sm" icon={<I.download size={12} />}>Export</S.Btn>
        </div>
        <table className="tbl">
          <thead><tr><th>Date</th><th>Detail</th><th>Method</th><th className="col-num">Amount</th></tr></thead>
          <tbody>
            {[
              { d: "Feb 2", t: "Maison Color & Co. — Full color", m: "Visa ····2118", a: -184, tone: "neg" },
              { d: "Feb 1", t: "Top-up", m: "Apple Pay", a: 100, tone: "pos" },
              { d: "Jan 28", t: "Forest Spa — Deep tissue", m: "Wallet", a: -142, tone: "neg" },
              { d: "Jan 24", t: "Cut & Co Barber", m: "Visa ····2118", a: -38, tone: "neg" },
              { d: "Jan 18", t: "Loyalty bonus", m: "Pamp credit", a: 25, tone: "pos" },
            ].map((r, i) => (
              <tr key={i}>
                <td className="mono muted">{r.d}</td>
                <td>{r.t}</td>
                <td className="muted">{r.m}</td>
                <td className="col-num mono" style={{ color: r.a < 0 ? "var(--ink)" : "var(--pos)", fontWeight: 500 }}>
                  {r.a > 0 ? "+" : "−"}${Math.abs(r.a).toLocaleString()}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* Card-style payment method tiles */
function PaymentCardTile({ brand, num, name, exp, tone = "ink", isDefault, onMakeDefault }) {
  const palettes = {
    ink: { bg: "var(--ink)", fg: "white", accent: "var(--accent)" },
    accent: { bg: "linear-gradient(135deg, oklch(38% 0.05 145) 0%, oklch(28% 0.08 145) 100%)", fg: "white", accent: "var(--accent)" },
  };
  const p = palettes[tone];
  return (
    <div className="card" style={{ padding: 0, overflow: "hidden", display: "flex", flexDirection: "column" }}>
      <div style={{
        background: p.bg, color: p.fg, padding: 20, position: "relative", minHeight: 170,
        display: "flex", flexDirection: "column", justifyContent: "space-between",
      }}>
        <div style={{
          position: "absolute", top: -40, right: -40, width: 200, height: 200, borderRadius: "50%",
          background: `radial-gradient(circle, ${tone === "accent" ? "var(--accent)" : "oklch(72% 0.14 145 / 0.18)"} 0%, transparent 60%)`,
        }} />
        <div className="row between" style={{ position: "relative" }}>
          <div style={{ display: "flex", gap: 4 }}>
            <span style={{ width: 28, height: 20, borderRadius: 4, background: "oklch(100% 0 0 / 0.20)" }} />
            <span style={{ width: 28, height: 20, borderRadius: 4, background: "oklch(100% 0 0 / 0.10)" }} />
          </div>
          {isDefault && <S.Chip tone="accent" style={{ background: "oklch(100% 0 0 / 0.16)", color: p.accent, borderColor: "transparent" }}>Default</S.Chip>}
        </div>
        <div style={{ position: "relative" }}>
          <div className="mono" style={{ fontSize: 15, letterSpacing: "0.05em", marginBottom: 14 }}>{num}</div>
          <div className="row between">
            <div>
              <div className="mono tiny" style={{ opacity: 0.6, letterSpacing: "0.10em" }}>CARDHOLDER</div>
              <div style={{ fontSize: 12, marginTop: 2 }}>{name}</div>
            </div>
            <div>
              <div className="mono tiny" style={{ opacity: 0.6, letterSpacing: "0.10em", textAlign: "right" }}>EXPIRES</div>
              <div className="mono" style={{ fontSize: 12, marginTop: 2 }}>{exp}</div>
            </div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 16, fontWeight: 600, letterSpacing: "0.04em", color: p.accent }}>{brand}</div>
          </div>
        </div>
      </div>
      <div className="row between" style={{ padding: "12px 16px" }}>
        {!isDefault ? (
          <button onClick={onMakeDefault} className="btn btn-ghost btn-sm">Make default</button>
        ) : <span className="muted tiny">Primary card</span>}
        <S.IconBtn><I.ellipsis size={16} /></S.IconBtn>
      </div>
    </div>
  );
}
function ApplePayTile({ isDefault, onMakeDefault }) {
  return (
    <div className="card" style={{ padding: 0, overflow: "hidden", display: "flex", flexDirection: "column" }}>
      <div style={{
        background: "var(--surface)", border: "1px solid var(--border)",
        padding: 20, minHeight: 170, display: "flex", flexDirection: "column", justifyContent: "space-between",
        position: "relative",
      }}>
        <div className="row between">
          <div style={{
            width: 44, height: 44, borderRadius: 12,
            background: "var(--ink)", color: "var(--surface)",
            display: "flex", alignItems: "center", justifyContent: "center",
            fontFamily: "var(--font-display)", fontSize: 22, fontWeight: 600,
          }}></div>
          {isDefault && <S.Chip tone="accent">Default</S.Chip>}
        </div>
        <div>
          <div style={{ fontSize: 16, fontWeight: 500 }}>Apple Pay</div>
          <div className="muted tiny" style={{ marginTop: 4 }}>iPhone 15 Pro · Touch ID</div>
          <div className="row" style={{ marginTop: 14, gap: 6 }}>
            <S.Chip>Touch ID</S.Chip>
            <S.Chip>Auto-fill</S.Chip>
          </div>
        </div>
      </div>
      <div className="row between" style={{ padding: "12px 16px" }}>
        {!isDefault ? (
          <button onClick={onMakeDefault} className="btn btn-ghost btn-sm">Make default</button>
        ) : <span className="muted tiny">Primary method</span>}
        <S.IconBtn><I.ellipsis size={16} /></S.IconBtn>
      </div>
    </div>
  );
}

/* ====================================================================
   USER — FAVORITES + NOTIFICATIONS
   ==================================================================== */
function UserFavorites({ userId, onNav }) {
  const toast = window.useToast();
  const [favorites, setFavorites] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    setFavorites(null);
    SB.getUserFavorites(userId).then(f => { if (alive) setFavorites(f || []); });
    return () => { alive = false; };
  }, [userId, reloadKey]);

  if (favorites === null) return <div className="page-enter"><window.LoadingState /></div>;

  const remove = async (vendorId) => {
    const { error } = await SB.client.from("favorites").delete().eq("user_id", userId).eq("vendor_id", vendorId);
    if (error) { toast.error("Couldn't unfavorite"); return; }
    toast.success("Removed from favorites");
    setReloadKey(k => k + 1);
  };

  return (
    <div className="page-enter">
      <S.PageHead eyebrow={`${favorites.length} saved vendor${favorites.length === 1 ? "" : "s"}`} title="Favorites" sub="Vendors you've saved for later." />
      {favorites.length === 0 ? (
        <window.EmptyState
          icon={<I.heart size={24} />}
          title="No favorites yet"
          sub="Tap the heart on any vendor to save them here."
          action={<S.Btn variant="primary" size="sm" icon={<I.sparkle size={14} />} onClick={() => onNav?.("discover")}>Discover vendors</S.Btn>}
        />
      ) : (
        <div className="grid-3">
          {favorites.map((item) => {
            const v = item.vendor_profiles;
            if (!v) return null;
            return (
              <div key={v.id} className="card" style={{ padding: 0, overflow: "hidden" }}>
                {v.logo_url ? (
                  <img src={v.logo_url} alt={v.business_name} style={{ width: "100%", height: 120, objectFit: "cover", display: "block" }} onError={(e) => { e.target.style.display = "none"; }} />
                ) : (
                  <div className="placeholder-img" style={{ height: 120, borderRadius: 0 }}>{v.business_name}</div>
                )}
                <div style={{ padding: 16 }}>
                  <div className="row between">
                    <span className="muted tiny">{v.city || ""}</span>
                    <button onClick={() => remove(v.id)} aria-label="Remove favorite">
                      <I.heart size={16} color="var(--neg)" style={{ fill: "var(--neg)" }} />
                    </button>
                  </div>
                  <div style={{ marginTop: 12, fontWeight: 500 }}>{v.business_name}</div>
                  <div className="row between" style={{ marginTop: 8 }}>
                    {v.rating != null ? (
                      <span className="row-tight tiny"><I.star size={12} color="var(--warn)" />{Number(v.rating).toFixed(1)}</span>
                    ) : <span />}
                    <S.Btn size="sm" variant="outline" onClick={() => onNav?.("discover")}>Book</S.Btn>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

function UserNotifications({ userId }) {
  const toast = window.useToast();
  const [items, setItems] = React.useState(null);
  const [filter, setFilter] = React.useState("all");
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    setItems(null);
    SB.client
      .from("notifications")
      .select("*")
      .eq("user_id", userId)
      .order("created_at", { ascending: false })
      .limit(100)
      .then(({ data }) => { if (alive) setItems(data || []); });
    return () => { alive = false; };
  }, [userId, reloadKey]);

  if (items === null) return <div className="page-enter"><window.LoadingState /></div>;

  const counts = {
    all: items.length,
    unread: items.filter(n => !n.read).length,
  };

  const filtered = filter === "all"
    ? items
    : filter === "unread"
      ? items.filter(n => !n.read)
      : items;

  // Group by date bucket (Today / Yesterday / Earlier)
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
  const groups = filtered.reduce((acc, n) => {
    const d = new Date(n.created_at);
    const bucket = d >= today ? "Today" : d >= yesterday ? "Yesterday" : "Earlier";
    (acc[bucket] = acc[bucket] || []).push(n);
    return acc;
  }, {});

  const markAllRead = async () => {
    const unread = items.filter(n => !n.read).map(n => n.id);
    if (unread.length === 0) return;
    const { error } = await SB.client.from("notifications").update({ read: true }).in("id", unread);
    if (error) { toast.error("Couldn't mark read"); return; }
    toast.success(`Marked ${unread.length} as read`);
    setReloadKey(k => k + 1);
  };

  const markOneRead = async (id) => {
    const { error } = await SB.client.from("notifications").update({ read: true }).eq("id", id);
    if (error) return;
    setReloadKey(k => k + 1);
  };

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`${counts.unread} unread \u00b7 ${counts.all} total`}
        title="Notifications"
        sub="Booking updates, perks, and system messages."
        right={counts.unread > 0 && <>
          <S.Btn variant="outline" size="sm" icon={<I.check size={14} />} onClick={markAllRead}>Mark all read</S.Btn>
        </>}
      />

      {counts.unread > 0 && (
        <div className="card" style={{
          padding: 22, marginBottom: 20,
          background: "var(--accent-soft)", color: "var(--accent-ink)", borderColor: "transparent",
          display: "flex", alignItems: "center", gap: 18,
        }}>
          <div style={{
            width: 48, height: 48, borderRadius: 14, background: "var(--accent)",
            color: "oklch(20% 0.10 145)", display: "flex", alignItems: "center", justifyContent: "center",
          }}>
            <I.bell size={22} />
          </div>
          <div style={{ flex: 1 }}>
            <div className="display" style={{ fontSize: 22, color: "var(--accent-ink)" }}>{counts.unread} unread notification{counts.unread === 1 ? "" : "s"}</div>
            <div className="muted tiny" style={{ marginTop: 2, color: "var(--accent-ink)", opacity: 0.7 }}>
              Tap any notification to mark it read.
            </div>
          </div>
        </div>
      )}

      <div className="row" style={{ gap: 8, marginBottom: 20 }}>
        {[
          { k: "all", l: "All", c: counts.all },
          { k: "unread", l: "Unread", c: counts.unread },
        ].map((f) => (
          <button key={f.k} onClick={() => setFilter(f.k)}
            className={`btn btn-sm ${filter === f.k ? "btn-primary" : "btn-outline"}`}>
            {f.l}
            <span className="mono tiny" style={{
              marginLeft: 4, opacity: filter === f.k ? 0.75 : 0.55,
              padding: "1px 7px", borderRadius: 999,
              background: filter === f.k ? "oklch(0% 0 0 / 0.10)" : "var(--surface-3)",
            }}>{f.c}</span>
          </button>
        ))}
      </div>

      {Object.keys(groups).length === 0 ? (
        <window.EmptyState
          icon={<I.bell size={24} />}
          title="All caught up"
          sub={filter === "unread" ? "No unread notifications." : "You'll see updates here as they come in."}
        />
      ) : (
        Object.entries(groups).map(([bucket, list]) => (
          <div key={bucket} style={{ marginBottom: 20 }}>
            <div className="row between" style={{ marginBottom: 10 }}>
              <div className="eyebrow">{bucket}</div>
              <span className="muted tiny">{list.length} {list.length === 1 ? "notification" : "notifications"}</span>
            </div>
            <div className="card card-flush">
              {list.map((n, i) => (
                <NotifRow key={n.id} n={n} isLast={i === list.length - 1} onMarkRead={markOneRead} />
              ))}
            </div>
          </div>
        ))
      )}
    </div>
  );
}

function NotifRow({ n, isLast, onMarkRead }) {
  const tone = n.tone || "info";
  return (
    <div className="row"
      onClick={() => !n.read && onMarkRead?.(n.id)}
      style={{
        padding: "18px 20px",
        borderBottom: isLast ? "none" : "1px solid var(--border)",
        gap: 16, position: "relative",
        background: n.read ? "transparent" : "var(--surface-2)",
        cursor: !n.read ? "pointer" : "default",
      }}>
      {!n.read && <span style={{
        position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)",
        width: 6, height: 6, borderRadius: "50%", background: "var(--accent)",
      }} />}
      <div style={{
        width: 42, height: 42, borderRadius: 12, flexShrink: 0,
        background: `var(--${tone === "accent" ? "accent" : tone}-soft)`,
        color: tone === "accent" ? "var(--accent-ink)" : `var(--${tone})`,
        display: "flex", alignItems: "center", justifyContent: "center",
      }}><I.bell size={18} /></div>

      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="row between" style={{ alignItems: "flex-start" }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: n.read ? 400 : 500, color: "var(--ink)" }}>{n.title}</div>
            <div className="muted" style={{ fontSize: 13, marginTop: 4, lineHeight: 1.5 }}>{n.body}</div>
          </div>
          <div style={{ textAlign: "right", marginLeft: 14 }}>
            <div className="muted tiny" style={{ whiteSpace: "nowrap" }}>{window.fmtDateTime(n.created_at)}</div>
          </div>
        </div>
      </div>
    </div>
  );
}


window.UserApp = UserApp;

/* ====================================================================
   USER — PAMP PROGRAM (rewards: invite friends + discount codes + payouts)
   ==================================================================== */
function UserInfluencer() {
  return (
    <div className="page-enter">
      <window.DemoBanner feature="Pamp Influencer program" />
      <S.PageHead
        eyebrow="Rewards · invite-only ambassadors"
        title="Pamp Program"
        sub="Invite friends, redeem codes, and earn for every booking you drive."
        right={<S.Btn variant="primary" size="sm" icon={<I.sparkle size={14} />}>View payout</S.Btn>}
      />

      {/* hero */}
      <div className="card" style={{
        padding: 36, marginBottom: 28, position: "relative", overflow: "hidden",
        background: "var(--ink)", color: "var(--surface)", borderColor: "transparent",
        display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 32, alignItems: "center",
      }}>
        <div style={{
          position: "absolute", inset: 0, opacity: 0.6,
          background: "radial-gradient(circle at 85% 20%, var(--accent) 0%, transparent 50%), radial-gradient(circle at 15% 80%, var(--accent) 0%, transparent 50%)",
          filter: "blur(40px)",
        }} />
        <div style={{ position: "relative" }}>
          <S.Chip tone="accent" style={{ background: "var(--accent)", color: "oklch(20% 0.10 145)" }}>Status · Gold ambassador</S.Chip>
          <div className="display" style={{ fontSize: 48, lineHeight: 1.05, letterSpacing: "-0.035em", marginTop: 18, color: "var(--surface)" }}>
            $1,248.40 <span style={{ opacity: 0.4, fontSize: 18 }}>earned this year</span>
          </div>
          <div style={{ color: "oklch(85% 0.02 145)", fontSize: 14, maxWidth: 480, marginTop: 10 }}>
            Your link drove 84 bookings across 12 vendors. Next tier (<strong style={{ color: "var(--accent)" }}>Platinum</strong>) unlocks 15% rev share + early access.
          </div>
          <div className="row" style={{ marginTop: 24, gap: 8 }}>
            <S.Btn variant="primary" style={{ background: "white", color: "var(--ink)" }} icon={<I.export size={14} />}>Share link</S.Btn>
            <S.Btn variant="ghost" style={{ color: "var(--surface)", background: "oklch(100% 0 0 / 0.12)" }}>How payouts work</S.Btn>
          </div>
        </div>
        <div style={{ position: "relative" }}>
          <div className="eyebrow" style={{ color: "var(--accent)", marginBottom: 16 }}>Tier progress</div>
          {[
            { tier: "Silver", at: 0, done: true },
            { tier: "Gold", at: 50, done: true, current: true },
            { tier: "Platinum", at: 80 },
            { tier: "Diamond", at: 100 },
          ].map((t, i) => (
            <div key={t.tier} className="row" style={{ gap: 14, padding: "10px 0" }}>
              <div style={{
                width: 32, height: 32, borderRadius: 10,
                background: t.current ? "var(--accent)" : t.done ? "oklch(100% 0 0 / 0.16)" : "oklch(100% 0 0 / 0.06)",
                color: t.current ? "oklch(20% 0.10 145)" : t.done ? "var(--accent)" : "oklch(60% 0 0)",
                display: "flex", alignItems: "center", justifyContent: "center",
                fontFamily: "var(--font-mono)", fontSize: 11, fontWeight: 600,
              }}>{t.done ? "✓" : i + 1}</div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 500, color: t.current ? "var(--accent)" : "var(--surface)" }}>{t.tier}</div>
                <div className="bar" style={{ marginTop: 4, background: "oklch(100% 0 0 / 0.10)" }}>
                  <span style={{ width: `${t.at}%`, background: t.current ? "var(--accent)" : "oklch(100% 0 0 / 0.40)" }} />
                </div>
              </div>
              <span className="mono tiny" style={{ color: "oklch(75% 0.02 145)" }}>{t.at}%</span>
            </div>
          ))}
        </div>
      </div>

      {/* ───────────── SECTION 1 · Invite friends ───────────── */}
      <PampSectionHead num="01" title="Invite friends" sub="Refer a friend. They get $15 off their first booking, you get $15 in credit." />
      <div className="grid-12" style={{ marginBottom: 32 }}>
        <div className="card" style={{ gridColumn: "span 7" }}>
          <div className="grid-3" style={{ marginBottom: 22 }}>
            <InviteStat label="Earned" value="$45" />
            <InviteStat label="Joined" value="3" />
            <InviteStat label="Booked" value="2" />
          </div>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Your invite link</div>
          <div className="row" style={{ gap: 8, marginBottom: 18 }}>
            <S.Input value="pamp.app/i/amelia-7k2" style={{ flex: 1 }} />
            <S.Btn variant="outline" icon={<I.export size={12} />}>Copy</S.Btn>
            <S.Btn variant="primary" icon={<I.mail size={12} />}>Email</S.Btn>
          </div>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Or send directly</div>
          <div className="row" style={{ gap: 8 }}>
            <S.Input icon={<I.mail size={14} />} placeholder="friend@example.com" style={{ flex: 1 }} />
            <S.Btn variant="primary">Send invite</S.Btn>
          </div>
        </div>

        <div className="card card-flush" style={{ gridColumn: "span 5" }}>
          <div className="row between" style={{ padding: "22px 22px 14px" }}>
            <div className="h3">Invite tracking</div>
            <span className="muted tiny">Last 30 days</span>
          </div>
          <div className="col" style={{ gap: 0 }}>
            {[
              { e: "mia@hey.com", s: "Booked", st: "pos", date: "Jan 14" },
              { e: "alex@gmail.com", s: "Joined", st: "info", date: "Jan 9" },
              { e: "sarah@me.com", s: "Pending", st: "warn", date: "Jan 4" },
              { e: "noah@hey.com", s: "Pending", st: "warn", date: "Dec 28" },
            ].map((r, i, a) => (
              <div key={r.e} className="row between" style={{
                padding: "14px 22px",
                borderBottom: i === a.length - 1 ? "none" : "1px solid var(--border)",
              }}>
                <span style={{ fontSize: 13 }}>{r.e}</span>
                <span className="row-tight" style={{ gap: 10 }}>
                  <span className="muted tiny">{r.date}</span>
                  <S.Chip tone={r.st}>{r.s}</S.Chip>
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* ───────────── SECTION 2 · Discount codes ───────────── */}
      <PampSectionHead num="02" title="Discount codes" sub="Redeem promotional codes and track what's active on your account." />
      <div className="grid-12" style={{ marginBottom: 32 }}>
        <div className="card" style={{ gridColumn: "span 5" }}>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Redeem a code</div>
          <div className="row" style={{ gap: 8, marginBottom: 16 }}>
            <S.Input icon={<I.coupon size={14} />} placeholder="Enter code" style={{ flex: 1 }} />
            <S.Btn variant="primary">Apply</S.Btn>
          </div>
          <div style={{
            padding: 14, borderRadius: 12,
            background: "var(--accent-soft)", color: "var(--accent-ink)",
            fontSize: 12.5, lineHeight: 1.5,
          }}>
            Codes apply to your next eligible booking. Some codes are vendor-specific — usage details show below.
          </div>
        </div>

        <div className="card card-flush" style={{ gridColumn: "span 7" }}>
          <div className="row between" style={{ padding: "22px 22px 12px" }}>
            <div>
              <div className="h3">Active codes</div>
              <div className="muted tiny" style={{ marginTop: 2 }}>2 active · 1 expiring soon</div>
            </div>
            <S.Btn variant="ghost" size="sm">See all</S.Btn>
          </div>
          <div className="col" style={{ gap: 0 }}>
            {[
              { code: "WELCOME10", desc: "10% off your first booking", exp: "Expires Mar 30", uses: "1 / 1 use" },
              { code: "PAMPGOLD", desc: "Gold-tier · 15% off facials", exp: "Always active", uses: "4 / unlimited" },
              { code: "FORESTLOVE", desc: "10% off Forest Spa", exp: "Expires Feb 24", uses: "0 / 1 use" },
            ].map((c, i, a) => (
              <div key={c.code} className="row" style={{
                padding: "16px 22px", gap: 14,
                borderBottom: i === a.length - 1 ? "none" : "1px solid var(--border)",
              }}>
                <div style={{
                  width: 44, height: 44, borderRadius: 10, background: "var(--accent-soft)",
                  color: "var(--accent-ink)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
                }}><I.coupon size={18} /></div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div className="row-tight" style={{ gap: 10 }}>
                    <span className="mono" style={{ fontSize: 14, fontWeight: 600 }}>{c.code}</span>
                    <span className="muted tiny">· {c.uses}</span>
                  </div>
                  <div className="muted tiny" style={{ marginTop: 4 }}>{c.desc}</div>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div className="tiny muted">{c.exp}</div>
                  <button style={{ fontSize: 12, color: "var(--accent-ink)", fontWeight: 500, marginTop: 4 }}>Remove</button>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* ───────────── SECTION 3 · Ambassador (payouts, link, perks) ───────────── */}
      <PampSectionHead num="03" title="Ambassador earnings" sub="Track clicks, sign-ups and payouts from your share link." />

      {/* metric strip */}
      <div className="grid-4" style={{ marginBottom: 20 }}>
        <S.Metric label="Total clicks" value="3,418" delta="+24%" />
        <S.Metric label="Sign-ups" value="142" delta="+12%" />
        <S.Metric label="Bookings driven" value="84" delta="+18%" />
        <S.Metric label="Avg. payout / booking" value="$14.86" delta="+$1.40" />
      </div>

      {/* perks + link */}
      <div className="grid-12">
        <div className="card" style={{ gridColumn: "span 7" }}>
          <div className="h3" style={{ marginBottom: 14 }}>Your share link</div>
          <div className="row" style={{ gap: 8, marginBottom: 22 }}>
            <S.Input value="pamp.app/i/amelia-7k2" style={{ flex: 1 }} />
            <S.Btn variant="outline" icon={<I.export size={12} />}>Copy</S.Btn>
            <S.Btn variant="primary" icon={<I.sparkle size={12} />}>Custom slug</S.Btn>
          </div>
          <div className="eyebrow" style={{ marginBottom: 12 }}>Share-ready assets</div>
          <div className="grid-3" style={{ gap: 10 }}>
            {["Story · 9:16", "Post · 1:1", "Banner · 16:9"].map((s) => (
              <div key={s} className="placeholder-img" style={{ height: 110, fontSize: 11 }}>{s}</div>
            ))}
          </div>
        </div>

        <div className="card" style={{ gridColumn: "span 5" }}>
          <div className="h3" style={{ marginBottom: 14 }}>Gold ambassador perks</div>
          <div className="col" style={{ gap: 14 }}>
            {[
              { i: <I.crown />, t: "10% revenue share on every booking" },
              { i: <I.sparkle />, t: "Early access to new vendors & launches" },
              { i: <I.heart />, t: "$15 credit for the friend you invite" },
              { i: <I.star />, t: "Featured slot in the Discover feed monthly" },
            ].map((p, i) => (
              <div key={i} className="row-tight" style={{ gap: 12 }}>
                <span style={{ width: 32, height: 32, borderRadius: 8, background: "var(--accent-soft)", color: "var(--accent-ink)", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
                  {React.cloneElement(p.i, { size: 16 })}
                </span>
                <div style={{ fontSize: 13 }}>{p.t}</div>
              </div>
            ))}
          </div>
        </div>

        <div className="card card-flush" style={{ gridColumn: "span 12" }}>
          <div className="row between" style={{ padding: "22px 22px 14px" }}>
            <div className="h3">Recent payouts</div>
            <S.Btn variant="ghost" size="sm">Statements</S.Btn>
          </div>
          <table className="tbl">
            <thead>
              <tr><th>Date</th><th>Period</th><th>Bookings driven</th><th>Method</th><th>Status</th><th className="col-num">Amount</th></tr>
            </thead>
            <tbody>
              {[
                { d: "Feb 1", p: "Jan 2026", n: 14, m: "Pamp credit", s: "Paid", st: "pos", a: 184.20 },
                { d: "Jan 1", p: "Dec 2025", n: 18, m: "PayPal ····42", s: "Paid", st: "pos", a: 248.80 },
                { d: "Dec 1", p: "Nov 2025", n: 12, m: "Pamp credit", s: "Paid", st: "pos", a: 156.40 },
              ].map((r, i) => (
                <tr key={i}>
                  <td className="mono">{r.d}</td>
                  <td className="muted">{r.p}</td>
                  <td className="mono">{r.n}</td>
                  <td className="muted">{r.m}</td>
                  <td><S.Chip tone={r.st}>{r.s}</S.Chip></td>
                  <td className="col-num mono" style={{ fontWeight: 500 }}>${r.a.toFixed(2)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

function PampSectionHead({ num, title, sub }) {
  return (
    <div className="row" style={{ gap: 14, alignItems: "flex-end", marginBottom: 16, marginTop: 8 }}>
      <span className="mono" style={{
        fontSize: 11, letterSpacing: "0.12em", color: "var(--ink-3)",
        padding: "4px 9px", borderRadius: 6, background: "var(--surface-3)",
      }}>{num}</span>
      <div>
        <div className="h3" style={{ lineHeight: 1.1 }}>{title}</div>
        {sub && <div className="muted tiny" style={{ marginTop: 4 }}>{sub}</div>}
      </div>
    </div>
  );
}

function InviteStat({ label, value }) {
  return (
    <div style={{
      padding: "14px 16px", borderRadius: 12,
      background: "var(--surface-2)", border: "1px solid var(--border)",
    }}>
      <div className="eyebrow">{label}</div>
      <div className="display" style={{ fontSize: 24, marginTop: 4, lineHeight: 1 }}>{value}</div>
    </div>
  );
}

/* ====================================================================
   USER — SETTINGS
   ==================================================================== */
function UserSettings({ userId, profile }) {
  const toast = window.useToast();
  const [data, setData] = React.useState(null);
  const [original, setOriginal] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [pwdData, setPwdData] = React.useState({ newPwd: "", confirmPwd: "" });

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    SB.getProfile(userId).then(p => {
      if (!alive) return;
      const next = {
        full_name: p?.full_name || "",
        phone:     p?.phone || "",
        city:      p?.city || "",
        email:     p?.email || profile?.email || "",
      };
      setData(next);
      setOriginal(JSON.stringify(next));
    });
    return () => { alive = false; };
  }, [userId]);

  if (data === null) return <div className="page-enter"><window.LoadingState /></div>;

  const dirty = JSON.stringify(data) !== original;
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));

  const save = async () => {
    setBusy(true);
    try {
      const { error } = await SB.client
        .from("profiles")
        .update({
          full_name: data.full_name.trim() || null,
          phone:     data.phone.trim() || null,
          city:      data.city.trim() || null,
        })
        .eq("id", userId);
      if (error) { toast.error(error.message || "Save failed"); return; }
      toast.success("Profile updated");
      setOriginal(JSON.stringify(data));
    } finally {
      setBusy(false);
    }
  };

  const changePassword = async () => {
    if (!pwdData.newPwd || pwdData.newPwd.length < 8) { toast.error("Password must be at least 8 characters"); return; }
    if (pwdData.newPwd !== pwdData.confirmPwd) { toast.error("Passwords don't match"); return; }
    setBusy(true);
    try {
      const { error } = await SB.client.auth.updateUser({ password: pwdData.newPwd });
      if (error) { toast.error(error.message || "Couldn't update password"); return; }
      toast.success("Password updated");
      setPwdData({ newPwd: "", confirmPwd: "" });
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Account"
        title="Settings"
        sub="Your profile, password, and account."
        right={<>
          <S.Btn variant="ghost" size="sm" onClick={() => setData(JSON.parse(original))} disabled={!dirty || busy}>Discard</S.Btn>
          <S.Btn variant="primary" size="sm" icon={<I.check size={14} />} onClick={save} disabled={!dirty || busy}>
            {busy ? "Saving…" : "Save changes"}
          </S.Btn>
        </>}
      />

      <div className="card" style={{ padding: 22, marginBottom: 20 }}>
        <div className="row between" style={{ marginBottom: 18 }}>
          <div>
            <div className="h3">Profile</div>
            <div className="muted tiny" style={{ marginTop: 4 }}>How you appear to vendors.</div>
          </div>
        </div>
        <div className="row" style={{ gap: 18, alignItems: "center", paddingBottom: 18, borderBottom: "1px solid var(--border)", marginBottom: 18 }}>
          <S.Avatar name={data.full_name || data.email} size="xl" />
          <div>
            <div style={{ fontSize: 16, fontWeight: 500 }}>{data.full_name || "—"}</div>
            <div className="muted tiny">{data.email}</div>
          </div>
        </div>
        <div className="grid-2" style={{ gap: 16 }}>
          <div>
            <label className="field-label">Full name</label>
            <S.Input value={data.full_name} onChange={(e) => set("full_name", e.target.value)} placeholder="Your name" />
          </div>
          <div>
            <label className="field-label">Phone</label>
            <S.Input icon={<I.phone size={14} />} value={data.phone} onChange={(e) => set("phone", e.target.value)} placeholder="+44 7700 900 142" />
          </div>
          <div>
            <label className="field-label">City</label>
            <S.Input icon={<I.location size={14} />} value={data.city} onChange={(e) => set("city", e.target.value)} placeholder="London, UK" />
          </div>
          <div>
            <label className="field-label">Email</label>
            <S.Input value={data.email} disabled style={{ opacity: 0.6 }} />
            <div className="field-hint">Email changes require admin support.</div>
          </div>
        </div>
      </div>

      <div className="card" style={{ padding: 22, marginBottom: 20 }}>
        <div className="h3" style={{ marginBottom: 4 }}>Change password</div>
        <div className="muted tiny" style={{ marginBottom: 18 }}>You'll stay signed in on this device.</div>
        <div className="grid-2" style={{ gap: 16 }}>
          <div>
            <label className="field-label">New password</label>
            <S.Input type="password" icon={<I.lock size={14} />} value={pwdData.newPwd} onChange={(e) => setPwdData(d => ({ ...d, newPwd: e.target.value }))} placeholder="At least 8 characters" />
          </div>
          <div>
            <label className="field-label">Confirm new password</label>
            <S.Input type="password" icon={<I.lock size={14} />} value={pwdData.confirmPwd} onChange={(e) => setPwdData(d => ({ ...d, confirmPwd: e.target.value }))} placeholder="Repeat password" />
          </div>
        </div>
        <div className="row" style={{ marginTop: 14 }}>
          <div className="spacer" />
          <S.Btn variant="primary" size="sm" onClick={changePassword} disabled={busy || !pwdData.newPwd || !pwdData.confirmPwd}>
            {busy ? "Saving…" : "Update password"}
          </S.Btn>
        </div>
      </div>
    </div>
  );
}

window.UserInfluencer = UserInfluencer;
window.UserSettings = UserSettings;

/* ====================================================================
   USER — REPORTS
   ==================================================================== */
function UserReports({ userId }) {
  const [bookings, setBookings] = React.useState(null);

  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    SB.getUserBookings(userId).then(b => { if (alive) setBookings(b || []); });
    return () => { alive = false; };
  }, [userId]);

  if (bookings === null) return <div className="page-enter"><window.LoadingState /></div>;

  const completed = bookings.filter(b => b.status === "completed");
  const totalSpent = completed.reduce((s, b) => s + Number(b.total_price || 0), 0);
  const avgPerVisit = completed.length ? totalSpent / completed.length : 0;

  // Distinct vendors visited
  const vendorMap = {};
  completed.forEach(b => {
    const name = b.vendor_profiles?.business_name;
    if (!name) return;
    vendorMap[name] = vendorMap[name] || { name, count: 0, spent: 0 };
    vendorMap[name].count += 1;
    vendorMap[name].spent += Number(b.total_price || 0);
  });
  const topVendors = Object.values(vendorMap).sort((a, b) => b.count - a.count).slice(0, 5);

  // Spend by month - last 12 months
  const now = new Date();
  const monthBuckets = [];
  const monthLabels = [];
  for (let i = 11; i >= 0; i--) {
    const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
    monthBuckets.push(0);
    monthLabels.push(d.toLocaleDateString("en-US", { month: "short" }));
  }
  completed.forEach(b => {
    const d = new Date(b.booking_date);
    const monthsAgo = (now.getFullYear() - d.getFullYear()) * 12 + (now.getMonth() - d.getMonth());
    if (monthsAgo >= 0 && monthsAgo < 12) {
      monthBuckets[11 - monthsAgo] += Number(b.total_price || 0);
    }
  });

  // Service categories
  const serviceMap = {};
  completed.forEach(b => {
    const name = b.services?.name;
    if (!name) return;
    serviceMap[name] = (serviceMap[name] || 0) + 1;
  });
  const topServices = Object.entries(serviceMap)
    .map(([name, count]) => ({ name, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 5);

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Your activity"
        title="Reports"
        sub="Where your time and money go on Pamp."
      />

      <div className="grid-4" style={{ marginBottom: 20 }}>
        <S.Metric hero label="Total spent" value={window.fmtMoney(totalSpent)} delta={`${completed.length} completed`} />
        <S.Metric label="Bookings" value={bookings.length.toString()} delta={`${completed.length} completed`} />
        <S.Metric label="Vendors visited" value={Object.keys(vendorMap).length.toString()} />
        <S.Metric label="Avg. per visit" value={window.fmtMoney(avgPerVisit)} />
      </div>

      <div className="grid-12" style={{ marginBottom: 20 }}>
        <div className="card" style={{ gridColumn: "span 8" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="eyebrow">Spending</div>
              <div className="h3" style={{ marginTop: 4 }}>By month \u00b7 last 12 months</div>
            </div>
          </div>
          {totalSpent === 0 ? (
            <div className="muted" style={{ padding: "60px 0", textAlign: "center" }}>No completed bookings yet</div>
          ) : (
            <S.BarChart height={240} labels={monthLabels} data={monthBuckets} color="var(--accent)" />
          )}
        </div>

        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="eyebrow" style={{ marginBottom: 4 }}>Loyalty</div>
          <div className="h3" style={{ marginBottom: 18 }}>Top vendors</div>
          {topVendors.length === 0 ? (
            <div className="muted tiny" style={{ padding: "20px 0" }}>No data yet</div>
          ) : (
            <div className="col" style={{ gap: 14 }}>
              {topVendors.map((v, i) => {
                const max = topVendors[0].count;
                const pct = (v.count / max) * 100;
                return (
                  <div key={v.name}>
                    <div className="row between" style={{ marginBottom: 4 }}>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{v.name}</span>
                      <span className="mono tiny muted">{v.count} \u00b7 {window.fmtMoney(v.spent)}</span>
                    </div>
                    <div className="bar"><span style={{ width: `${pct}%`, background: i === 0 ? "var(--accent)" : "var(--accent-soft)" }} /></div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>

      <div className="card">
        <div className="row between" style={{ marginBottom: 18 }}>
          <div>
            <div className="eyebrow">Habits</div>
            <div className="h3" style={{ marginTop: 4 }}>Most booked services</div>
          </div>
        </div>
        {topServices.length === 0 ? (
          <div className="muted" style={{ padding: "20px 0", textAlign: "center" }}>No completed services yet</div>
        ) : (
          <div className="col" style={{ gap: 14 }}>
            {topServices.map((s, i) => {
              const max = topServices[0].count;
              const pct = (s.count / max) * 100;
              return (
                <div key={s.name}>
                  <div className="row between" style={{ marginBottom: 4 }}>
                    <span style={{ fontSize: 13, fontWeight: 500 }}>{s.name}</span>
                    <span className="mono tiny muted">{s.count} {s.count === 1 ? "booking" : "bookings"}</span>
                  </div>
                  <div className="bar"><span style={{ width: `${pct}%`, background: i === 0 ? "var(--accent)" : "var(--accent-soft)" }} /></div>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}

window.UserReports = UserReports;

/* ====================================================================
   USER — MY PLAN
   ==================================================================== */
function UserPlan({ userId }) {
  const [plans, setPlans] = React.useState(null);

  React.useEffect(() => {
    let alive = true;
    SB.adminGetPlans(null).then(p => {
      if (!alive) return;
      // Filter to user-facing plans
      const filtered = (p || []).filter(plan => (plan.audience || "user") === "user" && plan.is_active !== false);
      setPlans(filtered);
    });
    return () => { alive = false; };
  }, [userId]);

  if (plans === null) return <div className="page-enter"><window.LoadingState /></div>;

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Membership"
        title="My plan"
        sub="Pamp memberships unlock perks, discounts, and priority booking."
      />

      <div className="card" style={{ padding: 32, marginBottom: 24, background: "var(--ink)", color: "var(--bg)", borderColor: "transparent", position: "relative", overflow: "hidden" }}>
        <div style={{
          position: "absolute", inset: 0, opacity: 0.6,
          background: "radial-gradient(circle at 85% 15%, var(--accent) 0%, transparent 45%), radial-gradient(circle at 20% 90%, oklch(55% 0.16 320) 0%, transparent 50%)",
          filter: "blur(40px)",
        }} />
        <div style={{ position: "relative", zIndex: 1 }}>
          <div className="eyebrow" style={{ color: "oklch(80% 0.04 290)" }}>Current plan</div>
          <div className="display" style={{ fontSize: 44, letterSpacing: "-0.035em", lineHeight: 1, margin: "16px 0 8px", color: "var(--bg)" }}>
            Free tier
          </div>
          <div className="muted" style={{ color: "oklch(82% 0.02 145)", fontSize: 14 }}>
            You're on the free Pamp plan. Upgrade for member perks and discounts.
          </div>
        </div>
      </div>

      {plans.length === 0 ? (
        <window.EmptyState
          icon={<I.crown size={24} />}
          title="No paid plans available yet"
          sub="Pamp memberships are coming soon. Check back in a bit."
        />
      ) : (
        <>
          <div className="eyebrow" style={{ marginBottom: 14 }}>Available plans</div>
          <div className="grid-3">
            {plans.map(p => {
              const features = Array.isArray(p.features) ? p.features : (p.features ? Object.values(p.features) : []);
              const price = Number(p.price || 0);
              return (
                <div key={p.id} className="card" style={{ padding: 24 }}>
                  <div className="row between">
                    <div className="h3">{p.name}</div>
                    <I.crown size={20} color="var(--accent-ink)" />
                  </div>
                  <div className="display" style={{ fontSize: 40, marginTop: 14, letterSpacing: "-0.03em" }}>
                    {price === 0 ? "Free" : window.fmtMoney(price)}
                    {price > 0 && <span className="muted" style={{ fontSize: 13, fontWeight: 400, marginLeft: 6 }}>/{p.duration === "Annual" ? "yr" : "mo"}</span>}
                  </div>
                  <div className="divider" style={{ margin: "18px 0" }} />
                  <ul style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 8 }}>
                    {features.length === 0
                      ? <li className="muted tiny">No features listed.</li>
                      : features.map((f, i) => (
                        <li key={i} className="row-tight" style={{ fontSize: 13 }}>
                          <I.check size={14} color="var(--pos)" /> {f}
                        </li>
                      ))}
                  </ul>
                  <S.Btn variant="outline" size="sm" style={{ width: "100%", marginTop: 22 }} disabled>
                    Coming soon
                  </S.Btn>
                </div>
              );
            })}
          </div>
        </>
      )}

      <div className="card" style={{ padding: 18, marginTop: 24, background: "var(--surface-2)", borderStyle: "dashed" }}>
        <div className="row-tight" style={{ gap: 10 }}>
          <span style={{ color: "var(--ink-3)" }}><I.alert size={14} /></span>
          <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
            Plan subscriptions and billing are still being wired up. You can browse plans here, but you can't subscribe yet.
            <span className="muted">{" "}This will be enabled in a future phase.</span>
          </div>
        </div>
      </div>
    </div>
  );
}
