/* ========================================================================
   sim-manage.jsx — Redesigned SIM Details page + Manage SIM slide-out
   Overrides the SimShowPage exported from pages-1.jsx (loaded after it).
   Reuses global helpers: Icon, Card, Button, BackLink, Empty, Avatar,
   SimTypeBadge, UsageRing, KvCell, KV, FakeQR (function declarations in
   app.jsx / pages-1.jsx are global across the Babel scripts).
   ======================================================================== */
const { useState: uS, useEffect: eS, useMemo: mS } = React;
const SD = window.MILO_DATA;

/* ---------- Service model (one source of truth — panel + glance) ---------- */
const SIM_SVC_MAIN = [
{ key: "data", label: "Data", sub: "Mobile data", icon: "signal", cost: false },
{ key: "sms", label: "SMS", sub: "Send SMS messages", icon: "message-square", cost: false },
{ key: "outgoing", label: "Outgoing calls", sub: "Master control for all outbound voice", icon: "phone-outgoing", cost: false },
{ key: "intl", label: "International Calls", sub: "Calls to outside the UK", icon: "languages", cost: true },
{ key: "premium", label: "Premium Calls", sub: "Premium-rate numbers", icon: "star", cost: true },
{ key: "wifi", label: "WiFi Calling", sub: "Make voice calls using Wi-Fi data when available", icon: "wifi", cost: false }];

const SIM_ROAMING = [
{ key: "roaming_eu", label: "Roaming (EU/EEA)", sub: "Voice and data while in the EU/EEA", icon: "map", cost: true },
{ key: "roaming_global", label: "Roaming (Global)", sub: "Voice and data outside the EU/EEA", icon: "globe", cost: true }];

const SIM_ALL_DEFS = [...SIM_SVC_MAIN, ...SIM_ROAMING];
const DEFAULT_SERVICES = {
  data: true, sms: true, outgoing: true, intl: false, premium: false, wifi: true,
  roaming_eu: true, roaming_global: false
};

const MACRO_META = {
  active: { label: "Active", tone: "active", icon: "circle-check" },
  /* Clay, matching StatusBadge's clay variant exactly: one status, one colour. */
  ready: { label: "Ready to Install", tone: "clay", icon: "qr-code" },
  scheduled: { label: "Scheduled for pause", tone: "scheduled", icon: "circle-pause" },
  paused: { label: "Paused", tone: "paused", icon: "circle-pause" },
  blocked: { label: "Blocked", tone: "blocked", icon: "ban" }
};

/* ---------- Helpers ---------- */
/* Two bundle types in the platform. IoT is always Data Only; everything else
   is deterministic from the SIM so it looks real but never drifts. */
function simBundleType(sim) {
  if (sim.sim_type === "IoT") return "Data Only";
  const seed = String(sim.id) + (sim.serial || "");
  let h = 0;
  for (let i = 0; i < seed.length; i++) { h = h * 31 + seed.charCodeAt(i) >>> 0; }
  return h % 3 === 0 ? "Data Only" : "Voice + Data";
}

/* Stable, format-correct demo IMEI (WW-XXXXXX-YYYYYY-Z) derived from the SIM */
function simImei(sim) {
  const seed = String(sim.id) + (sim.serial || "") + (sim.msisdn || "");
  let h = 0;
  for (let i = 0; i < seed.length; i++) {h = h * 31 + seed.charCodeAt(i) >>> 0;}
  const digits = [];
  let x = h || 1;
  for (let i = 0; i < 15; i++) {x = x * 1103515245 + 12345 >>> 0;digits.push(x % 10);}
  const d = digits.join("");
  return d.slice(0, 2) + "-" + d.slice(2, 8) + "-" + d.slice(8, 14) + "-" + d.slice(14);
}

function firstOfNextMonth() {
  const d = new Date();
  const n = new Date(d.getFullYear(), d.getMonth() + 1, 1);
  return n.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" });
}
function countOn(defs, services) {
  return defs.filter((d) => services[d.key]).length + " of " + defs.length + " on";
}
function diffServices(saved, work) {
  return SIM_ALL_DEFS.
  filter((d) => saved[d.key] !== work[d.key]).
  map((d) => ({ label: d.label, on: work[d.key], cost: d.cost }));
}
function simStateKey(id) {return "mp-sim-state-" + id;}
function loadSimState(sim) {
  try {
    const raw = localStorage.getItem(simStateKey(sim.id));
    if (raw) {
      const p = JSON.parse(raw);
      return {
        macro: p.macro || "active",
        date: p.date || null,
        services: { ...DEFAULT_SERVICES, ...(p.services || {}) },
        assignedUserId: p.assignedUserId !== undefined ? p.assignedUserId : null,
        imei: p.imei || null
      };
    }
  } catch (e) {}
  return {
    macro: sim.status === "Suspended" ? "paused" : "active",
    date: null,
    services: { ...DEFAULT_SERVICES },
    assignedUserId: null,
    imei: null
  };
}
function persistSimState(id, st) {
  try {localStorage.setItem(simStateKey(id), JSON.stringify(st));} catch (e) {}
}

function usageTone(pct) {
  return pct >= 100 ? "over" : pct >= 80 ? "warn" : "ok";
}
function simUser(sim) {
  return SD.USERS.find((u) => u.sim_ids.includes(sim.id)) || null;
}

/* ---------- Macro status badge ----------
   A SIM has one visible status. An eSIM waiting to be set up reads Ready to
   Install here too, so the hero never disagrees with the install section. */
function MacroBadge({ macro, date, sim }) {
  if (macro === "active" && sim && window.MP_ESIM && window.MP_ESIM.isReady(sim)) macro = "ready";
  const m = MACRO_META[macro] || MACRO_META.active;
  return (
    <span className={"mp-macro-badge mp-macro-badge--" + m.tone}>
      <Icon name={m.icon} size={13} />
      <span>{m.label}{macro === "scheduled" && date ? " · from " + date : ""}</span>
    </span>);

}

/* ---------- Generic collapsible section ---------- */
function Collapsible({ title, icon, defaultOpen = false, right, children }) {
  const [open, setOpen] = uS(defaultOpen);
  return (
    <div className={"mp-coll" + (open ? " is-open" : "")}>
      <button type="button" className="mp-coll-head" onClick={() => setOpen((o) => !o)} aria-expanded={open}>
        {icon ? <Icon name={icon} size={16} className="mp-coll-ic" /> : null}
        <span className="mp-coll-title">{title}</span>
        {right || null}
        <Icon name="chevron-down" size={16} className="mp-coll-caret" />
      </button>
      {open ? <div className="mp-coll-body">{children}</div> : null}
    </div>);

}

