@trading-game/design-intelligence-layer 1.0.5 → 1.0.7

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/index.d.cts CHANGED
@@ -337,7 +337,22 @@ declare function DrawerTrigger({ ...props }: React$1.ComponentProps<typeof Drawe
337
337
  declare function DrawerPortal({ ...props }: React$1.ComponentProps<typeof Drawer$1.Portal>): react_jsx_runtime.JSX.Element;
338
338
  declare function DrawerClose({ ...props }: React$1.ComponentProps<typeof Drawer$1.Close>): react_jsx_runtime.JSX.Element;
339
339
  declare function DrawerOverlay({ className, ...props }: React$1.ComponentProps<typeof Drawer$1.Overlay>): react_jsx_runtime.JSX.Element;
340
- declare function DrawerContent({ className, children, ...props }: React$1.ComponentProps<typeof Drawer$1.Content>): react_jsx_runtime.JSX.Element;
340
+ declare function DrawerContent({ className, children, dismiss, ...props }: React$1.ComponentProps<typeof Drawer$1.Content> & {
341
+ /**
342
+ * How the drawer offers to close.
343
+ *
344
+ * `"handle"` (default, unchanged) is the drag pill, shown only on the
345
+ * bottom direction. `"close"` swaps it for the same control Dialog and
346
+ * Sheet use — `NavigationButton size="sm"` around a `size-4` icon, a 32px
347
+ * circle on a 16px glyph — and shows it in every direction.
348
+ *
349
+ * The button sits in flow on its own row, not absolutely positioned, so
350
+ * nothing shares its line and the header always starts below it. `p-4 pb-0`
351
+ * puts it 16px from the top and right edges, matching the header's own
352
+ * padding.
353
+ */
354
+ dismiss?: "handle" | "close";
355
+ }): react_jsx_runtime.JSX.Element;
341
356
  declare function DrawerHeader({ className, ...props }: React$1.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
342
357
  declare function DrawerFooter({ className, ...props }: React$1.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
343
358
  declare function DrawerTitle({ className, ...props }: React$1.ComponentProps<typeof Drawer$1.Title>): react_jsx_runtime.JSX.Element;
@@ -810,7 +825,7 @@ interface SlideToConfirmProps extends Omit<React$1.ComponentProps<"div">, "onDra
810
825
  declare function SlideToConfirm({ onConfirm, label, confirmedLabel, disabled, confirmed: controlledConfirmed, className, ...props }: SlideToConfirmProps): react_jsx_runtime.JSX.Element;
811
826
 
812
827
  interface StepperProps {
813
- /** Uppercase label above the amount, e.g. "Stake (USDT)". */
828
+ /** Sentence-case caption above the amount, e.g. "Stake (USDT)". */
814
829
  label?: React$1.ReactNode;
815
830
  value?: number;
816
831
  defaultValue?: number;
@@ -1117,7 +1132,7 @@ interface GameLoadingBlockProps {
1117
1132
  label?: string;
1118
1133
  /** When true, swaps the label for a "taking longer" message. */
1119
1134
  delayed?: boolean;
1120
- /** Plays the zoom-out reveal and hides the bar. */
1135
+ /** Plays the reveal and hides the bar. */
1121
1136
  exiting?: boolean;
1122
1137
  /** Fires once the exit animation finishes. */
1123
1138
  onExitEnd?: () => void;
@@ -1128,20 +1143,35 @@ interface GameLoadingBlockProps {
1128
1143
  */
1129
1144
  contained?: boolean;
1130
1145
  /**
1131
- * Optional backdrop image (e.g. the app's `dot-pattern.webp`) for a
1132
- * pixel-perfect match with the game shell. Omit to use the token-derived
1133
- * dotted backdrop.
1146
+ * The product mark, as a URL to a transparent PNG or SVG. This block ships
1147
+ * in the package, so it cannot reach into a consuming app's asset folder —
1148
+ * pass the theme-matched file (`chmp-trd-logo-brand-light.png` in light,
1149
+ * `…-dark.png` in dark). The same URL draws the resting mark *and* cuts the
1150
+ * hole the reveal grows, so both always agree. Omit it and the reveal
1151
+ * degrades to a plain fade with no mark.
1152
+ */
1153
+ logoSrc?: string;
1154
+ /**
1155
+ * Optional backdrop image for a pixel-perfect match with the game shell.
1156
+ * Replaces the token-derived tinted canvas; the mark is still knocked out
1157
+ * of it, so the reveal works either way.
1134
1158
  */
1135
1159
  backgroundImageUrl?: string;
1136
1160
  className?: string;
1137
1161
  }
1138
1162
  /**
1139
- * Determinate loading splash for game entry: dotted brand backdrop, monogram,
1140
- * and a progress bar with a shimmer that keeps signalling life while a stage
1141
- * is held. Exits with a zoom-out reveal, or a plain fade under
1142
- * `prefers-reduced-motion`.
1163
+ * Determinate loading splash for game entry: the tinted-canvas backdrop, the
1164
+ * product mark, and a progress bar whose shimmer keeps signalling life while a
1165
+ * stage is held.
1166
+ *
1167
+ * The exit is a knock-out reveal. The mark is cut out of the backdrop as a
1168
+ * hole, and only that hole grows — the backdrop itself never moves, so its
1169
+ * gradient and dot grid stay put instead of appearing to zoom. The backdrop
1170
+ * fades across the same beat, so the app bleeds through from about a third of
1171
+ * the way in rather than arriving all at once. Under
1172
+ * `prefers-reduced-motion` the whole thing is a plain fade.
1143
1173
  */
1144
- declare function GameLoadingBlock({ progress, label, delayed, exiting, onExitEnd, contained, backgroundImageUrl, className, }: GameLoadingBlockProps): react_jsx_runtime.JSX.Element;
1174
+ declare function GameLoadingBlock({ progress, label, delayed, exiting, onExitEnd, contained, logoSrc, backgroundImageUrl, className, }: GameLoadingBlockProps): react_jsx_runtime.JSX.Element;
1145
1175
 
1146
1176
  declare function cn(...inputs: ClassValue[]): string;
1147
1177
 
package/dist/index.d.ts CHANGED
@@ -337,7 +337,22 @@ declare function DrawerTrigger({ ...props }: React$1.ComponentProps<typeof Drawe
337
337
  declare function DrawerPortal({ ...props }: React$1.ComponentProps<typeof Drawer$1.Portal>): react_jsx_runtime.JSX.Element;
338
338
  declare function DrawerClose({ ...props }: React$1.ComponentProps<typeof Drawer$1.Close>): react_jsx_runtime.JSX.Element;
339
339
  declare function DrawerOverlay({ className, ...props }: React$1.ComponentProps<typeof Drawer$1.Overlay>): react_jsx_runtime.JSX.Element;
340
- declare function DrawerContent({ className, children, ...props }: React$1.ComponentProps<typeof Drawer$1.Content>): react_jsx_runtime.JSX.Element;
340
+ declare function DrawerContent({ className, children, dismiss, ...props }: React$1.ComponentProps<typeof Drawer$1.Content> & {
341
+ /**
342
+ * How the drawer offers to close.
343
+ *
344
+ * `"handle"` (default, unchanged) is the drag pill, shown only on the
345
+ * bottom direction. `"close"` swaps it for the same control Dialog and
346
+ * Sheet use — `NavigationButton size="sm"` around a `size-4` icon, a 32px
347
+ * circle on a 16px glyph — and shows it in every direction.
348
+ *
349
+ * The button sits in flow on its own row, not absolutely positioned, so
350
+ * nothing shares its line and the header always starts below it. `p-4 pb-0`
351
+ * puts it 16px from the top and right edges, matching the header's own
352
+ * padding.
353
+ */
354
+ dismiss?: "handle" | "close";
355
+ }): react_jsx_runtime.JSX.Element;
341
356
  declare function DrawerHeader({ className, ...props }: React$1.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
342
357
  declare function DrawerFooter({ className, ...props }: React$1.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
343
358
  declare function DrawerTitle({ className, ...props }: React$1.ComponentProps<typeof Drawer$1.Title>): react_jsx_runtime.JSX.Element;
@@ -810,7 +825,7 @@ interface SlideToConfirmProps extends Omit<React$1.ComponentProps<"div">, "onDra
810
825
  declare function SlideToConfirm({ onConfirm, label, confirmedLabel, disabled, confirmed: controlledConfirmed, className, ...props }: SlideToConfirmProps): react_jsx_runtime.JSX.Element;
811
826
 
812
827
  interface StepperProps {
813
- /** Uppercase label above the amount, e.g. "Stake (USDT)". */
828
+ /** Sentence-case caption above the amount, e.g. "Stake (USDT)". */
814
829
  label?: React$1.ReactNode;
815
830
  value?: number;
816
831
  defaultValue?: number;
@@ -1117,7 +1132,7 @@ interface GameLoadingBlockProps {
1117
1132
  label?: string;
1118
1133
  /** When true, swaps the label for a "taking longer" message. */
1119
1134
  delayed?: boolean;
1120
- /** Plays the zoom-out reveal and hides the bar. */
1135
+ /** Plays the reveal and hides the bar. */
1121
1136
  exiting?: boolean;
1122
1137
  /** Fires once the exit animation finishes. */
1123
1138
  onExitEnd?: () => void;
@@ -1128,20 +1143,35 @@ interface GameLoadingBlockProps {
1128
1143
  */
1129
1144
  contained?: boolean;
1130
1145
  /**
1131
- * Optional backdrop image (e.g. the app's `dot-pattern.webp`) for a
1132
- * pixel-perfect match with the game shell. Omit to use the token-derived
1133
- * dotted backdrop.
1146
+ * The product mark, as a URL to a transparent PNG or SVG. This block ships
1147
+ * in the package, so it cannot reach into a consuming app's asset folder —
1148
+ * pass the theme-matched file (`chmp-trd-logo-brand-light.png` in light,
1149
+ * `…-dark.png` in dark). The same URL draws the resting mark *and* cuts the
1150
+ * hole the reveal grows, so both always agree. Omit it and the reveal
1151
+ * degrades to a plain fade with no mark.
1152
+ */
1153
+ logoSrc?: string;
1154
+ /**
1155
+ * Optional backdrop image for a pixel-perfect match with the game shell.
1156
+ * Replaces the token-derived tinted canvas; the mark is still knocked out
1157
+ * of it, so the reveal works either way.
1134
1158
  */
1135
1159
  backgroundImageUrl?: string;
1136
1160
  className?: string;
1137
1161
  }
1138
1162
  /**
1139
- * Determinate loading splash for game entry: dotted brand backdrop, monogram,
1140
- * and a progress bar with a shimmer that keeps signalling life while a stage
1141
- * is held. Exits with a zoom-out reveal, or a plain fade under
1142
- * `prefers-reduced-motion`.
1163
+ * Determinate loading splash for game entry: the tinted-canvas backdrop, the
1164
+ * product mark, and a progress bar whose shimmer keeps signalling life while a
1165
+ * stage is held.
1166
+ *
1167
+ * The exit is a knock-out reveal. The mark is cut out of the backdrop as a
1168
+ * hole, and only that hole grows — the backdrop itself never moves, so its
1169
+ * gradient and dot grid stay put instead of appearing to zoom. The backdrop
1170
+ * fades across the same beat, so the app bleeds through from about a third of
1171
+ * the way in rather than arriving all at once. Under
1172
+ * `prefers-reduced-motion` the whole thing is a plain fade.
1143
1173
  */
1144
- declare function GameLoadingBlock({ progress, label, delayed, exiting, onExitEnd, contained, backgroundImageUrl, className, }: GameLoadingBlockProps): react_jsx_runtime.JSX.Element;
1174
+ declare function GameLoadingBlock({ progress, label, delayed, exiting, onExitEnd, contained, logoSrc, backgroundImageUrl, className, }: GameLoadingBlockProps): react_jsx_runtime.JSX.Element;
1145
1175
 
1146
1176
  declare function cn(...inputs: ClassValue[]): string;
1147
1177
 
package/dist/index.js CHANGED
@@ -162,7 +162,7 @@ var buttonVariants = cva(
162
162
  variants: {
163
163
  variant: {
164
164
  // Primary brand blue (#2323FF)
165
- primary: "bg-background-brand-default text-text-on-brand-static hover:bg-background-brand-hover active:bg-background-brand-pressed active:opacity-100 disabled:[background-image:linear-gradient(var(--background-disabled-default),var(--background-disabled-default))] disabled:text-text-disabled-default",
165
+ primary: "bg-background-brand-default text-text-on-brand-static hover:bg-background-brand-hover active:bg-background-brand-pressed active:opacity-100 disabled:opacity-(--opacity-disabled)",
166
166
  // Primary Inverse — white bg + blue text; for use on dark/coloured surfaces
167
167
  // On-brand family — for buttons standing on a brand-coloured surface
168
168
  // (NOT theme inverses): white pill with primary ink, white outline,
@@ -181,7 +181,7 @@ var buttonVariants = cva(
181
181
  // (white-alpha-32 = 1.84:1 on brand, against 1.71:1 here) so both
182
182
  // read as the same quiet edge. Its contrast is higher only because it
183
183
  // has no fill behind it — there, the border IS the button.
184
- secondary: "bg-background-primary-surface border-[1.5px] border-border-control-default text-text-prominent-default hover:bg-background-secondary-surface disabled:[background-image:linear-gradient(var(--background-disabled-default),var(--background-disabled-default))] disabled:border-border-disabled-default disabled:text-text-disabled-default",
184
+ secondary: "button-disabled-secondary bg-background-primary-surface border-[1.5px] border-border-control-default text-text-prominent-default hover:bg-background-secondary-surface",
185
185
  // Secondary Inverse — white border + white text; for use on dark/coloured surfaces
186
186
  "secondary-on-brand": "bg-transparent border-[1.5px] border-(--primitive-white-alpha-32) text-text-on-brand-static hover:bg-(--primitive-white-alpha-8) disabled:border-(--primitive-white-alpha-16) disabled:text-text-on-brand-disabled-default",
187
187
  tertiary: "bg-transparent text-text-prominent-default hover:bg-background-hover-default disabled:text-text-disabled-default",
@@ -192,7 +192,7 @@ var buttonVariants = cva(
192
192
  // hover/pressed via the state-layer glazes stacked over the solid
193
193
  // fill); `frosted-on-brand` is the white frost for coloured/art
194
194
  // surfaces (hover thickens the frost, press thins it).
195
- frosted: "bg-background-brand-selected text-text-brand-selected active:opacity-100 hover:[background-image:linear-gradient(var(--background-hover-default),var(--background-hover-default))] active:[background-image:linear-gradient(var(--background-pressed-default),var(--background-pressed-default))] disabled:[background-image:linear-gradient(var(--background-disabled-default),var(--background-disabled-default))] disabled:text-text-disabled-default",
195
+ frosted: "bg-background-brand-selected text-text-brand-selected active:opacity-100 hover:[background-image:linear-gradient(var(--background-hover-default),var(--background-hover-default))] active:[background-image:linear-gradient(var(--background-pressed-default),var(--background-pressed-default))] disabled:opacity-(--opacity-disabled-frosted)",
196
196
  "frosted-on-brand": "bg-(--primitive-white-alpha-24) backdrop-blur-md text-text-on-brand-static hover:bg-(--primitive-white-alpha-32) active:bg-(--primitive-white-alpha-16) active:opacity-100 disabled:bg-(--primitive-white-alpha-8) disabled:text-text-on-brand-disabled-default",
197
197
  /* @deprecated aliases — shimmer became the `shimmer` boolean prop;
198
198
  the inverse names became the on-brand family; `glass` became
@@ -2465,7 +2465,7 @@ function Checkbox(_a) {
2465
2465
  __spreadProps(__spreadValues({
2466
2466
  "data-slot": "checkbox",
2467
2467
  className: cn(
2468
- "peer size-4 shrink-0 rounded-2xs border border-border-default-default bg-background-primary-surface transition-colors outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:cursor-not-allowed disabled:border-border-default-default disabled:text-text-disabled-default data-[state=checked]:border-transparent data-[state=checked]:bg-background-brand-default data-[state=checked]:text-text-on-brand-static",
2468
+ "peer size-4 shrink-0 rounded-2xs border border-border-default-default bg-background-primary-surface transition-colors outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:cursor-not-allowed disabled:opacity-(--opacity-disabled) data-[state=checked]:border-transparent data-[state=checked]:bg-background-brand-default data-[state=checked]:text-text-on-brand-static",
2469
2469
  className
2470
2470
  )
2471
2471
  }, props), {
@@ -3014,6 +3014,7 @@ function ContextMenuShortcut(_a) {
3014
3014
  }
3015
3015
 
3016
3016
  // components/ui/drawer.tsx
3017
+ import { XIcon as XIcon2 } from "lucide-react";
3017
3018
  import { Drawer as DrawerPrimitive } from "vaul";
3018
3019
  import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
3019
3020
  function Drawer(_a) {
@@ -3052,10 +3053,12 @@ function DrawerOverlay(_a) {
3052
3053
  function DrawerContent(_a) {
3053
3054
  var _b = _a, {
3054
3055
  className,
3055
- children
3056
+ children,
3057
+ dismiss = "handle"
3056
3058
  } = _b, props = __objRest(_b, [
3057
3059
  "className",
3058
- "children"
3060
+ "children",
3061
+ "dismiss"
3059
3062
  ]);
3060
3063
  return /* @__PURE__ */ jsxs15(DrawerPortal, { "data-slot": "drawer-portal", children: [
3061
3064
  /* @__PURE__ */ jsx23(DrawerOverlay, {}),
@@ -3073,7 +3076,15 @@ function DrawerContent(_a) {
3073
3076
  )
3074
3077
  }, props), {
3075
3078
  children: [
3076
- /* @__PURE__ */ jsx23("div", { className: "mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-border-default-default group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }),
3079
+ dismiss === "handle" ? /* @__PURE__ */ jsx23("div", { className: "mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-border-default-default group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }) : /* @__PURE__ */ jsx23("div", { className: "flex shrink-0 justify-end p-4 pb-0", children: /* @__PURE__ */ jsx23(DrawerPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx23(
3080
+ NavigationButton,
3081
+ {
3082
+ "data-slot": "drawer-close",
3083
+ size: "sm",
3084
+ "aria-label": "Close",
3085
+ children: /* @__PURE__ */ jsx23(XIcon2, { className: "size-4" })
3086
+ }
3087
+ ) }) }),
3077
3088
  children
3078
3089
  ]
3079
3090
  })
@@ -4761,7 +4772,7 @@ function NativeSelect(_a) {
4761
4772
  "data-slot": "native-select",
4762
4773
  "data-size": resolvedSize,
4763
4774
  className: cn(
4764
- "w-full min-w-0 appearance-none rounded-xs border border-border-default-default bg-background-primary-surface px-3 pr-9 text-text-prominent-default transition-[color,box-shadow] outline-none selection:bg-background-brand-default selection:text-text-on-brand-static disabled:pointer-events-none disabled:cursor-not-allowed disabled:[background-image:linear-gradient(var(--background-disabled-default),var(--background-disabled-default))]",
4775
+ "w-full min-w-0 appearance-none rounded-xs border border-border-default-default bg-background-primary-surface px-3 pr-9 text-text-prominent-default transition-[color,box-shadow] outline-none disabled:text-text-disabled-default selection:bg-background-brand-default selection:text-text-on-brand-static disabled:pointer-events-none disabled:cursor-not-allowed disabled:[background-image:linear-gradient(var(--background-disabled-default),var(--background-disabled-default))]",
4765
4776
  "focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-soft",
4766
4777
  sizeClasses[resolvedSize],
4767
4778
  className
@@ -4771,7 +4782,7 @@ function NativeSelect(_a) {
4771
4782
  /* @__PURE__ */ jsx37(
4772
4783
  ChevronDownIcon4,
4773
4784
  {
4774
- className: "pointer-events-none absolute top-1/2 right-3.5 size-4 -translate-y-1/2 text-icon-subtle-default select-none",
4785
+ className: "pointer-events-none absolute top-1/2 right-3.5 size-4 -translate-y-1/2 text-icon-subtle-default select-none group-has-[select:disabled]/native-select:text-icon-disabled-default",
4775
4786
  "aria-hidden": "true",
4776
4787
  "data-slot": "native-select-icon"
4777
4788
  }
@@ -5483,7 +5494,7 @@ function RadioGroupItem(_a) {
5483
5494
  __spreadProps(__spreadValues({
5484
5495
  "data-slot": "radio-group-item",
5485
5496
  className: cn(
5486
- "aspect-square size-4 shrink-0 rounded-full border border-border-default-default bg-background-primary-surface transition-[color,box-shadow] outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong data-[state=checked]:border-border-brand-selected disabled:cursor-not-allowed disabled:border-border-default-default disabled:text-text-disabled-default aria-invalid:border-border-error-default aria-invalid:ring-ring-error-soft",
5497
+ "aspect-square size-4 shrink-0 rounded-full border border-border-default-default bg-background-primary-surface transition-[color,box-shadow] outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong data-[state=checked]:border-border-brand-selected disabled:cursor-not-allowed disabled:opacity-(--opacity-disabled) aria-invalid:border-border-error-default aria-invalid:ring-ring-error-soft",
5487
5498
  className
5488
5499
  )
5489
5500
  }, props), {
@@ -5610,7 +5621,7 @@ function ScrollBar(_a) {
5610
5621
  }
5611
5622
 
5612
5623
  // components/ui/sheet.tsx
5613
- import { XIcon as XIcon2 } from "lucide-react";
5624
+ import { XIcon as XIcon3 } from "lucide-react";
5614
5625
  import { Dialog as SheetPrimitive } from "radix-ui";
5615
5626
  import { jsx as jsx46, jsxs as jsxs25 } from "react/jsx-runtime";
5616
5627
  function Sheet(_a) {
@@ -5682,7 +5693,7 @@ function SheetContent(_a) {
5682
5693
  size: "sm",
5683
5694
  "aria-label": "Close",
5684
5695
  className: "absolute top-4 right-4",
5685
- children: /* @__PURE__ */ jsx46(XIcon2, { className: "size-4" })
5696
+ children: /* @__PURE__ */ jsx46(XIcon3, { className: "size-4" })
5686
5697
  }
5687
5698
  ) })
5688
5699
  ]
@@ -7022,11 +7033,18 @@ function Stepper({
7022
7033
  }
7023
7034
  }, [currentValue, decimalPlaces, isFocused]);
7024
7035
  function commit(next) {
7025
- const clamped = clamp(next, min, max);
7026
- const rounded = decimalPlaces > 0 ? parseFloat(clamped.toFixed(decimalPlaces)) : Math.round(clamped);
7027
- if (!isControlled) setInternalValue(rounded);
7028
- setDisplayString(formatValue(rounded, decimalPlaces));
7029
- onValueChange == null ? void 0 : onValueChange(rounded);
7036
+ let committed;
7037
+ if (next <= min) {
7038
+ committed = min;
7039
+ } else if (next >= max) {
7040
+ committed = max;
7041
+ } else {
7042
+ const rounded = decimalPlaces > 0 ? parseFloat(next.toFixed(decimalPlaces)) : Math.round(next);
7043
+ committed = clamp(rounded, min, max);
7044
+ }
7045
+ if (!isControlled) setInternalValue(committed);
7046
+ setDisplayString(formatValue(committed, decimalPlaces));
7047
+ onValueChange == null ? void 0 : onValueChange(committed);
7030
7048
  }
7031
7049
  function handleDecrement() {
7032
7050
  commit(currentValue - step);
@@ -7072,7 +7090,11 @@ function Stepper({
7072
7090
  "data-slot": "stepper",
7073
7091
  "data-disabled": disabled || void 0,
7074
7092
  className: cn(
7075
- "flex w-full items-center justify-between gap-4",
7093
+ // Two rows: the label spans the control, then the -/value/+ row sits
7094
+ // under it with a 4px gap. The label is deliberately NOT inside the
7095
+ // value column — nesting it there makes the buttons centre against the
7096
+ // label+value stack, which drops them below the number.
7097
+ "flex w-full flex-col gap-1",
7076
7098
  // No opacity here on purpose. The +/- are Buttons and already carry
7077
7099
  // their own disabled treatment; dimming the wrapper too multiplied
7078
7100
  // with theirs (24% × 24% ≈ 6%) and made them all but invisible.
@@ -7081,63 +7103,72 @@ function Stepper({
7081
7103
  className
7082
7104
  ),
7083
7105
  children: [
7084
- /* @__PURE__ */ jsx53(
7085
- Button,
7106
+ label != null && /* @__PURE__ */ jsx53(
7107
+ "span",
7086
7108
  {
7087
- type: "button",
7088
- variant: "frosted",
7089
- size: "icon-lg",
7090
- onClick: handleDecrement,
7091
- disabled: disabled || currentValue <= min,
7092
- "aria-label": "Decrease value",
7093
- children: /* @__PURE__ */ jsx53(Minus, {})
7109
+ "data-slot": "stepper-label",
7110
+ className: cn(
7111
+ "type-stepper-stake-label text-center",
7112
+ disabled ? "text-text-disabled-default" : "text-text-subtle-default"
7113
+ ),
7114
+ children: label
7094
7115
  }
7095
7116
  ),
7096
- /* @__PURE__ */ jsxs31("div", { className: "flex min-w-0 flex-col items-center", children: [
7097
- label != null && /* @__PURE__ */ jsx53(
7098
- "span",
7099
- {
7100
- className: cn(
7101
- "type-stepper-stake-label",
7102
- disabled ? "text-text-disabled-default" : "text-text-subtle-default"
7103
- ),
7104
- children: label
7105
- }
7106
- ),
7107
- /* @__PURE__ */ jsx53(
7108
- "input",
7109
- {
7110
- type: "text",
7111
- inputMode: "decimal",
7112
- role: "spinbutton",
7113
- "aria-valuemin": min === -Infinity ? void 0 : min,
7114
- "aria-valuemax": max === Infinity ? void 0 : max,
7115
- "aria-valuenow": currentValue,
7116
- "aria-label": ariaLabel,
7117
- value: displayString,
7118
- onChange: handleInputChange,
7119
- onBlur: handleBlur,
7120
- onFocus: handleFocus,
7121
- onKeyDown: handleKeyDown,
7122
- disabled,
7123
- placeholder,
7124
- id,
7125
- name,
7126
- size: Math.max(displayString.length, 1),
7127
- className: "type-stepper-stake-amount w-full min-w-0 border-0 bg-transparent text-center text-text-prominent-default outline-none disabled:text-text-disabled-default [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
7128
- }
7129
- )
7130
- ] }),
7131
- /* @__PURE__ */ jsx53(
7132
- Button,
7117
+ /* @__PURE__ */ jsxs31(
7118
+ "div",
7133
7119
  {
7134
- type: "button",
7135
- variant: "frosted",
7136
- size: "icon-lg",
7137
- onClick: handleIncrement,
7138
- disabled: disabled || currentValue >= max,
7139
- "aria-label": "Increase value",
7140
- children: /* @__PURE__ */ jsx53(Plus, {})
7120
+ "data-slot": "stepper-row",
7121
+ className: "flex w-full items-center justify-between gap-4",
7122
+ children: [
7123
+ /* @__PURE__ */ jsx53(
7124
+ Button,
7125
+ {
7126
+ type: "button",
7127
+ variant: "frosted",
7128
+ size: "icon-lg",
7129
+ onClick: handleDecrement,
7130
+ disabled: disabled || currentValue <= min,
7131
+ "aria-label": "Decrease value",
7132
+ children: /* @__PURE__ */ jsx53(Minus, {})
7133
+ }
7134
+ ),
7135
+ /* @__PURE__ */ jsx53(
7136
+ "input",
7137
+ {
7138
+ type: "text",
7139
+ inputMode: "decimal",
7140
+ role: "spinbutton",
7141
+ "aria-valuemin": min === -Infinity ? void 0 : min,
7142
+ "aria-valuemax": max === Infinity ? void 0 : max,
7143
+ "aria-valuenow": currentValue,
7144
+ "aria-label": ariaLabel,
7145
+ value: displayString,
7146
+ onChange: handleInputChange,
7147
+ onBlur: handleBlur,
7148
+ onFocus: handleFocus,
7149
+ onKeyDown: handleKeyDown,
7150
+ disabled,
7151
+ placeholder,
7152
+ id,
7153
+ name,
7154
+ size: Math.max(displayString.length, 1),
7155
+ "data-slot": "stepper-value",
7156
+ className: "type-stepper-stake-amount min-w-0 flex-1 border-0 bg-transparent text-center text-text-prominent-default outline-none disabled:text-text-disabled-default [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
7157
+ }
7158
+ ),
7159
+ /* @__PURE__ */ jsx53(
7160
+ Button,
7161
+ {
7162
+ type: "button",
7163
+ variant: "frosted",
7164
+ size: "icon-lg",
7165
+ onClick: handleIncrement,
7166
+ disabled: disabled || currentValue >= max,
7167
+ "aria-label": "Increase value",
7168
+ children: /* @__PURE__ */ jsx53(Plus, {})
7169
+ }
7170
+ )
7171
+ ]
7141
7172
  }
7142
7173
  )
7143
7174
  ]
@@ -7367,7 +7398,7 @@ function Switch(_a) {
7367
7398
  "data-slot": "switch",
7368
7399
  "data-size": size,
7369
7400
  className: cn(
7370
- "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent p-[3px] transition-all outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:cursor-not-allowed disabled:border-border-default-default disabled:text-text-disabled-default data-[size=default]:h-6 data-[size=default]:w-11 data-[size=sm]:h-5 data-[size=sm]:w-9 data-[state=checked]:bg-background-brand-default data-[state=unchecked]:bg-border-default-default",
7401
+ "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent p-[3px] transition-all outline-none focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:cursor-not-allowed disabled:opacity-(--opacity-disabled) data-[size=default]:h-6 data-[size=default]:w-11 data-[size=sm]:h-5 data-[size=sm]:w-9 data-[state=checked]:bg-background-brand-default data-[state=unchecked]:bg-border-default-default",
7371
7402
  className
7372
7403
  )
7373
7404
  }, props), {
@@ -7603,7 +7634,7 @@ import { cva as cva15 } from "class-variance-authority";
7603
7634
  import { Toggle as TogglePrimitive } from "radix-ui";
7604
7635
  import { jsx as jsx58 } from "react/jsx-runtime";
7605
7636
  var toggleVariants = cva15(
7606
- "type-toggle inline-flex items-center justify-center gap-2 rounded-md border border-border-default-default bg-background-primary-surface text-text-prominent-default whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none hover:bg-background-secondary-surface active:bg-background-secondary-wash focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:pointer-events-none disabled:border-border-default-default disabled:text-text-disabled-default aria-invalid:border-border-error-default aria-invalid:ring-ring-error-soft data-[state=on]:border-transparent data-[state=on]:bg-background-brand-default data-[state=on]:text-text-on-brand-static [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7637
+ "type-toggle inline-flex items-center justify-center gap-2 rounded-md border border-border-default-default bg-background-primary-surface text-text-prominent-default whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none hover:bg-background-secondary-surface active:bg-background-secondary-wash focus-visible:border-ring-focus-default focus-visible:ring-[3px] focus-visible:ring-ring-focus-strong disabled:pointer-events-none disabled:opacity-(--opacity-disabled) aria-invalid:border-border-error-default aria-invalid:ring-ring-error-soft data-[state=on]:border-transparent data-[state=on]:bg-background-brand-default data-[state=on]:text-text-on-brand-static [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7607
7638
  {
7608
7639
  variants: {
7609
7640
  size: {
@@ -8300,7 +8331,6 @@ function useSmoothProgress({
8300
8331
  const label = done && progress >= 99.5 ? readyLabel : (_b = (_a = checkpoints[idx]) == null ? void 0 : _a.label) != null ? _b : readyLabel;
8301
8332
  return { progress, label, delayed, complete: done && progress >= 100 };
8302
8333
  }
8303
- var MONOGRAM_D = "M513.51,265.27l12.26-58.98H183.8l-12.26,58.98h105.29l-46.92,225.76,29.68-.85c1.65-.05,40.84-1.34,87-18.36,64.47-23.76,111.8-66.23,136.88-122.83l15.77-35.6h-139.02l-12.26,58.98h58.44l-6.31,6.26c-3.16,3.14-6.56,6.2-10.11,9.12-14.15,11.63-31.27,21.29-50.86,28.7-10.01,3.79-20.64,6.97-31.57,9.45l-5.55,1.26,33.65-161.89h177.86Z";
8304
8334
  function GameLoadingBlock({
8305
8335
  progress = 0,
8306
8336
  label = "",
@@ -8308,6 +8338,7 @@ function GameLoadingBlock({
8308
8338
  exiting = false,
8309
8339
  onExitEnd,
8310
8340
  contained = false,
8341
+ logoSrc,
8311
8342
  backgroundImageUrl,
8312
8343
  className
8313
8344
  }) {
@@ -8321,13 +8352,15 @@ function GameLoadingBlock({
8321
8352
  React23.useEffect(() => {
8322
8353
  if (!exiting) return;
8323
8354
  const raf = requestAnimationFrame(() => setGo(true));
8324
- const timer = setTimeout(() => onExitEnd == null ? void 0 : onExitEnd(), reduced ? 240 : 520);
8355
+ const timer = setTimeout(() => onExitEnd == null ? void 0 : onExitEnd(), reduced ? 240 : 700);
8325
8356
  return () => {
8326
8357
  cancelAnimationFrame(raf);
8327
8358
  clearTimeout(timer);
8328
8359
  };
8329
8360
  }, [exiting, reduced, onExitEnd]);
8330
8361
  const isAbsolute = exiting || contained;
8362
+ const punched = Boolean(logoSrc);
8363
+ const animate = exiting && go && !reduced;
8331
8364
  return /* @__PURE__ */ jsxs40(
8332
8365
  "div",
8333
8366
  {
@@ -8336,39 +8369,51 @@ function GameLoadingBlock({
8336
8369
  "aria-label": "Loading game",
8337
8370
  "data-slot": "game-loading-block",
8338
8371
  className: cn(
8339
- "z-50 inset-0 flex flex-col items-center justify-center gap-8 overflow-hidden",
8372
+ "z-50 inset-0 overflow-hidden",
8340
8373
  isAbsolute ? "absolute" : "fixed",
8341
- // Token-derived dotted brand backdrop; skipped when a real image is passed.
8342
- !backgroundImageUrl && "game-loader-backdrop",
8343
- backgroundImageUrl && "bg-primary bg-cover bg-center bg-no-repeat",
8344
- exiting && (reduced ? "transition-opacity duration-200" : "transition-opacity duration-[180ms] delay-[260ms]"),
8345
- exiting && go ? "opacity-0" : "opacity-100",
8374
+ // Reduced motion, and the no-mark fallback, fade the whole layer.
8375
+ exiting && (reduced || !punched) && "transition-opacity duration-200",
8376
+ exiting && go && (reduced || !punched) ? "opacity-0" : "opacity-100",
8346
8377
  className
8347
8378
  ),
8348
- style: backgroundImageUrl ? { backgroundImage: `url(${backgroundImageUrl})` } : void 0,
8349
8379
  children: [
8350
8380
  /* @__PURE__ */ jsx67(
8351
- "svg",
8381
+ "div",
8382
+ {
8383
+ "aria-hidden": "true",
8384
+ "data-slot": "game-loading-backdrop",
8385
+ className: cn(
8386
+ "game-loader-field",
8387
+ punched && "game-loader-punch",
8388
+ animate && punched && "game-loader-field-exit"
8389
+ ),
8390
+ style: __spreadValues(__spreadValues({}, logoSrc ? { "--game-loader-mark": `url(${logoSrc})` } : null), backgroundImageUrl ? {
8391
+ backgroundImage: `url(${backgroundImageUrl})`,
8392
+ backgroundSize: "cover",
8393
+ backgroundPosition: "center",
8394
+ backgroundRepeat: "no-repeat"
8395
+ } : null)
8396
+ }
8397
+ ),
8398
+ logoSrc && /* @__PURE__ */ jsx67(
8399
+ "img",
8352
8400
  {
8353
- width: "120",
8354
- height: "120",
8355
- viewBox: "0 0 697.31 697.31",
8356
- xmlns: "http://www.w3.org/2000/svg",
8401
+ src: logoSrc,
8402
+ alt: "",
8357
8403
  "aria-hidden": "true",
8358
- className: cn("game-loader-mark fill-on-primary", exiting && go && !reduced && "game-loader-mark-exit"),
8359
- children: /* @__PURE__ */ jsx67("path", { d: MONOGRAM_D })
8404
+ className: cn("game-loader-mark", animate && "game-loader-mark-exit")
8360
8405
  }
8361
8406
  ),
8362
- !exiting && /* @__PURE__ */ jsxs40("div", { className: "flex w-[200px] flex-col items-start gap-3.5", children: [
8363
- /* @__PURE__ */ jsx67("div", { className: "relative h-2 w-full overflow-hidden rounded-xs bg-on-primary/25", children: /* @__PURE__ */ jsx67(
8407
+ !exiting && /* @__PURE__ */ jsxs40("div", { className: "absolute bottom-10 left-1/2 flex w-[200px] -translate-x-1/2 flex-col items-start gap-3.5", children: [
8408
+ /* @__PURE__ */ jsx67("div", { className: "relative h-2 w-full overflow-hidden rounded-xs bg-background-secondary-surface", children: /* @__PURE__ */ jsx67(
8364
8409
  "div",
8365
8410
  {
8366
- className: "absolute inset-y-0 left-0 overflow-hidden rounded-xs bg-on-primary",
8411
+ className: "absolute inset-y-0 left-0 overflow-hidden rounded-xs bg-background-brand-default",
8367
8412
  style: { width: `${progress}%` },
8368
8413
  children: /* @__PURE__ */ jsx67("span", { "aria-hidden": "true", className: "game-loader-shimmer absolute inset-y-0 left-[-60%] w-[60%]" })
8369
8414
  }
8370
8415
  ) }),
8371
- /* @__PURE__ */ jsx67("span", { className: "caption text-on-primary/90", children: delayed ? "Taking longer than usual\u2026" : label })
8416
+ /* @__PURE__ */ jsx67("span", { className: "caption text-text-subtle-default", children: delayed ? "Taking longer than usual\u2026" : label })
8372
8417
  ] })
8373
8418
  ]
8374
8419
  }