@energy8platform/shell 0.6.2 → 0.6.3

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.d.ts CHANGED
@@ -513,7 +513,7 @@ declare class ShellController extends EventEmitter<ShellEvents> implements Shell
513
513
  tokens: ShellTokens;
514
514
  layout: ShellLayoutMode;
515
515
  soundOn: boolean;
516
- readonly engineVersion = "0.6.2";
516
+ readonly engineVersion = "0.6.3";
517
517
  readonly actions: ShellActions;
518
518
  private renderer;
519
519
  private i18n;
@@ -595,7 +595,7 @@ interface I18n {
595
595
  declare function createI18n(opts: I18nOptions): I18n;
596
596
 
597
597
  /** The @energy8platform/shell package version, stamped into the game-info footer. */
598
- declare const PACKAGE_VERSION = "0.6.2";
598
+ declare const PACKAGE_VERSION = "0.6.3";
599
599
 
600
600
  /** A shell: the renderer-agnostic controller plus the surface facade (safeArea/barHeight/setVisible)
601
601
  * an embedding host reads. `createShell`, `createGameShell` and `createPixiShell` all return this. */
package/dist/pixi.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { applySocialReplacements } from '@energy8platform/game-sdk/social';
2
- import { TextStyle, Text, CanvasTextMetrics, Container, Graphics, Rectangle, GraphicsContext, BlurFilter, Color, Assets, Sprite, RenderTexture, ColorMatrixFilter } from 'pixi.js';
2
+ import { TextStyle, Text, CanvasTextMetrics, Container, Graphics, Rectangle, GraphicsContextSystem, GraphicsContext, BlurFilter, Color, Assets, Sprite, RenderTexture, ColorMatrixFilter } from 'pixi.js';
3
3
 
4
4
  /**
5
5
  * Minimal typed event emitter — internal utility for platform-core.
@@ -1447,7 +1447,7 @@ class KeyboardController {
1447
1447
 
1448
1448
  // AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
1449
1449
  /** The @energy8platform/shell package version, stamped into the game-info footer. */
1450
- const PACKAGE_VERSION = '0.6.2';
1450
+ const PACKAGE_VERSION = '0.6.3';
1451
1451
 
1452
1452
  /** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
1453
1453
  function resolveConfig(config) {
@@ -2004,6 +2004,14 @@ function countUpText(ticker, text, from, to, fmt, durationMs = 450) {
2004
2004
  });
2005
2005
  }
2006
2006
 
2007
+ // AUTO-GENERATED from ../../icons.svg by scripts/gen-buy-bonus.mjs — do not edit by hand.
2008
+ // The full-colour buy-bonus coins (default / social / deactivate), shared by the DOM shell
2009
+ // (inline <svg>) and the Pixi shell (GraphicsContext.svg). To refresh: edit icons.svg, then
2010
+ // `node scripts/gen-buy-bonus.mjs`.
2011
+ 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>`;
2012
+ 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>`;
2013
+ 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>`;
2014
+
2007
2015
  function isSizable(n) {
2008
2016
  return !!n && typeof n.measureSize === 'function' && typeof n.setLayoutSize === 'function';
2009
2017
  }
@@ -2263,89 +2271,74 @@ function roundedPath(g, x, y, w, h, [tl, tr, br, bl]) {
2263
2271
  g.closePath();
2264
2272
  }
2265
2273
 
2266
- // AUTO-GENERATED from ./icons-preview.svg by scripts/gen-icons.mjs — do not edit by hand.
2274
+ // AUTO-GENERATED from ../../icons.svg by scripts/gen-icons-from-svg.mjs — do not edit by hand.
2267
2275
  // Sharp monochrome icon set: each glyph is a 24×24 viewBox fragment using currentColor
2268
- // (hollow shapes use fill-rule="evenodd"; the few stroked glyphs use stroke="currentColor").
2269
- // Coordinates are baked into the 24×24 space (no <g transform>), so the same fragment renders
2270
- // identically in the DOM <svg> and in Pixi's GraphicsContext.svg.
2271
- // To change an icon: edit icons-preview.svg, then run `node scripts/gen-icons.mjs`.
2276
+ // (hollow shapes use fill-rule="evenodd"). Coordinates are baked into the 24×24 space (no
2277
+ // <g transform>), so the same fragment renders identically in the DOM <svg> and in Pixi's
2278
+ // GraphicsContext.svg. To change an icon: edit icons.svg, then run
2279
+ // `node scripts/gen-icons-from-svg.mjs`.
2272
2280
  const SVGS = {
2273
- 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>`,
2274
- 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>`,
2275
- 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>`,
2276
- 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>`,
2277
- 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>`,
2278
- 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>`,
2279
- 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>`,
2281
+ 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>`,
2282
+ 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>`,
2283
+ 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>`,
2284
+ stop: `<g fill="currentColor" fill-rule="evenodd"><rect x="1.6" y="1.6" width="20.8" height="20.8" rx="2.9"/></g>`,
2285
+ 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>`,
2286
+ minus: `<g fill="currentColor" fill-rule="evenodd"><rect x="1.6" y="9.86" width="20.8" height="4.28" rx="2.11"/></g>`,
2287
+ 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>`,
2280
2288
  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)"/>`,
2281
- 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>`,
2282
- 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>`,
2283
- 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>`,
2284
- 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>`,
2285
- back: `<path d="M15 6l-6 6l6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`,
2286
- chevronRight: `<path d="M9 6l6 6l-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`,
2289
+ 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>`,
2290
+ 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>`,
2291
+ 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>`,
2292
+ 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>`,
2293
+ 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>`,
2294
+ 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>`,
2287
2295
  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"/>`,
2296
+ 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>`,
2297
+ 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>`,
2298
+ 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>`,
2299
+ 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>`,
2288
2300
  };
2289
2301
  /** A standalone, parseable SVG document with `currentColor` resolved to `color`.
2290
2302
  * Used by the Pixi renderer to build vector geometry via GraphicsContext.svg(). */
2291
2303
  function iconSVG(name, color = '#ffffff') {
2292
2304
  return `<svg viewBox="0 0 24 24">${SVGS[name].split('currentColor').join(color)}</svg>`;
2293
2305
  }
2294
- /** A standalone SVG with the glyph rendered as a stroke-only outline (fill:none).
2295
- * Used to build the outer-ring effect in Pixi: draw this first (under), then iconSVG on top;
2296
- * only the outer half of the stroke is visible — the paint-order:stroke CSS equivalent. */
2297
- function iconStrokeSVG(name, stroke, width = 4) {
2298
- const frag = SVGS[name].split('fill="currentColor"').join(`fill="none" stroke="${stroke}" stroke-width="${width}" stroke-linejoin="round"`);
2299
- return `<svg viewBox="0 0 24 24">${frag}</svg>`;
2300
- }
2301
2306
 
2307
+ // Icons/coins are parsed from small-viewBox SVGs (24-unit glyphs, ~260-unit coin). Pixi's default
2308
+ // bezierSmoothness (0.5) flattens curves with a ~1-unit path-space tolerance — coarse facets at
2309
+ // that scale that magnify when the glyph is scaled to button size. Max it out (capped at 0.99) so
2310
+ // every SVG-parsed curve stays smooth. Global default; set once, before any GraphicsContext builds.
2311
+ GraphicsContextSystem.defaultOptions.bezierSmoothness = 0.99;
2302
2312
  // The DOM shell renders each icon as an inline <svg> sized to 1em and recoloured via
2303
2313
  // `currentColor`. The Pixi shell rebuilds the same 24×24 vector paths through Pixi's SVG
2304
2314
  // parser (GraphicsContext.svg) and scales them to the requested pixel size — same shapes,
2305
2315
  // crisp at any scale. Recolour rebuilds the geometry with the colour substituted for
2306
2316
  // `currentColor` (recolour happens only on hover/active, so this is cheap).
2307
2317
  const VIEWBOX = 24;
2308
- // Cache parsed contexts by `name|fill|ring|width` — many icons repeat across the bar at the same colour.
2318
+ // Cache parsed contexts by `name|fill` — many icons repeat across the bar at the same colour.
2309
2319
  const cache = new Map();
2310
- function context(name, color, ring, ringWidth = 4) {
2311
- const key = `${name}|${color}|${ring ?? ''}|${ring ? ringWidth : 0}`;
2320
+ function context(name, color) {
2321
+ const key = `${name}|${color}`;
2312
2322
  let ctx = cache.get(key);
2313
2323
  if (!ctx) {
2314
- if (ring) {
2315
- // Two-pass layering: stroke context first (under), then fill on top.
2316
- // Only the outer half of the stroke shows — the paint-order:stroke CSS equivalent.
2317
- ctx = new GraphicsContext()
2318
- .svg(iconStrokeSVG(name, ring, ringWidth))
2319
- .svg(iconSVG(name, color));
2320
- }
2321
- else {
2322
- ctx = new GraphicsContext().svg(iconSVG(name, color));
2323
- }
2324
+ ctx = new GraphicsContext().svg(iconSVG(name, color));
2324
2325
  cache.set(key, ctx);
2325
2326
  }
2326
2327
  return ctx;
2327
2328
  }
2328
2329
  /** A recolourable, scalable icon. Its content is centred on the local origin's box so the view's
2329
- * bounds are `size × size` and `rotation` spins around the glyph centre (like CSS 50% 50%).
2330
- *
2331
- * Optional `ring` and `ringWidth` enable the outer-ring treatment (fill-on-top-of-stroke): the
2332
- * stroke is drawn first (underneath), then the fill path is drawn on top — only the outer half
2333
- * of the stroke is visible, mirroring the DOM `paint-order:stroke` technique. */
2330
+ * bounds are `size × size` and `rotation` spins around the glyph centre (like CSS 50% 50%). */
2334
2331
  class IconView extends Container {
2335
2332
  gfx;
2336
2333
  _size;
2337
2334
  _color;
2338
- _ring;
2339
- _ringWidth;
2340
2335
  iconName;
2341
- constructor(name, size, color = '#ffffff', ring, ringWidth = 4) {
2336
+ constructor(name, size, color = '#ffffff') {
2342
2337
  super();
2343
2338
  this.iconName = name;
2344
2339
  this._size = size;
2345
2340
  this._color = color;
2346
- this._ring = ring;
2347
- this._ringWidth = ringWidth;
2348
- this.gfx = new Graphics(context(name, color, ring, ringWidth));
2341
+ this.gfx = new Graphics(context(name, color));
2349
2342
  this.addChild(this.gfx);
2350
2343
  this.layout();
2351
2344
  }
@@ -2359,20 +2352,11 @@ class IconView extends Container {
2359
2352
  return this._size;
2360
2353
  }
2361
2354
  setColor(color) {
2362
- if (color === this._color && !this._ring)
2355
+ if (color === this._color)
2363
2356
  return;
2364
2357
  this._color = color;
2365
- this._ring = undefined;
2366
2358
  this.gfx.context = context(this.iconName, color);
2367
2359
  }
2368
- /** Update fill colour and ring colour simultaneously (ring is preserved if provided). */
2369
- setColors(fill, ring) {
2370
- if (fill === this._color && ring === this._ring)
2371
- return;
2372
- this._color = fill;
2373
- this._ring = ring;
2374
- this.gfx.context = context(this.iconName, fill, ring, this._ringWidth);
2375
- }
2376
2360
  setSize(size) {
2377
2361
  if (size === this._size)
2378
2362
  return;
@@ -2399,11 +2383,6 @@ class IconView extends Container {
2399
2383
  function makeIcon(name, size, color = '#ffffff') {
2400
2384
  return new IconView(name, size, color);
2401
2385
  }
2402
- /** Create a ringed icon — glyph filled with `fill`, outer ring coloured `ring` (width `ringWidth`).
2403
- * Uses the two-pass stroke-under-fill technique to show only the outer half of the stroke. */
2404
- function makeRingedIcon(name, size, fill, ring, ringWidth = 4) {
2405
- return new IconView(name, size, fill, ring, ringWidth);
2406
- }
2407
2386
 
2408
2387
  // Shared interactive primitives, ported from the DOM shell's CSS rules. Each widget reproduces
2409
2388
  // one CSS class (.ge-iconbtn, .ge-rd, .ge-shell-spin, .ge-shell-buybonus, .ge-chip, .ge-slider …)
@@ -2674,6 +2653,34 @@ function drawGlow(glow, size, accent, on) {
2674
2653
  const r = size / 2;
2675
2654
  glow.circle(r, r, r + 6).fill({ color: accent, alpha: 0.7 }); // blurred by the glow's filter → halo
2676
2655
  }
2656
+ // Each buy-bonus coin variant (default/social/disabled) is parsed once from its shared SVG art
2657
+ // (same vectors as the DOM shell), keyed by the art string.
2658
+ const _coinCache = new Map();
2659
+ function coinData(art) {
2660
+ let d = _coinCache.get(art);
2661
+ if (!d) {
2662
+ const m = art.match(/viewBox="([-\d.]+) ([-\d.]+) ([-\d.]+) ([-\d.]+)"/);
2663
+ d = {
2664
+ ctx: new GraphicsContext().svg(art),
2665
+ vb: m ? { x: +m[1], y: +m[2], w: +m[3], h: +m[4] } : { x: 0, y: 0, w: 24, h: 24 },
2666
+ };
2667
+ _coinCache.set(art, d);
2668
+ }
2669
+ return d;
2670
+ }
2671
+ /** A Container holding the coin `art` scaled to fit `size`, pivoted on its centre so it can pulse. */
2672
+ function buildCoin(size, art) {
2673
+ const { ctx, vb } = coinData(art);
2674
+ const wrap = new Container();
2675
+ const g = new Graphics(ctx);
2676
+ const s = size / Math.max(vb.w, vb.h);
2677
+ g.scale.set(s);
2678
+ g.position.set(-vb.x * s + (size - vb.w * s) / 2, -vb.y * s + (size - vb.h * s) / 2);
2679
+ wrap.addChild(g);
2680
+ wrap.pivot.set(size / 2, size / 2);
2681
+ wrap.position.set(size / 2, size / 2);
2682
+ return wrap;
2683
+ }
2677
2684
  class SpinDisc extends Container {
2678
2685
  size;
2679
2686
  glyphSize;
@@ -2731,8 +2738,9 @@ class SpinDisc extends Container {
2731
2738
  drawDisc(this.disc, this.size, this.tokens.btn, 4);
2732
2739
  const glyphColor = hot ? this.tokens.accent : this.tokens.btnInk;
2733
2740
  this.glyph.setColor(glyphColor);
2741
+ // the count sits ON the solid (btnInk) STOP square, so it must be light to read
2734
2742
  if (this.countText)
2735
- this.countText.style.fill = hot ? this.tokens.accent : this.tokens.btnInk;
2743
+ this.countText.style.fill = '#ffffff';
2736
2744
  // Disabled (mid-spin / can't spin): darken OPAQUELY (≈ filter:grayscale(.4) brightness(.62))
2737
2745
  // with a dark veil over the disc — not alpha, which would let the bright board show through and
2738
2746
  // read as a translucent/missing button (what looked "transparent" while spinning).
@@ -2750,7 +2758,7 @@ class SpinDisc extends Container {
2750
2758
  this.glyph.visible = false;
2751
2759
  this.stopGlyph();
2752
2760
  if (!this.countText) {
2753
- this.countText = makeText('', { size: 22, weight: '800', color: this.tokens.btnInk, align: 'center', family: NUM_FONT_FAMILY });
2761
+ this.countText = makeText('', { size: 22, weight: '800', color: '#ffffff', align: 'center', family: NUM_FONT_FAMILY });
2754
2762
  this.addChild(this.countText); // added after the STOP glyph → renders on top of it
2755
2763
  }
2756
2764
  const label = Number.isFinite(remaining) ? String(remaining) : '∞';
@@ -2831,7 +2839,9 @@ class BuyBonusBadge extends Container {
2831
2839
  disc;
2832
2840
  labelText;
2833
2841
  iconView;
2834
- content; // labelText or iconView — the pulsed node
2842
+ content; // labelText / iconView / coin — the pulsed node
2843
+ isCoin = false;
2844
+ dim; // disabled veil over the coin (no filter → crisp, mirrors the spin disc)
2835
2845
  bg;
2836
2846
  fg;
2837
2847
  border;
@@ -2848,7 +2858,14 @@ class BuyBonusBadge extends Container {
2848
2858
  this.ticker = opts.ticker;
2849
2859
  this.disc = new Graphics();
2850
2860
  this.addChild(this.glow, this.disc);
2851
- if (opts.icon) {
2861
+ if (opts.coinArt) {
2862
+ this.isCoin = true;
2863
+ const coin = buildCoin(this.size, opts.coinArt);
2864
+ this.content = coin;
2865
+ this.dim = new Graphics();
2866
+ this.addChild(coin, this.dim); // veil on top for the disabled state
2867
+ }
2868
+ else if (opts.icon) {
2852
2869
  const gs = opts.iconSize ?? this.size * 0.62;
2853
2870
  this.iconView = makeIcon(opts.icon, gs, opts.iconColor ?? '#0b0e16');
2854
2871
  this.iconView.pivot.set(gs / 2, gs / 2); // pulse/scale around the glyph centre
@@ -2881,12 +2898,23 @@ class BuyBonusBadge extends Container {
2881
2898
  });
2882
2899
  }
2883
2900
  paint(hovering) {
2884
- // disabled → grayscale(.5) brightness(.72) baked into the fill/label (no filter → crisp)
2885
- drawDisc(this.disc, this.size, this._disabled ? dimColor(this.bg) : this.bg, this.border);
2886
- if (this.labelText)
2887
- this.labelText.style.fill = this._disabled ? dimColor(this.fg) : this.fg;
2901
+ if (this.isCoin) {
2902
+ // no accent disc the coin IS the button. disabled → dark veil (crisp, no filter).
2903
+ if (this.dim) {
2904
+ this.dim.clear();
2905
+ if (this._disabled)
2906
+ this.dim.circle(this.size / 2, this.size / 2, this.size / 2).fill({ color: 0x000000, alpha: 0.5 });
2907
+ }
2908
+ }
2909
+ else {
2910
+ // disabled → grayscale(.5) brightness(.72) baked into the fill/label (no filter → crisp)
2911
+ drawDisc(this.disc, this.size, this._disabled ? dimColor(this.bg) : this.bg, this.border);
2912
+ if (this.labelText)
2913
+ this.labelText.style.fill = this._disabled ? dimColor(this.fg) : this.fg;
2914
+ }
2888
2915
  const on = hovering && !this._disabled;
2889
- drawGlow(this.glow, this.size, this.bg, on); // soft accent glow only (no ring) `.ge-shell-buybonus:hover`
2916
+ // the coin carries its own gold look no accent halo (mirrors `.ge-bb-coin:hover`)
2917
+ drawGlow(this.glow, this.size, this.bg, this.isCoin ? false : on);
2890
2918
  if (on)
2891
2919
  this.startPulse();
2892
2920
  else
@@ -2998,77 +3026,33 @@ const BAR_REF_W = 840; // zoom reference width
2998
3026
  const BAR_MIN_SCALE = 0.5;
2999
3027
  const WIDE_PAD_BOTTOM = 8;
3000
3028
  const WIDE_BAR_H = WIDE_PAD_BOTTOM + SPIN; // ≈92
3001
- const BUY_W = 62; // buy-bonus disc on desktop
3029
+ const BUY_W = 71; // buy-bonus coin on desktop (+15% over the old 62 disc)
3002
3030
  const DISC = 38; // white-disc icon button box (auto/turbo)
3003
3031
  const FS_BOX = 90; // fixed bet-value box width
3004
3032
  // mobile
3005
3033
  const M_CTRL_H = 62, M_INFO_H = 40, M_GAP = 10, M_PAD_BOTTOM = 8, M_SIDE = 10;
3006
- const M_BUY = 50;
3034
+ const M_BUY = 58; // mobile buy-bonus coin (+15%)
3007
3035
  const MOBILE_BAR_H = M_PAD_BOTTOM + SPIN + M_GAP + M_INFO_H; // spin pops above the controls
3008
- /** Three-state turbo button: single `turbo1` bolt on a white disc, with fill+ring treatment
3009
- * matching the DOM redesign. Level is conveyed by fill colour + ring colour (not glyph swap):
3010
- * - off (0): bolt fill #fff + BLACK ring, container alpha .5
3011
- * - L1: bolt fill #fff + ACCENT ring, alpha 1
3012
- * - L≥2: bolt fill ACCENT + ACCENT ring, alpha 1
3013
- * Hover at any level: bolt fill+ring → accent, disc border → accent (standard bar-button hover). */
3014
- class TurboButton extends Container {
3015
- box;
3016
- view;
3017
- discG;
3018
- discBorder;
3019
- level;
3020
- accent;
3021
- constructor(opts) {
3022
- super();
3023
- this.box = opts.size;
3024
- this.accent = opts.accent;
3025
- this.level = opts.level;
3026
- this.discBorder = opts.discBorder ?? 2;
3027
- this.discG = new Graphics();
3028
- this.addChild(this.discG);
3029
- const { fill, ring } = this._colors(false);
3030
- this.view = makeRingedIcon('turbo1', opts.glyph, fill, ring);
3031
- this.view.position.set((this.box - opts.glyph) / 2, (this.box - opts.glyph) / 2);
3032
- this.addChild(this.view);
3033
- // off is no longer dimmed — it reads as off via the black ring (DOM dropped the opacity:.5 rule)
3034
- this.eventMode = 'static';
3035
- this.cursor = 'pointer';
3036
- this.hitArea = new Rectangle(0, 0, this.box, this.box);
3037
- this._paint(false);
3038
- attachHover(this, () => this._paint(true), () => this._paint(false));
3039
- attachPress(this, 0.92, () => opts.onTap());
3040
- }
3041
- _colors(hovering) {
3042
- if (hovering)
3043
- return { fill: this.accent, ring: this.accent };
3044
- if (this.level === 0)
3045
- return { fill: '#ffffff', ring: '#000000' };
3046
- if (this.level === 1)
3047
- return { fill: '#ffffff', ring: this.accent };
3048
- return { fill: this.accent, ring: this.accent };
3049
- }
3050
- _paint(hovering) {
3051
- const { fill, ring } = this._colors(hovering);
3052
- this.view.setColors(fill, ring);
3053
- const r = this.box / 2 - this.discBorder / 2;
3054
- this.discG.clear();
3055
- this.discG.circle(this.box / 2, this.box / 2, r).fill('#ffffff');
3056
- // border lights accent on hover OR when engaged (level>0) — mirrors DOM .ge-iconbtn.ge-active
3057
- const ringActive = hovering || this.level > 0;
3058
- this.discG.stroke({ color: ringActive ? this.accent : '#000000', width: this.discBorder });
3059
- }
3060
- /** Update turbo level and repaint (called when the shell re-renders the bar). */
3061
- setLevel(level, accent) {
3062
- this.level = level;
3063
- this.accent = accent;
3064
- this._paint(false);
3065
- }
3066
- measureSize() {
3067
- return { w: this.box, h: this.box };
3068
- }
3069
- setLayoutSize() {
3070
- /* fixed */
3071
- }
3036
+ /** Three-state turbo glyph: the level is shown by SWAPPING the glyph (off → single bolt `turboOff`,
3037
+ * L1 single bolt `turbo1`, L≥2 bolt-with-speed-lines `turbo2`). off = svg turbo-off grey (#ccc),
3038
+ * engaged/hover = accent. On desktop it sits on the white disc (like auto); mobile is disc-less. */
3039
+ function turboGlyph(level) {
3040
+ if (level <= 0)
3041
+ return 'turboOff';
3042
+ return level >= 2 ? 'turbo2' : 'turbo1';
3043
+ }
3044
+ function makeTurboButton(host, level, onTap, size = DISC, glyph = 19, disc = false) {
3045
+ const { tokens } = host;
3046
+ return new IconButton(turboGlyph(level), {
3047
+ size,
3048
+ glyph,
3049
+ ...(disc ? { disc: tokens.btn, discBorder: 2 } : {}),
3050
+ color: '#cccccc', // svg turbo-off grey (off); engaged/hover switch to accent
3051
+ hover: tokens.accent,
3052
+ activeColor: tokens.accent,
3053
+ active: level > 0,
3054
+ onTap,
3055
+ });
3072
3056
  }
3073
3057
  /** A readout in the bar (white Oswald value, plaque-label caption, no shadow). */
3074
3058
  function readout(host, label, value, opts = {}) {
@@ -3237,15 +3221,7 @@ class BottomBar extends Container {
3237
3221
  }));
3238
3222
  }
3239
3223
  if (config.features.turbo > 0) {
3240
- this.turboBtn = new TurboButton({
3241
- size: DISC,
3242
- glyph: 19,
3243
- discFill: tokens.btn,
3244
- discBorder: 2,
3245
- accent: tokens.accent,
3246
- level: state.turbo,
3247
- onTap: () => this.onTurbo(),
3248
- });
3224
+ this.turboBtn = makeTurboButton(this.host, state.turbo, () => this.onTurbo(), DISC, 19, true);
3249
3225
  spinWrap.add(this.turboBtn);
3250
3226
  }
3251
3227
  const right = new FlexBox({ direction: 'row', align: 'center', gap: ZONE_GAP });
@@ -3261,14 +3237,13 @@ class BottomBar extends Container {
3261
3237
  return null;
3262
3238
  const feature = state.activeFeature;
3263
3239
  if (feature) {
3264
- const accent = effectiveAccent(feature);
3240
+ // a feature is active → the coin becomes the "deactivate" variant
3265
3241
  return new BuyBonusBadge({
3266
3242
  size,
3267
- fontSize,
3268
3243
  border,
3269
- bg: accent,
3270
- fg: contrastText(accent),
3271
- label: this.host.t('DISABLE'),
3244
+ bg: effectiveAccent(feature),
3245
+ coinArt: BUY_BONUS_DISABLED_ART,
3246
+ label: '',
3272
3247
  tokens,
3273
3248
  ticker: this.host.ticker,
3274
3249
  onTap: () => this.host.actions.deactivateFeature(),
@@ -3278,9 +3253,7 @@ class BottomBar extends Container {
3278
3253
  size,
3279
3254
  border,
3280
3255
  bg: tokens.accent,
3281
- icon: 'ticket',
3282
- iconSize: size * 0.55,
3283
- iconColor: tokens.btnInk,
3256
+ coinArt: config.isSocial ? BUY_BONUS_SOCIAL_ART : BUY_BONUS_ART,
3284
3257
  label: '',
3285
3258
  tokens,
3286
3259
  ticker: this.host.ticker,
@@ -3343,15 +3316,7 @@ class BottomBar extends Container {
3343
3316
  this.autoBtn.setGlow(true);
3344
3317
  }
3345
3318
  if (config.features.turbo > 0) {
3346
- this.turboBtn = new TurboButton({
3347
- size: 40,
3348
- glyph: 22,
3349
- discFill: tokens.btn,
3350
- discBorder: 2,
3351
- accent: tokens.accent,
3352
- level: state.turbo,
3353
- onTap: () => this.onTurbo(),
3354
- });
3319
+ this.turboBtn = makeTurboButton(this.host, state.turbo, () => this.onTurbo(), 40, 22);
3355
3320
  }
3356
3321
  const buy = isBase ? (this.buildBuy(M_BUY, 9, 2) ?? undefined) : undefined;
3357
3322
  // level 1 — controls bar (dark)
@@ -3576,7 +3541,11 @@ class BottomBar extends Container {
3576
3541
  left.position.set(panelX + PANEL_PAD, panelCenterY - left.outerHeight / 2);
3577
3542
  right.position.set(panelRight - PANEL_PAD - right.outerWidth, panelCenterY - right.outerHeight / 2);
3578
3543
  this.inner.scale.set(s);
3579
- this.inner.position.set((W - barW * s) / 2, H - WIDE_PAD_BOTTOM - SPIN * s);
3544
+ // Scale the bottom gap WITH the bar (…* s), not a flat 8px. On a small/short popout the bar is
3545
+ // fit-scaled down but a constant 8px gap would look like too much air — so the bar floated off the
3546
+ // bottom edge. Scaling matches the HTML shell, whose whole barhost scales from transform-origin
3547
+ // bottom center (gap → 8·s). Desktop (s≈1) is unchanged.
3548
+ this.inner.position.set((W - barW * s) / 2, H - (WIDE_PAD_BOTTOM + SPIN) * s);
3580
3549
  this.measureFootprint();
3581
3550
  }
3582
3551
  applyFitMobile() {
@@ -4310,11 +4279,10 @@ function sectionControls(host, title, width) {
4310
4279
  const box = new Container();
4311
4280
  const badge = new BuyBonusBadge({
4312
4281
  size: 46,
4313
- fontSize: 8,
4314
4282
  border: 2,
4315
4283
  bg: host.tokens.accent,
4316
- fg: '#ffffff',
4317
- label: host.t('BUY BONUS').split(/\s+/).join('\n'),
4284
+ coinArt: host.config.isSocial ? BUY_BONUS_SOCIAL_ART : BUY_BONUS_ART,
4285
+ label: '',
4318
4286
  tokens: host.tokens,
4319
4287
  ticker: host.ticker,
4320
4288
  onTap: () => { },
@@ -5366,11 +5334,11 @@ function volatilityRow(_host, level, accent, size) {
5366
5334
  const n = Math.max(0, Math.min(5, level));
5367
5335
  let x = 0;
5368
5336
  for (let i = 0; i < 5; i++) {
5369
- // active = solid accent bolt; inactive = solid black bolt, dimmed (fill==ring, 1px hairline ring
5370
- // per the DOM: .ge-bonus-vol svg path { stroke-width:1; fill/stroke = accent (on) / #000 (off) })
5337
+ // active = solid accent bolt; inactive = solid black bolt, dimmed
5338
+ // (DOM: .ge-bonus-vol svg path fill = accent (on) / #000 (off))
5371
5339
  const active = i < n;
5372
5340
  const col = active ? accent : '#000000';
5373
- const bolt = makeRingedIcon('turbo1', size, col, col, 1);
5341
+ const bolt = makeIcon('turbo1', size, col);
5374
5342
  bolt.alpha = active ? 1 : 0.5;
5375
5343
  bolt.position.set(x, 0);
5376
5344
  c.addChild(bolt);