/* ---------- Toggle pill (restyled to brand palette) ---------- */
function ServiceToggle({ on, disabled, onChange }) {
  return (
    <button
      type="button"
      role="switch"
      aria-checked={on}
      className={"mp-toggle" + (on ? " is-on" : "") + (disabled ? " is-disabled" : "")}
      onClick={() => {if (!disabled) onChange(!on);}}>
      <span className="mp-toggle-label">{on ? "On" : "Off"}</span>
      <span className="mp-toggle-knob" />
    </button>);

}

/* ---------- One service row — editable (toggle) or read-only (pill) ---------- */
function ServiceRow({ def, on, readOnly, disabled, onToggle }) {
  return (
    <div className="mp-svc-row">
      <span className={"mp-svc-ic " + (on ? "mp-svc-ic--on" : "mp-svc-ic--off")}><Icon name={def.icon} size={16} /></span>
      <div className="mp-svc-text">
        <div className="mp-svc-label">{def.label}</div>
        {def.sub ? <div className="mp-svc-sub">{def.sub}</div> : null}
      </div>
      {def.cost ?
      <span className="mp-svc-cost" tabIndex={0} aria-label="May incur out-of-bundle charges">
          <Icon name="pound-sterling" size={13} />
          <span className="mp-cost-tip">Turning this on may incur out-of-bundle charges. Check your contract or ask your account manager.</span>
        </span> :
      null}
      {readOnly ?
      <span className={"mp-state-pill" + (on ? " is-on" : "")}>{on ? "On" : "Off"}</span> :
      <ServiceToggle on={on} disabled={disabled} onChange={(v) => onToggle(def.key, v)} />}
    </div>);

}

/* ---------- Service list — two collapsible sections, shared by panel + glance ---------- */
function ServiceList({ services, readOnly, disabled, onToggle, servicesOpen = false, roamingOpen = false }) {
  const row = (def) =>
  <ServiceRow key={def.key} def={def} on={!!services[def.key]} readOnly={readOnly} disabled={disabled} onToggle={onToggle} />;

  return (
    <>
      <Collapsible
        title="Voice and Data Services"
        icon="shield-check"
        defaultOpen={servicesOpen}
        right={<span className="mp-coll-meta">{countOn(SIM_SVC_MAIN, services)}</span>}>
        <div className={"mp-svc-list" + (disabled ? " is-locked" : "")}>{SIM_SVC_MAIN.map(row)}</div>
      </Collapsible>
      <Collapsible
        title="International Calls &amp; Data Roaming"
        icon="plane"
        defaultOpen={roamingOpen}
        right={<span className="mp-coll-meta">{countOn(SIM_ROAMING, services)}</span>}>
        <div className={"mp-svc-list" + (disabled ? " is-locked" : "")}>{SIM_ROAMING.map(row)}</div>
      </Collapsible>
    </>);

}

/* ---------- Save-confirmation modal (diff of changes) ---------- */
function SaveDiffModal({ diff, onCancel, onConfirm }) {
  const costy = diff.some((d) => d.cost && d.on);
  return (
    <div className="mp-modal-overlay" onClick={onCancel}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="sliders-horizontal" size={20} /></div>
        <h3 className="mp-modal-title">Confirm changes</h3>
        <p className="mp-modal-text">
          You're about to apply {diff.length} change{diff.length === 1 ? "" : "s"} to this SIM. These take effect immediately.
        </p>
        <ul className="mp-diff">
          {diff.map((d, i) =>
          <li key={i} className={d.on ? "is-on" : "is-off"}>
              <span className="mp-diff-label">{d.label}</span>
              <span className="mp-diff-arrow">→</span>
              <span className="mp-diff-to">{d.on ? "Enabled" : "Disabled"}</span>
            </li>
          )}
        </ul>
        {costy ?
        <div className="mp-modal-note mp-modal-note--warn">
            <Icon name="triangle-alert" size={16} />
            <span>Please note this may make you liable for out-of-bundle charges or extra costs.</span>
          </div> :
        null}
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onCancel}>Cancel</Button>
          <Button variant="primary" icon="check" onClick={onConfirm}>Confirm Changes</Button>
        </div>
      </div>
    </div>);

}

