@energy8platform/platform-core 0.26.1 → 0.27.0

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.
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ // Regenerates src/shell/fonts-digits.ts — Oswald, subset to ONLY the glyphs that appear in the
3
+ // shell's numeric readouts (digits, separators, currency symbols, the FS "3 / 10" counter, the
4
+ // autoplay ∞), embedded as base64 woff2. Tiny payload, no network fetch at runtime, language-
5
+ // independent (digits render the same in every locale). Run from the package root:
6
+ // node scripts/build-digit-font.mjs
7
+ // Oswald is licensed under the SIL Open Font License 1.1.
8
+
9
+ import { writeFile } from 'node:fs/promises';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { dirname, resolve } from 'node:path';
12
+
13
+ const FAMILY = 'Oswald';
14
+ const CSS_FAMILY = 'OswaldNum'; // local alias so it can't clash with a system "Oswald"
15
+ const WEIGHTS = '500;600;700';
16
+
17
+ // Every glyph a formatted money / counter value can contain. Built from code points to avoid any
18
+ // source-string quoting hazards. Generous on currency + space variants (Intl uses NBSP / narrow-NBSP
19
+ // as thousands separators in some locales) so a number never falls back to Inter mid-string.
20
+ const CHARS = [
21
+ ...'0123456789',
22
+ '.', ',', '’', "'", // . , ’ '
23
+ ' ', ' ', ' ', ' ', // space, NBSP, narrow-NBSP, thin space
24
+ '€', '$', '£', '¥', '₹', '¢', '₩', // € $ £ ¥ ₹ ¢ ₩
25
+ '%', '+', '−', '-', '×', '÷', '/', ':', '(', ')', '∞', // % + − - × ÷ / : ( ) ∞
26
+ ].join('');
27
+
28
+ const UA =
29
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36';
30
+
31
+ const cssUrl =
32
+ `https://fonts.googleapis.com/css2?family=${FAMILY}:wght@${WEIGHTS}` +
33
+ `&text=${encodeURIComponent(CHARS)}&display=swap`;
34
+
35
+ const cssRes = await fetch(cssUrl, { headers: { 'User-Agent': UA } });
36
+ if (!cssRes.ok) throw new Error(`GET css -> ${cssRes.status}`);
37
+ const css = await cssRes.text();
38
+
39
+ // Each @font-face block: pull its font-weight + the woff2 url.
40
+ const blocks = css.split('@font-face').slice(1);
41
+ const faces = [];
42
+ let raw = 0;
43
+ for (const blk of blocks) {
44
+ const weight = (blk.match(/font-weight:\s*(\d+)/) || [, '400'])[1];
45
+ const url = (blk.match(/url\(([^)]+)\)\s*format\('woff2'\)/) || [])[1];
46
+ if (!url) continue;
47
+ const res = await fetch(url, { headers: { 'User-Agent': UA } });
48
+ if (!res.ok) throw new Error(`GET ${url} -> ${res.status}`);
49
+ const bytes = Buffer.from(await res.arrayBuffer());
50
+ raw += bytes.length;
51
+ const b64 = bytes.toString('base64');
52
+ faces.push(
53
+ `@font-face{font-family:'${CSS_FAMILY}';font-style:normal;font-display:swap;` +
54
+ `font-weight:${weight};src:url(data:font/woff2;base64,${b64}) format('woff2');}`,
55
+ );
56
+ }
57
+ if (!faces.length) throw new Error('no @font-face parsed from Google CSS');
58
+
59
+ const header = `/* eslint-disable */
60
+ // Oswald — subset to numerals + currency/separator glyphs only — embedded as base64 woff2, used for
61
+ // the shell's numeric readouts (balance/bet/win/FS counter, autoplay countdown). Digit-only, so it's
62
+ // language-independent and tiny. Oswald is licensed under the SIL Open Font License 1.1.
63
+ // GENERATED by scripts/build-digit-font.mjs — regenerate, don't hand-edit.
64
+ `;
65
+ const body =
66
+ `export const SHELL_DIGIT_FONT_FAMILY = '${CSS_FAMILY}';\n\n` +
67
+ `export const SHELL_DIGIT_FONT_CSS =\n` +
68
+ faces.map((f, i) => ` \`${f}\`` + (i < faces.length - 1 ? ' +\n' : ';\n')).join('');
69
+
70
+ const here = dirname(fileURLToPath(import.meta.url));
71
+ await writeFile(resolve(here, '../src/shell/fonts-digits.ts'), header + '\n' + body);
72
+ console.log(`wrote src/shell/fonts-digits.ts (${faces.length} faces, ${raw} bytes raw woff2)`);
@@ -148,23 +148,21 @@ export class GameShell extends EventEmitter<ShellEvents> {
148
148
  const host = this.barHost;
149
149
  const bar = host.querySelector('.ge-shell-bottom') as HTMLElement | null;
150
150
  if (!bar) return;
151
- // reset to baseline (idempotent — the pill may have been lifted on a prior pass)
152
- const pill = host.querySelector('.ge-winpill') as HTMLElement | null;
153
- if (pill && pill.parentElement === host) { // put a lifted pill back inline
154
- const right = bar.querySelector('.ge-zone-right');
155
- if (right) bar.insertBefore(pill, right); else bar.appendChild(pill);
156
- pill.classList.remove('ge-up');
157
- }
151
+ // reset to baseline (idempotent)
158
152
  host.classList.remove('ge-fit');
159
153
  host.style.transform = '';
160
154
  host.style.transformOrigin = '';
161
- // clear any per-zone scale/zoom from a prior pass
162
- for (const el of host.querySelectorAll('.ge-zone, .ge-winpill')) {
155
+ // clear any zoom from a prior pass. We zoom the whole dark PANEL (so the bar surface shrinks with
156
+ // its content on a narrow popout), plus BUY BONUS + a lifted WIN pill, which live outside it.
157
+ for (const el of host.querySelectorAll('.ge-bar-panel, .ge-shell-buybonus')) {
163
158
  (el as HTMLElement).style.transform = '';
164
159
  (el as HTMLElement).style.transformOrigin = '';
165
160
  (el as HTMLElement).style.removeProperty('zoom');
166
161
  }
167
162
  if (this.layout === 'mobile') {
163
+ // First shrink long numbers inside the info pill (per-readout) so the buttons row stays
164
+ // full-size; then, only if a row still overflows (tiny phones), scale the whole stack.
165
+ this.fitBet();
168
166
  // Shrink the whole stack to fit narrow phones (mobile-s, or big balance/win/total-win
169
167
  // numbers in a row). The rows use space-between, so on overflow their content is
170
168
  // left-anchored and spills off the RIGHT edge — scale from the bottom-left corner so
@@ -183,18 +181,22 @@ export class GameShell extends EventEmitter<ShellEvents> {
183
181
  // must not resize the bar. The factor is the frame WIDTH vs the bar's design width, never the
184
182
  // current mode's content width.
185
183
  //
186
- // It's applied with `zoom` (not `transform`): zoom shrinks the LAYOUT, so the zones genuinely
187
- // take less room and still sit edge-to-edge (menu hard-left, controls hard-right) even when base's
188
- // wide row would overflow a merely-visually-scaled bar — so there is no per-mode centred cluster
189
- // and no width/mode branching. A wide WIN pill is still lifted above the row first so it can't
190
- // shove the controls off-screen. (Mobile, above, keeps its own stacked fit.)
191
- if (pill && bar.scrollWidth > bar.clientWidth + 1) { host.insertBefore(pill, bar); pill.classList.add('ge-up'); }
184
+ // It's applied with `zoom` (not `transform`): zoom shrinks the LAYOUT, so the bar genuinely
185
+ // takes less room and still sits edge-to-edge (menu hard-left, controls hard-right) even when
186
+ // base's wide row would overflow a merely-visually-scaled bar — so there is no per-mode centred
187
+ // cluster and no width/mode branching. The WIN pill stays inline in the bar and scales with it
188
+ // (no lifting above the row). (Mobile, above, keeps its own stacked fit.)
192
189
  const zoomBar = (z: number): void => {
193
190
  const v = z < 0.999 ? z.toFixed(4) : '';
194
- for (const el of host.querySelectorAll('.ge-zone, .ge-winpill')) {
191
+ const set = (el: Element | null): void => {
192
+ if (!el) return;
195
193
  if (v) (el as HTMLElement).style.setProperty('zoom', v);
196
194
  else (el as HTMLElement).style.removeProperty('zoom');
197
- }
195
+ };
196
+ // zoom the whole panel (surface + content, incl. the inline WIN pill, shrink together);
197
+ // BUY BONUS sits outside the panel, so zoom it too.
198
+ set(host.querySelector('.ge-bar-panel'));
199
+ set(bar.querySelector('.ge-shell-buybonus'));
198
200
  };
199
201
  const s = Math.max(GameShell.BAR_MIN_SCALE, Math.min(1, this.root.clientWidth / GameShell.BAR_REF_WIDTH));
200
202
  zoomBar(s);
@@ -204,6 +206,27 @@ export class GameShell extends EventEmitter<ShellEvents> {
204
206
  if (bar.scrollWidth > bar.clientWidth + 1 && bar.scrollWidth > 0) {
205
207
  zoomBar(s * (bar.clientWidth / bar.scrollWidth));
206
208
  }
209
+ this.fitBet();
210
+ }
211
+
212
+ /** Keep the BET box a fixed width (so the steppers/divider/SPIN never shift as the stake changes)
213
+ * by shrinking just the number when it would overflow the box — e.g. amounts above ~€100,000. */
214
+ private fitBet(): void {
215
+ // Shrink a readout's value span (.ge-rd-val, inline-block so its true width is measurable even
216
+ // inside an overflow:hidden slot) to fit `box`. The label is left untouched.
217
+ const fit = (val: HTMLElement | null, box: HTMLElement | null | undefined): void => {
218
+ if (!val || !box) return;
219
+ val.style.transform = ''; // measure at full size
220
+ const avail = box.clientWidth, need = val.scrollWidth;
221
+ if (need > avail + 0.5 && need > 0) val.style.transform = `scale(${(avail / need).toFixed(3)})`;
222
+ };
223
+ // BET (desktop + mobile): the value fits its fixed-width box so +/- never resizes/shifts it
224
+ const betBox = this.barHost.querySelector('.ge-bet-value') as HTMLElement | null;
225
+ fit(betBox?.querySelector('.ge-rd-val') as HTMLElement | null, betBox);
226
+ // mobile info pill: balance/win values fit their flex slots
227
+ for (const rd of this.barHost.querySelectorAll('.ge-m-info > .ge-rd')) {
228
+ fit(rd.querySelector('.ge-rd-val') as HTMLElement | null, rd as HTMLElement);
229
+ }
207
230
  }
208
231
 
209
232
  /** Pull window focus into the iframe on first pointer interaction so `document` keydown (the
@@ -399,14 +422,10 @@ export class GameShell extends EventEmitter<ShellEvents> {
399
422
  }
400
423
  }
401
424
 
402
- /** Count-up the trailing text node of a .ge-rd readout (keeps its label span).
425
+ /** Count-up the value span (.ge-rd-val) of a readout, leaving its label untouched.
403
426
  * Returns the count-up canceler so the shell can stop it before the node is replaced. */
404
427
  function animateReadout(el: HTMLElement, from: number, to: number, fmt: (n: number) => string): () => void {
405
- const textNode = el.lastChild;
406
- if (!textNode || textNode.nodeType !== Node.TEXT_NODE) { el.textContent = fmt(to); return () => {}; }
407
- const proxy = {
408
- set textContent(v: string) { (textNode as Text).data = v; },
409
- get textContent() { return (textNode as Text).data; },
410
- } as unknown as HTMLElement;
411
- return countUp(proxy, from, to, fmt);
428
+ const val = el.querySelector('.ge-rd-val') as HTMLElement | null;
429
+ if (!val) { el.textContent = fmt(to); return () => {}; }
430
+ return countUp(val, from, to, fmt);
412
431
  }
@@ -3,15 +3,17 @@ import { formatCurrency } from '../format';
3
3
  import { stepBet, nextTurbo } from '../state';
4
4
  import { effectiveAccent, contrastText } from '../colors';
5
5
  import { icon, type IconName } from './icons';
6
- import { twoLine } from './primitives';
7
6
 
8
7
  /** A floating labelled money readout (balance/win/bet). */
9
8
  function readout(ge: string, label: string, value: string): HTMLElement {
10
9
  const el = document.createElement('div');
11
10
  el.dataset.ge = ge;
12
11
  el.className = `ge-rd ge-${ge}`;
13
- el.innerHTML = `<span class="ge-lbl">${label}</span>`;
14
- el.append(document.createTextNode(value));
12
+ // The value lives in its own inline-block span (.ge-rd-val) so it can be measured & shrunk to fit
13
+ // (see GameShell.fitBet) independently of the label, and so the count-up animates just the number.
14
+ const lbl = document.createElement('span'); lbl.className = 'ge-lbl'; lbl.textContent = label;
15
+ const val = document.createElement('span'); val.className = 'ge-rd-val'; val.textContent = value;
16
+ el.append(lbl, val);
15
17
  return el;
16
18
  }
17
19
 
@@ -91,47 +93,61 @@ export function renderBottomBar(shell: GameShell): HTMLElement {
91
93
  // current = number → "current / total"; current = null/undefined → just the (game-driven) total.
92
94
  const fs = state.freeSpins;
93
95
  const fsText = fs.current == null ? `${fs.total}` : `${fs.current} / ${fs.total}`;
94
- const fsCounter = showFsBlocks ? readout('fs-counter', shell.t('Free spins'), fsText) : null;
96
+ // In FS the spins counter takes the SPIN slot as a rectangular hero plaque (same white/black-ring
97
+ // style as the SPIN disc); Total Win stays an inline readout.
98
+ const fsHero = showFsBlocks ? fsHeroPlaque(shell, fsText) : null;
95
99
  const fsTotalWin = showFsBlocks ? readout('fs-totalwin', shell.t('Total win'), fmtWin(fs.totalWin)) : null;
100
+ // The hero in the centre/spin position: SPIN in base, the FS counter in free spins, nothing else.
101
+ const hero = isBase ? spin : fsHero;
96
102
 
97
103
  if (mobile) {
98
- // rows: [balance · win] · [menu · auto · spin · FS counter · Total Win · turbo · buy] · [− bet +]
99
- // FS counter + Total Win live in the controls row (alongside menu/turbo), not the top readouts.
100
- bar.appendChild(plaque('ge-m-top ge-pl ge-pl-glass', compact([balance, winEl])));
101
- const center = isBase ? spin : null;
102
- bar.appendChild(plaque('ge-m-controls ge-pl-dark', compact([menu, auto, center, fsCounter, fsTotalWin, turbo, buy])));
103
- bar.appendChild(plaque('ge-m-bet ge-pl ge-pl-dark', compact([betDown, betValue, betUp])));
104
+ // Two levels:
105
+ // 1) controls bar [menu · auto · SPIN-or-FS · Total Win · turbo · buy]
106
+ // 2) a small info pill below — [balance · − bet + · win]
107
+ bar.appendChild(plaque('ge-m-controls', compact([menu, auto, hero, fsTotalWin, turbo, buy])));
108
+ const betGroup = plaque('ge-m-betgroup', compact([betDown, betValue, betUp]));
109
+ // WIN always occupies its slot (shows €0 between wins) so the pill never reflows on win↔0.
110
+ const mWin = readout('win', shell.t('Win'), fmtWin(state.win));
111
+ bar.appendChild(plaque('ge-m-info', compact([balance, betGroup, mWin])));
104
112
  } else {
105
- // LEFT: [menu] ⊐ BUY BONUS coin [balance] · [Free Spins] · [Total Win]
106
- // (the last two only render in FS / a free-spins replay)
107
- const menuPlaque = plaque('ge-pl ge-pl-dark ge-pl-menu', [menu]);
108
- const balPlaque = balance ? plaque('ge-pl ge-pl-glass ge-pl-bal', [balance]) : null;
109
- const fsPlaque = fsCounter ? plaque('ge-pl ge-pl-glass ge-pl-fs', [fsCounter]) : null;
110
- const totalWinPlaque = fsTotalWin ? plaque('ge-pl ge-pl-glass ge-pl-totalwin', [fsTotalWin]) : null;
111
- const left = zone('ge-zone-left ge-zone-plaques', ...compact([menuPlaque, buy, balPlaque, fsPlaque, totalWinPlaque]));
112
-
113
- // RIGHT: [bet (+ step)] · |divider| · [auto · SPIN · turbo]
113
+ // DESKTOP: BUY BONUS floats OUTSIDE, to the left of one continuous dark bar panel.
114
+ // LEFT (all the info): [menu] · [balance] · [Total Win] · [WIN]
115
+ // (Total Win only in FS / a fs replay; WIN only when there's a win this spin)
116
+ const left = zone('ge-zone-left', ...compact([menu, balance, fsTotalWin, winEl]));
117
+
118
+ // RIGHT (the controls): [bet (+ step)] · |divider| · [auto · SPIN-or-FS · turbo]
114
119
  const betKids: HTMLElement[] = [betValue];
115
120
  if (betUp && betDown) {
116
121
  const step = document.createElement('div'); step.className = 'ge-betstep'; step.append(betUp, betDown);
117
122
  betKids.push(step);
118
123
  }
119
- const betPlaque = plaque('ge-pl ge-pl-dark ge-pl-bet', betKids);
124
+ const betGroup = plaque('ge-betgroup', betKids);
120
125
  const divider = document.createElement('div'); divider.className = 'ge-pl-divider';
121
- const spinWrap = document.createElement('div'); spinWrap.className = 'ge-spinwrap ge-pl-dark';
122
- spinWrap.append(...compact([auto, spin, turbo]));
123
- const right = zone('ge-zone-right ge-zone-plaques', betPlaque, divider, spinWrap);
124
-
125
- // MIDDLE: per-spin WIN pill in every mode lifts above the bar on overflow.
126
- let middle: HTMLElement | null = null;
127
- if (winEl) { winEl.classList.add('ge-winpill'); middle = winEl; }
128
- bar.append(...compact([left, middle, right]));
126
+ const spinWrap = document.createElement('div'); spinWrap.className = 'ge-spinwrap';
127
+ spinWrap.append(...compact([auto, hero, turbo]));
128
+ const right = zone('ge-zone-right', betGroup, divider, spinWrap);
129
+
130
+ // One continuous dark panel: info group hard-left, controls hard-right (space-between).
131
+ // BUY BONUS sits to its left, outside the panel.
132
+ const panel = plaque('ge-bar-panel', [left, right]);
133
+ bar.append(...compact([buy, panel]));
129
134
  }
130
135
 
131
136
  applyBusy(shell, bar);
132
137
  return bar;
133
138
  }
134
139
 
140
+ /** Free-spins hero plaque — takes the SPIN slot in FS: same white disc/black-ring language as SPIN,
141
+ * but a rounded RECTANGLE showing the spins counter ("3 / 10"). */
142
+ function fsHeroPlaque(shell: GameShell, text: string): HTMLElement {
143
+ const el = document.createElement('div');
144
+ el.className = 'ge-fs-hero'; el.dataset.ge = 'fs-counter';
145
+ const lbl = document.createElement('span'); lbl.className = 'ge-fs-lbl'; lbl.textContent = shell.t('Free spins');
146
+ const num = document.createElement('span'); num.className = 'ge-fs-num'; num.textContent = text;
147
+ el.append(lbl, num);
148
+ return el;
149
+ }
150
+
135
151
  function zone(cls: string, ...children: HTMLElement[]): HTMLElement {
136
152
  const z = document.createElement('div');
137
153
  z.className = `ge-zone ${cls}`;
@@ -159,7 +175,9 @@ function buyBtn(shell: GameShell): HTMLButtonElement {
159
175
  buy.style.background = accent; buy.style.color = contrastText(accent);
160
176
  buy.addEventListener('click', () => { if (!buy.disabled) shell.deactivateFeature(); });
161
177
  } else {
162
- buy.innerHTML = `<span>${twoLine(shell.t('BUY BONUS'))}</span>`;
178
+ // Ticket icon (no text); keep the label for screen readers.
179
+ buy.setAttribute('aria-label', shell.t('BUY BONUS'));
180
+ buy.innerHTML = `<span class="ge-bb-tk">${icon('ticket')}</span>`;
163
181
  buy.addEventListener('click', () => { if (!buy.disabled) shell.openBuyBonus(); });
164
182
  }
165
183
  return buy;
@@ -0,0 +1,139 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 384" width="576" height="384">
2
+ <!-- Energy8 shell icon set — generated from packages/platform-core/src/shell/components/icons.ts.
3
+ Reusable as a sprite: <use href="shell-icons.svg#ge-icon-<name>"/>. -->
4
+ <rect width="576" height="384" fill="#0c111c"/>
5
+ <defs>
6
+ <symbol id="ge-icon-spin" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M17.92 4.68 L13.91 2.81 L10.55 1.6 L12.05 3.47 L11.95 3.56 L10.93 3.65 L9.25 4.12 L7.94 4.77 L7.01 5.42 L5.61 6.82 L4.58 8.41 L4.03 9.53 L3.28 11.67 L2.91 13.91 L4.49 16.52 L4.68 16.62 L6.54 14.94 L6.17 14.01 L6.08 13.17 L5.98 13.07 L5.98 11.49 L6.08 10.93 L6.45 9.71 L6.82 8.97 L7.48 8.04 L8.22 7.29 L9.25 6.54 L9.99 6.17 L11.21 5.8 L11.77 5.7 L13.73 5.7 L13.82 5.8 L14.57 5.89 L15.87 6.45 L16.06 6.45 L17.92 4.86Z"/><path d="M19.6 7.66 L19.42 7.57 L17.83 9.16 L18.11 9.9 L18.2 10.74 L18.3 10.83 L18.3 12.7 L18.2 12.79 L18.11 13.54 L17.46 15.03 L16.9 15.87 L15.87 16.9 L14.94 17.55 L14.1 17.92 L13.17 18.2 L12.05 18.39 L11.02 18.39 L10.93 18.3 L9.9 18.2 L9.06 17.92 L8.41 17.55 L8.22 17.55 L6.73 18.76 L6.26 19.32 L11.21 21.56 L12.7 22.03 L13.45 22.4 L13.73 22.4 L12.23 20.53 L12.33 20.44 L13.54 20.35 L15.31 19.79 L16.8 18.95 L17.64 18.3 L18.76 17.08 L19.51 15.96 L20.16 14.66 L20.25 14.19 L20.53 13.63 L20.72 12.98 L20.72 12.61 L20.91 12.14 L21.09 10.37 L19.97 8.5Z"/></g></symbol>
7
+ <symbol id="ge-icon-turbo" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M19.16 1.71 L16.47 1.71 L16.36 1.6 L13.23 1.6 L12.78 1.71 L11.78 3.39 L10.55 5.85 L10.32 6.07 L8.31 9.99 L8.09 10.21 L7.19 12.11 L12 12.34 L14.46 9.88 L14.24 9.65 L12.89 9.54 L12.89 9.2 L17.03 4.4Z"/><path d="M19.83 6.97 L18.93 7.64 L16.36 9.99 L9.65 16.47 L4.17 21.62 L4.17 22.4 L5.4 21.39 L13.34 13.9 L13.45 14.12 L10.43 20.16 L10.21 20.83 L9.65 21.95 L9.76 21.95 L19.27 10.32 L19.27 10.21 L17.59 10.1 L17.48 9.88 L18.71 8.53Z"/></g></symbol>
8
+ <symbol id="ge-icon-turbo1" viewBox="0 0 24 24"><g fill="currentColor" transform="translate(6.94 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g></symbol>
9
+ <symbol id="ge-icon-turbo2" viewBox="0 0 24 24"><g fill="currentColor" transform="translate(3.81 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(133.33 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g></symbol>
10
+ <symbol id="ge-icon-turbo3" viewBox="0 0 24 24"><g fill="currentColor" transform="translate(0.69 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(133.33 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(266.67 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g></symbol>
11
+ <symbol id="ge-icon-autoplay" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M19.48 5.36 L15.02 1.6 L14.82 1.6 L15.62 3.28 L15.52 3.78 L14.82 3.78 L14.72 3.88 L12.64 3.88 L12.54 3.78 L5.71 3.78 L3.23 6.35 L3.23 16.26 L3.33 16.26 L4.82 14.48 L4.82 12.5 L4.72 12.4 L4.72 7.25 L4.82 7.05 L6.4 5.56 L8.29 5.56 L8.38 5.46 L19.48 5.46Z"/><path d="M9.87 8.83 L9.87 15.27 L9.97 15.27 L11.26 14.38 L15.12 12.1 L15.12 12 L11.16 9.62 L10.66 9.23Z"/><path d="M20.67 7.94 L20.17 8.34 L19.18 9.52 L19.18 16.85 L17.5 18.44 L17.1 18.54 L4.42 18.54 L4.42 18.64 L7.3 21.21 L8.78 22.4 L8.78 22 L8.09 20.42 L8.19 20.22 L18.29 20.22 L20.77 17.65 L20.67 17.35Z"/></g></symbol>
12
+ <symbol id="ge-icon-stop" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M22.4 3.04 L21.1 4.82 L21.1 9.47 L21.03 9.54 L21.03 12.41 L21.1 12.96 L21.03 18.84 L21.1 19.18 L20.35 20.01 L19.39 20.89 L17.27 20.89 L16.72 20.96 L4.75 20.96 L4.68 20.89 L3.04 22.33 L4.13 22.33 L4.2 22.4 L6.66 22.4 L6.73 22.33 L9.13 22.33 L9.19 22.4 L20.48 22.4 L22.4 20.48Z"/><path d="M20.96 1.6 L3.38 1.6 L1.6 3.45 L1.6 20.96 L2.9 19.12 L2.9 4.75 L4.54 3.11 L19.12 3.11 L19.46 2.97Z"/></g></symbol>
13
+ <symbol id="ge-icon-menu" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M1.6 13.52 L19.61 13.52 L22.27 10.73 L22.4 10.35 L4.39 10.35 L2.36 12.51Z"/><path d="M1.6 6.04 L19.61 6.04 L22.15 3.38 L22.4 2.87 L4.39 2.87 L2.36 5.02Z"/><path d="M1.6 21 L3.25 21 L3.38 21.13 L4.9 21.13 L5.02 21 L19.61 21 L22.4 17.96 L4.52 17.83 L4.26 17.96 L2.36 19.99Z"/></g></symbol>
14
+ <symbol id="ge-icon-betUp" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M21.01 15.43 L19.18 13.07 L14.68 6.75 L12.32 3.64 L12 3.42 L8.57 7.93 L6.42 11.04 L2.89 15.75 L2.78 16.07 L12 8.14 L12.21 8.14 L20.68 15.43Z"/><path d="M22.4 20.26 L20.04 17.79 L12.21 10.28 L12 10.28 L6.53 15.43 L6.42 15.65 L1.81 20.15 L1.6 20.58 L12 14.04 L12.21 14.04 L12.75 14.47 L18.11 17.68 L18.65 18.11 L19.51 18.54 L22.29 20.36Z"/></g></symbol>
15
+ <symbol id="ge-icon-betDown" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M1.6 2.74 L1.84 3.22 L5.57 7.43 L11.7 14.04 L12.06 14.28 L12.42 14.04 L18.79 7.19 L22.4 2.98 L22.28 2.86 L18.55 5.51 L12.06 10.44 L5.81 5.63Z"/><path d="M20.84 9.35 L18.07 11.52 L12.18 16.57 L11.94 16.57 L4.49 10.2 L3.52 9.48 L3.4 9.6 L8.57 16.57 L8.81 17.05 L10.26 18.85 L10.5 19.33 L11.34 20.3 L11.58 20.78 L12.18 21.26 L18.43 12.84Z"/></g></symbol>
16
+ <symbol id="ge-icon-minus" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M1.6 13.26 L12.42 13.26 L12.5 13.18 L19.81 13.26 L22.4 10.82 L4.27 10.74Z"/></g></symbol>
17
+ <symbol id="ge-icon-plus" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M13.16 1.6 L12.26 3.17 L10.77 5.42 L10.77 10.73 L10.69 10.8 L4.33 10.8 L1.79 13.2 L10.69 13.2 L10.77 13.27 L10.77 22.4 L12.41 19.71 L13.16 18.66 L13.16 13.27 L13.23 13.2 L19.59 13.2 L22.21 10.8 L13.23 10.8 L13.16 10.73Z"/></g></symbol>
18
+ <symbol id="ge-icon-gift" viewBox="0 0 24 24"><rect x="4" y="9" width="16" height="11" rx="2" fill="currentColor"/><path d="M9 9a2.5 2.5 0 1 1 3-3 2.5 2.5 0 1 1 3 3z" fill="currentColor"/><rect x="11" y="9" width="2" height="11" fill="rgba(0,0,0,.35)"/></symbol>
19
+ <symbol id="ge-icon-ticket" viewBox="0 0 24 24"><g transform="translate(12 12) scale(0.0354) translate(-518.2 -535.2)"><g transform="rotate(-15 512 512)"><path d="M250 392H774L774 462C739 474 720 504 720 536C720 568 739 598 774 610V680H250V610C285 598 304 568 304 536C304 504 285 474 250 462V392Z" fill="none" stroke="currentColor" stroke-width="52" stroke-linejoin="miter" stroke-linecap="square"/><path d="M562.9 408.3L441.5 553.9L506.9 546.3L472.9 664.1L604 504L528.9 514.3Z" fill="currentColor"/></g></g></symbol>
20
+ <symbol id="ge-icon-info" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M14.22 7.78 L11.13 7.86 L9.4 9.21 L9.17 9.29 L10.15 9.29 L10.23 9.59 L9.32 13.73 L8.87 17.12 L8.57 18.78 L8.5 19.69 L8.27 20.74 L8.12 22.32 L8.04 22.4 L13.62 17.95 L11.96 17.95 L11.89 17.58 L12.41 15.69 L12.49 15.01 L12.87 13.73 L12.87 13.43 L13.24 12.15 L13.77 9.97 L14 8.68 L14.22 8.08Z"/><path d="M15.96 1.6 L12.94 1.6 L11.74 3.18 L11.51 3.63 L10.08 5.67 L12.79 5.59 L14.37 3.71Z"/></g></symbol>
21
+ <symbol id="ge-icon-soundOn" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M16.61 6.68 L17.16 8.4 L17.4 9.97 L17.4 13.88 L17.32 13.95 L17.16 15.44 L16.61 17.16 L18.88 13.72 L18.88 12.86 L18.96 12.78 L18.88 10.12Z"/><path d="M19.27 4.34 L19.58 4.88 L19.66 5.28 L20.05 6.14 L20.6 7.93 L20.91 9.5 L20.91 10.44 L20.99 10.51 L20.99 13.25 L20.91 13.33 L20.91 14.19 L20.76 15.13 L20.05 17.63 L19.27 19.43 L20.29 18.02 L21.15 16.61 L22.4 14.19 L22.4 9.58 L21.31 7.39 L20.29 5.74Z"/><path d="M13.17 1.76 L10.28 4.34 L6.29 8.17 L1.6 8.25 L1.6 15.6 L2.15 15.75 L6.29 16.3 L9.97 19.58 L13.17 22.24Z"/><path d="M11.69 5.59 L11.92 5.67 L11.92 19.04 L11.69 19.12 L7.07 14.82 L4.57 14.5 L4.42 14.35 L4.42 10.51 L4.57 10.36 L7.07 10.28Z"/></g></symbol>
22
+ <symbol id="ge-icon-soundOff" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M13.68 13.18 L12.53 14.4 L12.53 18.44 L12.3 18.51 L10.4 16.76 L9.33 17.83 L12.84 20.88 L13.75 21.56 L13.75 13.18Z"/><path d="M17.71 8.69 L17.49 8.91 L17.56 9.9 L17.64 9.98 L17.64 13.1 L17.33 14.7 L17.03 15.39 L18.78 12.88 L18.78 11.66 L18.86 11.58 L18.78 10.29Z"/><path d="M19.47 6.63 L19.85 7.47 L20.46 9.6 L20.53 10.13 L20.53 13.03 L20.08 15.01 L19.31 16.91 L20.61 14.93 L21.3 13.49 L21.52 13.18 L21.52 9.9 L20.76 8.53Z"/><path d="M20.91 2.21 L16.5 6.63 L13.98 9.3 L13.75 9.22 L13.75 1.6 L10.86 4.19 L7.05 7.85 L2.4 7.92 L2.48 8 L2.48 15.16 L6.51 15.7 L7.73 14.32 L5.3 14.02 L5.22 13.94 L5.22 10.13 L5.75 9.98 L7.81 9.9 L12.3 5.33 L12.53 5.41 L12.53 10.9 L10.32 13.26 L6.9 17.14 L2.55 22.4 L6.9 18.36 L9.79 15.47 L13.52 11.5 L18.25 5.71Z"/></g></symbol>
23
+ <symbol id="ge-icon-close" viewBox="0 0 24 24"><g fill="currentColor" fill-rule="evenodd"><path d="M22.16 1.6 L21.3 2.09 L20.44 2.82 L16.89 5.27 L12.12 10.29 L10.53 8.82 L7.35 5.39 L2.21 2.09 L5.88 7.23 L8.21 9.55 L10.41 12 L5.76 16.89 L2.33 21.54 L1.84 22.4 L2.58 22.03 L2.95 21.67 L4.17 20.93 L5.88 19.59 L7.23 18.73 L12 13.71 L12.12 13.71 L17.02 18.73 L22.16 22.16 L22.16 21.91 L20.2 19.46 L18.48 17.02 L13.71 12.12 L13.71 11.88 L18.48 6.86 L20.32 4.17 L21.67 2.46Z"/></g></symbol>
24
+ <symbol id="ge-icon-back" viewBox="0 0 24 24"><path d="M15 6l-6 6 6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
25
+ <symbol id="ge-icon-chevronRight" viewBox="0 0 24 24"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
26
+ <symbol id="ge-icon-star" viewBox="0 0 24 24"><path d="M12 3l2.6 5.6 6.1.7-4.5 4.2 1.2 6L12 16.9 6.6 19.5l1.2-6L3.3 9.3l6.1-.7z" fill="currentColor"/></symbol>
27
+ <symbol id="ge-icon-lightning" viewBox="0 0 24 24"><path transform="scale(0.019139)" d="M747,205L433,629L622,633L497,986L801,550L614,547Z" fill="currentColor"/></symbol>
28
+ </defs>
29
+ <g>
30
+ <rect x="4" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
31
+ <use href="#ge-icon-spin" x="26" y="14" width="44" height="44" color="#f4f6fb"/>
32
+ <text x="48" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">spin</text>
33
+ </g>
34
+ <g>
35
+ <rect x="100" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
36
+ <use href="#ge-icon-turbo" x="122" y="14" width="44" height="44" color="#f4f6fb"/>
37
+ <text x="144" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">turbo</text>
38
+ </g>
39
+ <g>
40
+ <rect x="196" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
41
+ <use href="#ge-icon-turbo1" x="218" y="14" width="44" height="44" color="#f4f6fb"/>
42
+ <text x="240" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">turbo1</text>
43
+ </g>
44
+ <g>
45
+ <rect x="292" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
46
+ <use href="#ge-icon-turbo2" x="314" y="14" width="44" height="44" color="#f4f6fb"/>
47
+ <text x="336" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">turbo2</text>
48
+ </g>
49
+ <g>
50
+ <rect x="388" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
51
+ <use href="#ge-icon-turbo3" x="410" y="14" width="44" height="44" color="#f4f6fb"/>
52
+ <text x="432" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">turbo3</text>
53
+ </g>
54
+ <g>
55
+ <rect x="484" y="4" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
56
+ <use href="#ge-icon-autoplay" x="506" y="14" width="44" height="44" color="#f4f6fb"/>
57
+ <text x="528" y="82" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">autoplay</text>
58
+ </g>
59
+ <g>
60
+ <rect x="4" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
61
+ <use href="#ge-icon-stop" x="26" y="110" width="44" height="44" color="#f4f6fb"/>
62
+ <text x="48" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">stop</text>
63
+ </g>
64
+ <g>
65
+ <rect x="100" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
66
+ <use href="#ge-icon-menu" x="122" y="110" width="44" height="44" color="#f4f6fb"/>
67
+ <text x="144" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">menu</text>
68
+ </g>
69
+ <g>
70
+ <rect x="196" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
71
+ <use href="#ge-icon-betUp" x="218" y="110" width="44" height="44" color="#f4f6fb"/>
72
+ <text x="240" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">betUp</text>
73
+ </g>
74
+ <g>
75
+ <rect x="292" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
76
+ <use href="#ge-icon-betDown" x="314" y="110" width="44" height="44" color="#f4f6fb"/>
77
+ <text x="336" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">betDown</text>
78
+ </g>
79
+ <g>
80
+ <rect x="388" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
81
+ <use href="#ge-icon-minus" x="410" y="110" width="44" height="44" color="#f4f6fb"/>
82
+ <text x="432" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">minus</text>
83
+ </g>
84
+ <g>
85
+ <rect x="484" y="100" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
86
+ <use href="#ge-icon-plus" x="506" y="110" width="44" height="44" color="#f4f6fb"/>
87
+ <text x="528" y="178" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">plus</text>
88
+ </g>
89
+ <g>
90
+ <rect x="4" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
91
+ <use href="#ge-icon-gift" x="26" y="206" width="44" height="44" color="#f4f6fb"/>
92
+ <text x="48" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">gift</text>
93
+ </g>
94
+ <g>
95
+ <rect x="100" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
96
+ <use href="#ge-icon-ticket" x="122" y="206" width="44" height="44" color="#f4f6fb"/>
97
+ <text x="144" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">ticket</text>
98
+ </g>
99
+ <g>
100
+ <rect x="196" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
101
+ <use href="#ge-icon-info" x="218" y="206" width="44" height="44" color="#f4f6fb"/>
102
+ <text x="240" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">info</text>
103
+ </g>
104
+ <g>
105
+ <rect x="292" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
106
+ <use href="#ge-icon-soundOn" x="314" y="206" width="44" height="44" color="#f4f6fb"/>
107
+ <text x="336" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">soundOn</text>
108
+ </g>
109
+ <g>
110
+ <rect x="388" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
111
+ <use href="#ge-icon-soundOff" x="410" y="206" width="44" height="44" color="#f4f6fb"/>
112
+ <text x="432" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">soundOff</text>
113
+ </g>
114
+ <g>
115
+ <rect x="484" y="196" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
116
+ <use href="#ge-icon-close" x="506" y="206" width="44" height="44" color="#f4f6fb"/>
117
+ <text x="528" y="274" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">close</text>
118
+ </g>
119
+ <g>
120
+ <rect x="4" y="292" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
121
+ <use href="#ge-icon-back" x="26" y="302" width="44" height="44" color="#f4f6fb"/>
122
+ <text x="48" y="370" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">back</text>
123
+ </g>
124
+ <g>
125
+ <rect x="100" y="292" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
126
+ <use href="#ge-icon-chevronRight" x="122" y="302" width="44" height="44" color="#f4f6fb"/>
127
+ <text x="144" y="370" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">chevronRight</text>
128
+ </g>
129
+ <g>
130
+ <rect x="196" y="292" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
131
+ <use href="#ge-icon-star" x="218" y="302" width="44" height="44" color="#f4f6fb"/>
132
+ <text x="240" y="370" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">star</text>
133
+ </g>
134
+ <g>
135
+ <rect x="292" y="292" width="88" height="88" rx="12" fill="#11161f" stroke="#222a38"/>
136
+ <use href="#ge-icon-lightning" x="314" y="302" width="44" height="44" color="#f4f6fb"/>
137
+ <text x="336" y="370" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#9aa3b6">lightning</text>
138
+ </g>
139
+ </svg>
@@ -7,10 +7,12 @@ const SVGS: Record<string, string> = {
7
7
  // hollow loop ring + two arrowheads (renders dark-on-bright inside SPIN)
8
8
  spin: `<g fill="currentColor" fill-rule="evenodd"><path d="M17.92 4.68 L13.91 2.81 L10.55 1.6 L12.05 3.47 L11.95 3.56 L10.93 3.65 L9.25 4.12 L7.94 4.77 L7.01 5.42 L5.61 6.82 L4.58 8.41 L4.03 9.53 L3.28 11.67 L2.91 13.91 L4.49 16.52 L4.68 16.62 L6.54 14.94 L6.17 14.01 L6.08 13.17 L5.98 13.07 L5.98 11.49 L6.08 10.93 L6.45 9.71 L6.82 8.97 L7.48 8.04 L8.22 7.29 L9.25 6.54 L9.99 6.17 L11.21 5.8 L11.77 5.7 L13.73 5.7 L13.82 5.8 L14.57 5.89 L15.87 6.45 L16.06 6.45 L17.92 4.86Z"/><path d="M19.6 7.66 L19.42 7.57 L17.83 9.16 L18.11 9.9 L18.2 10.74 L18.3 10.83 L18.3 12.7 L18.2 12.79 L18.11 13.54 L17.46 15.03 L16.9 15.87 L15.87 16.9 L14.94 17.55 L14.1 17.92 L13.17 18.2 L12.05 18.39 L11.02 18.39 L10.93 18.3 L9.9 18.2 L9.06 17.92 L8.41 17.55 L8.22 17.55 L6.73 18.76 L6.26 19.32 L11.21 21.56 L12.7 22.03 L13.45 22.4 L13.73 22.4 L12.23 20.53 L12.33 20.44 L13.54 20.35 L15.31 19.79 L16.8 18.95 L17.64 18.3 L18.76 17.08 L19.51 15.96 L20.16 14.66 L20.25 14.19 L20.53 13.63 L20.72 12.98 L20.72 12.61 L20.91 12.14 L21.09 10.37 L19.97 8.5Z"/></g>`,
9
9
  turbo: `<g fill="currentColor" fill-rule="evenodd"><path d="M19.16 1.71 L16.47 1.71 L16.36 1.6 L13.23 1.6 L12.78 1.71 L11.78 3.39 L10.55 5.85 L10.32 6.07 L8.31 9.99 L8.09 10.21 L7.19 12.11 L12 12.34 L14.46 9.88 L14.24 9.65 L12.89 9.54 L12.89 9.2 L17.03 4.4Z"/><path d="M19.83 6.97 L18.93 7.64 L16.36 9.99 L9.65 16.47 L4.17 21.62 L4.17 22.4 L5.4 21.39 L13.34 13.9 L13.45 14.12 L10.43 20.16 L10.21 20.83 L9.65 21.95 L9.76 21.95 L19.27 10.32 L19.27 10.21 L17.59 10.1 L17.48 9.88 L18.71 8.53Z"/></g>`,
10
- // bolt with 1/2/3 speed lines escalating turbo level
11
- turbo1: `<g fill="currentColor" fill-rule="evenodd"><path d="M21.82 1.6 L21.59 1.72 L21.01 1.72 L20.44 1.95 L18.7 2.29 L18.12 2.29 L18.01 2.41 L16.39 2.64 L14.77 3.1 L13.73 5.41 L13.73 5.64 L13.27 6.45 L13.27 6.68 L12.81 7.49 L12.81 7.72 L12.35 8.53 L12.35 8.76 L11.77 9.8 L11.42 10.84 L10.15 13.5 L10.15 13.73 L14.54 13.73 L14.66 13.85 L13.39 16.16 L12.81 16.97 L11.54 19.4 L11.31 19.63 L11.08 20.2 L10.04 21.82 L9.8 22.4 L9.92 22.4 L20.9 11.19 L22.05 10.15 L22.05 10.04 L16.62 10.15 L16.51 10.27 L15.7 10.27 L15.58 10.15 L15.81 9.69 L16.28 9.23 L21.48 2.29Z"/><path d="M8.53 12.46 L7.72 12.58 L7.26 12.81 L6.92 12.81 L6.45 13.04 L6.11 13.04 L5.64 13.27 L3.68 13.73 L1.95 14.31 L1.95 14.43 L7.61 14.43Z"/></g>`,
12
- turbo2: `<g fill="currentColor" fill-rule="evenodd"><path d="M22.4 2.68 L18.38 3.61 L15.4 4.43 L14.68 5.98 L13.96 7.93 L13.65 8.45 L13.65 8.65 L13.34 9.17 L13.34 9.37 L13.03 9.89 L13.03 10.1 L12.72 10.61 L12.72 10.82 L12.41 11.33 L12.41 11.54 L12.1 12.05 L12.1 12.26 L11.79 12.77 L11.49 13.7 L15.3 13.7 L15.5 13.9 L14.47 15.55 L14.16 16.27 L13.96 16.48 L11.28 21.32 L11.9 20.91 L20.65 11.95 L22.09 10.61 L22.09 10.51 L20.55 10.51 L20.44 10.61 L16.32 10.71 L16.22 10.51 L19.83 6.08Z"/><path d="M10.04 15.04 L9.43 15.14 L8.81 14.93 L7.98 14.93 L7.88 15.04 L6.34 15.14 L6.23 15.24 L5.62 15.24 L4.28 15.55 L2.84 15.76 L1.6 16.17 L10.04 16.17Z"/><path d="M10.56 9.99 L9.43 10.1 L9.32 10.2 L7.37 10.51 L6.85 10.71 L6.44 10.71 L5.51 11.02 L3.04 11.54 L2.94 11.74 L5.1 11.85 L5.2 11.95 L6.65 11.95 L6.75 12.05 L9.01 12.05 L9.12 12.15 L9.73 12.15 L10.56 10.3Z"/></g>`,
13
- turbo3: `<g fill="currentColor" fill-rule="evenodd"><path d="M22.4 3 L22 3 L20.3 3.5 L19.9 3.5 L19.5 3.7 L19.1 3.7 L15.9 4.6 L13.9 9.1 L13.9 9.3 L13.6 10 L13.2 10.7 L13.2 10.9 L12.6 12.1 L12.3 13 L12 13.6 L15.8 13.6 L15.9 13.8 L14.4 16.3 L13.7 17.7 L13.2 18.4 L12.8 19.1 L12.5 19.8 L12 20.5 L11.9 21 L22.2 10.6 L22.2 10.5 L16.8 10.6 L16.7 10.4 L22.3 3.3Z"/><path d="M11 11.3 L9.9 11.3 L9.8 11.4 L7.8 11.6 L6 11.9 L5.4 12.1 L3.9 12.3 L3.1 12.5 L3.1 12.6 L5.6 12.7 L5.7 12.8 L7.9 12.8 L8 12.9 L10.4 12.9 L11 11.6Z"/><path d="M12.7 7.3 L12 7.3 L11.9 7.4 L10.7 7.5 L10.1 7.7 L9.6 7.7 L7.2 8.2 L6.7 8.4 L5.5 8.6 L5.6 8.8 L7 8.8 L7.1 8.9 L8.5 8.9 L8.6 9 L12 9.1Z"/><path d="M10.9 15.4 L10.3 15.7 L10 15.7 L9.1 15.4 L7.8 15.5 L7.7 15.6 L6.9 15.6 L6.8 15.7 L6 15.7 L5.9 15.8 L4.1 16 L3.5 16.2 L2.5 16.3 L1.6 16.6 L2.6 16.6 L2.7 16.7 L10.9 16.7Z"/></g>`,
10
+ // Lightning bolt(s) escalating turbo level (1/2/3 overlapping bolts). The bolt is authored in a
11
+ // 216×512 space (M118 0…Z); each glyph scales it into 24×24 (×0.046875) and centres the cluster.
12
+ // Sibling bolts are offset by 133.33 (= 96/0.72, the source sheet's spacing) so they overlap.
13
+ turbo1: `<g fill="currentColor" transform="translate(6.94 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g>`,
14
+ turbo2: `<g fill="currentColor" transform="translate(3.81 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(133.33 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g>`,
15
+ turbo3: `<g fill="currentColor" transform="translate(0.69 0) scale(0.046875)"><path d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(133.33 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/><path transform="translate(266.67 0)" d="M118 0L0 232L86 232L28 512L216 220L126 220Z"/></g>`,
14
16
  autoplay: `<g fill="currentColor" fill-rule="evenodd"><path d="M19.48 5.36 L15.02 1.6 L14.82 1.6 L15.62 3.28 L15.52 3.78 L14.82 3.78 L14.72 3.88 L12.64 3.88 L12.54 3.78 L5.71 3.78 L3.23 6.35 L3.23 16.26 L3.33 16.26 L4.82 14.48 L4.82 12.5 L4.72 12.4 L4.72 7.25 L4.82 7.05 L6.4 5.56 L8.29 5.56 L8.38 5.46 L19.48 5.46Z"/><path d="M9.87 8.83 L9.87 15.27 L9.97 15.27 L11.26 14.38 L15.12 12.1 L15.12 12 L11.16 9.62 L10.66 9.23Z"/><path d="M20.67 7.94 L20.17 8.34 L19.18 9.52 L19.18 16.85 L17.5 18.44 L17.1 18.54 L4.42 18.54 L4.42 18.64 L7.3 21.21 L8.78 22.4 L8.78 22 L8.09 20.42 L8.19 20.22 L18.29 20.22 L20.77 17.65 L20.67 17.35Z"/></g>`,
15
17
  // hollow square — stop autoplay / halt
16
18
  stop: `<g fill="currentColor" fill-rule="evenodd"><path d="M22.4 3.04 L21.1 4.82 L21.1 9.47 L21.03 9.54 L21.03 12.41 L21.1 12.96 L21.03 18.84 L21.1 19.18 L20.35 20.01 L19.39 20.89 L17.27 20.89 L16.72 20.96 L4.75 20.96 L4.68 20.89 L3.04 22.33 L4.13 22.33 L4.2 22.4 L6.66 22.4 L6.73 22.33 L9.13 22.33 L9.19 22.4 L20.48 22.4 L22.4 20.48Z"/><path d="M20.96 1.6 L3.38 1.6 L1.6 3.45 L1.6 20.96 L2.9 19.12 L2.9 4.75 L4.54 3.11 L19.12 3.11 L19.46 2.97Z"/></g>`,
@@ -20,6 +22,9 @@ const SVGS: Record<string, string> = {
20
22
  minus: `<g fill="currentColor" fill-rule="evenodd"><path d="M1.6 13.26 L12.42 13.26 L12.5 13.18 L19.81 13.26 L22.4 10.82 L4.27 10.74Z"/></g>`,
21
23
  plus: `<g fill="currentColor" fill-rule="evenodd"><path d="M13.16 1.6 L12.26 3.17 L10.77 5.42 L10.77 10.73 L10.69 10.8 L4.33 10.8 L1.79 13.2 L10.69 13.2 L10.77 13.27 L10.77 22.4 L12.41 19.71 L13.16 18.66 L13.16 13.27 L13.23 13.2 L19.59 13.2 L22.21 10.8 L13.23 10.8 L13.16 10.73Z"/></g>`,
22
24
  gift: `<rect x="4" y="9" width="16" height="11" rx="2" fill="currentColor"/><path d="M9 9a2.5 2.5 0 1 1 3-3 2.5 2.5 0 1 1 3 3z" fill="currentColor"/><rect x="11" y="9" width="2" height="11" fill="rgba(0,0,0,.35)"/>`,
25
+ // bonus ticket — a perforated ticket (stroke) with a lightning bolt (fill), tilted −15°.
26
+ // Authored in a 1024 space; the outer transform fits the rotated cluster into 24×24 (currentColor).
27
+ ticket: `<g transform="translate(12 12) scale(0.0354) translate(-518.2 -535.2)"><g transform="rotate(-15 512 512)"><path d="M250 392H774L774 462C739 474 720 504 720 536C720 568 739 598 774 610V680H250V610C285 598 304 568 304 536C304 504 285 474 250 462V392Z" fill="none" stroke="currentColor" stroke-width="52" stroke-linejoin="miter" stroke-linecap="square"/><path d="M562.9 408.3L441.5 553.9L506.9 546.3L472.9 664.1L604 504L528.9 514.3Z" fill="currentColor"/></g></g>`,
23
28
  info: `<g fill="currentColor" fill-rule="evenodd"><path d="M14.22 7.78 L11.13 7.86 L9.4 9.21 L9.17 9.29 L10.15 9.29 L10.23 9.59 L9.32 13.73 L8.87 17.12 L8.57 18.78 L8.5 19.69 L8.27 20.74 L8.12 22.32 L8.04 22.4 L13.62 17.95 L11.96 17.95 L11.89 17.58 L12.41 15.69 L12.49 15.01 L12.87 13.73 L12.87 13.43 L13.24 12.15 L13.77 9.97 L14 8.68 L14.22 8.08Z"/><path d="M15.96 1.6 L12.94 1.6 L11.74 3.18 L11.51 3.63 L10.08 5.67 L12.79 5.59 L14.37 3.71Z"/></g>`,
24
29
  soundOn: `<g fill="currentColor" fill-rule="evenodd"><path d="M16.61 6.68 L17.16 8.4 L17.4 9.97 L17.4 13.88 L17.32 13.95 L17.16 15.44 L16.61 17.16 L18.88 13.72 L18.88 12.86 L18.96 12.78 L18.88 10.12Z"/><path d="M19.27 4.34 L19.58 4.88 L19.66 5.28 L20.05 6.14 L20.6 7.93 L20.91 9.5 L20.91 10.44 L20.99 10.51 L20.99 13.25 L20.91 13.33 L20.91 14.19 L20.76 15.13 L20.05 17.63 L19.27 19.43 L20.29 18.02 L21.15 16.61 L22.4 14.19 L22.4 9.58 L21.31 7.39 L20.29 5.74Z"/><path d="M13.17 1.76 L10.28 4.34 L6.29 8.17 L1.6 8.25 L1.6 15.6 L2.15 15.75 L6.29 16.3 L9.97 19.58 L13.17 22.24Z"/><path d="M11.69 5.59 L11.92 5.67 L11.92 19.04 L11.69 19.12 L7.07 14.82 L4.57 14.5 L4.42 14.35 L4.42 10.51 L4.57 10.36 L7.07 10.28Z"/></g>`,
25
30
  soundOff: `<g fill="currentColor" fill-rule="evenodd"><path d="M13.68 13.18 L12.53 14.4 L12.53 18.44 L12.3 18.51 L10.4 16.76 L9.33 17.83 L12.84 20.88 L13.75 21.56 L13.75 13.18Z"/><path d="M17.71 8.69 L17.49 8.91 L17.56 9.9 L17.64 9.98 L17.64 13.1 L17.33 14.7 L17.03 15.39 L18.78 12.88 L18.78 11.66 L18.86 11.58 L18.78 10.29Z"/><path d="M19.47 6.63 L19.85 7.47 L20.46 9.6 L20.53 10.13 L20.53 13.03 L20.08 15.01 L19.31 16.91 L20.61 14.93 L21.3 13.49 L21.52 13.18 L21.52 9.9 L20.76 8.53Z"/><path d="M20.91 2.21 L16.5 6.63 L13.98 9.3 L13.75 9.22 L13.75 1.6 L10.86 4.19 L7.05 7.85 L2.4 7.92 L2.48 8 L2.48 15.16 L6.51 15.7 L7.73 14.32 L5.3 14.02 L5.22 13.94 L5.22 10.13 L5.75 9.98 L7.81 9.9 L12.3 5.33 L12.53 5.41 L12.53 10.9 L10.32 13.26 L6.9 17.14 L2.55 22.4 L6.9 18.36 L9.79 15.47 L13.52 11.5 L18.25 5.71Z"/></g>`,
@@ -0,0 +1,12 @@
1
+ /* eslint-disable */
2
+ // Oswald — subset to numerals + currency/separator glyphs only — embedded as base64 woff2, used for
3
+ // the shell's numeric readouts (balance/bet/win/FS counter, autoplay countdown). Digit-only, so it's
4
+ // language-independent and tiny. Oswald is licensed under the SIL Open Font License 1.1.
5
+ // GENERATED by scripts/build-digit-font.mjs — regenerate, don't hand-edit.
6
+
7
+ export const SHELL_DIGIT_FONT_FAMILY = 'OswaldNum';
8
+
9
+ export const SHELL_DIGIT_FONT_CSS =
10
+ `@font-face{font-family:'OswaldNum';font-style:normal;font-display:swap;font-weight:500;src:url(data:font/woff2;base64,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) format('woff2');}` +
11
+ `@font-face{font-family:'OswaldNum';font-style:normal;font-display:swap;font-weight:600;src:url(data:font/woff2;base64,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) format('woff2');}` +
12
+ `@font-face{font-family:'OswaldNum';font-style:normal;font-display:swap;font-weight:700;src:url(data:font/woff2;base64,d09GMgABAAAAABYoABMAAAAAIUgAABW9AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGj8bgk4ccj9IVkFSgQYGYD9TVEFUWCceAIFML0QRCAqZLJQnC1gAMJU4ATYCJAOBLAQgBYUMByAbIx1lRE5aPZCpqkkJytvBN03TNE0NDNOeOK69CEJ7k6T2oSjtS9Paj8/XDgI4ZreMsG7cPpqikQvkTX5PNngex9L3AweA6RXB1aFrLSlEC+502XWbAhYOUKjZuRlFbvGJ+/l+1jaqoIjE0Xwgw6QGHeJAd15gmf7/z+3dDb9oIhSovyEpbB4aoeL10Wms4Xo6l2vY5pJStoCsqjpVtbUIRgFtdGyR8D+5E/6N+aW1bf9tQ0LVCNESySpJvHVoTcQT/LZrkeH18nOFlbj1gXgpUoiTJnKltu5dPXlZ+DlxzY8IkNoasJIqaRZl0QSb/81GLdaAm7jmV27nXVQa2TZ8oAlNpEEeeFqUlDn/dvrjAr6Yl5KYSG19HVZihibW3DSaaFpzbeLavm0Db5BVEreQCJFsE9f8XleAJU2LCvBv9L6kEh/YQId9j957H0ZBJ4Xzcymot4vD2E7gJi8TOGzy4Y/l+1cVFkVdeICVa5DCadpsItU8T5Cc/n6+P4umpk6KKpC1RQGvfVZaCdYgo+FwN8qjuWzueFM6pKUQlpIrEDk7T968EX33sorgr7netxTATTbJEeSuhKhQqM5Xlb2UfMdX0fgKh4oQgoNzZcp3feQBspuekHNz8+P+gK1+piNKEZIm5eFjLX0/wLzJZDYXYCiROyN3ak1lha9jowh8eL33T9g69zlxQY6kpo9h0tjtCytniQd2eoX8W0FMAD8fcmsydRk42cOYrcSHLPz/z73ad9uxYiySMJtRUy65yYeX15ToDZNBoDxgFg5RFhj9wAEJ2Qk1ofTOlJvFcPqXeHVbJkadGPnCV/VZCJoMiVlB6ARGHKrdaTGCJQj8fbxpJqycQKc8qdu0CF1MQM71p1vU4/PXe1RMNc6dyg5H18/38PmbgWBQhFBsIqLo08tcIANV4PgvAgqz5ClQpEadmFaoinkRPYx8BDD9RVXUnRpzgDBvecI153Rp0iBFCDWN6ohbItp2yJ9R+WJHjlN027J+i3Wm2/kv3OiP9JC/wYwc37D6U6TNlKYV8k/4q63FP2En5PdQAVMJe1aposXOyviA5/VW2LaQa+4+n1/ilGlCCO3iBSJjqkugKWFRJAgQU9Zp4kB5uMIUT4fZKDbn8mG2DIpigWQqE0uUwzoj5JOlfCEarRSb5VC6FjHVbbXRIQzG/cGQuautTq4j47r/zBc/dsfrizPlC5VqRzAUjsQTqWy+UCpX6o1ub7Da7m7vX9agwo18knssqEu1guj5r+fIKhOC9qpwyFOUr+EmXgWn1x+vLOGCXvPu/5b2s8OCCz/ysEjSZ0QBX3XrA0qDFqJQ29dQZ7d3r3OePoQL5ClZSEB9FpUjlof8N83Ib1xfDCVa7nGEDi5b/h3ff/fLLwbkA98TZxatA6XPcuZlw/S9x7twy2w4HN30M8okBZ7yglf8xD+3w326H/fbMra8/s9++y56GWRMY7XPk/5nKbrhV//1fwj8/N86xv+p7egwPHT+LL8k01ktuuhz2/kHtrHKmgxQp0KVbgqUI7tEg1ZBltpmkD8LCUcWLhHEMEm0Gi8mor8jXJZilCoBoWzxHv4QBSuIaXVqlArwf5jsk8PKLZVFU50dkOpkCo/Z/55rrKNWl95Rr7K+U6Hc65SPEOHhISll5NmNml9qNTizKvwSi8kFiqDC2NigVFGr20xl5kRQPVBAQK7YwEARHIofH/2CMu2ldGCbmiFXnmNtFRwyUp8dPOTK3Uu9MOCQ3aHPwMHDVGL5+Pw8AX2RNZzvHao70gsDIKE8x9oCGUkHJalSM2RIBJOzl6ivPVRuZT6U0BqfA1QuqYlNqAiGGaXn97NKCUOigQ6ClHr6VZUoWLuiTUlsDo6VdpBIZ/8pdLUI++z4ZBAkq9jxGSR79lXumfRgJRKC7VoKCJLGyp+t5revc35uU+4tLHebs0VkN4jB5ob39Tx7DWj2suD2ialiSLc26mzkhUo7UkjSPjOh8JidqM+O2K5Eg14DavaHaaa2pO4IuFfNITTo1zjIB7SJenuyXQDqdb3EDQglvOMmtbwEMh2XFV1NRIZQZdbbTOZu2U0HCLVgwG52+GBo+5s1UIw1ODDCaR/VrIuF5yzd2SyHkVXXWjIw6/1ymkoEZAbAShf3nyFTXlAFw1xiY6qZWpO6MgNAu6jXp3k32ghJFczq/kJPrO9RuUVvdx7H2IgWHL6eNO4kti95bIE289xtfYklWZzYljKnK9GAw4kKzCdma8mu3C7VpYe9ZC+SY4nh8k2SZnkmHGVkab+ZsIewIKuwyxVD8onrYsJ0TtiEmdhSm2QhNCAEZMFDAOVgCYHxsH+94i176lde5s9ql4Z/udS/1gxWHcXovyqbLBZq2oDL7gRWh9PiUksqsWigwaKB6uRs0emWo4+/WcOSu55Zj5+FPT54erV278D20Zniwd3VmDz7Ti7siP+0ZNLZuLx1YPssODdhd1pnHh3Y7p3JlP8tNbAf42wd6UcgiEjQQqxFyajRZpqvUgE+2qxmVFgLEChAVkuQL7MCDlQ0wfBQoAKuyAyKTwHHA+DU18C8+3Q33qUxyG24cdW0xfhIjpjM2uBjcHwvIZzV6OJqqivaqwti4rC850oENKAz4QG5OCOJ73qQnvC/nQn3BsoJCWXZkvu699wJeKdH2BlSNjtdE4OQHt14N15K58rkIBcvk2pFwKzLjC+wNXAz4EHy78g9rrsf1YrS571zgoMeeNjJzmjStmT4x1sRwubrYrP9YzSa+tRvXrZb/mMr255WphMm9VSi0C5hMuIQQCSBChnUhSbTRytGg9hFUiAIwuA+nylM7Ck5wcjviUmu5yZ31Fp4AKg0dMZgiBfJ8UlbqKjQ+moIDUkMQvWF1zKnKFh5A38iDLhZzRr0fRJlhnNdcgnMOPKkUlsezEgUOc7Juuz0bNBkNbu4Gge8xsWwrJDopibzQIzCWHBsTzsn2B5utVzIgcUiOHDNbkvgRU4FMxkhyhAcUoUjRUYT9bq07P1st3ODjUqOrqTCYAdnxyBHcpGrShOqjHq69+s2nkdUZUsxBNWjTWS2TCcaXJB01HBtHRVc3efCIIeKDOkc8Kwlymq+7U9c5T1DeO/yUrIb2qwpAhsXR0su01WtG7BfBI+D9vFuVvGjDZ8aw0sWu5ytZ9KWfmkMDhicXQ7ar5Jzt7exdLaUMpLnT58GG3cb8L+Ol2InbKmx3IKetnCMd4A0RWlFIFzBmPtXRfIycwS3gHGkk56bZpmbngsUiElphOKmFIj+O3cdQNuvHWJKnNoKunO6onDsShLnLJE4mxDclRfIM68nkkDNCW4mgL4vswnuygvkudcTSaBmBDe2E+wspsSpraEblysKx64lcc5i4DYhPYzEgpwCHY9OkxYIeJq/HvEXuPlcChd5aatqs2ZvfuRs5mhlR9H1m5vFQMTBQzL1DdDsVNf1+kDd0BVDhvXC9jRLJ/CpOyQiBuVIIU7PquH/sNHPnCKOrU/tvFenJA6KifZD5iC7judW7OJE6YpULRebgx87oeUDGF76bU18eCKKrytLwwYoMrFIJ3yJGwWWwvGwOawXwpdE2ga6B4uISS7UNMhDmDA9HhF5iipGh7SltrW1pbSlpGmyr+zwKVFBpH+vf6FniE6HSd3/uxS1Ej7kngpLsZFK/bH7oH0aPrtpcuOs8dgwRfMm6Jdr4CeO2hOyG3n7NAyw0A4hXp5SlyLqdFXkhCXFPlMqMWI9qdtLm1Td/priZFk+pToFgP7g2nCh5ACvWXJtuKRqoSm4wZfXl13en1dN1AmtwZVD9DAN2wmTz2QxeaXbj8zMbG02t/Xw5DFZTD4zCoPn/nZjuV/f7jY2+vBNVIRUQFIaQUSkaESkEBEpRCDMK+IqnvYDarCaGaQGYbQkCczJJWgyjgj/uhpCVSmWozQ3hyzLYeESIbd3e0R8TeT567WTnChttECZkOi3aP1DSsbPkwFm2S+/TvbNv1yrItt9GUxBI0UV1GIBTTRXlZsbe9pcEBkQkBxUYGltix9DRBudgflNlC+/DvORaKoqN/e2NPkgMiAgOajA0toGHCB8mwEncEkbAJgQkde/D1gg5J3BCVyyAAAmJOT03wcsEH+NgRO45AAAExLy8vcBBgCuG3wDapXDg06pVCPVA3EANc+RXtrgh9o9VYT+p8lFGNyQhxVuwDekZllYdXIO/dA15j7zgtGZhJ3Gq9Ov02/Sb9Pv0v/xMXwKn8Y32B+cRARZkflOLnC/+RPZ+dkd2aHsx+xRepI+FvoXsQcpYLUB1JcXHTjK3zGw3uyXDJLCDyOXglbPT19w/K3lx2b7mxPHZYYD0MHwDUWeJ1DBP4MY3V8wp/8BdX2ODlhXQdx7aeGnIej65g8O18sh12zX0GFjdBTkaKD9r1WKB1sUSKbyRwsWa1Hzl+ctxf1Tw23yuDTNVxpjGqJ2gzmGAT0c1EdVOdfRp1UKfaj77XYYEP5AXLCpo140fhmE/cbcJk0okHHuZE7vaK8eCmJy2nccp6yAfpKWDV+Kp7i/4Esa8EqhszRcmfOchpgj6OPsN5SbGWGaDhvWQpd806kc+qpr2DjD8az2HvbtBFa9UHARJ0GpKE79BPHdagFiyyHsvV1kjuPcnZNybo58Z+AiDvDjYkeRYlQsghgd6cHmv9vwyTRK01uhL+rkp2maTipX2uKBTk2FtOlZWq09GjHahA76/xOQ0xTQW23a0Ir/1VarpZXLinlfHncsp1yzc5wkyVcACBQYGgFMq8rfCCGE+cGO6Far1ep7CIYqY+I4nvM1ITVN04a+8lvTNCsbmhk9F8dxwCDEKZ8EIzIwcO0wijhPoiiKjFKp1DbUmQnH9bgl5JwcP+5bQv9Zr9ehhywydNwoeM1RXrGUPkpGMBW/oNs7Cpz5Nh4O/gPmK6m/vh+4pm5GSRQSUZ6ptBr11ghTF5Tyoad96fV6wwRyfUQURUZTe9UhhL48sixL70IQzf1IuS4znWVMhjHOOJ5SXGCMMiYjbM8ESU8xVseJq+u6g9mRDlPIh5fYh4eHNvLT/E+OsPezm1piQFEJIUkiS+qzqqq6SwDFGFOpv9rTdV3X+i75qqqqy/c3JiRJMi+hh5M/CWUESVFJpctYWwQv27Zp+DhiRUqpzo0vRkBmZjhzyOdqtaq7RtjTPwhgErT92b9cdwYC5ScLUN9Fv0UVsKocgSHv24V9cNxDP7DgGZiAgB6OwUlQvr8kzMxsJJvRo8LPsTDXalCa4A27cKG/OcrMECJZotLxKzY3RyOYgl9sAXmKsQ+pNiuKEkxnxSTwfDo1tT3BVmN8RUYYZMTcnqOgyZBPEti5utcaQdJzZbc2fK6q6TJUHybgT2GU5loMZYSbm8ce9B/+zKGcEa6UDm0l2/2NXDc6DfIcD25iaozyUVTyhkCefID0sAHUooMKWCWyjFyxYQZ+QSFfy6DRG0N3nVYL4/Ge24PJyP2lqa/ww7VqrlUJJUstyJOj7OfhFUrZaf65T+n+1+UUxBqjEZjK7CVXWjwzA35E/vX3/9OC6R2uhB0d/gdBkICuashNWxdCGK7FYQSWuKVhLBCzhKOm8b0Dt6fBfmXHHo2LdkKSMkQ5jhRpJopWY4QXRZGn9y1YQq2dFfeoyw/r3/f3WKyWhJlFQLVpgk4fLayWOC+yyclK2eNQjdjnOPJqNYWPPVe1V2JfKmMjOzAa4aICFwn2dGkcY7yUYIx7T1JqGNxbXV1NY0zM9vDwZanVUgGT+R32pWnCUrzyl2CrcnBhaDMydS4NkKQ9WPIHLJEvVZj+0H36Z+vwb3DwV0QZurRfigu+I7RpnWF94297ydfqUrcSGxXHygznbW0o+O29GuoZTCVfxydkquzm4moaQ4w97wlIBnuZPwajSIuESRdXt8qaR9ljTUK+V0pW6NZ394+O3PbR0bjnmEUtl5MyYJ8xU/RdDUkVN82tVBq9cGUN5MMX6A8X9k6SLi6Q+2TT52VIQV40dOzBfJz+SeKI9vUZxqtGpcKLjFJoVHBpOgLeliqC0ol/lUaju9u2X4knOB3czJoQ+gkhpmH7zqOe+wcNpYUCG4E5bG25Gj7eu7qjuVd7wVCben69OWIPeIlf6L2jAkLNyv/1Rq1UaK2iPyrwv2Gn3e50IJwVv5dBuK5+fl5UDYWWf6PFau3vY7Ur/unBg4dJYR2ReuDU0vb+wcE+GnB7qz9b9h4Z+/Lk6+lRXcmz8PUdv7jBHyfdnB54e3/mU/3lqXBpO4L4feUPZovlYMdCvkbp4j2z4r3D5Y2Xnm/1MfBA7BW9s5PLLS3l3kilh6vMYIHj+GvYu41DnCU+wlWqrKjr97zyd16h3ZrPAPWAeWXZieMEgRBdX0Fx5qbrhAgCxxkFw/Ao5igKzDspiE/m9vvjw9X1/z/u+vHxvT6XJYppq8ozpx+urlukVLSCDs6rWIo/f3X46mIORr90TeMcG9uW3Vf08tKss08daXg6N7e7m2nomXMVB9nFzl/+PCv+edDVtehat////67eLrWy79jQeJqmyWCPaDWbTCab7WP0BUEwqZqu65qqOuyigogsso6Ihn+aprMj05Pp1HCv6EmIRbYTw9A079WgVElSDd/hkZGhgS7RFGznz5zY20mS5iNUUc3Ba8fHx8drSTJ6oqZNJGOT5y0ZyeHsUep9nz18nM/n808OD/d2dnZ2jg8PTk9PT48OA8ayiYz//4Djql/8/fv7+/XpT4t/fr7/uF6rZTKZ9tb1z/uns7NrLytrmibS3tVFiiJpQb+9XDjO/U9Cj6SsgUS/Crnxk8/3s6HatK/uTsyLE1ftqnYO/SrywaNq/n/4f1lhVaHkAYDrFmY0bl8fxBz6P/x/0qnqxvIRL40NLdhBbYELUmJWLHUPguMuBMXjtDN3IDK+Q1Gswk59hqx4gxQn/g8XHkIyNaS+sFdxlGuOeeTHMgpjmxZQAHyqZxHtBEHOQVqMiKEiBUWInHCGhsPQsQQrtY7QeA3x8fH/zeEHkNgFmr4JfnEJXGMfJGoD4bGE6OgVRE8LYeb4MTdDZeFwLtYO+UZ4hoeDP/GsSzxrh8ryouBOxXnR8KQCvBjEsHuxUHHDi0MliRcPFZ0rPZEgQ4mnEqofzmCq04OF+wMR9Lw4EDhTPsIb0eUzUI1rg6IhqdAA4yYPTZe/PQmGiJvtzcXEUSQyKmzMGDYSJq5H07oCmk+VZggbJl2ROvWacAiMVJqeqjSmGIqjGsHWCcUu0nwGOkScNNEyZCvWhYCLwcfk6BPldSZZmljZ0rRD8RVI1iVDlsLo+ZkKEQwYWxVyVOUCXj1KgKuY3zGUo7S2r8bAJLJfFud3QsTIkCkPohwRCmFSXDE2BjLUmC7PxhMV5XowByJIYN6FNLU4nlFp2jDQxqAoFIs5iiAcyn92uiG1bhxLfDwjpg/7PwUxXgAAAAA=) format('woff2');}`;