@bounded-sh/client 0.0.112-ux-audit.2 → 0.0.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/auth/bounded-widget-modal.d.ts +24 -2
  2. package/dist/{email-auth-provider-C7RXLVd9.mjs → email-auth-provider-BV1Iea4A.mjs} +2 -2
  3. package/dist/{email-auth-provider-C7RXLVd9.mjs.map → email-auth-provider-BV1Iea4A.mjs.map} +1 -1
  4. package/dist/{email-auth-provider-53sA5_i2.js → email-auth-provider-CyFsnSzx.js} +2 -2
  5. package/dist/{email-auth-provider-53sA5_i2.js.map → email-auth-provider-CyFsnSzx.js.map} +1 -1
  6. package/dist/{email-auth-provider-BfCH7K6N.mjs → email-auth-provider-D0_iXVYk.mjs} +2 -2
  7. package/dist/{email-auth-provider-BfCH7K6N.mjs.map → email-auth-provider-D0_iXVYk.mjs.map} +1 -1
  8. package/dist/{email-auth-provider-DTrCfOJd.js → email-auth-provider-OVzQ63dn.js} +2 -2
  9. package/dist/{email-auth-provider-DTrCfOJd.js.map → email-auth-provider-OVzQ63dn.js.map} +1 -1
  10. package/dist/{guest-auth-provider-Tndt6tzJ.js → guest-auth-provider-0WlOutqU.js} +2 -2
  11. package/dist/{guest-auth-provider-Tndt6tzJ.js.map → guest-auth-provider-0WlOutqU.js.map} +1 -1
  12. package/dist/{guest-auth-provider-DjOFjtnk.mjs → guest-auth-provider-AP80a700.mjs} +2 -2
  13. package/dist/{guest-auth-provider-DjOFjtnk.mjs.map → guest-auth-provider-AP80a700.mjs.map} +1 -1
  14. package/dist/{guest-auth-provider-00KkSNpE.js → guest-auth-provider-B4WIWOjV.js} +2 -2
  15. package/dist/{guest-auth-provider-00KkSNpE.js.map → guest-auth-provider-B4WIWOjV.js.map} +1 -1
  16. package/dist/{guest-auth-provider-2J4fnTX5.mjs → guest-auth-provider-Cqx1zH23.mjs} +2 -2
  17. package/dist/{guest-auth-provider-2J4fnTX5.mjs.map → guest-auth-provider-Cqx1zH23.mjs.map} +1 -1
  18. package/dist/{index-DJeEMevo.js → index-BmNNZlTl.js} +127 -44
  19. package/dist/index-BmNNZlTl.js.map +1 -0
  20. package/dist/{index-D3kdhCpH.mjs → index-D76-cZcD.mjs} +127 -44
  21. package/dist/index-D76-cZcD.mjs.map +1 -0
  22. package/dist/index.js +1 -1
  23. package/dist/index.mjs +1 -1
  24. package/dist/{index.native-ingNhWPw.js → index.native-C5glqiTU.js} +59 -14
  25. package/dist/index.native-C5glqiTU.js.map +1 -0
  26. package/dist/{index.native-CAH_ks0s.mjs → index.native-DyR93n8K.mjs} +59 -14
  27. package/dist/index.native-DyR93n8K.mjs.map +1 -0
  28. package/dist/index.native.js +1 -1
  29. package/dist/index.native.mjs +1 -1
  30. package/dist/{injected-evm-wallet-provider-Cao1U0NZ.js → injected-evm-wallet-provider-4ICYUEU4.js} +2 -2
  31. package/dist/{injected-evm-wallet-provider-Cao1U0NZ.js.map → injected-evm-wallet-provider-4ICYUEU4.js.map} +1 -1
  32. package/dist/{injected-evm-wallet-provider-IlkuKffc.js → injected-evm-wallet-provider-C8YItSiB.js} +2 -2
  33. package/dist/{injected-evm-wallet-provider-IlkuKffc.js.map → injected-evm-wallet-provider-C8YItSiB.js.map} +1 -1
  34. package/dist/{injected-evm-wallet-provider-DXjwPjLW.mjs → injected-evm-wallet-provider-CS4R8c51.mjs} +2 -2
  35. package/dist/{injected-evm-wallet-provider-DXjwPjLW.mjs.map → injected-evm-wallet-provider-CS4R8c51.mjs.map} +1 -1
  36. package/dist/{injected-evm-wallet-provider-BtyG1HOX.mjs → injected-evm-wallet-provider-WxUbyMZL.mjs} +2 -2
  37. package/dist/{injected-evm-wallet-provider-BtyG1HOX.mjs.map → injected-evm-wallet-provider-WxUbyMZL.mjs.map} +1 -1
  38. package/dist/{injected-wallet-provider-CfYNIIHd.mjs → injected-wallet-provider-D1ygndjX.mjs} +2 -2
  39. package/dist/{injected-wallet-provider-CfYNIIHd.mjs.map → injected-wallet-provider-D1ygndjX.mjs.map} +1 -1
  40. package/dist/{injected-wallet-provider-BEYwsn6M.js → injected-wallet-provider-D8vIsUHf.js} +2 -2
  41. package/dist/{injected-wallet-provider-BEYwsn6M.js.map → injected-wallet-provider-D8vIsUHf.js.map} +1 -1
  42. package/dist/{injected-wallet-provider-0SSONh1d.mjs → injected-wallet-provider-UuGrzdNW.mjs} +2 -2
  43. package/dist/{injected-wallet-provider-0SSONh1d.mjs.map → injected-wallet-provider-UuGrzdNW.mjs.map} +1 -1
  44. package/dist/{injected-wallet-provider-DSlHfgMU.js → injected-wallet-provider-nwd3ialR.js} +2 -2
  45. package/dist/{injected-wallet-provider-DSlHfgMU.js.map → injected-wallet-provider-nwd3ialR.js.map} +1 -1
  46. package/package.json +2 -2
  47. package/dist/index-D3kdhCpH.mjs.map +0 -1
  48. package/dist/index-DJeEMevo.js.map +0 -1
  49. package/dist/index.native-CAH_ks0s.mjs.map +0 -1
  50. package/dist/index.native-ingNhWPw.js.map +0 -1