/* ---------- Manage SIM slide-out panel ---------- */
function ManageSimPanel({ sim, services, locked, lockReason, macro, onAction, onClose, onSave, onBack }) {
  const [work, setWork] = uS(services);
  const [showDiff, setShowDiff] = uS(false);
  const ctx = window.useRoles ? window.useRoles() : null;
  const toggle = (k, v) => setWork((w) => ({ ...w, [k]: v }));
  const diff = diffServices(services, work);

  // Esc to close
  eS(() => {
    const onKey = (e) => {if (e.key === "Escape") {if (showDiff) setShowDiff(false);else onClose();}};
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [showDiff]);

  const handleSave = () => {
    if (diff.length === 0) {onClose();return;}
    setShowDiff(true);
  };

  return (
    <>
      <div className="mp-drawer-scrim" onClick={onClose} />
      <aside className="mp-drawer" role="dialog" aria-label="Manage SIM">
        <header className="mp-drawer-head">
          <div style={{ minWidth: 0 }}>
            <div className="mp-drawer-headline">
              {onBack ? (
                <button type="button" className="mp-drawer-back" onClick={onBack} aria-label="Back to SIM details">
                  <Icon name="arrow-left" size={16} />
                </button>
              ) : null}
              <h3>Manage SIM</h3>
            </div>
            <div className="mp-drawer-sub">
              {simLabel(sim)}
              {simUser(sim) ? <> · Assigned to <strong>{simUser(sim).full_name}</strong></> : <> · Unassigned</>}
            </div>
          </div>
          <button type="button" className="mp-drawer-x" onClick={onClose} aria-label="Close">
            <Icon name="x" size={18} />
          </button>
        </header>

        <div className="mp-drawer-body">
          <SimActionsList onAction={onAction} macro={macro} sim={sim} />

          {locked ?
          <div className={"mp-svc-banner mp-svc-banner--" + (sim._macro === "blocked" ? "blocked" : "paused")}>
              <Icon name={sim._macro === "blocked" ? "ban" : "circle-pause"} size={16} />
              <span>{lockReason}</span>
            </div> :
          null}

          <div className="mp-action-group-title" style={{ marginTop: 4 }}>Service controls</div>
          <ServiceList services={work} disabled={locked} onToggle={toggle} servicesOpen={false} roamingOpen={false} />
        </div>

        <footer className="mp-drawer-foot">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button
            variant="primary"
            icon="check"
            className={locked ? "is-disabled" : ""}
            onClick={locked ? undefined : handleSave}>
            Save changes
          </Button>
        </footer>
      </aside>

      {showDiff ?
      <SaveDiffModal
        diff={diff}
        onCancel={() => setShowDiff(false)}
        onConfirm={() => {
          onSave(work);
          setShowDiff(false);
          onClose();
          if (ctx && ctx.toast) ctx.toast({ kind: "ok", title: "Service changes submitted", body: "These changes are being applied and will update shortly." });
        }} /> :

      null}
    </>);

}

/* ---------- Macro confirm dialogs ---------- */
function dialogConfig(type, planPrice) {
  if (type === "pause") return {
    icon: "circle-pause", tone: "neutral", title: "Pause this SIM?",
    body: <>Your SIM and number will remain active, but your plan and all services will be paused. You'll pay <strong>£2/month</strong> instead of <strong>£{planPrice}/month</strong> from <strong>{firstOfNextMonth()}</strong>, and you can resume at any time.</>,
    confirm: { label: "Schedule pause", icon: "circle-pause" }, confirmVariant: "primary"
  };
  if (type === "resume") return {
    icon: "circle-play", tone: "neutral", title: "Resume this SIM?",
    body: <>Service will be restored immediately and the plan reinstated, prorated for the rest of the billing period.</>,
    confirm: { label: "Resume SIM", icon: "circle-play" }, confirmVariant: "primary"
  };
  if (type === "block") return {
    icon: "ban", tone: "danger", title: "Block this SIM?",
    body: <>Use this if the SIM has been lost or stolen. All service (calls, texts and data) stops immediately. You can unblock it later.</>,
    confirm: { label: "Block SIM", icon: "ban" }, confirmVariant: "danger-solid"
  };
  if (type === "unblock") return {
    icon: "rotate-ccw", tone: "neutral", title: "Unblock this SIM?",
    body: <>This will request reactivation of the SIM and restore its previous service settings.</>,
    note: "Restoring a blocked SIM can take some time while the network reactivates it. Service may not return instantly.",
    noteTone: "warn",
    confirm: { label: "Unblock SIM", icon: "rotate-ccw" }, confirmVariant: "primary"
  };
  return null;
}
function ConfirmDialog({ cfg, onConfirm, onCancel }) {
  if (!cfg) return null;
  return (
    <div className="mp-modal-overlay" onClick={onCancel}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className={"mp-modal-ic mp-modal-ic--" + cfg.tone}><Icon name={cfg.icon} size={22} /></div>
        <h3 className="mp-modal-title">{cfg.title}</h3>
        <p className="mp-modal-text">{cfg.body}</p>
        {cfg.note ?
        <div className={"mp-modal-note mp-modal-note--" + (cfg.noteTone || "warn")}>
            <Icon name="triangle-alert" size={16} />
            <span>{cfg.note}</span>
          </div> :
        null}
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onCancel}>Cancel</Button>
          <Button variant={cfg.confirmVariant} icon={cfg.confirm.icon} onClick={onConfirm}>{cfg.confirm.label}</Button>
        </div>
      </div>
    </div>);

}

/* ---------- Header actions — Manage SIM + state-aware macro actions ---------- */
function MacroActions({ macro, onManage, onAction }) {
  return (
    <div className="mp-sim-actions">
      <Button variant="primary" icon="sliders-horizontal" onClick={onManage}>Manage SIM</Button>
      <span className="mp-sim-actions-div" />
      {macro === "active" ?
      <>
          <Button variant="secondary" icon="circle-pause" onClick={() => onAction("pause")}>Pause SIM</Button>
          <Button variant="danger" icon="ban" onClick={() => onAction("block")}>Block SIM</Button>
        </> :
      null}
      {macro === "scheduled" ?
      <>
          <Button variant="secondary" icon="rotate-ccw" onClick={() => onAction("cancelPause")}>Cancel pause</Button>
          <Button variant="danger" icon="ban" onClick={() => onAction("block")}>Block SIM</Button>
        </> :
      null}
      {macro === "paused" ?
      <>
          <Button variant="secondary" icon="circle-play" onClick={() => onAction("resume")}>Resume SIM</Button>
          <Button variant="danger" icon="ban" onClick={() => onAction("block")}>Block SIM</Button>
        </> :
      null}
      {macro === "blocked" ?
      <Button variant="primary" icon="rotate-ccw" onClick={() => onAction("unblock")}>Unblock SIM</Button> :
      null}
    </div>);

}

/* ---------- One tappable action row (matches expander tiles) ---------- */
function ActionRow({ icon, label, onClick, tone }) {
  return (
    <button type="button" className={"mp-action-row" + (tone ? " mp-action-row--" + tone : "")} onClick={onClick}>
      <Icon name={icon} size={16} className="mp-action-ic-lead" />
      <span className="mp-action-label">{label}</span>
      <Icon name="chevron-right" size={16} className="mp-action-chev" />
    </button>);

}

