/** * When the redeem paywall opens (TASK-birth-sky-polish-20260928 P4). * * It no longer opens by itself when the starter home appears — that collided * with the first-chart star convergence (BUG-1080). Instead the first send on * this page that is refused for lack of credits (the pre-flight balance check * or a 402) opens it; every later refusal opens billing as before. The caller * keeps the typed question in the composer either way. */ export type RedeemPaywallGate = Readonly<{ uiPreview: boolean; /** Page-lifetime flag: the paywall has been shown once. */ shown?: { current: boolean }; open?: (open: boolean) => void; }>; /** True when it opened the paywall; false means the caller opens billing. */ export function tryOpenRedeemPaywall(gate: RedeemPaywallGate): boolean { if (gate.uiPreview || !gate.shown || !gate.open || gate.shown.current) return false; gate.shown.current = true; gate.open(true); return true; }