@@ -3897,9 +3897,13 @@ async function ensureSolanaMobileWalletRegistered(config, network) {
3897
3897
  }
3898
3898
  catch (_e) {
3899
3899
  throw new WalletConfigError(`Bounded: Solana Mobile wallet support needs the optional peer dependency ` +
3900
- `'@solana-mobile/wallet-standard-mobile', which is not installed. Install it ` +
3901
- `in your app to enable the mobile wallet, or leave the Solana Mobile wallet ` +
3902
- `out of this app's wallet configuration.`);
3900
+ `'@solana-mobile/wallet-standard-mobile', which is not installed. Until it is, ` +
3901
+ `Android users (Seeker, Saga, any phone browser) get NO wallet to connect: ` +
3902
+ `installed wallet apps are never injected into a page there, the mobile adapter ` +
3903
+ `is the only route. Fix: npm install @solana-mobile/wallet-standard-mobile ` +
3904
+ `(a web app also needs legacy-peer-deps=true in its .npmrc, because the adapter's ` +
3905
+ `protocol package declares react-native as a peer). Or leave the Solana Mobile ` +
3906
+ `wallet out of this app's wallet configuration on purpose.`);
3903
3907
  }
3904
3908
  const { registerMwa, createDefaultChainSelector, SolanaMobileWalletAdapterWalletName, SolanaMobileWalletAdapterRemoteWalletName, } = mwa;
3905
3909
  const before = new Set(getWallets().get());