/* ---------- SIM actions list (top of Manage SIM panel) ---------- */
function SimActionsList({ onAction, macro = "active", sim }) {
  const canMove = sim && window.MP_ESIM && window.MP_ESIM.isInstalled(sim) &&
    !(window.MP_REQ && window.MP_REQ.openRequestFor(sim.id));
  return (
    <>
      <div className="mp-action-group">
        <div className="mp-action-group-title">Service status</div>
        <div className="mp-action-list">
          {macro === "active" ? <>
            <ActionRow icon="circle-pause" label="Pause SIM" onClick={() => onAction("pause")} />
            <ActionRow icon="ban" label="Block SIM" tone="danger" onClick={() => onAction("block")} />
          </> : null}
          {macro === "scheduled" ? <>
            <ActionRow icon="rotate-ccw" label="Cancel scheduled pause" onClick={() => onAction("cancelPause")} />
            <ActionRow icon="ban" label="Block SIM" tone="danger" onClick={() => onAction("block")} />
          </> : null}
          {macro === "paused" ? <>
            <ActionRow icon="circle-play" label="Resume SIM" onClick={() => onAction("resume")} />
            <ActionRow icon="ban" label="Block SIM" tone="danger" onClick={() => onAction("block")} />
          </> : null}
          {macro === "blocked" ? (
            <ActionRow icon="rotate-ccw" label="Unblock SIM" onClick={() => onAction("unblock")} />
          ) : null}
        </div>
      </div>
      <div className="mp-action-group">
        <div className="mp-action-group-title">SIM actions</div>
        <div className="mp-action-list">
          <ActionRow icon="user-round-cog" label="Reassign SIM" onClick={() => onAction("reassign")} />
          {canMove ? <ActionRow icon="smartphone" label="Move to Another Device" onClick={() => onAction("moveDevice")} /> : null}
          <ActionRow icon="pencil" label="Edit IMEI" onClick={() => onAction("editImei")} />
        </div>
      </div>
    </>);

}

/* ---------- Reassign SIM dialog ---------- */
function ReassignDialog({ currentUserId, onCancel, onConfirm }) {
  const [val, setVal] = uS(currentUserId != null ? String(currentUserId) : "");
  const opts = SD.USERS.map((u) => ({ value: String(u.id), label: u.full_name + " (" + u.email + ")" }));
  return (
    <div className="mp-modal-overlay" onClick={onCancel}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="user-round-cog" size={22} /></div>
        <h3 className="mp-modal-title">Reassign SIM</h3>
        <p className="mp-modal-text">Choose the user this SIM should be assigned to. They'll see it on their account immediately.</p>
        <div className="mp-field">
          <label className="mp-field-label">Assign to</label>
          {window.UserSearchPicker
            ? <window.UserSearchPicker candidates={SD.USERS} value={val} onChange={setVal} />
            : <Select value={val} onChange={setVal} options={opts} placeholder="Unassigned" />}
        </div>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onCancel}>Cancel</Button>
          <Button variant="primary" icon="check" onClick={() => onConfirm(val === "" ? null : Number(val))}>Reassign SIM</Button>
        </div>
      </div>
    </div>);

}

/* ---------- Edit IMEI dialog ---------- */
function EditImeiDialog({ current, onCancel, onConfirm }) {
  const [val, setVal] = uS(current);
  const digits = (val.match(/\d/g) || []).length;
  const valid = digits === 15;
  return (
    <div className="mp-modal-overlay" onClick={onCancel}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="pencil" size={20} /></div>
        <h3 className="mp-modal-title">Edit IMEI</h3>
        <p className="mp-modal-text">The IMEI is the 15-digit identifier of the device this SIM sits in.</p>
        <div className="mp-field">
          <label className="mp-field-label">IMEI number</label>
          <input
            className="mp-field-input"
            value={val}
            inputMode="numeric"
            placeholder="WW-XXXXXX-YYYYYY-Z"
            onChange={(e) => setVal(e.target.value)} />
          <div className="mp-field-hint">{valid ? "15 digits entered, looks good." : digits + " of 15 digits entered."}</div>
        </div>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onCancel}>Cancel</Button>
          <Button variant="primary" icon="check" className={valid ? "" : "is-disabled"} onClick={valid ? () => onConfirm(val.trim()) : undefined}>Save IMEI</Button>
        </div>
      </div>
    </div>);

}

/* ---------- Macro page banner (non-active states) ---------- */
function MacroBanner({ macro, date, onAction }) {
  if (macro === "active") return null;
  if (macro === "scheduled") return (
    <div className="mp-macro-banner mp-macro-banner--scheduled">
      <Icon name="circle-pause" size={18} />
      <span className="mp-macro-banner-text">
        This SIM is <strong>scheduled to pause on {date}</strong>. You'll be charged £2/month while paused and all services will be barred.
      </span>
      <Button variant="secondary" size="sm" icon="rotate-ccw" onClick={() => onAction("cancelPause")}>Cancel pause</Button>
    </div>);

  if (macro === "paused") return (
    <div className="mp-macro-banner mp-macro-banner--paused">
      <Icon name="circle-pause" size={18} />
      <span className="mp-macro-banner-text">
        This SIM is <strong>paused</strong>. You're charged £2/month and all services are barred. Service controls are unavailable until it's resumed.
      </span>
      <Button variant="secondary" size="sm" icon="circle-play" onClick={() => onAction("resume")}>Resume SIM</Button>
    </div>);

  if (macro === "blocked") return (
    <div className="mp-macro-banner mp-macro-banner--blocked">
      <Icon name="ban" size={18} />
      <span className="mp-macro-banner-text">
        This SIM is <strong>blocked</strong> (lost or stolen). All service has stopped. Unblock it to begin reactivation.
      </span>
      <Button variant="primary" size="sm" icon="rotate-ccw" onClick={() => onAction("unblock")}>Unblock SIM</Button>
    </div>);

  return null;
}

