@energy8platform/shell 0.6.2 → 0.6.4

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.
package/dist/pixi.cjs.js CHANGED
@@ -1221,12 +1221,19 @@ function normalizeLang(code) {
1221
1221
  return (LANG_SET.has(base) ? base : 'en');
1222
1222
  }
1223
1223
  function createI18n(opts) {
1224
- // Social is the `en-social` pseudo-locale: it rewrites the English source. Non-English locales are
1225
- // authored social-safe already, so `socialize` only runs on the English source string.
1224
+ // Social is the `en-social` pseudo-locale: it rewrites the English source into social-safe
1225
+ // vocabulary. The replacement dictionary only exists for English, so social mode FORCES English
1226
+ // the requested `language` is ignored, matching the `isSocial` contract ("…derived from English…
1227
+ // regardless of `language`"). Rendering a non-English locale in social mode would leak untranslated
1228
+ // restricted terms, so we never do it.
1229
+ if (opts.isSocial) {
1230
+ const t = (src) => socialize(src);
1231
+ return { lang: 'en', t };
1232
+ }
1226
1233
  const lang = normalizeLang(opts.language);
1227
1234
  const t = (src) => {
1228
1235
  if (lang === 'en')
1229
- return opts.isSocial ? socialize(src) : src;
1236
+ return src;
1230
1237
  return opts.messages?.[lang]?.[src] ?? LOCALES[lang]?.[src] ?? src;
1231
1238
  };
1232
1239
  return { lang, t };
@@ -1449,7 +1456,7 @@ class KeyboardController {
1449
1456
 
1450
1457
  // AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
1451
1458
  /** The @energy8platform/shell package version, stamped into the game-info footer. */
1452
- const PACKAGE_VERSION = '0.6.2';
1459
+ const PACKAGE_VERSION = '0.6.4';
1453
1460
 
1454
1461
  /** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
1455
1462
  function resolveConfig(config) {
@@ -2006,6 +2013,14 @@ function countUpText(ticker, text, from, to, fmt, durationMs = 450) {
2006
2013
  });
2007
2014
  }
2008
2015
 
2016
+ // AUTO-GENERATED from ../../icons.svg by scripts/gen-buy-bonus.mjs — do not edit by hand.
2017
+ // The full-colour buy-bonus coins (default / social / deactivate), shared by the DOM shell
2018
+ // (inline <svg>) and the Pixi shell (GraphicsContext.svg). To refresh: edit icons.svg, then
2019
+ // `node scripts/gen-buy-bonus.mjs`.
2020
+ const BUY_BONUS_ART = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="850.09 834.52 263.91 264.00"><path fill="#ebac28" stroke="#fac64c" stroke-miterlimit="10" d="M1112.44,966.72c-.06,72.01-58.5,130.3-130.51,130.19-72.01-.11-130.34-58.58-130.28-130.59.06-72.01,58.5-130.3,130.51-130.19s130.34,58.58,130.28,130.59Z"/> <path fill="#724d23" stroke="#b05f05" stroke-miterlimit="10" d="M1095.56,966.7c.02,62.62-50.73,113.37-113.35,113.35s-113.4-50.8-113.42-113.42c-.02-62.62,50.73-113.37,113.35-113.35,62.62.02,113.4,50.8,113.42,113.42h0Z"/> <path fill="#e8be56" stroke="#fdf3a8" stroke-miterlimit="10" d="M1087.69,966.08c.02,58.32-47.24,105.58-105.56,105.56s-105.61-47.31-105.63-105.63,47.24-105.58,105.56-105.56c58.32.02,105.61,47.31,105.63,105.63Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M981.14,1039.18l2.77,8.52c.05.15.2.26.35.26h8.86c.39,0,.56.5.24.74l-7.17,5.21c-.13.1-.19.26-.14.41l2.77,8.52c.11.35-.28.64-.58.41l-7.25-5.26c-.13-.1-.31-.1-.44,0l-7.25,5.26c-.3.21-.69-.07-.58-.41l2.77-8.52c.05-.15,0-.32-.14-.41l-7.25-5.26c-.3-.21-.14-.68.22-.68h8.96c.16,0,.31-.1.35-.26l2.77-8.52c.11-.35.6-.35.71,0h-.02s.01-.01.01-.01Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M1005.2,1043.69l1.31,4.05c.03.07.1.13.17.13h4.25c.18,0,.24.23.11.33l-3.44,2.5c-.07.04-.1.13-.07.2l1.31,4.05c.05.17-.14.31-.28.2l-3.44-2.5c-.07-.04-.15-.04-.21,0l-3.44,2.5c-.14.1-.33-.03-.28-.2l1.31-4.05c.03-.07,0-.16-.07-.2l-3.44-2.5c-.14-.1-.07-.33.11-.33h4.25c.07,0,.15-.05.17-.13l1.31-4.05c.05-.17.29-.17.35,0h-.01Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M957.17,1043.81l1.31,4.05c.03.07.1.13.17.13h4.25c.18,0,.24.23.11.33l-3.44,2.5c-.07.04-.1.13-.07.2l1.31,4.05c.05.17-.14.31-.28.2l-3.44-2.5c-.07-.04-.15-.04-.21,0l-3.44,2.5c-.14.1-.33-.03-.28-.2l1.31-4.05c.03-.07,0-.16-.07-.2l-3.44-2.5c-.14-.1-.07-.33.11-.33h4.25c.07,0,.15-.05.17-.13l1.31-4.05c.05-.17.29-.17.35,0h-.01Z"/> <rect fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" x="970.41" y="888.96" width="21.53" height="3.12" rx="1.44" ry="1.44"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M995.46,872.54c0,.66-.55,1.2-1.21,1.2-.16,0-.32-.04-.46-.1l-2.45,14.68s-.01.03-.03.03l-20.36-.11s-.03-.01-.03-.03l-2.38-14.63c-.16.08-.32.12-.5.12-.67,0-1.2-.55-1.2-1.21s.54-1.2,1.2-1.2,1.21.54,1.21,1.2c0,.42-.22.79-.55,1-.02.01-.02.03,0,.04l7.01,5.83s.04,0,.04-.01l5-10.38s0-.04-.02-.04c-.21-.03-.4-.11-.59-.22-.68-.46-.83-1.48-.31-2.11.47-.55,1.29-.67,1.9-.25.65.45.82,1.34.37,1.98-.21.32-.54.52-.87.58-.02,0-.03.02-.02.04l5.86,9.71s.03.02.04,0l6.38-5.15s.01-.03,0-.04c-.29-.22-.47-.57-.47-.95,0-.67.54-1.21,1.2-1.21s1.21.55,1.21,1.21v.03s0,0,0,0Z"/> <g> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M935.88,905.66c2.96-.3,7.26-.06,10.52-.12,4.7.14,10.12-.21,13.66,3.32,3.36,3.25,3.94,10.96,1.95,15.25-.68,1.37-3.04,2.32-3.17,3.1-.13.7.87,1.21,1.46,1.66,2.23,1.36,3.21,3.44,3.55,6.27.21,4.87,1.3,12.42-2.92,15.88-1.83,1.43-3.82,1.61-6.79,1.8-3.57.19-5.87.14-10.03.15-2.46-.03-5.72.08-7.99-.08-.36-.06-.54-.16-.64-.33-.3-4.82-.04-35.33-.08-46.34.04-.27.13-.43.41-.53l.07-.02ZM948.07,913.71c-.51.13-.33.75-.36,1.83,0,1.21,0,2.45,0,3.82.11,2.16-.25,3.85.2,4.68.72.4,2.27,0,2.89-.41,1.2-.9.85-3.93.95-5.59.08-2.62-.76-4.69-3.56-4.35l-.11.03ZM948.19,931.6c-.69.13-.42.96-.47,2.37,0,2.47,0,5.42,0,8.01,0,.82,0,1.52,0,2.01,0,.49.16.75.56.83,1.05.07,2.45-.2,2.96-1.23.89-2.78.47-6.31.42-9.17-.06-2.29-1.3-2.87-3.35-2.83l-.12.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M996.05,905.73c.38.19.45.58.48.97.04,1.17,0,3.62.02,6.68-.13,12,.28,20.25-.22,29.52-.46,7.23-7.19,11.55-14.25,10.98-5.09-.1-10.69-2.42-12.63-7.43-1.35-3.23-.97-7.4-1.1-11.17-.04-6.25,0-12.99-.01-21.52.06-3.51-.13-5.79.11-7.41.45-1.14,1.54-.76,3.86-.88,2.08,0,4.73-.02,6.22.02,1,.06,2.12.01,2.12,1.1.15,5.89-.15,28.48.13,35.86.12,1.43,1.14,3,2.07,2.44,1.2-.83,1.29-2.56,1.35-3.88.07-9.17,0-24.77.03-33.63-.12-1.61.51-1.85,1.98-1.87,2.57.08,7.02-.3,9.78.2l.07.03Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1027.34,905.76c.3.16.3.42.25.74-.36,1.44-1.67,5.54-3.08,10.27-2.15,7.09-4.69,15.42-5.42,17.89-.35,1.09-.35,2.07-.35,3.27-.01,2.86.01,9.73-.01,12.73.06,1.7-.58,2.32-2.39,2.28-1.76.04-4.69.03-6.48.01-2.15.05-2.84-.48-2.77-2.3-.02-2.48,0-7.65-.01-10.96-.05-2.36.16-3.21-.34-5.04-1.19-4.25-6.82-23.02-8.19-28.15-.08-.99.61-.84,1.76-.95,1.45-.02,4.06-.05,6.01.01,4.72.05,4.18,5.07,5.07,8.61.29,1.66.57,3.32.82,4.97.31,1.97.47,3.95.68,3.74.92-3.48,1.17-6.83,2.08-10.81.49-2.09.73-5.34,2.6-6.07,1.45-.62,3.11-.43,4.7-.47,1.51.02,3.99-.11,5.01.2l.07.03Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M901.92,977.66c2.96-.3,7.26-.06,10.52-.12,4.7.14,10.12-.21,13.66,3.32,3.36,3.25,3.94,10.96,1.95,15.25-.68,1.37-3.04,2.32-3.17,3.1-.13.7.87,1.21,1.46,1.66,2.23,1.36,3.21,3.44,3.55,6.27.21,4.87,1.3,12.42-2.92,15.88-1.83,1.43-3.82,1.61-6.79,1.8-3.57.19-5.87.14-10.03.15-2.46-.03-5.72.08-7.99-.08-.36-.06-.54-.16-.64-.33-.3-4.82-.04-35.33-.08-46.34.04-.27.13-.43.41-.53l.07-.02ZM914.12,985.71c-.51.13-.33.75-.36,1.83,0,1.21,0,2.45,0,3.82.11,2.16-.25,3.85.2,4.68.72.4,2.27,0,2.89-.41,1.2-.9.85-3.93.95-5.59.08-2.62-.76-4.69-3.56-4.35l-.11.03ZM914.24,1003.6c-.69.13-.42.96-.47,2.37,0,2.47,0,5.42,0,8.01,0,.82,0,1.52,0,2.01,0,.49.16.75.56.83,1.05.07,2.45-.2,2.96-1.23.89-2.78.47-6.31.42-9.17-.06-2.29-1.3-2.87-3.35-2.83l-.12.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M962.74,1005.96c-.18,5.2.5,10.77-2.72,15.03-5.29,6.84-18.04,6.66-23.12-.06-3.89-5.6-2.31-12.71-2.69-19.34.15-10.8-1.95-23.36,12.25-24.95,6.93-.87,14.4,2.56,15.7,9.65.98,6.26.44,13.16.57,19.47v.21ZM950.38,988.4c-.04-.8-.09-1.72-.39-2.53-1.09-2.61-3.17-.91-3.28,1.17-.39,5.72-.05,17.95-.16,23.77.02,1.68-.04,3.37.21,5.04.23,2.39,2.78,2.97,3.37.18.13-.58.18-1.21.21-1.8.16-7.09.07-17.52.04-25.69v-.15Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M994.31,977.71c.56.17.56.58.57,1.08,0,5.94.01,39.72,0,45.1-.07.98-.49.94-1.77,1.05-1.53.05-4.68.04-6.57,0-.87-.05-1.89-.03-2.47-.74-1.54-3.38-2.75-9.04-4.5-14.4-.94-2.89-1.62-6.09-1.86-5.59-.13,3.1,0,14.27-.06,18.61-.03.6-.04,1.21-.42,1.6-1.25.82-2.88.42-4.72.53-1.41,0-2.75,0-3.6-.05-1.27-.08-1.52-.32-1.55-1.03-.01-5.46-.03-40.18,0-45.35.1-.9.56-.85,1.69-.96,1.5-.05,4.63-.06,6.43,0,1.14.01,2.29.3,2.65,1.51.89,2.51,3.19,9.82,4.78,14.65.94,2.85,1.47,4.74,1.59,4.44.23-2.46-.02-15.02.11-18.93.04-1.66,1.31-1.65,2.91-1.7,1.82,0,5.18-.12,6.72.14l.08.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1027.37,977.73c.38.19.45.58.48.97.04,1.17,0,3.62.02,6.68-.13,12,.28,20.25-.22,29.52-.46,7.23-7.19,11.55-14.25,10.98-5.09-.1-10.69-2.42-12.63-7.43-1.35-3.23-.97-7.4-1.1-11.17-.04-6.25,0-12.99-.01-21.52.06-3.51-.13-5.79.11-7.41.45-1.14,1.54-.76,3.86-.88,2.08,0,4.73-.02,6.22.02,1,.06,2.12.01,2.12,1.1.15,5.89-.15,28.48.13,35.86.12,1.43,1.14,3,2.07,2.44,1.2-.83,1.29-2.56,1.35-3.88.07-9.17,0-24.77.03-33.63-.12-1.61.51-1.85,1.98-1.87,2.57.08,7.02-.3,9.78.2l.07.03Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1058.28,990.89c-.4.56-1.14.81-2.19.89-1.95.06-4.54.16-6.51-.08-2.37-.28-2.12-2.56-2.53-4.31-.2-1.02-1.05-2.4-2.19-1.86-.95.5-1.35,1.83-1.39,2.88-.24,5.1,5.86,7.07,9.22,9.8,3.83,2.83,5.49,4.39,6.48,8.37.85,5,1.65,11.82-2.22,15.69-5.98,5.26-17.55,5.13-22.7-1.18-2.2-3.02-2.68-8.11-2.02-11.62,1.03-1.98,3.23-1.32,5.92-1.47,7.65-.59,4.08,3.47,5.95,8.01.97,1.86,2.9,1.05,3.41-.76.76-2.5.16-5.88-1.78-7.52-4.15-3.81-10.9-6.14-13.05-11.8-1.67-4.95-1.82-12.38,2.1-16.06,4.54-4.02,11.78-4.04,17.28-2.21,3.75,1.41,6.07,3.96,6.44,7.6.18,1.64.63,4.13-.15,5.51l-.07.11Z"/> </g></svg>`;
2021
+ const BUY_BONUS_SOCIAL_ART = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="1142.49 836.33 263.91 264.00"><path fill="#ebac28" stroke="#fac64c" stroke-miterlimit="10" d="M1404.84,968.53c-.06,72.01-58.5,130.3-130.51,130.19-72.01-.11-130.34-58.58-130.28-130.59.06-72.01,58.5-130.3,130.51-130.19s130.34,58.58,130.28,130.59Z"/> <path fill="#724d23" stroke="#b05f05" stroke-miterlimit="10" d="M1387.96,968.51c.02,62.62-50.73,113.37-113.35,113.35s-113.4-50.8-113.42-113.42c-.02-62.62,50.73-113.37,113.35-113.35,62.62.02,113.4,50.8,113.42,113.42h0Z"/> <path fill="#e8be56" stroke="#fdf3a8" stroke-miterlimit="10" d="M1380.09,967.89c.02,58.32-47.24,105.58-105.56,105.56s-105.61-47.31-105.63-105.63,47.24-105.58,105.56-105.56c58.32.02,105.61,47.31,105.63,105.63Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M1273.54,1040.98l2.77,8.52c.05.15.2.26.35.26h8.86c.39,0,.56.5.24.74l-7.17,5.21c-.13.1-.19.26-.14.41l2.77,8.52c.11.35-.28.64-.58.41l-7.25-5.26c-.13-.1-.31-.1-.44,0l-7.25,5.26c-.3.21-.69-.07-.58-.41l2.77-8.52c.05-.15,0-.32-.14-.41l-7.25-5.26c-.3-.21-.14-.68.22-.68h8.96c.16,0,.31-.1.35-.26l2.77-8.52c.11-.35.6-.35.71,0h-.02s.01-.01.01-.01Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M1297.6,1045.5l1.31,4.05c.03.07.1.13.17.13h4.25c.18,0,.24.23.11.33l-3.44,2.5c-.07.04-.1.13-.07.2l1.31,4.05c.05.17-.14.31-.28.2l-3.44-2.5c-.07-.04-.15-.04-.21,0l-3.44,2.5c-.14.1-.33-.03-.28-.2l1.31-4.05c.03-.07,0-.16-.07-.2l-3.44-2.5c-.14-.1-.07-.33.11-.33h4.25c.07,0,.15-.05.17-.13l1.31-4.05c.05-.17.29-.17.35,0h-.01Z"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M1249.57,1045.61l1.31,4.05c.03.07.1.13.17.13h4.25c.18,0,.24.23.11.33l-3.44,2.5c-.07.04-.1.13-.07.2l1.31,4.05c.05.17-.14.31-.28.2l-3.44-2.5c-.07-.04-.15-.04-.21,0l-3.44,2.5c-.14.1-.33-.03-.28-.2l1.31-4.05c.03-.07,0-.16-.07-.2l-3.44-2.5c-.14-.1-.07-.33.11-.33h4.25c.07,0,.15-.05.17-.13l1.31-4.05c.05-.17.29-.17.35,0h-.01Z"/> <rect fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" x="1262.81" y="890.76" width="21.53" height="3.12" rx="1.44" ry="1.44"/> <path fill="#c38a32" stroke="#944f09" stroke-width=".5px" stroke-miterlimit="10" d="M1287.86,874.34c0,.66-.55,1.2-1.21,1.2-.16,0-.32-.04-.46-.1l-2.45,14.68s-.01.03-.03.03l-20.36-.11s-.03-.01-.03-.03l-2.38-14.63c-.16.08-.32.12-.5.12-.67,0-1.2-.55-1.2-1.21s.54-1.2,1.2-1.2,1.21.54,1.21,1.2c0,.42-.22.79-.55,1-.02.01-.02.03,0,.04l7.01,5.83s.04,0,.04-.01l5-10.38s0-.04-.02-.04c-.21-.03-.4-.11-.59-.22-.68-.46-.83-1.48-.31-2.11.47-.55,1.29-.67,1.9-.25.65.45.82,1.34.37,1.98-.21.32-.54.52-.87.58-.02,0-.03.02-.02.04l5.86,9.71s.03.02.04,0l6.38-5.15s.01-.03,0-.04c-.29-.22-.47-.57-.47-.95,0-.67.54-1.21,1.2-1.21s1.21.55,1.21,1.21v.03s0,0,0,0Z"/> <g> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1260.24,923.82c-1.21,1.32-3.18.8-5.84.92-4.55.03-6.12.36-5.96-4.95-.11-1.7.01-3.73-1.57-4.59-1.62-.51-2.36,2.26-2.33,3.77-.11,5.71-.01,15.47-.04,21.13.14,2.2-.46,5.02,1.39,6.62,2.74,1.36,3.06-4.16,2.95-6.1.04-2.52-1.18-3.59-2.01-5.57-.72-2.3-.92-5.88,1.97-5.72,2.33-.07,6.98-.02,9.42-.02.86.08,2.1-.15,2.47.78.35,5.76.06,19.15.12,23.15-.03.52-.11.98-.51,1.28-1.73.77-4.7.59-6.48-.27-.92-.45-1.48-.9-2.08-.99-1.61-.15-2.95,1.56-4.5,1.95-3.95,1.37-8.65-.09-11.49-3.06-4.95-5.67-3.19-12.08-3.58-19.74.04-5.03-.14-9.89.33-14.88.34-8.33,9.22-12.5,16.95-10.97,5.72.74,10.69,5.2,11.02,11.05.14,1.84.66,4.55-.15,6.13l-.07.1Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1265.94,907.48c4.26-.34,13.96-.1,18.76-.09,1.14.03,1.38,1.04,1.41,2-.05,1.89.4,4.69-.41,6.5-1.63,1.91-5.25.08-7.07,1.62-.98,1.03-.66,3.54-.67,5.42.15,6.15,8.37-.74,7.67,6.97,0,1.75.09,4.06-1.06,4.52-1.34.67-3.3.28-4.74.56-1.74.28-1.85,1.42-1.9,3.14.03,1.77-.15,3.97.17,5.68.16.69.61,1.13,1.28,1.28,2.4.74,7.59-1.12,7.54,2.61-.05,2.1.43,4.74-.39,6.59-.52.67-1.93.44-4.22.49-4.59-.13-12.11.26-16.38-.16-.34-.17-.32-.53-.34-.9,0-4.1,0-24.6,0-36.82.01-4.43-.02-7.74.02-8.85.02-.24.07-.42.29-.54l.05-.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1314.36,907.94c.31.97.19,2.84.22,4.14-.11,1.48.39,3.48-1.04,4.36-1.57.8-4.56-.06-6,.79-.45.54-.22,1.21-.28,1.96,0,2.08,0,5.62,0,9.67-.08,9.98.16,21.72-.1,25.34-.47.73-1.16.46-2.32.56-2.4-.09-7.2.26-9.48-.21-.45-.22-.41-.68-.43-1.16,0-4.84,0-26.16,0-33.6-.07-1.73.29-2.57-.82-2.81-1.47-.35-4.12.11-5.44-.55-1.05-.58-.99-1.7-1.04-3.44.19-1.78-.65-5.66,1.23-5.64,3.61-.07,19.83-.02,24.13-.02.56.02,1.07.01,1.33.52l.04.08Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1194.32,979.47c2.96-.3,7.26-.06,10.52-.12,4.7.14,10.12-.21,13.66,3.32,3.36,3.25,3.94,10.96,1.95,15.25-.68,1.37-3.04,2.32-3.17,3.1-.13.7.87,1.21,1.46,1.66,2.23,1.36,3.21,3.44,3.55,6.27.21,4.87,1.3,12.42-2.92,15.88-1.83,1.43-3.82,1.61-6.79,1.8-3.57.19-5.87.14-10.03.15-2.46-.03-5.72.08-7.99-.08-.36-.06-.54-.16-.64-.33-.3-4.82-.04-35.33-.08-46.34.04-.27.13-.43.41-.53l.07-.02ZM1206.52,987.51c-.51.13-.33.75-.36,1.83,0,1.21,0,2.45,0,3.82.11,2.16-.25,3.85.2,4.68.72.4,2.27,0,2.89-.41,1.2-.9.85-3.93.95-5.59.08-2.62-.76-4.69-3.56-4.35l-.11.03ZM1206.64,1005.41c-.69.13-.42.96-.47,2.37,0,2.47,0,5.42,0,8.01,0,.82,0,1.52,0,2.01,0,.49.16.75.56.83,1.05.07,2.45-.2,2.96-1.23.89-2.78.47-6.31.42-9.17-.06-2.29-1.3-2.87-3.35-2.83l-.12.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1255.14,1007.76c-.18,5.2.5,10.77-2.72,15.03-5.29,6.84-18.04,6.66-23.12-.06-3.89-5.6-2.31-12.71-2.69-19.34.15-10.8-1.95-23.36,12.25-24.95,6.93-.87,14.4,2.56,15.7,9.65.98,6.26.44,13.16.57,19.47v.21ZM1242.78,990.2c-.04-.8-.09-1.72-.39-2.53-1.09-2.61-3.17-.91-3.28,1.17-.39,5.72-.05,17.95-.16,23.77.02,1.68-.04,3.37.21,5.04.23,2.39,2.78,2.97,3.37.18.13-.58.18-1.21.21-1.8.16-7.09.07-17.52.04-25.69v-.15Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1286.71,979.51c.56.17.56.58.57,1.08,0,5.94.01,39.72,0,45.1-.07.98-.49.94-1.77,1.05-1.53.05-4.68.04-6.57,0-.87-.05-1.89-.03-2.47-.74-1.54-3.38-2.75-9.04-4.5-14.4-.94-2.89-1.62-6.09-1.86-5.59-.13,3.1,0,14.27-.06,18.61-.03.6-.04,1.21-.42,1.6-1.25.82-2.88.42-4.72.53-1.41,0-2.75,0-3.6-.05-1.27-.08-1.52-.32-1.55-1.03-.01-5.46-.03-40.18,0-45.35.1-.9.56-.85,1.69-.96,1.5-.05,4.63-.06,6.43,0,1.14.01,2.29.3,2.65,1.51.89,2.51,3.19,9.82,4.78,14.65.94,2.85,1.47,4.74,1.59,4.44.23-2.46-.02-15.02.11-18.93.04-1.66,1.31-1.65,2.91-1.7,1.82,0,5.18-.12,6.72.14l.08.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1319.77,979.53c.38.19.45.58.48.97.04,1.17,0,3.62.02,6.68-.13,12,.28,20.25-.22,29.52-.46,7.23-7.19,11.55-14.25,10.98-5.09-.1-10.69-2.42-12.63-7.43-1.35-3.23-.97-7.4-1.1-11.17-.04-6.25,0-12.99-.01-21.52.06-3.51-.13-5.79.11-7.41.45-1.14,1.54-.76,3.86-.88,2.08,0,4.73-.02,6.22.02,1,.06,2.12.01,2.12,1.1.15,5.89-.15,28.48.13,35.86.12,1.43,1.14,3,2.07,2.44,1.2-.83,1.29-2.56,1.35-3.88.07-9.17,0-24.77.03-33.63-.12-1.61.51-1.85,1.98-1.87,2.57.08,7.02-.3,9.78.2l.07.03Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1350.68,992.69c-.4.56-1.14.81-2.19.89-1.95.06-4.54.16-6.51-.08-2.37-.28-2.12-2.56-2.53-4.31-.2-1.02-1.05-2.4-2.19-1.86-.95.5-1.35,1.83-1.39,2.88-.24,5.1,5.86,7.07,9.22,9.8,3.83,2.83,5.49,4.39,6.48,8.37.85,5,1.65,11.82-2.22,15.69-5.98,5.26-17.55,5.13-22.7-1.18-2.2-3.02-2.68-8.11-2.02-11.62,1.03-1.98,3.23-1.32,5.92-1.47,7.65-.59,4.08,3.47,5.95,8.01.97,1.86,2.9,1.05,3.41-.76.76-2.5.16-5.88-1.78-7.52-4.15-3.81-10.9-6.14-13.05-11.8-1.67-4.95-1.82-12.38,2.1-16.06,4.54-4.02,11.78-4.04,17.28-2.21,3.75,1.41,6.07,3.96,6.44,7.6.18,1.64.63,4.13-.15,5.51l-.07.11Z"/> </g></svg>`;
2022
+ const BUY_BONUS_DISABLED_ART = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="1427.21 845.04 263.91 264.00"><path fill="#ebac28" stroke="#fac64c" stroke-miterlimit="10" d="M1689.56,977.24c-.06,72.01-58.5,130.3-130.51,130.19-72.01-.11-130.34-58.58-130.28-130.59.06-72.01,58.5-130.3,130.51-130.19s130.34,58.58,130.28,130.59Z"/> <path fill="#724d23" stroke="#b05f05" stroke-miterlimit="10" d="M1672.68,977.22c.02,62.62-50.73,113.37-113.35,113.35s-113.4-50.8-113.42-113.42c-.02-62.62,50.73-113.37,113.35-113.35,62.62.02,113.4,50.8,113.42,113.42h0Z"/> <path fill="#e8be56" stroke="#fdf3a8" stroke-miterlimit="10" d="M1664.81,976.6c.02,58.32-47.24,105.58-105.56,105.56s-105.61-47.31-105.63-105.63,47.24-105.58,105.56-105.56c58.32.02,105.61,47.31,105.63,105.63Z"/> <g> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1463,957.03c2.56-.29,8.57-.12,11.76-.04,5.58-.09,11.59,1.52,12.44,7.62.66,7.82.32,17.48.24,24.98.14,10.47-9.06,9.13-17.32,9.19-2.17-.03-5.06.09-7.03-.09-.63-.1-.74-.36-.76-.9,0-4.3-.06-30.8.02-40.15.06-.33.21-.49.56-.59l.09-.02ZM1473.96,964.03c-1.03-.07-.69,2.43-.74,4.21,0,6.76-.02,15.33,0,22.09-.03,1.34.99,1.52,1.85.95,2.18-1.68,1.38-5.18,1.59-7.63,0-2.48,0-7.55,0-10.85-.26-3.14,1.01-8.14-2.62-8.78h-.09Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1502.08,957.04c.27.1.37.26.41.52.06,1.07.01,4.28.03,8.51,0,7.65.01,27,0,31.75-.02.94-.66.89-1.64.95-1.21.04-3.49.01-5.4.02-1.35-.14-3.91.46-3.84-.97,0-5.08-.06-34.32.02-40.19.23-.96,1.12-.62,2.51-.74,2.53.07,5.57-.17,7.85.13l.07.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1529.42,968.56c-.85,1.03-2.68.92-4.09.95-1.35-.02-2.79.09-4.01-.42-1.48-.59-1.34-2.38-1.93-3.86-.25-.68-.9-1.48-1.68-1.07-.65.35-1.02,1.25-1.13,1.99-.61,4.62,5.09,6.64,8.11,9.08,3.6,2.65,5.08,4.21,5.85,8.48.5,4.24,1.02,9.62-2.34,12.79-5.22,4.53-15.5,4.43-19.94-1.23-1.85-2.65-2.4-6.91-1.69-9.95,1.16-2.1,3.98-1.35,6.42-1.48,4.23-.11,3.01,3.19,3.8,6.28.24.81.87,1.75,1.81,1.56,1.52-.55,1.73-2.71,1.6-4.15-.26-3.34-2.56-4.65-5.14-6.48-2.81-2.04-6.27-3.87-7.79-7.15-1.89-4.39-2.2-11.51,1.64-15.04,5.19-4.47,17.33-4.04,20.28,2.82.6,1.99,1.25,4.91.3,6.76l-.08.11Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1552.87,957.05c.42.18.43.63.52,1.07.82,5.55,5.33,35.33,5.96,39.77,0,.98-.61.77-1.89.88-2.19-.1-5.81.31-8.09-.26-2.04-.92-.88-4.45-2.16-6.1-.6-1-1.97-1.25-2.76-.35-1.61,1.51-.51,4.92-2.14,6.26-1.61.89-7.78.33-9.37.41-.9-.09-1.16-.19-1.11-.92.92-5.43,3.98-32.81,5.65-40.64.51-.33,1.24-.25,1.9-.28,3.58.11,10.36-.22,13.44.14l.06.02ZM1547.05,983.96c.36-.37.29-.99.24-1.5-.48-4.19-.92-9.67-1.45-15.13-.26-1.5-.51.91-.59,1.36-.79,5.88-1.35,10.57-1.66,13.97-.45,2,2.26,2.08,3.36,1.39l.09-.09Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1561.74,957.03c3.14-.32,7.34-.09,10.7-.12,6.59-.11,12.7,1.62,13.11,9.39.18,2.07.16,4.77-.7,6.54-.69,1.55-2.61,2.36-2.72,3.15-.11.93,1.25,1.54,1.87,2.17,1.31,1.07,1.95,2.62,2.25,4.47.34,4.17.97,9.41-1.37,13.16-3.15,4.13-10.24,2.63-14.89,2.98-2.46-.05-5.73.12-8.09-.11-.33-.07-.51-.18-.6-.36-.31-4.81-.07-30.82-.08-40.74.05-.27.16-.43.44-.53l.07-.02ZM1572.4,964.11c-.47.13-.25.83-.3,1.99v2.76c.1,1.97-.22,3.52.17,4.36.63.38,1.99.03,2.54-.33.92-.56.77-2.75.86-4.06.09-2.51-.16-5.13-3.16-4.75l-.11.03ZM1572.52,979.92c-.57.12-.39.77-.42,1.9,0,2.2,0,4.85,0,7.16.06,1.43-.2,2.39.4,2.57.96.16,2.29-.15,2.73-1.11.72-2.21.38-5.09.39-7.46-.08-2.19-.63-3.14-2.99-3.08l-.12.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1600.9,957.09c.46.21.45.63.47,1.1.02,4.6,0,25.94.01,30.78.02.59.1,1.02.74,1.21,4.86.63,6.14-.68,5.87,5.67.04,3.11-.8,2.98-4.49,2.92-3.95-.07-9.05.16-12.46-.1-.53-.13-.53-.49-.56-.97,0-5.34-.01-31.54,0-39.66-.13-1.21,1.14-1.11,2.02-1.15,2.39.08,5.98-.23,8.32.17l.07.03Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1611.03,957.04c3.53-.41,11.5-.05,15.56-.14.74.03,1.54.08,1.87.8.26.56.29,1.3.32,1.95-.04,2.41.48,5.14-2.08,5.5-3.78.3-5.42-.13-5.16,4.7-.09,5.4,4.65,1.78,6.41,4.68.58,1.7.6,4.92-.4,5.93-1.48,1.38-4.4,0-5.59,1.79-.73,1.81-.5,4.61-.24,6.58.76,3.03,6.18.22,7.44,2.86.47,1.06.35,3.19.32,4.72-.04.62-.08,1.26-.39,1.76-.49.77-1.77.6-3.87.63-4.03-.13-10.44.28-14.21-.18-.37-.19-.35-.59-.37-1.01,0-3.97,0-21.65,0-32.24.02-3.86-.03-6.74.03-7.75.03-.24.1-.42.31-.53l.05-.02Z"/> <path fill="#412b16" stroke="#331700" stroke-miterlimit="10" d="M1633.34,957.03c2.56-.29,8.57-.12,11.76-.04,5.58-.09,11.59,1.52,12.44,7.62.66,7.82.32,17.48.24,24.98.14,10.47-9.06,9.13-17.32,9.19-2.17-.03-5.06.09-7.03-.09-.63-.1-.74-.36-.76-.9,0-4.3-.06-30.8.02-40.15.06-.33.21-.49.56-.59l.09-.02ZM1644.29,964.03c-1.03-.07-.69,2.43-.74,4.21,0,6.76-.02,15.33,0,22.09-.03,1.34.99,1.52,1.85.95,2.18-1.68,1.38-5.18,1.59-7.63,0-2.48,0-7.55,0-10.85-.26-3.14,1.01-8.14-2.62-8.78h-.09Z"/> </g></svg>`;
2023
+
2009
2024
  function isSizable(n) {
2010
2025
  return !!n && typeof n.measureSize === 'function' && typeof n.setLayoutSize === 'function';
2011
2026
  }
@@ -2265,89 +2280,74 @@ function roundedPath(g, x, y, w, h, [tl, tr, br, bl]) {
2265
2280
  g.closePath();
2266
2281
  }
2267
2282
 
2268
- // AUTO-GENERATED from ./icons-preview.svg by scripts/gen-icons.mjs — do not edit by hand.
2283
+ // AUTO-GENERATED from ../../icons.svg by scripts/gen-icons-from-svg.mjs — do not edit by hand.
2269
2284
  // Sharp monochrome icon set: each glyph is a 24×24 viewBox fragment using currentColor
2270
- // (hollow shapes use fill-rule="evenodd"; the few stroked glyphs use stroke="currentColor").
2271
- // Coordinates are baked into the 24×24 space (no <g transform>), so the same fragment renders
2272
- // identically in the DOM <svg> and in Pixi's GraphicsContext.svg.
2273
- // To change an icon: edit icons-preview.svg, then run `node scripts/gen-icons.mjs`.
2285
+ // (hollow shapes use fill-rule="evenodd"). Coordinates are baked into the 24×24 space (no
2286
+ // <g transform>), so the same fragment renders identically in the DOM <svg> and in Pixi's
2287
+ // GraphicsContext.svg. To change an icon: edit icons.svg, then run
2288
+ // `node scripts/gen-icons-from-svg.mjs`.
2274
2289
  const SVGS = {
2275
- spin: `<g fill="currentColor" fill-rule="evenodd"><path d="M17.72 4.86c-1.77 -0.89 -5.48 -2.51 -7.37 -3.08l1.4 1.96h0c-5.36 0.16 -8.6 5.47 -9.04 10.35l1.58 2.61l0.19 0.1l1.86 -1.68c-0.21 -0.42 -0.56 -1.87 -0.56 -1.87h0c-0.41 -4.55 3.28 -7.88 7.75 -7.37h0l2.33 0.75l1.86 -1.59v-0.18Z"/><path d="M6.29 19.38c1.79 0.86 5.54 2.39 7.43 2.92l-1.44 -1.93h0c5.36 -0.27 8.48 -5.65 8.81 -10.54l-1.64 -2.57l-0.19 -0.1l-1.82 1.72c0.22 0.42 0.6 1.86 0.6 1.86h0c0.51 4.54 -3.12 7.95 -7.59 7.53h0l-2.35 -0.7l-1.83 1.63v0.18Z"/></g>`,
2276
- turbo1: `<g fill="currentColor" fill-rule="evenodd"><path d="M11.77 2.71l-4.62 10.63h4.39c-2.08 3.86 -4.74 8.67 -4.74 8.67h0.23s11.95 -12.16 11.95 -12.16l-5.79 0.03l5.63 -8.67l-7.05 1.5Z"/></g>`,
2277
- autoplay: `<g fill="currentColor" fill-rule="evenodd"><path d="M9.61 8.97v6.44h0.1c0.82 -0.65 4.19 -2.6 5.15 -3.17v-0.1c-0.99 -0.55 -4.32 -2.68 -5.25 -3.17Z"/><path d="M20.32 8.33l-1.5 1.31v7.33l-2.08 1.69s-12.68 0 -12.68 0v0.1l4.36 3.76l-0.59 -2.18h10.1l2.48 -2.57h0l-0.09 -9.44Z"/><path d="M2.88 15.89l1.51 -1.3l0.05 -7.33l2.09 -1.67s12.68 0.08 12.68 0.08v-0.1s-4.34 -3.79 -4.34 -3.79l0.58 2.18h0l-10.1 -0.07l-2.5 2.55h0l0.03 9.44Z"/></g>`,
2278
- stop: `<g fill="currentColor" fill-rule="evenodd"><path d="M20.96 1.6h-17.58l-1.78 1.85v17.51l1.3 -1.84v-14.37l1.64 -1.64h14.58l1.84 -1.51Z"/><path d="M3.09 22.37l17.58 -0.04l1.78 -1.85l-0.04 -17.51l-1.3 1.84l0.03 14.37l-1.64 1.64l-14.58 0.03h0l-1.84 1.52Z"/></g>`,
2279
- menu: `<g fill="currentColor" fill-rule="evenodd"><path d="M1.6 13.52h18.01l2.79 -3.17h-18.01l-2.79 3.17h0Z"/><path d="M1.6 6.04h18.01l2.79 -3.17h-18.01l-2.79 3.17h0Z"/><path d="M1.64 21.02h18.01l2.79 -3.17h-18.01l-2.79 3.17h0Z"/></g>`,
2280
- minus: `<g fill="currentColor" fill-rule="evenodd"><path d="M19.81 13.26l2.59 -2.44l-18.13 -0.08l-2.67 2.52"/></g>`,
2281
- plus: `<g fill="currentColor" fill-rule="evenodd"><path d="M13.16 1.6h0l-2.39 3.82v5.31l-0.08 0.07h-6.36l-2.54 2.4h8.9l0.08 0.07v9.13l2.39 -3.74h0v-5.39l0.07 -0.07h6.36l2.62 -2.4h-8.98l-0.07 -0.07v-9.13Z"/></g>`,
2290
+ spin: `<g fill="currentColor" fill-rule="evenodd"><path d="M13.57 8.41C13.3 8.31 13.51 7.09 13.59 6.65C13.61 6.56 13.55 6.48 13.46 6.48C12.32 6.45 5.74 6.61 4.16 14.85C4.15 14.9 4 15.16 3.8 14.91C3.27 14.23 2.43 12.08 3.46 9.16C6.01 1.92 13 3.07 13.79 3.23C13.83 3.23 13.86 3.2 13.86 3.17C13.85 2.86 13.82 1.68 14.17 1.64C14.51 1.6 19.04 5.61 18.96 5.95C18.86 6.36 13.83 8.51 13.57 8.41Z"/><path d="M10.43 15.59C10.7 15.69 10.49 16.91 10.41 17.35C10.39 17.44 10.45 17.52 10.54 17.52C11.68 17.55 18.26 17.39 19.84 9.15C19.85 9.1 20 8.84 20.2 9.09C20.73 9.77 21.57 11.92 20.54 14.85C17.99 22.08 11 20.93 10.21 20.77C10.17 20.77 10.13 20.8 10.14 20.83C10.15 21.14 10.18 22.32 9.83 22.36C9.49 22.4 4.96 18.39 5.04 18.05C5.14 17.64 10.17 15.49 10.43 15.59Z"/></g>`,
2291
+ turbo1: `<g fill="currentColor" fill-rule="evenodd"><path d="M17.81 2.62L14.41 8.21C14.15 8.64 14.46 9.2 14.97 9.2L18.84 9.21C19.42 9.21 19.72 9.9 19.32 10.31L8.02 22.19C7.89 22.33 7.72 22.4 7.53 22.4L7.53 22.4C7.08 22.39 6.77 21.93 6.93 21.5L9.91 13.91C10.08 13.48 9.76 13.01 9.29 13.01L5.11 13.06C4.61 13.06 4.28 12.53 4.53 12.09L10.07 1.94C10.19 1.73 10.41 1.6 10.65 1.6L17.26 1.62C17.77 1.62 18.08 2.18 17.81 2.62Z"/></g>`,
2292
+ autoplay: `<g fill="currentColor" fill-rule="evenodd"><path d="M19.97 12.41C20.22 11.94 20.95 11.88 20.97 12.47C21.14 16.4 18.71 19.92 14.44 20.97C8.59 22.4 5.29 18.55 5.28 18.52C5.2 18.33 4.41 19.77 4.19 19.59C3.81 19.28 3.78 14.9 3.9 14.78C4.01 14.67 8.39 14.95 8.48 15.31C8.58 15.64 7.2 16.1 7.4 16.38C9.14 18.67 15.82 20.29 19.97 12.41Z"/><path d="M9.3 15.36L9.3 8.67C9.3 8.32 9.97 7.74 10.58 8.14C15.83 11.56 16 11.46 16.01 12.04C16.02 12.61 15.12 12.98 10.63 15.91C10.32 16.11 9.29 15.72 9.29 15.36Z"/><path d="M4.03 11.59C3.78 12.06 3.05 12.12 3.03 11.53C2.86 7.6 5.29 4.08 9.56 3.03C15.41 1.6 18.71 5.45 18.72 5.48C18.8 5.67 19.59 4.23 19.81 4.41C20.19 4.72 20.22 9.1 20.1 9.22C19.99 9.33 15.61 9.05 15.52 8.69C15.42 8.36 16.8 7.9 16.6 7.62C14.86 5.33 8.18 3.71 4.03 11.59Z"/></g>`,
2293
+ stop: `<g fill="currentColor" fill-rule="evenodd"><rect x="1.6" y="1.6" width="20.8" height="20.8" rx="2.9"/></g>`,
2294
+ menu: `<g fill="currentColor" fill-rule="evenodd"><rect x="1.61" y="3.81" width="20.79" height="4.47" rx="2.23"/><rect x="1.6" y="9.77" width="20.79" height="4.46" rx="2.23"/><rect x="1.6" y="15.72" width="20.79" height="4.47" rx="2.23"/></g>`,
2295
+ minus: `<g fill="currentColor" fill-rule="evenodd"><rect x="1.6" y="9.86" width="20.8" height="4.28" rx="2.11"/></g>`,
2296
+ plus: `<g fill="currentColor" fill-rule="evenodd"><path d="M19.72 14.37L13.84 14.37L13.84 20.33C13.84 21.48 12.89 22.4 11.74 22.36C10.61 22.36 9.7 21.45 9.7 20.33L9.7 14.37L3.67 14.37C2.52 14.37 1.6 13.42 1.63 12.27C1.63 11.15 2.55 10.23 3.67 10.23L9.7 10.23L9.7 4.28C9.71 1.61 13.83 1.6 13.84 4.28L13.84 10.23L19.72 10.23C22.39 10.24 22.4 14.36 19.72 14.37Z"/></g>`,
2282
2297
  gift: `<rect x="4" y="9" width="16" height="11" rx="2" fill="currentColor"/><path d="M9 9c-1.35 -0.31 -2.18 -1.65 -1.87 -3s1.65 -2.18 3 -1.87c0.93 0.22 1.65 0.94 1.87 1.87c0.31 -1.35 1.65 -2.18 3 -1.87c1.35 0.31 2.18 1.65 1.87 3c-0.22 0.93 -0.94 1.65 -1.87 1.87h-6Z" fill="currentColor"/><rect x="11" y="9" width="2" height="11" fill="rgba(0,0,0,.35)"/>`,
2283
- info: `<g fill="currentColor" fill-rule="evenodd"><path d="M14.22 7.78l-3.09 0.08s-1.82 1.49 -1.96 1.43h0.98l-2.03 13.03h0l5.5 -4.37h-1.66"/><path d="M15.96 1.6h-3.02c-0.86 1.04 -2.06 2.98 -2.86 4.07l2.71 -0.08c0.84 -0.95 2.43 -2.96 3.17 -3.99Z"/></g>`,
2284
- soundOn: `<g fill="currentColor" fill-rule="evenodd"><path d="M18.88 10.12l-2.27 -3.44l0.55 1.72l0.24 1.57v3.91l-0.24 1.56l-0.55 1.72l2.27 -3.44"/><path d="M20.91 13.33c0.08 1.91 -0.87 4.39 -1.64 6.1c1.12 -1.38 2.35 -3.64 3.13 -5.24c0 0 0 -4.61 0 -4.61c-0.75 -1.65 -2 -3.83 -3.13 -5.24c0.85 1.78 1.69 4.08 1.64 6.1"/><path d="M13.17 1.76c-1.7 1.45 -5.26 4.82 -6.88 6.41l-4.69 0.08v7.35c0.14 0.14 4.37 0.65 4.69 0.7c1.67 1.52 5.13 4.54 6.88 5.94v-20.48Z"/><path d="M11.69 5.59l0.23 0.08v13.37l-0.23 0.08l-4.62 -4.3l-2.5 -0.32l-0.15 -0.15v-3.84l0.15 -0.15l2.5 -0.08l4.62 -4.69Z"/></g>`,
2285
- soundOff: `<g fill="currentColor" fill-rule="evenodd"><path d="M13.68 13.18l-1.15 1.22v4.04l-0.23 0.07l-1.9 -1.75l-1.07 1.07l3.51 3.05l0.91 0.68v-8.38h-0.07Z"/><path d="M17.71 8.69l-0.22 0.22l0.07 0.99s0.22 4.19 -0.53 5.49l1.75 -2.51v-2.59l-1.07 -1.6Z"/><path d="M19.47 6.63l1.06 3.5v2.9l-1.22 3.88l2.21 -3.73v-3.28l-2.05 -3.27Z"/><path d="M20.91 2.21c-1.64 1.63 -5.41 5.42 -6.93 7.09l-0.23 -0.08v-7.62c-1.67 1.43 -5.11 4.69 -6.7 6.25l-4.65 0.07l0.08 0.08v7.16l4.03 0.54l1.22 -1.38l-2.43 -0.3l-0.08 -0.08v-3.81l2.59 -0.23l4.49 -4.57l0.23 0.08v5.49c-3.03 3.13 -7.21 8.09 -9.98 11.5c6.55 -5.77 13.23 -13.13 18.36 -20.19Z"/></g>`,
2286
- close: `<g fill="currentColor" fill-rule="evenodd"><path d="M16.89 5.27l-4.77 5.02l-4.77 -4.9l-5.14 -3.3l3.67 5.14l4.53 4.77l-5.05 5.19l-3.52 5.21l5.39 -3.67l4.77 -5.02h0.12l4.9 5.02l5.14 3.43l-3.5 -4.99l-4.95 -5.05v-0.24l4.82 -5.08l3.63 -5.19"/></g>`,
2287
- back: `<path d="M15 6l-6 6l6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`,
2288
- chevronRight: `<path d="M9 6l6 6l-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`,
2298
+ info: `<g fill="currentColor" fill-rule="evenodd"><circle cx="11.98" cy="4.27" r="2.67"/><path d="M16.05 21.09L16.05 21.54C16.05 22.02 15.67 22.4 15.19 22.4L8.89 22.4C8.42 22.4 8.04 22.02 8.04 21.54L8.04 20.98C8.04 20.5 8.42 20.12 8.89 20.12L8.89 20.12C9.13 20.12 9.32 19.93 9.32 19.7L9.32 11.59C9.32 11.29 9.08 11.05 8.8 11.05C8.33 11.05 7.95 10.67 7.95 10.19L7.95 9.18C7.95 8.7 8.33 8.32 8.8 8.32L9.32 8.32C9.32 8.32 13.8 8.32 13.8 8.32C14.27 8.32 14.65 8.71 14.65 9.18L14.65 19.7C14.65 19.93 14.84 20.12 15.07 20.12L15.07 20.12C15.61 20.12 16.05 20.56 16.05 21.09Z"/></g>`,
2299
+ soundOn: `<g fill="currentColor" fill-rule="evenodd"><path d="M1.6 15.04L1.6 9.18C1.6 8.75 1.95 8.4 2.38 8.4L5.03 8.4C5.21 8.4 5.39 8.36 5.56 8.28L11.6 5.26C12.12 5 12.73 5.38 12.73 5.96L12.73 18.27C12.73 18.85 12.12 19.22 11.6 18.96L5.56 15.94C5.39 15.86 5.22 15.82 5.03 15.82L2.38 15.82C1.95 15.82 1.6 15.47 1.6 15.04Z"/><path d="M16.01 12.11C16.04 12.36 15.67 14.7 14.7 15.23C13.92 15.42 13.54 14.77 13.86 14.1C14.89 12.56 14.88 11.66 13.86 10.13C13.54 9.46 13.92 8.8 14.7 8.99C15.67 9.53 16.06 11.81 16.01 12.11Z"/><path d="M19.15 12.12C19.2 12.51 18.6 16.4 17.3 17.05C16.32 17.54 15.99 16.87 16.42 15.81C17.8 13.4 17.59 9.93 16.42 8.41C15.73 7.5 16.34 6.58 17.26 7.18C18.74 8.15 19.21 11.64 19.15 12.12Z"/><path d="M22.4 12.16C22.16 15.18 21 17.95 19.71 18.82C18.73 19.48 18.22 18.42 18.93 17.32C20.96 14.17 21.92 9.95 18.9 6.29C18.13 5.35 19.35 4.52 20.11 5.48C21.43 7.14 22.33 9.14 22.4 12.16Z"/></g>`,
2300
+ soundOff: `<g fill="currentColor" fill-rule="evenodd"><path d="M1.6 14.77L1.6 9.23C1.6 8.82 1.93 8.49 2.34 8.49L4.85 8.49C5.02 8.49 5.19 8.45 5.34 8.38L11.06 5.52C11.55 5.27 12.12 5.63 12.12 6.18L12.12 17.82C12.12 18.37 11.55 18.73 11.06 18.48L5.34 15.62C5.19 15.55 5.02 15.51 4.85 15.51L2.34 15.51C1.93 15.51 1.6 15.18 1.6 14.77Z"/><path d="M21.95 16.53C21.5 16.98 20.78 16.98 20.33 16.53L17.79 13.99L15.25 16.54C14.8 16.99 14.07 16.99 13.62 16.54C13.17 16.09 13.17 15.36 13.62 14.92L16.17 12.37L13.63 9.83C13.18 9.38 13.18 8.65 13.63 8.21C13.85 7.98 14.14 7.87 14.44 7.87C14.73 7.87 15.02 7.98 15.25 8.21L17.79 10.75L20.33 8.21C20.77 7.76 21.5 7.76 21.95 8.21C22.17 8.44 22.28 8.73 22.28 9.02C22.28 9.32 22.17 9.61 21.95 9.83L19.41 12.37L21.95 14.91C22.4 15.36 22.4 16.08 21.95 16.53Z"/></g>`,
2301
+ close: `<g fill="currentColor" fill-rule="evenodd"><path d="M21.39 21.37C20.38 22.38 18.74 22.38 17.73 21.37L12.01 15.64L6.27 21.38C5.26 22.39 3.62 22.39 2.61 21.38C1.6 20.38 1.6 18.74 2.61 17.73L8.35 11.99L2.62 6.25C1.61 5.24 1.61 3.61 2.62 2.6C3.12 2.09 3.79 1.84 4.45 1.84C5.11 1.84 5.77 2.09 6.28 2.6L12.01 8.33L17.72 2.62C18.73 1.61 20.37 1.61 21.38 2.62C21.89 3.12 22.14 3.78 22.14 4.44C22.14 5.11 21.89 5.77 21.38 6.27L15.67 11.99L21.39 17.71C22.4 18.72 22.4 20.36 21.39 21.37Z"/></g>`,
2302
+ back: `<g fill="currentColor" fill-rule="evenodd"><path d="M17.49 2.32L17.49 2.32C18.2 3.03 18.2 4.19 17.49 4.9L11.68 10.71C10.97 11.42 10.97 12.58 11.68 13.29L17.49 19.1C18.21 19.81 18.21 20.97 17.49 21.69L17.49 21.69C16.78 22.4 15.62 22.4 14.91 21.69L7.8 14.58L7.8 14.58C7.8 14.58 6.51 13.29 6.51 13.29C5.79 12.58 5.79 11.42 6.51 10.71L14.9 2.31C15.62 1.6 16.77 1.6 17.49 2.31Z"/></g>`,
2303
+ chevronRight: `<g fill="currentColor" fill-rule="evenodd"><path d="M6.51 21.68L6.51 21.68C5.8 20.97 5.8 19.81 6.51 19.1L12.32 13.29C13.03 12.58 13.03 11.42 12.32 10.71L6.51 4.9C5.79 4.19 5.79 3.03 6.51 2.31L6.51 2.31C7.22 1.6 8.38 1.6 9.09 2.31L16.2 9.42L16.2 9.42C16.2 9.42 17.49 10.71 17.49 10.71C18.21 11.42 18.21 12.58 17.49 13.29L9.1 21.69C8.38 22.4 7.23 22.4 6.51 21.69Z"/></g>`,
2289
2304
  ticket: `<path d="M1.72 9.48L19.64 4.67L20.28 7.07C19.19 7.8 18.82 9 19.11 10.09C19.41 11.19 20.33 12.04 21.64 12.13L22.28 14.52L4.36 19.32L3.72 16.93C4.81 16.2 5.18 15 4.89 13.91C4.59 12.81 3.67 11.96 2.36 11.87L1.72 9.48Z" fill="none" stroke="currentColor" stroke-width="1.84" stroke-linejoin="miter"/><path d="M12.57 7.17L9.75 13.26L11.92 12.4L11.84 16.74L14.85 10.06L12.38 11.1Z" fill="currentColor"/>`,
2305
+ turbo2: `<g fill="currentColor" fill-rule="evenodd"><path d="M8.24 8.81L3.92 7.68C3.88 7.67 3.88 7.61 3.92 7.61L9.66 6.45C9.8 6.43 9.89 6.56 9.83 6.68L8.86 8.35C8.67 8.73 8.33 8.83 8.24 8.81Z"/><path d="M20.58 3.04L17.34 8.38C17.09 8.8 17.39 9.33 17.87 9.33L21.57 9.33C22.12 9.33 22.4 9.99 22.02 10.39L11.24 21.73C11.12 21.86 10.95 21.93 10.77 21.92L10.77 21.92C10.34 21.92 10.04 21.47 10.2 21.07L13.04 13.82C13.21 13.41 12.9 12.96 12.45 12.97L8.46 13.01C7.98 13.01 7.67 12.5 7.9 12.08L13.2 2.4C13.31 2.2 13.52 2.07 13.75 2.07L20.05 2.09C20.54 2.1 20.84 2.63 20.58 3.04Z"/><path d="M5.96 12.68L1.64 11.54C1.6 11.54 1.6 11.47 1.64 11.47L7.38 10.31C7.52 10.3 7.61 10.42 7.55 10.55L6.58 12.22C6.39 12.59 6.05 12.69 5.96 12.68Z"/><path d="M9.67 16.66L5.35 15.53C5.31 15.52 5.31 15.46 5.35 15.46L11.09 14.3C11.22 14.28 11.32 14.41 11.26 14.53L10.29 16.2C10.1 16.58 9.76 16.68 9.67 16.66Z"/></g>`,
2306
+ turboOff: `<g fill="currentColor" fill-rule="evenodd"><path d="M17.81 2.62L14.41 8.21C14.15 8.64 14.46 9.2 14.97 9.2L18.84 9.21C19.42 9.21 19.72 9.9 19.32 10.31L8.02 22.19C7.89 22.33 7.72 22.4 7.53 22.4L7.53 22.4C7.08 22.39 6.77 21.93 6.93 21.5L9.91 13.91C10.08 13.48 9.76 13.01 9.29 13.01L5.11 13.06C4.61 13.06 4.28 12.53 4.53 12.09L10.07 1.94C10.19 1.73 10.41 1.6 10.65 1.6L17.26 1.62C17.77 1.62 18.08 2.18 17.81 2.62Z"/></g>`,
2307
+ chevronUp: `<g fill="currentColor" fill-rule="evenodd"><path d="M21.68 17.49L21.68 17.49C20.97 18.2 19.81 18.2 19.1 17.49L13.29 11.68C12.58 10.97 11.42 10.97 10.71 11.68L4.9 17.49C4.19 18.21 3.03 18.21 2.31 17.49L2.31 17.49C1.6 16.78 1.6 15.62 2.31 14.91L9.42 7.8L9.42 7.8C9.42 7.8 10.71 6.51 10.71 6.51C11.42 5.79 12.58 5.79 13.29 6.51L21.69 14.9C22.4 15.62 22.4 16.77 21.69 17.49Z"/></g>`,
2308
+ chevronDown: `<g fill="currentColor" fill-rule="evenodd"><path d="M2.32 6.51L2.32 6.51C3.03 5.8 4.19 5.8 4.9 6.51L10.71 12.32C11.42 13.03 12.58 13.03 13.29 12.32L19.1 6.51C19.82 5.79 20.97 5.79 21.69 6.51L21.69 6.51C22.4 7.22 22.4 8.38 21.69 9.09L14.58 16.19L14.58 16.2C14.58 16.2 13.29 17.49 13.29 17.49C12.58 18.21 11.42 18.21 10.71 17.49L2.31 9.1C1.6 8.38 1.6 7.23 2.31 6.51Z"/></g>`,
2290
2309
  };
2291
2310
  /** A standalone, parseable SVG document with `currentColor` resolved to `color`.
2292
2311
  * Used by the Pixi renderer to build vector geometry via GraphicsContext.svg(). */
2293
2312
  function iconSVG(name, color = '#ffffff') {
2294
2313
  return `<svg viewBox="0 0 24 24">${SVGS[name].split('currentColor').join(color)}</svg>`;
2295
2314
  }
2296
- /** A standalone SVG with the glyph rendered as a stroke-only outline (fill:none).
2297
- * Used to build the outer-ring effect in Pixi: draw this first (under), then iconSVG on top;
2298
- * only the outer half of the stroke is visible — the paint-order:stroke CSS equivalent. */
2299
- function iconStrokeSVG(name, stroke, width = 4) {
2300
- const frag = SVGS[name].split('fill="currentColor"').join(`fill="none" stroke="${stroke}" stroke-width="${width}" stroke-linejoin="round"`);
2301
- return `<svg viewBox="0 0 24 24">${frag}</svg>`;
2302
- }
2303
2315
 
2316
+ // Icons/coins are parsed from small-viewBox SVGs (24-unit glyphs, ~260-unit coin). Pixi's default
2317
+ // bezierSmoothness (0.5) flattens curves with a ~1-unit path-space tolerance — coarse facets at
2318
+ // that scale that magnify when the glyph is scaled to button size. Max it out (capped at 0.99) so
2319
+ // every SVG-parsed curve stays smooth. Global default; set once, before any GraphicsContext builds.
2320
+ pixi_js.GraphicsContextSystem.defaultOptions.bezierSmoothness = 0.99;
2304
2321
  // The DOM shell renders each icon as an inline <svg> sized to 1em and recoloured via
2305
2322
  // `currentColor`. The Pixi shell rebuilds the same 24×24 vector paths through Pixi's SVG
2306
2323
  // parser (GraphicsContext.svg) and scales them to the requested pixel size — same shapes,
2307
2324
  // crisp at any scale. Recolour rebuilds the geometry with the colour substituted for
2308
2325
  // `currentColor` (recolour happens only on hover/active, so this is cheap).
2309
2326
  const VIEWBOX = 24;
2310
- // Cache parsed contexts by `name|fill|ring|width` — many icons repeat across the bar at the same colour.
2327
+ // Cache parsed contexts by `name|fill` — many icons repeat across the bar at the same colour.
2311
2328
  const cache = new Map();
2312
- function context(name, color, ring, ringWidth = 4) {
2313
- const key = `${name}|${color}|${ring ?? ''}|${ring ? ringWidth : 0}`;
2329
+ function context(name, color) {
2330
+ const key = `${name}|${color}`;
2314
2331
  let ctx = cache.get(key);
2315
2332
  if (!ctx) {
2316
- if (ring) {
2317
- // Two-pass layering: stroke context first (under), then fill on top.
2318
- // Only the outer half of the stroke shows — the paint-order:stroke CSS equivalent.
2319
- ctx = new pixi_js.GraphicsContext()
2320
- .svg(iconStrokeSVG(name, ring, ringWidth))
2321
- .svg(iconSVG(name, color));
2322
- }
2323
- else {
2324
- ctx = new pixi_js.GraphicsContext().svg(iconSVG(name, color));
2325
- }
2333
+ ctx = new pixi_js.GraphicsContext().svg(iconSVG(name, color));
2326
2334
  cache.set(key, ctx);
2327
2335
  }
2328
2336
  return ctx;
2329
2337
  }
2330
2338
  /** A recolourable, scalable icon. Its content is centred on the local origin's box so the view's
2331
- * bounds are `size × size` and `rotation` spins around the glyph centre (like CSS 50% 50%).
2332
- *
2333
- * Optional `ring` and `ringWidth` enable the outer-ring treatment (fill-on-top-of-stroke): the
2334
- * stroke is drawn first (underneath), then the fill path is drawn on top — only the outer half
2335
- * of the stroke is visible, mirroring the DOM `paint-order:stroke` technique. */
2339
+ * bounds are `size × size` and `rotation` spins around the glyph centre (like CSS 50% 50%). */
2336
2340
  class IconView extends pixi_js.Container {
2337
2341
  gfx;
2338
2342
  _size;
2339
2343
  _color;
2340
- _ring;
2341
- _ringWidth;
2342
2344
  iconName;
2343
- constructor(name, size, color = '#ffffff', ring, ringWidth = 4) {
2345
+ constructor(name, size, color = '#ffffff') {
2344
2346
  super();
2345
2347
  this.iconName = name;
2346
2348
  this._size = size;
2347
2349
  this._color = color;
2348
- this._ring = ring;
2349
- this._ringWidth = ringWidth;
2350
- this.gfx = new pixi_js.Graphics(context(name, color, ring, ringWidth));
2350
+ this.gfx = new pixi_js.Graphics(context(name, color));
2351
2351
  this.addChild(this.gfx);
2352
2352
  this.layout();
2353
2353
  }
@@ -2361,20 +2361,11 @@ class IconView extends pixi_js.Container {
2361
2361
  return this._size;
2362
2362
  }
2363
2363
  setColor(color) {
2364
- if (color === this._color && !this._ring)
2364
+ if (color === this._color)
2365
2365
  return;
2366
2366
  this._color = color;
2367
- this._ring = undefined;
2368
2367
  this.gfx.context = context(this.iconName, color);
2369
2368
  }
2370
- /** Update fill colour and ring colour simultaneously (ring is preserved if provided). */
2371
- setColors(fill, ring) {
2372
- if (fill === this._color && ring === this._ring)
2373
- return;
2374
- this._color = fill;
2375
- this._ring = ring;
2376
- this.gfx.context = context(this.iconName, fill, ring, this._ringWidth);
2377
- }
2378
2369
  setSize(size) {
2379
2370
  if (size === this._size)
2380
2371
  return;
@@ -2401,11 +2392,6 @@ class IconView extends pixi_js.Container {
2401
2392
  function makeIcon(name, size, color = '#ffffff') {
2402
2393
  return new IconView(name, size, color);
2403
2394
  }
2404
- /** Create a ringed icon — glyph filled with `fill`, outer ring coloured `ring` (width `ringWidth`).
2405
- * Uses the two-pass stroke-under-fill technique to show only the outer half of the stroke. */
2406
- function makeRingedIcon(name, size, fill, ring, ringWidth = 4) {
2407
- return new IconView(name, size, fill, ring, ringWidth);
2408
- }
2409
2395
 
2410
2396
  // Shared interactive primitives, ported from the DOM shell's CSS rules. Each widget reproduces
2411
2397
  // one CSS class (.ge-iconbtn, .ge-rd, .ge-shell-spin, .ge-shell-buybonus, .ge-chip, .ge-slider …)
@@ -2676,6 +2662,34 @@ function drawGlow(glow, size, accent, on) {
2676
2662
  const r = size / 2;
2677
2663
  glow.circle(r, r, r + 6).fill({ color: accent, alpha: 0.7 }); // blurred by the glow's filter → halo
2678
2664
  }
2665
+ // Each buy-bonus coin variant (default/social/disabled) is parsed once from its shared SVG art
2666
+ // (same vectors as the DOM shell), keyed by the art string.
2667
+ const _coinCache = new Map();
2668
+ function coinData(art) {
2669
+ let d = _coinCache.get(art);
2670
+ if (!d) {
2671
+ const m = art.match(/viewBox="([-\d.]+) ([-\d.]+) ([-\d.]+) ([-\d.]+)"/);
2672
+ d = {
2673
+ ctx: new pixi_js.GraphicsContext().svg(art),
2674
+ vb: m ? { x: +m[1], y: +m[2], w: +m[3], h: +m[4] } : { x: 0, y: 0, w: 24, h: 24 },
2675
+ };
2676
+ _coinCache.set(art, d);
2677
+ }
2678
+ return d;
2679
+ }
2680
+ /** A Container holding the coin `art` scaled to fit `size`, pivoted on its centre so it can pulse. */
2681
+ function buildCoin(size, art) {
2682
+ const { ctx, vb } = coinData(art);
2683
+ const wrap = new pixi_js.Container();
2684
+ const g = new pixi_js.Graphics(ctx);
2685
+ const s = size / Math.max(vb.w, vb.h);
2686
+ g.scale.set(s);
2687
+ g.position.set(-vb.x * s + (size - vb.w * s) / 2, -vb.y * s + (size - vb.h * s) / 2);
2688
+ wrap.addChild(g);
2689
+ wrap.pivot.set(size / 2, size / 2);
2690
+ wrap.position.set(size / 2, size / 2);
2691
+ return wrap;
2692
+ }
2679
2693
  class SpinDisc extends pixi_js.Container {
2680
2694
  size;
2681
2695
  glyphSize;
@@ -2733,8 +2747,9 @@ class SpinDisc extends pixi_js.Container {
2733
2747
  drawDisc(this.disc, this.size, this.tokens.btn, 4);
2734
2748
  const glyphColor = hot ? this.tokens.accent : this.tokens.btnInk;
2735
2749
  this.glyph.setColor(glyphColor);
2750
+ // the count sits ON the solid (btnInk) STOP square, so it must be light to read
2736
2751
  if (this.countText)
2737
- this.countText.style.fill = hot ? this.tokens.accent : this.tokens.btnInk;
2752
+ this.countText.style.fill = '#ffffff';
2738
2753
  // Disabled (mid-spin / can't spin): darken OPAQUELY (≈ filter:grayscale(.4) brightness(.62))
2739
2754
  // with a dark veil over the disc — not alpha, which would let the bright board show through and
2740
2755
  // read as a translucent/missing button (what looked "transparent" while spinning).
@@ -2752,7 +2767,7 @@ class SpinDisc extends pixi_js.Container {
2752
2767
  this.glyph.visible = false;
2753
2768
  this.stopGlyph();
2754
2769
  if (!this.countText) {
2755
- this.countText = makeText('', { size: 22, weight: '800', color: this.tokens.btnInk, align: 'center', family: NUM_FONT_FAMILY });
2770
+ this.countText = makeText('', { size: 22, weight: '800', color: '#ffffff', align: 'center', family: NUM_FONT_FAMILY });
2756
2771
  this.addChild(this.countText); // added after the STOP glyph → renders on top of it
2757
2772
  }
2758
2773
  const label = Number.isFinite(remaining) ? String(remaining) : '∞';
@@ -2833,7 +2848,9 @@ class BuyBonusBadge extends pixi_js.Container {
2833
2848
  disc;
2834
2849
  labelText;
2835
2850
  iconView;
2836
- content; // labelText or iconView — the pulsed node
2851
+ content; // labelText / iconView / coin — the pulsed node
2852
+ isCoin = false;
2853
+ dim; // disabled veil over the coin (no filter → crisp, mirrors the spin disc)
2837
2854
  bg;
2838
2855
  fg;
2839
2856
  border;
@@ -2850,7 +2867,14 @@ class BuyBonusBadge extends pixi_js.Container {
2850
2867
  this.ticker = opts.ticker;
2851
2868
  this.disc = new pixi_js.Graphics();
2852
2869
  this.addChild(this.glow, this.disc);
2853
- if (opts.icon) {
2870
+ if (opts.coinArt) {
2871
+ this.isCoin = true;
2872
+ const coin = buildCoin(this.size, opts.coinArt);
2873
+ this.content = coin;
2874
+ this.dim = new pixi_js.Graphics();
2875
+ this.addChild(coin, this.dim); // veil on top for the disabled state
2876
+ }
2877
+ else if (opts.icon) {
2854
2878
  const gs = opts.iconSize ?? this.size * 0.62;
2855
2879
  this.iconView = makeIcon(opts.icon, gs, opts.iconColor ?? '#0b0e16');
2856
2880
  this.iconView.pivot.set(gs / 2, gs / 2); // pulse/scale around the glyph centre
@@ -2883,12 +2907,23 @@ class BuyBonusBadge extends pixi_js.Container {
2883
2907
  });
2884
2908
  }
2885
2909
  paint(hovering) {
2886
- // disabled → grayscale(.5) brightness(.72) baked into the fill/label (no filter → crisp)
2887
- drawDisc(this.disc, this.size, this._disabled ? dimColor(this.bg) : this.bg, this.border);
2888
- if (this.labelText)
2889
- this.labelText.style.fill = this._disabled ? dimColor(this.fg) : this.fg;
2910
+ if (this.isCoin) {
2911
+ // no accent disc the coin IS the button. disabled → dark veil (crisp, no filter).
2912
+ if (this.dim) {
2913
+ this.dim.clear();
2914
+ if (this._disabled)
2915
+ this.dim.circle(this.size / 2, this.size / 2, this.size / 2).fill({ color: 0x000000, alpha: 0.5 });
2916
+ }
2917
+ }
2918
+ else {
2919
+ // disabled → grayscale(.5) brightness(.72) baked into the fill/label (no filter → crisp)
2920
+ drawDisc(this.disc, this.size, this._disabled ? dimColor(this.bg) : this.bg, this.border);
2921
+ if (this.labelText)
2922
+ this.labelText.style.fill = this._disabled ? dimColor(this.fg) : this.fg;
2923
+ }
2890
2924
  const on = hovering && !this._disabled;
2891
- drawGlow(this.glow, this.size, this.bg, on); // soft accent glow only (no ring) `.ge-shell-buybonus:hover`
2925
+ // the coin carries its own gold look no accent halo (mirrors `.ge-bb-coin:hover`)
2926
+ drawGlow(this.glow, this.size, this.bg, this.isCoin ? false : on);
2892
2927
  if (on)
2893
2928
  this.startPulse();
2894
2929
  else
@@ -3000,77 +3035,33 @@ const BAR_REF_W = 840; // zoom reference width
3000
3035
  const BAR_MIN_SCALE = 0.5;
3001
3036
  const WIDE_PAD_BOTTOM = 8;
3002
3037
  const WIDE_BAR_H = WIDE_PAD_BOTTOM + SPIN; // ≈92
3003
- const BUY_W = 62; // buy-bonus disc on desktop
3038
+ const BUY_W = 71; // buy-bonus coin on desktop (+15% over the old 62 disc)
3004
3039
  const DISC = 38; // white-disc icon button box (auto/turbo)
3005
3040
  const FS_BOX = 90; // fixed bet-value box width
3006
3041
  // mobile
3007
3042
  const M_CTRL_H = 62, M_INFO_H = 40, M_GAP = 10, M_PAD_BOTTOM = 8, M_SIDE = 10;
3008
- const M_BUY = 50;
3043
+ const M_BUY = 58; // mobile buy-bonus coin (+15%)
3009
3044
  const MOBILE_BAR_H = M_PAD_BOTTOM + SPIN + M_GAP + M_INFO_H; // spin pops above the controls
3010
- /** Three-state turbo button: single `turbo1` bolt on a white disc, with fill+ring treatment
3011
- * matching the DOM redesign. Level is conveyed by fill colour + ring colour (not glyph swap):
3012
- * - off (0): bolt fill #fff + BLACK ring, container alpha .5
3013
- * - L1: bolt fill #fff + ACCENT ring, alpha 1
3014
- * - L≥2: bolt fill ACCENT + ACCENT ring, alpha 1
3015
- * Hover at any level: bolt fill+ring → accent, disc border → accent (standard bar-button hover). */
3016
- class TurboButton extends pixi_js.Container {
3017
- box;
3018
- view;
3019
- discG;
3020
- discBorder;
3021
- level;
3022
- accent;
3023
- constructor(opts) {
3024
- super();
3025
- this.box = opts.size;
3026
- this.accent = opts.accent;
3027
- this.level = opts.level;
3028
- this.discBorder = opts.discBorder ?? 2;
3029
- this.discG = new pixi_js.Graphics();
3030
- this.addChild(this.discG);
3031
- const { fill, ring } = this._colors(false);
3032
- this.view = makeRingedIcon('turbo1', opts.glyph, fill, ring);
3033
- this.view.position.set((this.box - opts.glyph) / 2, (this.box - opts.glyph) / 2);
3034
- this.addChild(this.view);
3035
- // off is no longer dimmed — it reads as off via the black ring (DOM dropped the opacity:.5 rule)
3036
- this.eventMode = 'static';
3037
- this.cursor = 'pointer';
3038
- this.hitArea = new pixi_js.Rectangle(0, 0, this.box, this.box);
3039
- this._paint(false);
3040
- attachHover(this, () => this._paint(true), () => this._paint(false));
3041
- attachPress(this, 0.92, () => opts.onTap());
3042
- }
3043
- _colors(hovering) {
3044
- if (hovering)
3045
- return { fill: this.accent, ring: this.accent };
3046
- if (this.level === 0)
3047
- return { fill: '#ffffff', ring: '#000000' };
3048
- if (this.level === 1)
3049
- return { fill: '#ffffff', ring: this.accent };
3050
- return { fill: this.accent, ring: this.accent };
3051
- }
3052
- _paint(hovering) {
3053
- const { fill, ring } = this._colors(hovering);
3054
- this.view.setColors(fill, ring);
3055
- const r = this.box / 2 - this.discBorder / 2;
3056
- this.discG.clear();
3057
- this.discG.circle(this.box / 2, this.box / 2, r).fill('#ffffff');
3058
- // border lights accent on hover OR when engaged (level>0) — mirrors DOM .ge-iconbtn.ge-active
3059
- const ringActive = hovering || this.level > 0;
3060
- this.discG.stroke({ color: ringActive ? this.accent : '#000000', width: this.discBorder });
3061
- }
3062
- /** Update turbo level and repaint (called when the shell re-renders the bar). */
3063
- setLevel(level, accent) {
3064
- this.level = level;
3065
- this.accent = accent;
3066
- this._paint(false);
3067
- }
3068
- measureSize() {
3069
- return { w: this.box, h: this.box };
3070
- }
3071
- setLayoutSize() {
3072
- /* fixed */
3073
- }
3045
+ /** Three-state turbo glyph: the level is shown by SWAPPING the glyph (off → single bolt `turboOff`,
3046
+ * L1 single bolt `turbo1`, L≥2 bolt-with-speed-lines `turbo2`). off = svg turbo-off grey (#ccc),
3047
+ * engaged/hover = accent. On desktop it sits on the white disc (like auto); mobile is disc-less. */
3048
+ function turboGlyph(level) {
3049
+ if (level <= 0)
3050
+ return 'turboOff';
3051
+ return level >= 2 ? 'turbo2' : 'turbo1';
3052
+ }
3053
+ function makeTurboButton(host, level, onTap, size = DISC, glyph = 19, disc = false) {
3054
+ const { tokens } = host;
3055
+ return new IconButton(turboGlyph(level), {
3056
+ size,
3057
+ glyph,
3058
+ ...(disc ? { disc: tokens.btn, discBorder: 2 } : {}),
3059
+ color: '#cccccc', // svg turbo-off grey (off); engaged/hover switch to accent
3060
+ hover: tokens.accent,
3061
+ activeColor: tokens.accent,
3062
+ active: level > 0,
3063
+ onTap,
3064
+ });
3074
3065
  }
3075
3066
  /** A readout in the bar (white Oswald value, plaque-label caption, no shadow). */
3076
3067
  function readout(host, label, value, opts = {}) {
@@ -3239,15 +3230,7 @@ class BottomBar extends pixi_js.Container {
3239
3230
  }));
3240
3231
  }
3241
3232
  if (config.features.turbo > 0) {
3242
- this.turboBtn = new TurboButton({
3243
- size: DISC,
3244
- glyph: 19,
3245
- discFill: tokens.btn,
3246
- discBorder: 2,
3247
- accent: tokens.accent,
3248
- level: state.turbo,
3249
- onTap: () => this.onTurbo(),
3250
- });
3233
+ this.turboBtn = makeTurboButton(this.host, state.turbo, () => this.onTurbo(), DISC, 19, true);
3251
3234
  spinWrap.add(this.turboBtn);
3252
3235
  }
3253
3236
  const right = new FlexBox({ direction: 'row', align: 'center', gap: ZONE_GAP });
@@ -3263,14 +3246,13 @@ class BottomBar extends pixi_js.Container {
3263
3246
  return null;
3264
3247
  const feature = state.activeFeature;
3265
3248
  if (feature) {
3266
- const accent = effectiveAccent(feature);
3249
+ // a feature is active → the coin becomes the "deactivate" variant
3267
3250
  return new BuyBonusBadge({
3268
3251
  size,
3269
- fontSize,
3270
3252
  border,
3271
- bg: accent,
3272
- fg: contrastText(accent),
3273
- label: this.host.t('DISABLE'),
3253
+ bg: effectiveAccent(feature),
3254
+ coinArt: BUY_BONUS_DISABLED_ART,
3255
+ label: '',
3274
3256
  tokens,
3275
3257
  ticker: this.host.ticker,
3276
3258
  onTap: () => this.host.actions.deactivateFeature(),
@@ -3280,9 +3262,7 @@ class BottomBar extends pixi_js.Container {
3280
3262
  size,
3281
3263
  border,
3282
3264
  bg: tokens.accent,
3283
- icon: 'ticket',
3284
- iconSize: size * 0.55,
3285
- iconColor: tokens.btnInk,
3265
+ coinArt: config.isSocial ? BUY_BONUS_SOCIAL_ART : BUY_BONUS_ART,
3286
3266
  label: '',
3287
3267
  tokens,
3288
3268
  ticker: this.host.ticker,
@@ -3345,15 +3325,7 @@ class BottomBar extends pixi_js.Container {
3345
3325
  this.autoBtn.setGlow(true);
3346
3326
  }
3347
3327
  if (config.features.turbo > 0) {
3348
- this.turboBtn = new TurboButton({
3349
- size: 40,
3350
- glyph: 22,
3351
- discFill: tokens.btn,
3352
- discBorder: 2,
3353
- accent: tokens.accent,
3354
- level: state.turbo,
3355
- onTap: () => this.onTurbo(),
3356
- });
3328
+ this.turboBtn = makeTurboButton(this.host, state.turbo, () => this.onTurbo(), 40, 22);
3357
3329
  }
3358
3330
  const buy = isBase ? (this.buildBuy(M_BUY, 9, 2) ?? undefined) : undefined;
3359
3331
  // level 1 — controls bar (dark)
@@ -3578,7 +3550,11 @@ class BottomBar extends pixi_js.Container {
3578
3550
  left.position.set(panelX + PANEL_PAD, panelCenterY - left.outerHeight / 2);
3579
3551
  right.position.set(panelRight - PANEL_PAD - right.outerWidth, panelCenterY - right.outerHeight / 2);
3580
3552
  this.inner.scale.set(s);
3581
- this.inner.position.set((W - barW * s) / 2, H - WIDE_PAD_BOTTOM - SPIN * s);
3553
+ // Scale the bottom gap WITH the bar (…* s), not a flat 8px. On a small/short popout the bar is
3554
+ // fit-scaled down but a constant 8px gap would look like too much air — so the bar floated off the
3555
+ // bottom edge. Scaling matches the HTML shell, whose whole barhost scales from transform-origin
3556
+ // bottom center (gap → 8·s). Desktop (s≈1) is unchanged.
3557
+ this.inner.position.set((W - barW * s) / 2, H - (WIDE_PAD_BOTTOM + SPIN) * s);
3582
3558
  this.measureFootprint();
3583
3559
  }
3584
3560
  applyFitMobile() {
@@ -4312,11 +4288,10 @@ function sectionControls(host, title, width) {
4312
4288
  const box = new pixi_js.Container();
4313
4289
  const badge = new BuyBonusBadge({
4314
4290
  size: 46,
4315
- fontSize: 8,
4316
4291
  border: 2,
4317
4292
  bg: host.tokens.accent,
4318
- fg: '#ffffff',
4319
- label: host.t('BUY BONUS').split(/\s+/).join('\n'),
4293
+ coinArt: host.config.isSocial ? BUY_BONUS_SOCIAL_ART : BUY_BONUS_ART,
4294
+ label: '',
4320
4295
  tokens: host.tokens,
4321
4296
  ticker: host.ticker,
4322
4297
  onTap: () => { },
@@ -5368,11 +5343,11 @@ function volatilityRow(_host, level, accent, size) {
5368
5343
  const n = Math.max(0, Math.min(5, level));
5369
5344
  let x = 0;
5370
5345
  for (let i = 0; i < 5; i++) {
5371
- // active = solid accent bolt; inactive = solid black bolt, dimmed (fill==ring, 1px hairline ring
5372
- // per the DOM: .ge-bonus-vol svg path { stroke-width:1; fill/stroke = accent (on) / #000 (off) })
5346
+ // active = solid accent bolt; inactive = solid black bolt, dimmed
5347
+ // (DOM: .ge-bonus-vol svg path fill = accent (on) / #000 (off))
5373
5348
  const active = i < n;
5374
5349
  const col = active ? accent : '#000000';
5375
- const bolt = makeRingedIcon('turbo1', size, col, col, 1);
5350
+ const bolt = makeIcon('turbo1', size, col);
5376
5351
  bolt.alpha = active ? 1 : 0.5;
5377
5352
  bolt.position.set(x, 0);
5378
5353
  c.addChild(bolt);