@@ -3986,7 +3990,7 @@ const OVERLAY_CSS = `
3986
3990
  :host{all:initial}
3987
3991
  *{box-sizing:border-box}
3988
3992
  .bw-ov{position:fixed;inset:0;z-index:2147483647;display:none;
3989
- font-family:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
3993
+ font-family:"Bounded Schibsted Grotesk","Schibsted Grotesk","Helvetica Neue",Arial,sans-serif}
3990
3994
  .bw-ov.mounted{display:block}
3991
3995
  .bw-back{position:fixed;inset:0;background:rgba(4,4,5,.62);opacity:0;
3992
3996
  transition:opacity .24s ease;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
@@ -4019,6 +4023,29 @@ const OVERLAY_CSS = `
4019
4023
  }
4020
4024
  @media(prefers-reduced-motion:reduce){.bw-back,.bw-panel{transition:opacity .12s linear!important}}
4021
4025
  `;
4026
+ /**
4027
+ * Style the shadow tree with `css` as constructed stylesheets, and say whether it could. A host
4028
+ * CSP whose style-src lacks 'unsafe-inline' refuses an inline <style> even inside a shadow root,
4029
+ * which left the widget unstyled (the Bounded router compiles exactly `style-src 'self'` for an
4030
+ * app that declares browser boundaries and names no style sources); CSP does not govern
4031
+ * constructed sheets. A browser without them (they shipped with adoptedStyleSheets everywhere)
4032
+ * gets <style> elements instead (styleTag).
4033
+ */
4034
+ function adoptStyles(shadow, css) {
4035
+ if (!("adoptedStyleSheets" in shadow))
4036
+ return false;
4037
+ shadow.adoptedStyleSheets = css.map((text) => {
4038
+ const sheet = new CSSStyleSheet();
4039
+ sheet.replaceSync(text);
4040
+ return sheet;
4041
+ });
4042
+ return true;
4043
+ }
4044
+ function styleTag(css) {
4045
+ const style = document.createElement("style");
4046
+ style.textContent = css;
4047
+ return style;
4048
+ }
4022
4049
  let modal = null;
4023
4050
  function getModal() {
4024
4051
  if (modal)
@@ -4026,9 +4053,8 @@ function getModal() {
4026
4053
  const root = document.createElement("div");
4027
4054
  root.setAttribute("data-bounded-widget", "");
4028
4055
  const shadow = root.attachShadow({ mode: "open" });
4029
- const style = document.createElement("style");
4030
- style.textContent = OVERLAY_CSS;
4031
- shadow.appendChild(style);
4056
+ if (!adoptStyles(shadow, [OVERLAY_CSS]))
4057
+ shadow.appendChild(styleTag(OVERLAY_CSS));
4032
4058
  const overlay = document.createElement("div");
4033
4059
  overlay.className = "bw-ov";
4034
4060
  const back = document.createElement("div");
@@ -4163,12 +4189,15 @@ function fitPanelToContent(m) {
4163
4189
  m.fitObserver = ro;
4164
4190
  }
4165
4191
  }
4166
- /** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`. */
4167
- function mountContent(m, node) {
4192
+ /** Switch the modal into NATIVE-content mode: detach any iframe, mount `node`, styled by `css` until the next mount. */
4193
+ function mountContent(m, node, css) {
4168
4194
  var _a;
4169
4195
  detachIframe(m);
4170
4196
  (_a = m.fitObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
4171
4197
  m.fitObserver = null;
4198
+ const shadow = m.root.shadowRoot;
4199
+ if (!(shadow && adoptStyles(shadow, [OVERLAY_CSS, css] )) && css)
4200
+ node.prepend(styleTag(css));
4172
4201
  m.content.replaceChildren(node);
4173
4202
  m.content.style.display = "block";
4174
4203
  }
@@ -4230,27 +4259,39 @@ function detachIframe(m) {
4230
4259
  m.iframeContext = "";
4231
4260
  m.onIframeMessage = null;
4232
4261
  }
4233
- // Load the Bounded editorial typefaces (Newsreader display + Schibsted Grotesk body +
4234
- // JetBrains Mono) once at the document level so they apply inside the shadow root. A
4235
- // no-op if already present or off-DOM. Fonts loaded here match the hosted auth page.
4236
- const FONTS_HREF = "https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,500&family=Schibsted+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap";
4262
+ /**
4263
+ * The Bounded editorial typefaces the hosted auth page uses (Newsreader display, Schibsted
4264
+ * Grotesk body), registered once at the document level so they apply inside the shadow root.
4265
+ *
4266
+ * The Bounded router serves them same-origin at /__bounded/fonts/*.woff2 on every site it
4267
+ * serves (bounded-router scripts/build-widget-styles.cjs), and they load through the FontFace
4268
+ * API: no stylesheet, so a host CSP's style-src never applies, and the only fetch is same-origin,
4269
+ * which font-src 'self' admits. Google Fonts CSS injected here was refused by strict hosts such
4270
+ * as the OpenApps venue (style-src 'self'), with a CSP error on every page. A page the router
4271
+ * does not serve has none of its /__bounded/ scripts: nothing is fetched there, and the widget's
4272
+ * font stacks fall back to the page's own faces or system ones. The Bounded-prefixed family
4273
+ * names never restyle the host page's own text.
4274
+ */
4275
+ const WIDGET_FONT_FACES = [
4276
+ { family: "Bounded Newsreader", url: "/__bounded/fonts/newsreader.woff2", weight: "200 800" },
4277
+ { family: "Bounded Schibsted Grotesk", url: "/__bounded/fonts/schibsted.woff2", weight: "400 900" },
4278
+ ];
4237
4279
  function ensureFonts() {
4238
- if (!hasDOM$5())
4280
+ if (!hasDOM$5() || typeof FontFace === "undefined" || !document.fonts)
4239
4281
  return;
4240
- if (document.querySelector('link[data-bounded-fonts="1"]'))
4282
+ if (!document.querySelector('script[src^="/__bounded/"]'))
4241
4283
  return;
4242
- const pre1 = document.createElement("link");
4243
- pre1.rel = "preconnect";
4244
- pre1.href = "https://fonts.googleapis.com";
4245
- const pre2 = document.createElement("link");
4246
- pre2.rel = "preconnect";
4247
- pre2.href = "https://fonts.gstatic.com";
4248
- pre2.crossOrigin = "anonymous";
4249
- const link = document.createElement("link");
4250
- link.rel = "stylesheet";
4251
- link.href = FONTS_HREF;
4252
- link.setAttribute("data-bounded-fonts", "1");
4253
- document.head.append(pre1, pre2, link);
4284
+ const registered = new Set();
4285
+ document.fonts.forEach((face) => registered.add(face.family.replace(/^["']|["']$/g, "")));
4286
+ for (const { family, url, weight } of WIDGET_FONT_FACES) {
4287
+ if (registered.has(family))
4288
+ continue;
4289
+ // Against the page's origin, not its base URL: a <base href> elsewhere must not move the fetch off this origin.
4290
+ const face = new FontFace(family, `url("${location.origin}${url}") format("woff2")`, { weight, display: "swap" });
4291
+ document.fonts.add(face);
4292
+ // A face that cannot load is taken back out; the font stack falls back to the next face.
4293
+ face.load().catch(() => { document.fonts.delete(face); });
4294
+ }
4254
4295
  }
4255
4296
 
4256
4297
  // turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
@@ -6270,7 +6311,7 @@ async function getAuthProvider(config, fromStorage = false) {
6270
6311
  // manager as legacy email sessions. Human login should be started
6271
6312
  // with loginWithRedirect(); this provider is kept as the restore and
6272
6313
  // logout surface for those sessions.
6273
- currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-53sA5_i2.js'); })).EmailAuthProvider();
6314
+ currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-CyFsnSzx.js'); })).EmailAuthProvider();
6274
6315
  break;
6275
6316
  case "phantom": {
6276
6317
  // First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
@@ -6312,7 +6353,7 @@ async function getAuthProvider(config, fromStorage = false) {
6312
6353
  // (bounded-login-widget.ts), so registration never counts as
6313
6354
  // evidence the user has a wallet.
6314
6355
  await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
6315
- const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
6356
+ const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
6316
6357
  currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
6317
6358
  break;
6318
6359
  }
@@ -6325,7 +6366,7 @@ async function getAuthProvider(config, fromStorage = false) {
6325
6366
  // Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
6326
6367
  // to point at a specific wallet or set chainId/domain.
6327
6368
  const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
6328
- const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-IlkuKffc.js'); });
6369
+ const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-C8YItSiB.js'); });
6329
6370
  currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
6330
6371
  break;
6331
6372
  }
@@ -6350,7 +6391,7 @@ async function getAuthProvider(config, fromStorage = false) {
6350
6391
  break;
6351
6392
  case "guest":
6352
6393
  // Anonymous auth: a device-local ed25519 keypair signs the challenge.
6353
- currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-00KkSNpE.js'); })).GuestAuthProvider();
6394
+ currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-B4WIWOjV.js'); })).GuestAuthProvider();
6354
6395
  break;
6355
6396
  }
6356
6397
  if (!currentAuthProvider) {
@@ -6412,7 +6453,7 @@ async function signInAnonymously() {
6412
6453
  // Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
6413
6454
  // the main bundle for data-only apps. Specifier is a static string literal
6414
6455
  // so bundle-splitting can see it.
6415
- const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-00KkSNpE.js'); })).GuestAuthProvider();
6456
+ const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-B4WIWOjV.js'); })).GuestAuthProvider();
6416
6457
  setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
6417
6458
  // adoptSessionProvider awaits only getConfig() (already resolved here) and then
6418
6459
  // runs every write - provider/method/config/marker/user - in one synchronous
@@ -6583,7 +6624,7 @@ function ensureSharedWalletLoginReady() {
6583
6624
  if (!sharedWalletReady) {
6584
6625
  sharedWalletReady = (async () => {
6585
6626
  await core.getConfig();
6586
- await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
6627
+ await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
6587
6628
  })().catch((error) => {
6588
6629
  sharedWalletReady = null;
6589
6630
  throw error;
@@ -6686,7 +6727,7 @@ async function loginWithWallet(options) {
6686
6727
  await ensureSharedWalletLoginReady();
6687
6728
  else
6688
6729
  await ensureWalletLoginReady();
6689
- const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-BEYwsn6M.js'); });
6730
+ const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-D8vIsUHf.js'); });
6690
6731
  // Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
6691
6732
  // set of methods, so cleanup below must speak to the provider that actually
6692
6733
  // holds the config rather than to whatever is wrapping it.
@@ -7053,6 +7094,13 @@ function registerStorageBridge() {
7053
7094
  void syncStoredSession().catch((error) => console.warn('Bounded session synchronization failed:', error));
7054
7095
  });
7055
7096
  }
7097
+ function sameSessionIdentity(next, previous) {
7098
+ if (!next || !previous)
7099
+ return false;
7100
+ const a = core.deriveUserIdentityFromIdToken(next);
7101
+ const b = core.deriveUserIdentityFromIdToken(previous);
7102
+ return !!a.id && a.id === b.id && a.address === b.address && a.email === b.email && a.evmAddress === b.evmAddress;
7103
+ }
7056
7104
  async function syncStoredSession() {
7057
7105
  const config = initializedConfig;
7058
7106
  if (!config)
@@ -7061,6 +7109,18 @@ async function syncStoredSession() {
7061
7109
  const issuer = core.WebSessionManager.getIssuer();
7062
7110
  if (token === observedIdToken && issuer === observedIssuer)
7063
7111
  return;
7112
+ // Another tab refreshed this same session (tokens rotate every few minutes):
7113
+ // who is signed in did not change, so keep the user and its live reads, whose
7114
+ // sockets take the new token on their own, instead of hiding and restoring it.
7115
+ if (currentUser && issuer === observedIssuer && sameSessionIdentity(token, observedIdToken)) {
7116
+ const record = await core.WebSessionManager.readSessionWithGeneration();
7117
+ if (config !== initializedConfig || core.WebSessionManager.getIdToken() !== token)
7118
+ return;
7119
+ if ((record === null || record === void 0 ? void 0 : record.idToken) === token && (!record.appId || record.appId === config.appId)) {
7120
+ observedIdToken = token;
7121
+ return;
7122
+ }
7123
+ }
7064
7124
  observedIdToken = token;
7065
7125
  observedIssuer = issuer;
7066
7126
  const generation = ++initializationGeneration;
@@ -8088,8 +8148,8 @@ const CARD_CSS = `
8088
8148
  --line:rgba(232,230,222,.08);--line-strong:rgba(232,230,222,.16);
8089
8149
  --text:#e8e6de;--dim:#9b9991;--faint:#85837c;
8090
8150
  --green:#58c98f;--green-bg:rgba(88,201,143,.09);--green-line:rgba(88,201,143,.28);--red:#ec8488;
8091
- --disp:"Newsreader","Iowan Old Style",Georgia,serif;
8092
- --body:"Schibsted Grotesk","Helvetica Neue",Arial,sans-serif;
8151
+ --disp:"Bounded Newsreader","Newsreader","Iowan Old Style",Georgia,serif;
8152
+ --body:"Bounded Schibsted Grotesk","Schibsted Grotesk","Helvetica Neue",Arial,sans-serif;
8093
8153
  position:relative;padding:34px 32px 20px;color:var(--text);font-family:var(--body);
8094
8154
  -webkit-font-smoothing:antialiased}
8095
8155
  .x{position:absolute;top:20px;right:24px;border:0;background:transparent;color:var(--faint);
@@ -8210,6 +8270,17 @@ function discoverWallets(configuredNetwork) {
8210
8270
  // beats a click that does nothing, which is what "one at a time" looks like from
8211
8271
  // the outside.
8212
8272
  const BUSY_MSG = "A sign-in is already in progress - finish or cancel it first.";
8273
+ // Shown instead of an empty card when no lane can be offered (wallet-only app,
8274
+ // no wallet in this browser). A phone browser never sees installed wallet apps
8275
+ // as injected providers, so the honest advice there is a different browser,
8276
+ // not "install a wallet".
8277
+ function noLaneCopy(mobile) {
8278
+ return mobile
8279
+ ? "No wallet is available in this browser. Open this page in your wallet app's " +
8280
+ "browser, or on a desktop browser with a wallet extension, then try again."
8281
+ : "No wallet was found in this browser. Install a Solana wallet extension such as " +
8282
+ "Phantom or Solflare, reload the page, then try again.";
8283
+ }
8213
8284
  const METHOD_LABEL = {
8214
8285
  google: "Continue with Google",
8215
8286
  apple: "Continue with Apple",
@@ -8551,12 +8622,9 @@ async function prepareAndOpen(opts, pending) {
8551
8622
  cancelPendingOpens();
8552
8623
  };
8553
8624
  m.onBackdrop = cancel;
8554
- const style = el("style");
8555
- style.textContent = CARD_CSS;
8556
8625
  let emailDraft = "";
8557
8626
  const renderChoose = (initialError) => {
8558
8627
  const card = el("div", "c");
8559
- card.appendChild(style.cloneNode(true));
8560
8628
  const x = el("button", "x", "Close");
8561
8629
  x.type = "button";
8562
8630
  x.setAttribute("aria-label", "Close");
@@ -8773,6 +8841,24 @@ async function prepareAndOpen(opts, pending) {
8773
8841
  });
8774
8842
  };
8775
8843
  }
8844
+ // A card with no lane at all. It happens when an app asks for wallet-only
8845
+ // (`methods: []`, `wallet: true`) and this browser has no wallet to offer:
8846
+ // no injected wallet, and no Solana Mobile wallet (off-Android, or the app
8847
+ // never installed the adapter). A blank card between the title and the
8848
+ // footer was the shipped behaviour, and it reads as "the site is broken"
8849
+ // to the person and tells the developer nothing. Say what is missing on
8850
+ // screen, and name the usual cause once in the console, where the
8851
+ // developer's own preview run will show it.
8852
+ if (!hasEmail && social.length === 0 && !walletEnabled) {
8853
+ card.appendChild(el("p", "sub", noLaneCopy(detectMobile())));
8854
+ console.warn("[Bounded] openBoundedWidget has no sign-in lane to show: the app asked for " +
8855
+ "no email or social method and no wallet is available in this browser. " +
8856
+ (offerMobile
8857
+ ? "On Android the Solana Mobile wallet is offered only when the app installs " +
8858
+ "'@solana-mobile/wallet-standard-mobile' (see the warning above if registration failed); "
8859
+ : "") +
8860
+ "Add a method, or make sure wallet login is enabled and the mobile adapter is installed.");
8861
+ }
8776
8862
  card.appendChild(status);
8777
8863
  const foot = el("div", "foot");
8778
8864
  const poweredBy = el("a", undefined, "Powered by Bounded");
@@ -8819,7 +8905,6 @@ async function prepareAndOpen(opts, pending) {
8819
8905
  const renderSignInGesture = (choice, done) => {
8820
8906
  var _a;
8821
8907
  const card = el("div", "c");
8822
- card.appendChild(style.cloneNode(true));
8823
8908
  const x = el("button", "x", "Close");
8824
8909
  x.type = "button";
8825
8910
  x.setAttribute("aria-label", "Close");
@@ -8840,7 +8925,6 @@ async function prepareAndOpen(opts, pending) {
8840
8925
  };
8841
8926
  const renderWallets = (initialError) => {
8842
8927
  const card = el("div", "c");
8843
- card.appendChild(style.cloneNode(true));
8844
8928
  const back = el("button", "back", "\u2190 Back");
8845
8929
  back.type = "button";
8846
8930
  // Leaving the wallet list supersedes any attempt still preparing, so it
@@ -8920,7 +9004,6 @@ async function prepareAndOpen(opts, pending) {
8920
9004
  // experience still feels native; the code input, sealing, and verify all live behind the frame.
8921
9005
  const renderOtpFrame = (handle) => {
8922
9006
  const card = el("div", "c");
8923
- card.appendChild(style.cloneNode(true));
8924
9007
  const back = el("button", "back", "\u2190 Back");
8925
9008
  back.type = "button";
8926
9009
  card.appendChild(back);
@@ -8967,7 +9050,7 @@ async function prepareAndOpen(opts, pending) {
8967
9050
  // land after a newer open has taken over the DOM.
8968
9051
  if (!owner.owns())
8969
9052
  return;
8970
- mountContent(m, node);
9053
+ mountContent(m, node, CARD_CSS);
8971
9054
  requestAnimationFrame(() => {
8972
9055
  if (owner.owns())
8973
9056
  fitPanelToContent(m);
@@ -11359,4 +11442,4 @@ exports.useAuth = useAuth;
11359
11442
  exports.useBuildRun = useBuildRun;
11360
11443
  exports.useQuery = useQuery;
11361
11444
  exports.waitForAuthReady = waitForAuthReady;
11362
- //# sourceMappingURL=index-DJeEMevo.js.map
11445
+ //# sourceMappingURL=index-BmNNZlTl.js.map