/* ---------- Redesigned SIM Details page ---------- */
function SimDetail({ sim }) {
  const plan = SD.PLANS[sim.plan];
  const baseUser = SD.USERS.find((u) => u.sim_ids.includes(sim.id));
  const init = mS(() => loadSimState(sim), [sim.id]);

  const [macro, setMacro] = uS(init.macro);
  const [schedDate, setSchedDate] = uS(init.date);
  const [services, setServices] = uS(init.services);
  const [assignedUserId, setAssignedUserId] = uS(init.assignedUserId !== null ? init.assignedUserId : baseUser ? baseUser.id : null);
  const [imei, setImei] = uS(init.imei || simImei(sim));
  const [panelOpen, setPanelOpen] = uS(false);
  const [dialog, setDialog] = uS(null);
  const [detailsOpen, setDetailsOpen] = uS(false);
  if (window.MP_REQ) window.MP_REQ.useRequests();
  if (window.MP_ESIM) window.MP_ESIM.useInstall();
  const reqState = window.MP_REQ ? window.MP_REQ.openRequestFor(sim.id) || window.MP_REQ.noticeFor(sim.id) : null;

  const user = assignedUserId != null ? SD.USERS.find((u) => u.id === assignedUserId) : null;

  eS(() => {persistSimState(sim.id, { macro, date: schedDate, services, assignedUserId, imei });}, [macro, schedDate, services, assignedUserId, imei, sim.id]);
  eS(() => {if (window.lucide) {try {window.lucide.createIcons();} catch (e) {}}});

  const locked = macro === "paused" || macro === "blocked";
  const lockReason = macro === "blocked" ?
  "This SIM is blocked. Service controls are unavailable until it's unblocked." :
  "This SIM is paused. Service controls are unavailable until it's resumed.";

  const handleAction = (type) => {
    if (type === "cancelPause") {setMacro("active");setSchedDate(null);return;}
    setDialog(type);
  };
  const confirmDialog = () => {
    if (dialog === "pause") {setMacro("scheduled");setSchedDate(firstOfNextMonth());} else
    if (dialog === "resume") {setMacro("active");setSchedDate(null);} else
    if (dialog === "block") {setMacro("blocked");setSchedDate(null);} else
    if (dialog === "unblock") {setMacro("active");setSchedDate(null);}
    setDialog(null);
  };

  // expose macro to the panel banner without prop-drilling extra flags
  const simForPanel = { ...sim, _macro: macro };

  return (
    <>
      <PageHead title="SIM Management" />
      <BackLink href="#/sims">Back to SIMs</BackLink>

      {/* ---- Summary card ---- */}
      <Card style={{ overflow: "hidden" }}>
        <div className="mp-sim-bar">
          <div>
            <div className="mp-sim-hero-eyebrow">SIM details</div>
            <h2 className="mp-sim-hero-number">{simLabel(sim)}</h2>
            <div className="mp-sim-hero-meta">
              {user ?
              <>
                  <Avatar initials={user.initials} size={26} tone="mist" />
                  <span>Assigned to <a href={"#/users/" + user.id} style={{ color: "var(--mp-pine)", fontWeight: 700, textDecoration: "underline" }}>{user.full_name}</a></span>
                </> :

              <span style={{ color: "var(--fg-3)" }}>Unassigned</span>
              }
              <span className="mp-dot-sep">•</span>
              <SimTypeBadge type={sim.sim_type} />
              <MacroBadge macro={macro} date={schedDate} sim={sim} />
            </div>
          </div>
          {MP_ALLOW("sim.manage") ?
          <div className="mp-sim-hero-actions">
            <MacroActions macro={macro} onManage={() => setPanelOpen(true)} onAction={handleAction} />
          </div> : null}
        </div>

        {macro !== "active" && MP_ALLOW("sim.manage") ?
        <div className="mp-sim-banner-wrap">
            <MacroBanner macro={macro} date={schedDate} onAction={handleAction} />
          </div> :
        null}

        {reqState ? <div className="mp-sim-banner-wrap"><window.RequestBanner sim={sim} /></div> : null}

        {window.AssignmentPendingBanner ?
        <div className="mp-sim-banner-wrap"><window.AssignmentPendingBanner sim={sim} /></div> : null}

        <button
          type="button"
          className={"mp-sim-disclosure" + (detailsOpen ? " is-open" : "")}
          onClick={() => setDetailsOpen((o) => !o)}
          aria-expanded={detailsOpen}>
          <Icon name="chevron-down" size={16} />
          <span>{detailsOpen ? "Hide" : "Show"} usage and full SIM details</span>
        </button>

        {detailsOpen ?
        <div className="mp-sim-details">
            <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 16 }}>
              <div className="mp-profile-block">
                <h4 style={{ margin: 0, fontSize: 15, fontWeight: 700, marginBottom: 14 }}>Data Usage</h4>
                <div className="mp-usage-ring-wrap">
                  <UsageRing used={sim.used} limit={plan.limit_gb} />
                </div>
                <div className="mp-usage-stats">
                  <KV label="Plan allowance" value={window.MP_POOL && window.MP_POOL.isPooled(sim.id) ? window.MP_POOL.label + " (shared)" : plan.data} />
                  <KV label="Used this period" value={sim.used.toFixed(1) + " GB"} />
                  {plan.limit_gb ? <KV label="Remaining" value={Math.max(0, plan.limit_gb - sim.used).toFixed(1) + " GB"} /> : null}
                </div>
              </div>
              <div className="mp-profile-block">
                <h4 style={{ margin: 0, fontSize: 15, fontWeight: 700, marginBottom: 14 }}>SIM Card Information</h4>
                <div className="mp-kv-grid">
                  {sim.msisdn ? <KvCell label="Phone Number" value={sim.msisdn} /> : null}
                  <KvCell label="SIM Serial" value={sim.serial} />
                  <KvCell label="IMEI" value={imei} />
                  <KvCell label="Data Active" value={sim.data_active ? "Yes" : "No"} />
                  <KvCell label="SIM Type" value={sim.sim_type} />
                  <KvCell label="Bundle Type" value={simBundleType(sim)} />
                  <KvCell label="Activation Date" value={fmtActivation(sim.activation_date)} />
                </div>
              </div>
            </div>

            {user &&
          <div className="mp-profile-block" style={{ marginTop: 16 }}>
                <div className="mp-profile-row">
                  <div className="mp-profile-av">{user.initials}</div>
                  <div>
                    <div className="mp-profile-name">
                      <a href={"#/users/" + user.id} style={{ color: "var(--mp-pine)", textDecoration: "underline" }}>{user.full_name}</a>{" "}
                      <span style={{ color: "var(--fg-3)", fontWeight: 500, fontSize: 16 }}>({user.email})</span>
                    </div>
                    <div className="mp-profile-meta">Assigned user · <a href={"#/users/" + user.id} style={{ color: "var(--mp-pine)", fontWeight: 600 }}>View profile</a></div>
                  </div>
                </div>
              </div>
          }
          </div> :
        null}
      </Card>

      {/* ---- Install this eSIM (install state, not SIM status) ---- */}
      {window.EsimInstallCard ? <window.EsimInstallCard sim={sim} /> : null}

      {/* ---- Services at a glance (read-only) ---- */}
      <Card>
        <div className="mp-card-head">
          <div className="mp-glance-head" style={{ width: "100%" }}>
            <div>
              <h3>Services at a glance</h3>
              <div className="mp-card-head-sub">Current voice, data, and roaming service settings for this SIM. {!MP_ALLOW("sim.manage") ? "These are set by your account administrators." : locked ? "Controls are locked while " + (macro === "blocked" ? "blocked" : "paused") + "." : "Open Manage SIM to change them."}</div>
            </div>
            {MP_ALLOW("sim.manage") ?
            <button type="button" className="mp-glance-link" onClick={() => setPanelOpen(true)}>
              <Icon name="sliders-horizontal" size={15} /> Manage SIM
            </button> : null}
          </div>
        </div>
        <div className="mp-card-body">
          <ServiceList services={services} readOnly={true} servicesOpen={false} roamingOpen={false} />
        </div>
      </Card>

      {panelOpen ?
      <ManageSimPanel
        sim={simForPanel}
        services={services}
        locked={locked}
        lockReason={lockReason}
        macro={macro}
        onAction={handleAction}
        onClose={() => setPanelOpen(false)}
        onSave={(next) => setServices(next)} /> :

      null}

      <ConfirmDialog cfg={dialogConfig(dialog, plan.price)} onConfirm={confirmDialog} onCancel={() => setDialog(null)} />

      {dialog === "reassign" ?
      <ReassignDialog
        currentUserId={assignedUserId}
        onCancel={() => setDialog(null)}
        onConfirm={(uid) => {
          setAssignedUserId(uid);
          /* Assigning an eSIM that is waiting to be set up sends its
             activation email to the new user. */
          if (uid != null && window.MP_ESIM && window.MP_ESIM.isReady(sim)) window.MP_ESIM.sendActivationEmail(sim.id);
          setDialog(null);
        }} /> :

      null}

      {dialog === "moveDevice" && window.RequestConfirmModal ?
      <window.RequestConfirmModal sim={sim} type="move_device"
        onCancel={() => setDialog(null)}
        onConfirm={() => { window.MP_REQ.createRequest(sim.id, "move_device"); setDialog(null); setPanelOpen(false); }} /> :
      null}

      {dialog === "editImei" ?
      <EditImeiDialog
        current={imei}
        onCancel={() => setDialog(null)}
        onConfirm={(v) => {setImei(v);setDialog(null);}} /> :

      null}
    </>);

}

/* ---------- Page wrapper — keyed remount so state resets per SIM ---------- */
function SimShowPage({ id }) {
  const sim = SD.SIMS.find((s) => s.id === Number(id));
  if (!sim) return <Empty icon="search" title="Not found" message="That SIM could not be found." />;
  return <SimDetail key={sim.id} sim={sim} />;
}

/* ---------- Reusable read-only SIM summary card (used on the User page) ----------
   Matches the SIM Details page main card: same hero bar, eyebrow, macro badge,
   collapsible "usage and full SIM details", and the same field set / terms.
   Links out to the full SIM Details page instead of opening the drawer. */
function UserSimCard({ sim }) {
  const plan = SD.PLANS[sim.plan];
  const st = mS(() => loadSimState(sim), [sim.id]);
  const [open, setOpen] = uS(false);
  eS(() => {if (window.lucide) {try {window.lucide.createIcons();} catch (e) {}}});

  const macro = st.macro;
  const schedDate = st.date;
  const imei = st.imei || simImei(sim);

  return (
    <Card style={{ overflow: "hidden" }}>
      <div className="mp-sim-bar">
        <div>
          <div className="mp-estate-card-kind">Assigned SIM Details</div>
          <h2 className="mp-estate-card-line">{simLabel(sim)}</h2>
          <div className="mp-sim-hero-meta">
            <SimTypeBadge type={sim.sim_type} />
            <MacroBadge macro={macro} date={schedDate} sim={sim} />
          </div>
        </div>
      </div>

      <div className="mp-sim-cardfoot">
        <button
          type="button"
          className={"mp-sim-disclosure" + (open ? " is-open" : "")}
          onClick={() => setOpen((o) => !o)}
          aria-expanded={open}>
          <Icon name="chevron-down" size={16} />
          <span>{open ? "Hide" : "Show"} usage and full SIM details</span>
        </button>
        <a className="mp-glance-link" href={"#/sims/" + sim.id}>
          View further details and manage this SIM <Icon name="arrow-right" size={15} />
        </a>
      </div>

      {open ?
      <div className="mp-sim-details">
          <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 16 }}>
            <div className="mp-profile-block">
              <h4 style={{ margin: 0, fontSize: 15, fontWeight: 700, marginBottom: 14 }}>Data Usage</h4>
              <div className="mp-usage-ring-wrap">
                <UsageRing used={sim.used} limit={plan.limit_gb} />
              </div>
              <div className="mp-usage-stats">
                <KV label="Plan allowance" value={window.MP_POOL && window.MP_POOL.isPooled(sim.id) ? window.MP_POOL.label + " (shared)" : plan.data} />
                <KV label="Used this period" value={sim.used.toFixed(1) + " GB"} />
                {plan.limit_gb ? <KV label="Remaining" value={Math.max(0, plan.limit_gb - sim.used).toFixed(1) + " GB"} /> : null}
              </div>
            </div>
            <div className="mp-profile-block">
              <h4 style={{ margin: 0, fontSize: 15, fontWeight: 700, marginBottom: 14 }}>SIM Card Information</h4>
              <div className="mp-kv-grid">
                {sim.msisdn ? <KvCell label="Phone Number" value={sim.msisdn} /> : null}
                <KvCell label="SIM Serial" value={sim.serial} />
                <KvCell label="IMEI" value={imei} />
                <KvCell label="SIM Type" value={sim.sim_type} />
                <KvCell label="Bundle Type" value={simBundleType(sim)} />
                <KvCell label="Activation Date" value={fmtActivation(sim.activation_date)} />
              </div>
            </div>
          </div>
        </div> :
      null}
    </Card>);

}

/* ---------- SIM details drawer ----------
   Manage SIM is itself a right-hand drawer, so the details view and the manage
   view share one panel and swap, rather than stacking two drawers. */
function SimDetailDrawer({ sim, onClose }) {
  const [view, setView] = uS("details");
  const [st, setSt] = uS(() => loadSimState(sim));
  const [dialog, setDialog] = uS(null);
  const [assignedUserId, setAssignedUserId] = uS(() => (simUser(sim) || {}).id ?? null);
  const [imei, setImei] = uS(() => st.imei || simImei(sim));
  const plan = SD.PLANS[sim.plan];
  const user = SD.USERS.find((u) => u.id === assignedUserId) || null;
  const macro = st.macro;
  const locked = macro === "paused" || macro === "blocked";
  const canManage = MP_ALLOW("sim.manage");
  const pct = plan.limit_gb ? Math.round(sim.used / plan.limit_gb * 100) : 0;

  const commit = (patch) => {
    const merged = { ...st, ...patch };
    setSt(merged); persistSimState(sim.id, merged);
    return merged;
  };
  const save = (next) => { commit({ services: next }); setView("details"); };

  /* Same confirmation flow as the SIM Details page */
  const act = (type) => {
    if (type === "cancelPause") { commit({ macro: "active", scheduled_date: null }); return; }
    setDialog(type);
  };
  const confirmDialog = () => {
    if (dialog === "pause") commit({ macro: "scheduled", scheduled_date: firstOfNextMonth() });
    else if (dialog === "resume") commit({ macro: "active", scheduled_date: null });
    else if (dialog === "block") commit({ macro: "blocked", scheduled_date: null });
    else if (dialog === "unblock") commit({ macro: "active", scheduled_date: null });
    setDialog(null);
  };

  const dialogs = (
    <>
      <ConfirmDialog cfg={dialogConfig(dialog, plan.price)} onConfirm={confirmDialog} onCancel={() => setDialog(null)} />
      {dialog === "reassign" ?
        <ReassignDialog currentUserId={assignedUserId} onCancel={() => setDialog(null)}
          onConfirm={(uid) => { setAssignedUserId(uid); setDialog(null); }} /> : null}
      {dialog === "editImei" ?
        <EditImeiDialog current={imei} onCancel={() => setDialog(null)}
          onConfirm={(v) => { setImei(v); commit({ imei: v }); setDialog(null); }} /> : null}
      {dialog === "moveDevice" && window.RequestConfirmModal ?
        <window.RequestConfirmModal sim={sim} type="move_device"
          onCancel={() => setDialog(null)}
          onConfirm={() => { window.MP_REQ.createRequest(sim.id, "move_device"); setDialog(null); onClose(); }} /> : null}
    </>
  );

  if (view === "manage") {
    return (
      <>
        <ManageSimPanel
          sim={sim} services={st.services} locked={locked}
          lockReason={locked ? "Controls are locked while " + (macro === "blocked" ? "blocked" : "paused") + "." : null}
          macro={macro} onAction={act} onClose={onClose} onSave={save}
          onBack={() => setView("details")} />
        {dialogs}
      </>
    );
  }

  return (
    <>
      <div className="mp-drawer-scrim" onClick={onClose} />
      <aside className="mp-drawer mp-drawer--wide" role="dialog" aria-label="SIM details">
        <header className="mp-drawer-head">
          <div style={{ minWidth: 0 }}>
            <h3>SIM Details</h3>
            <div className="mp-drawer-sub">{sim.serial}</div>
          </div>
          <button type="button" className="mp-drawer-x" onClick={onClose} aria-label="Close">
            <Icon name="x" size={18} />
          </button>
        </header>

        <div className="mp-drawer-body">
          <div className="mp-simd-actions">
            {canManage ? <Button variant="primary" size="sm" icon="sliders-horizontal" onClick={() => setView("manage")}>Manage SIM</Button> : null}
            {sim.sim_type === "eSIM" && window.MP_ESIM && window.MP_ESIM.isReady(sim)
              ? <Button variant="secondary" size="sm" icon="qr-code" href={"#/sims/" + sim.id} onClick={onClose}>Install eSIM</Button> : null}
            <Button variant="secondary" size="sm" icon="external-link" href={"#/sims/" + sim.id} onClick={onClose}>Open Full Page</Button>
          </div>

          <div className="mp-simd-hero">
            <div className="mp-simd-number">{simLabel(sim)}</div>
            <div className="mp-simd-meta">
              <SimTypeBadge type={sim.sim_type} />
              <MacroBadge macro={macro} date={st.scheduled_date} sim={sim} />
            </div>
          </div>

          <div className="mp-simd-user">
            {user ? (
              <a href={"#/users/" + user.id} className="mp-assigned" onClick={onClose}>
                <Avatar initials={user.initials} size={34} tone="mist" />
                <span>{user.full_name}</span>
              </a>
            ) : <span style={{ color: "var(--fg-3)", fontSize: 14 }}>Unassigned</span>}
            <span className="mp-simd-user-label">{user ? "Assigned user" : ""}</span>
          </div>

          <div className="mp-dl">
            <div className="mp-dl-row"><span className="mp-dl-k">Data plan</span><span className="mp-dl-v">{plan.data}</span></div>
            <div className="mp-dl-row">
              <span className="mp-dl-k">Data used</span>
              <span className="mp-dl-v">
                <span className="mp-simd-used">
                  <span>{sim.used.toFixed(1)} GB{plan.limit_gb ? " of " + plan.limit_gb + " GB" : ""}</span>
                  {plan.limit_gb ? <PctIndicator pct={pct} /> : null}
                </span>
                {plan.limit_gb ? <span className={"mp-simd-bar mp-simd-bar--" + usageTone(pct)}><span style={{ width: Math.min(pct, 100) + "%" }} /></span> : null}
              </span>
            </div>
            <div className="mp-dl-row"><span className="mp-dl-k">Monthly spend</span><span className="mp-dl-v">{gbp(plan.price)}</span></div>
            <div className="mp-dl-row"><span className="mp-dl-k">SIM serial</span><span className="mp-dl-v mp-mono">{sim.serial}</span></div>
            <div className="mp-dl-row"><span className="mp-dl-k">IMEI</span><span className="mp-dl-v mp-mono">{imei}</span></div>
            <div className="mp-dl-row"><span className="mp-dl-k">Bundle type</span><span className="mp-dl-v">{simBundleType(sim)}</span></div>
            <div className="mp-dl-row"><span className="mp-dl-k">Activation date</span><span className="mp-dl-v">{fmtActivation(sim.activation_date)}</span></div>
          </div>

          <div className="mp-drawer-block">
            <div className="mp-drawer-block-title">Services at a glance</div>
            <ServiceList services={st.services} readOnly />
          </div>
        </div>
      </aside>
      {dialogs}
    </>
  );
}

/* ---------- Transfer Your Number ----------
   Matches the production flow: three numbered steps explaining how to get a
   PAC code, the SIM context callout, and the form. */
function TransferNumberPage({ id }) {
  const sim = SD.SIMS.find((s) => s.id === Number(id));
  const ctx = window.useRoles ? window.useRoles() : null;
  const [phone, setPhone] = uS("");
  const [pac, setPac] = uS("");
  const [dateIdx, setDateIdx] = uS(0);
  const [done, setDone] = uS(false);
  React.useEffect(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });

  if (!sim) return (<><PageHead title="SIM Management" /><BackLink href="#/sims">Back to SIMs</BackLink>
    <Card><div className="mp-card-body"><Empty icon="card-sim" title="SIM not found" /></div></Card></>);

  const user = simUser(sim);
  /* Valid dates: weekdays only, starting tomorrow, for 21 days. */
  const validDates = [];
  const now = new Date();
  for (let i = 1; i <= 21; i++) {
    const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() + i);
    if (d.getDay() !== 0 && d.getDay() !== 6) validDates.push(d);
  }
  const fmtDate = (d) => d.toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long", year: "numeric" });
  const fmtShort = (d) => d.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" });
  const phoneOk = /^07[0-9]{9}$/.test(phone.replace(/\s/g, ""));
  const pacOk = /^[A-Za-z]{3}[0-9]{6}$/.test(pac);
  const ready = phoneOk && pacOk;

  const submit = () => {
    if (!ready) return;
    setDone(true);
    if (ctx) ctx.toast({ kind: "ok", title: "Number transfer scheduled", body: "The transfer is scheduled for " + fmtShort(validDates[dateIdx]) + "." });
  };

  if (done) return (
    <>
      <PageHead title="SIM Management" />
      <BackLink href="#/sims">Back to SIMs</BackLink>
      <Card style={{ maxWidth: 640 }}>
        <div className="mp-batch-done">
          <div className="mp-batch-done-ic"><Icon name="calendar-check" size={24} /></div>
          <Badge variant="ok" icon="circle-check">Scheduled</Badge>
          <h3 className="mp-batch-done-title" style={{ marginTop: 14 }}>Number transfer scheduled</h3>
          <p className="mp-batch-done-msg">Your number transfer request has been confirmed and is scheduled to complete on <strong>{fmtShort(validDates[dateIdx])}</strong>.</p>
          <div className="mp-kv-grid" style={{ textAlign: "left", marginTop: 22 }}>
            <KvCell label="SIM Holder" value={user ? user.full_name : "Unassigned"} />
            <KvCell label="Existing Number" value={sim.msisdn} />
            <KvCell label="Number Being Transferred" value={phone.replace(/\s/g, "")} />
            <KvCell label="Transfer Date" value={fmtShort(validDates[dateIdx])} />
          </div>
          <p className="mp-batch-done-msg" style={{ marginTop: 18 }}>{user ? "We will let " + user.full_name + " know by text and email the moment it is done." : "A confirmation text will be sent to the SIM when the transfer completes."}</p>
          <div className="mp-batch-done-cta">
            <Button variant="primary" href={"#/sims/" + sim.id}>Back to SIM Details</Button>
          </div>
        </div>
      </Card>
    </>);

  const steps = [
    { n: 1, head: "Get the code", body: "Text PAC to 65075 using the SIM from your previous network. You will receive a text back containing your PAC code in a few minutes." },
    { n: 2, head: "Enter your details", body: "Enter the PAC code you just received, and select which date you would like your number to be transferred on." },
    { n: 3, head: "We will handle the rest", body: "We will get working right away to transfer your number, and let you know as soon as it is complete." }];

  return (
    <>
      <PageHead title="Transfer Your Existing Number" subtitle="Bring your current mobile number with you to your new Meaningful Planet SIM." />
      <BackLink href={"#/sims/" + sim.id}>Back to SIM Details</BackLink>

      <Card style={{ maxWidth: 640 }}>
        <div className="mp-card-body">
          {steps.map((s) =>
            <div key={s.n} className="mp-transfer-step">
              <span className="mp-transfer-step-num">{s.n}</span>
              <div>
                <h4 className="mp-transfer-step-head">{s.head}</h4>
                <p className="mp-transfer-step-body">{s.body}</p>
              </div>
            </div>)}

          <div className="mp-transfer-callout">
            <div className="mp-transfer-callout-label">You are transferring the number for</div>
            <div className="mp-kv-grid">
              <KvCell label="SIM Holder" value={user ? user.full_name : "Unassigned"} />
              <KvCell label="Current Number" value={sim.msisdn} />
              <KvCell label="Serial Number" value={sim.serial} />
            </div>
          </div>

          <h4 style={{ margin: "28px 0 16px", fontSize: 15, fontWeight: 700, color: "var(--mp-deep-forest)" }}>What we need to know</h4>

          <form onSubmit={(e) => { e.preventDefault(); submit(); }} style={{ display: "flex", flexDirection: "column", gap: 18 }}>
            <div className="mp-field">
              <label className="mp-field-label">The mobile number you want to keep</label>
              <input className="mp-field-input" value={phone} onChange={(e) => setPhone(e.target.value)}
                placeholder="07012345678" maxLength={11} />
              {phone && !phoneOk ? <div className="mp-field-hint" style={{ color: "var(--mp-ember-ink)" }}>Enter an 11-digit UK mobile number starting with 07, with no spaces.</div> : null}
            </div>
            <div className="mp-field">
              <label className="mp-field-label">Your PAC code</label>
              <input className="mp-field-input" value={pac} onChange={(e) => setPac(e.target.value.toUpperCase())}
                placeholder="ABC123456" maxLength={9} style={{ fontFamily: "var(--font-mono, ui-monospace, monospace)", letterSpacing: "0.04em" }} />
              {pac && !pacOk ? <div className="mp-field-hint" style={{ color: "var(--mp-ember-ink)" }}>Enter your PAC code: three letters followed by six numbers (e.g. ABC123456).</div> : null}
            </div>
            <div className="mp-field">
              <label className="mp-field-label">When would you like to transfer your number?</label>
              <Select value={String(dateIdx)} onChange={(v) => setDateIdx(Number(v))}
                options={validDates.map((d, i) => ({ value: String(i), label: fmtDate(d) }))} />
            </div>
            <div>
              <Button variant="primary" size="lg" type="submit" className={ready ? "" : "is-disabled"}>Transfer This Number</Button>
            </div>
          </form>
        </div>
      </Card>
    </>);
}

/* ---------- Export (overrides pages-1.jsx's SimShowPage) ---------- */
Object.assign(window, { SimShowPage, UserSimCard, MacroBadge, loadSimState, SimDetailDrawer, EditImeiDialog, simImei, persistSimState, simBundleType, TransferNumberPage });