@tastic/hud 0.16.0 → 0.18.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.
package/dist/index.js CHANGED
@@ -38,22 +38,22 @@ __export(TriggerGauge_exports, {
38
38
  function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, dashWidth, startDeg = DEFAULT_START_DEG, endDeg = startDeg }) {
39
39
  const totalDurationMs = MOUNT_DURATION_MS + Math.max(0, segments - 1) * MOUNT_STAGGER_MS;
40
40
  const mountProgress = (0, import_react_native_reanimated.useSharedValue)(0);
41
- (0, import_react7.useLayoutEffect)(() => {
41
+ (0, import_react8.useLayoutEffect)(() => {
42
42
  mountProgress.value = (0, import_react_native_reanimated.withTiming)(1, { duration: totalDurationMs, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
43
43
  }, []);
44
44
  const rawSweepDeg = ((endDeg - startDeg) % 360 + 360) % 360;
45
45
  const totalSweepDeg = rawSweepDeg === 0 ? 360 : rawSweepDeg;
46
46
  const step = segments > 0 ? totalSweepDeg / segments : 0;
47
- const centerDeg = (0, import_react7.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
47
+ const centerDeg = (0, import_react8.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
48
48
  const singleSelect = litIndices.length === 1;
49
49
  const angleDeg = (0, import_react_native_reanimated.useSharedValue)(centerDeg(litIndices[0] ?? 0));
50
50
  const litIndicesKey = [...litIndices].sort((a, b) => a - b).join(",");
51
- const [transitionFrom, setTransitionFrom] = (0, import_react7.useState)(litIndices);
51
+ const [transitionFrom, setTransitionFrom] = (0, import_react8.useState)(litIndices);
52
52
  const transitionFromKey = [...transitionFrom].sort((a, b) => a - b).join(",");
53
- const lastKeyRef = (0, import_react7.useRef)(litIndicesKey);
54
- const lastIndicesRef = (0, import_react7.useRef)(litIndices);
53
+ const lastKeyRef = (0, import_react8.useRef)(litIndicesKey);
54
+ const lastIndicesRef = (0, import_react8.useRef)(litIndices);
55
55
  const selectionProgress = (0, import_react_native_reanimated.useSharedValue)(1);
56
- (0, import_react7.useLayoutEffect)(() => {
56
+ (0, import_react8.useLayoutEffect)(() => {
57
57
  if (litIndicesKey !== lastKeyRef.current) {
58
58
  if (singleSelect && lastIndicesRef.current.length === 1) {
59
59
  angleDeg.value = (0, import_react_native_reanimated.withTiming)(centerDeg(litIndices[0]), { duration: SELECTION_TRANSITION_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
@@ -75,27 +75,27 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
75
75
  const canvasSize = diameter + LIT_THICKNESS;
76
76
  const oval = import_react_native_skia.Skia.XYWHRect(LIT_THICKNESS / 2, LIT_THICKNESS / 2, diameter, diameter);
77
77
  const unlitPath = (0, import_react_native_reanimated.useDerivedValue)(() => {
78
- const path = import_react_native_skia.Skia.Path.Make();
78
+ const path = import_react_native_skia.Skia.PathBuilder.Make();
79
79
  for (let i = 0; i < segments; i++) {
80
80
  if (litIndices.includes(i)) continue;
81
81
  let local = 1;
82
82
  if (mountProgress.value < 1) {
83
83
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
84
84
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
85
- local = (0, import_core6.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
85
+ local = (0, import_core7.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
86
86
  }
87
87
  const sweep = dashAngleDeg * local;
88
88
  if (sweep <= 0) continue;
89
89
  const dashCenterDeg = startDeg + (i + 0.5) * step;
90
90
  path.addArc(oval, dashCenterDeg - 90 - sweep / 2, sweep);
91
91
  }
92
- return path;
92
+ return path.detach();
93
93
  }, [segments, litIndicesKey, step, startDeg, dashAngleDeg, totalDurationMs, oval.x, oval.y, oval.width, oval.height]);
94
94
  const litPath = (0, import_react_native_reanimated.useDerivedValue)(() => {
95
- const path = import_react_native_skia.Skia.Path.Make();
95
+ const path = import_react_native_skia.Skia.PathBuilder.Make();
96
96
  if (mountProgress.value >= 1 && singleSelect) {
97
97
  path.addArc(oval, angleDeg.value - 90 - dashAngleDeg / 2, dashAngleDeg);
98
- return path;
98
+ return path.detach();
99
99
  }
100
100
  for (let i = 0; i < segments; i++) {
101
101
  const isLitNow = litIndices.includes(i);
@@ -106,7 +106,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
106
106
  if (!isLitNow) continue;
107
107
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
108
108
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
109
- local = (0, import_core6.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
109
+ local = (0, import_core7.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
110
110
  } else if (isLitNow === wasLit) {
111
111
  local = 1;
112
112
  } else if (isLitNow) {
@@ -119,7 +119,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
119
119
  const dashCenterDeg = startDeg + (i + 0.5) * step;
120
120
  path.addArc(oval, dashCenterDeg - 90 - sweep / 2, sweep);
121
121
  }
122
- return path;
122
+ return path.detach();
123
123
  }, [segments, litIndicesKey, transitionFromKey, singleSelect, step, startDeg, dashAngleDeg, totalDurationMs, oval.x, oval.y, oval.width, oval.height]);
124
124
  if (segments < 2) return null;
125
125
  const gaugeSizeStyle = {
@@ -130,21 +130,21 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
130
130
  height: canvasSize,
131
131
  width: canvasSize
132
132
  };
133
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native14.View, { style: [styles12.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
133
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native17.View, { style: [styles14.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
136
136
  ] }) });
137
137
  }
138
- var import_react_native_skia, import_core6, import_react7, import_react_native14, import_react_native_reanimated, import_jsx_runtime14, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles12;
138
+ var import_react_native_skia, import_core7, import_react8, import_react_native17, import_react_native_reanimated, import_jsx_runtime16, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles14;
139
139
  var init_TriggerGauge = __esm({
140
140
  "src/TriggerGauge.tsx"() {
141
141
  "use strict";
142
142
  import_react_native_skia = require("@shopify/react-native-skia");
143
- import_core6 = require("@tastic/core");
144
- import_react7 = require("react");
145
- import_react_native14 = require("react-native");
143
+ import_core7 = require("@tastic/core");
144
+ import_react8 = require("react");
145
+ import_react_native17 = require("react-native");
146
146
  import_react_native_reanimated = require("react-native-reanimated");
147
- import_jsx_runtime14 = require("react/jsx-runtime");
147
+ import_jsx_runtime16 = require("react/jsx-runtime");
148
148
  UNLIT_THICKNESS = 3;
149
149
  LIT_THICKNESS = 7;
150
150
  DASH_GAP_PX = 9;
@@ -154,7 +154,7 @@ var init_TriggerGauge = __esm({
154
154
  MOUNT_DURATION_MS = 450;
155
155
  MOUNT_STAGGER_MS = 40;
156
156
  SELECTION_TRANSITION_DURATION_MS = 260;
157
- styles12 = import_react_native14.StyleSheet.create({
157
+ styles14 = import_react_native17.StyleSheet.create({
158
158
  container: {
159
159
  alignItems: "center",
160
160
  justifyContent: "center",
@@ -173,16 +173,20 @@ __export(index_exports, {
173
173
  ActivityStatSection: () => ActivityStatSection,
174
174
  BaseSettingsDialog: () => BaseSettingsDialog,
175
175
  BaseStatsScreen: () => BaseStatsScreen,
176
+ COMPACT_DIALOG_HEIGHT: () => COMPACT_DIALOG_HEIGHT,
176
177
  ConfirmDialog: () => ConfirmDialog,
177
178
  ContentGutter: () => ContentGutter,
178
179
  ControlSchemePicker: () => ControlSchemePicker,
179
180
  CornerActionButtons: () => CornerActionButtons,
180
181
  CornerStatusBadges: () => CornerStatusBadges,
182
+ DialogHeader: () => DialogHeader,
181
183
  InlineColorPicker: () => InlineColorPicker,
182
184
  LABELED_DROPDOWN_POPOVER_WIDTH: () => LABELED_DROPDOWN_POPOVER_WIDTH,
183
185
  LOCKED_BADGE_COLOR: () => LOCKED_BADGE_COLOR,
184
186
  LabeledDropdown: () => LabeledDropdown,
185
187
  MONO_FONT: () => MONO_FONT,
188
+ OverlayBackdrop: () => OverlayBackdrop,
189
+ OverlayCard: () => OverlayCard,
186
190
  PlayerSetupPanel: () => PlayerSetupPanel,
187
191
  PopoverBody: () => PopoverBody,
188
192
  PressAwayOverlay: () => PressAwayOverlay,
@@ -200,12 +204,14 @@ __export(index_exports, {
200
204
  getCpuDifficultyPopoverId: () => getCpuDifficultyPopoverId,
201
205
  getInlineColorPickerContentSize: () => getInlineColorPickerContentSize,
202
206
  getLabeledDropdownContentHeight: () => getLabeledDropdownContentHeight,
203
- getOverlayCardColors: () => getOverlayCardColors,
204
207
  getStaggeredWordDuration: () => getStaggeredWordDuration,
208
+ isCompactDialogHeight: () => isCompactDialogHeight,
205
209
  loadSkiaWeb: () => loadSkiaWeb,
206
210
  overlayActionStyles: () => overlayActionStyles,
207
211
  overlayStyles: () => overlayStyles,
208
212
  useAutoAlign: () => useAutoAlign,
213
+ useCompactDialog: () => useCompactDialog,
214
+ useOverlayCardColors: () => useOverlayCardColors,
209
215
  usePopoverHost: () => usePopoverHost,
210
216
  useQuitConfirmation: () => useQuitConfirmation,
211
217
  useZoneClampedAlign: () => useZoneClampedAlign
@@ -417,39 +423,74 @@ function ActivityStatSection({ stats }) {
417
423
  }
418
424
 
419
425
  // src/BaseSettingsDialog.tsx
420
- var import_auto_paper7 = require("@rific/auto-paper");
426
+ var import_auto_paper9 = require("@rific/auto-paper");
421
427
  var import_feedback_press2 = require("@rific/feedback-press");
422
428
  var import_updater = require("@rific/updater");
423
- var import_core3 = require("@tastic/core");
424
- var import_react4 = require("react");
425
- var import_react_native10 = require("react-native");
426
- var import_react_native_paper8 = require("react-native-paper");
429
+ var import_core4 = require("@tastic/core");
430
+ var import_react5 = require("react");
431
+ var import_react_native13 = require("react-native");
432
+ var import_react_native_paper9 = require("react-native-paper");
433
+ var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
427
434
 
428
435
  // src/ConfirmDialog.tsx
429
- var import_auto_paper6 = require("@rific/auto-paper");
436
+ var import_auto_paper8 = require("@rific/auto-paper");
430
437
  var import_feedback_press = require("@rific/feedback-press");
431
- var import_core = require("@tastic/core");
432
- var import_react_native8 = require("react-native");
433
- var import_react_native_paper6 = require("react-native-paper");
438
+ var import_core2 = require("@tastic/core");
439
+ var import_react_native11 = require("react-native");
440
+ var import_react_native_paper7 = require("react-native-paper");
434
441
 
435
- // src/overlayCard.ts
442
+ // src/DialogHeader.tsx
443
+ var import_auto_paper6 = require("@rific/auto-paper");
436
444
  var import_react_native7 = require("react-native");
437
- function getOverlayCardColors(dark) {
438
- return {
439
- fg: dark ? "#FFFFFF" : "#000000",
440
- fgMuted: dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)",
441
- cardBg: dark ? "#111111" : "#F2F2F2",
442
- cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
443
- };
445
+ var import_react_native_paper6 = require("react-native-paper");
446
+ var import_jsx_runtime7 = require("react/jsx-runtime");
447
+ var COMPACT_DIALOG_HEIGHT = 528;
448
+ function isCompactDialogHeight(height) {
449
+ return height < COMPACT_DIALOG_HEIGHT;
444
450
  }
445
- var overlayStyles = import_react_native7.StyleSheet.create({
451
+ function DialogHeader({ icon, title, color, compact = false, style }) {
452
+ const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
453
+ const accent = color ?? colors.primary;
454
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: [compact ? styles6.compact : styles6.full, style], children: [
455
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Icon, { source: icon, size: compact ? COMPACT_ICON_SIZE : ICON_SIZE, color: accent }),
456
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { accessibilityRole: "header", variant: compact ? "headlineSmall" : "headlineLarge", style: [styles6.title, compact && styles6.titleCompact, { color: accent }], children: title })
457
+ ] });
458
+ }
459
+ var ICON_SIZE = 64;
460
+ var COMPACT_ICON_SIZE = 32;
461
+ var styles6 = import_react_native7.StyleSheet.create({
462
+ compact: {
463
+ alignItems: "center",
464
+ alignSelf: "stretch",
465
+ flexDirection: "row",
466
+ gap: 12,
467
+ justifyContent: "center"
468
+ },
469
+ full: {
470
+ alignItems: "center",
471
+ alignSelf: "stretch",
472
+ gap: 16
473
+ },
474
+ // textAlign matters once a title wraps: the card centers the Text's block, but each wrapped line
475
+ // still defaults to left-aligned without it.
476
+ title: {
477
+ fontWeight: "bold",
478
+ textAlign: "center"
479
+ },
480
+ titleCompact: {
481
+ flexShrink: 1
482
+ }
483
+ });
484
+
485
+ // src/overlayCard.ts
486
+ var import_react_native8 = require("react-native");
487
+ var overlayStyles = import_react_native8.StyleSheet.create({
446
488
  card: {
447
489
  alignItems: "center",
448
- borderRadius: 20,
449
- borderWidth: 1,
490
+ borderRadius: 28,
450
491
  gap: 16,
451
492
  maxWidth: 360,
452
- padding: 32
493
+ padding: 24
453
494
  },
454
495
  overlay: {
455
496
  alignItems: "center",
@@ -462,7 +503,7 @@ var overlayStyles = import_react_native7.StyleSheet.create({
462
503
  top: 0
463
504
  }
464
505
  });
465
- var overlayActionStyles = import_react_native7.StyleSheet.create({
506
+ var overlayActionStyles = import_react_native8.StyleSheet.create({
466
507
  // minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
467
508
  // still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
468
509
  // on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
@@ -504,26 +545,64 @@ var overlayActionStyles = import_react_native7.StyleSheet.create({
504
545
  }
505
546
  });
506
547
 
548
+ // src/OverlaySurface.tsx
549
+ var import_auto_paper7 = require("@rific/auto-paper");
550
+ var import_react_native9 = require("react-native");
551
+ var import_jsx_runtime8 = require("react/jsx-runtime");
552
+ function useOverlayCardColors() {
553
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
554
+ return { fg: colors.onSurface, fgMuted: colors.onSurfaceVariant, cardBorder: colors.outlineVariant, backdrop: colors.backdrop };
555
+ }
556
+ function OverlayBackdrop({ children, style, onLayout }) {
557
+ const { backdrop } = useOverlayCardColors();
558
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { onLayout, style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
559
+ }
560
+ function OverlayCard({ children, style, ...rest }) {
561
+ const { isV3, roundness } = (0, import_auto_paper7.useAutoPaperTheme)();
562
+ const blur = (0, import_auto_paper7.useBlur)();
563
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.BlurView, { blur, style: [overlayStyles.card, styles7.card, { borderRadius: (isV3 ? 7 : 1) * roundness }, style], ...rest, children });
564
+ }
565
+ var styles7 = import_react_native9.StyleSheet.create({
566
+ card: { overflow: "hidden" }
567
+ });
568
+
569
+ // src/useCompactDialog.ts
570
+ var import_core = require("@tastic/core");
571
+ var import_react2 = require("react");
572
+ var import_react_native10 = require("react-native");
573
+ function useCompactDialog(rotation = 0) {
574
+ const window = (0, import_react_native10.useWindowDimensions)();
575
+ const framed = (0, import_core.useRotatedWindowDimensions)();
576
+ const [measured, setMeasured] = (0, import_react2.useState)(null);
577
+ const onLayout = (0, import_react2.useCallback)((e) => {
578
+ const { width, height } = e.nativeEvent.layout;
579
+ setMeasured((prev) => prev && prev.width === width && prev.height === height ? prev : { width, height });
580
+ }, []);
581
+ const box = measured ?? (rotation === 0 ? framed : window);
582
+ const turned = rotation === 90 || rotation === -90;
583
+ return { compact: isCompactDialogHeight(turned ? box.width : box.height), onLayout };
584
+ }
585
+
507
586
  // src/ConfirmDialog.tsx
508
- var import_jsx_runtime7 = require("react/jsx-runtime");
587
+ var import_jsx_runtime9 = require("react/jsx-runtime");
509
588
  function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
510
- const { dark, colors } = (0, import_auto_paper6.useAutoPaperTheme)();
589
+ const { colors } = (0, import_auto_paper8.useAutoPaperTheme)();
590
+ const { fg } = useOverlayCardColors();
591
+ const { compact, onLayout } = useCompactDialog(rotation);
511
592
  if (!visible) return null;
512
- const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
513
593
  const accent = destructive ? colors.danger : colors.primary;
514
594
  const onAccent = destructive ? colors.onDanger : colors.onPrimary;
515
595
  const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
516
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [overlayStyles.overlay, styles6.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: [overlayStyles.card, styles6.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core.toRotationStyle)(rotation)], children: [
517
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Icon, { source: icon, size: 64, color: accent }),
518
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "headlineLarge", style: [styles6.title, { color: accent }], children: title }),
519
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: [styles6.body, { color: fg }], children: message }),
520
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: overlayActionStyles.actions, children: [
521
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
522
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
596
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OverlayBackdrop, { style: styles8.overlay, onLayout, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(OverlayCard, { style: [styles8.card, (0, import_core2.toRotationStyle)(rotation)], children: [
597
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DialogHeader, { icon, title, color: accent, compact }),
598
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: [styles8.body, { color: fg }], children: message }),
599
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native11.View, { style: overlayActionStyles.actions, children: [
600
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
601
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
523
602
  ] })
524
603
  ] }) }) });
525
604
  }
526
- var styles6 = import_react_native8.StyleSheet.create({
605
+ var styles8 = import_react_native11.StyleSheet.create({
527
606
  body: {
528
607
  textAlign: "center"
529
608
  },
@@ -541,35 +620,28 @@ var styles6 = import_react_native8.StyleSheet.create({
541
620
  // screen narrower than maxWidth's own 360.
542
621
  overlay: {
543
622
  paddingHorizontal: 24
544
- },
545
- // textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
546
- // within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
547
- // line inside that block still defaults to left-aligned without this.
548
- title: {
549
- fontWeight: "bold",
550
- textAlign: "center"
551
623
  }
552
624
  });
553
625
 
554
626
  // src/RotatedFrame.tsx
555
- var import_core2 = require("@tastic/core");
556
- var import_react2 = require("react");
557
- var import_react_native9 = require("react-native");
558
- var import_react_native_paper7 = require("react-native-paper");
627
+ var import_core3 = require("@tastic/core");
628
+ var import_react3 = require("react");
629
+ var import_react_native12 = require("react-native");
630
+ var import_react_native_paper8 = require("react-native-paper");
559
631
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
560
- var import_jsx_runtime8 = require("react/jsx-runtime");
632
+ var import_jsx_runtime10 = require("react/jsx-runtime");
561
633
  function RotatedFrame({ children, rotation: rotationOverride, rotatedSafeArea = false, portalHost = false, passThrough = false, maxContentWidth }) {
562
- const ambientRotation = (0, import_core2.useRotation)();
634
+ const ambientRotation = (0, import_core3.useRotation)();
563
635
  const rotation = rotationOverride ?? ambientRotation;
564
- const window = (0, import_react_native9.useWindowDimensions)();
565
- const { width, height } = (0, import_core2.rotateDimensions)(window.width, window.height, rotation);
636
+ const window = (0, import_react_native12.useWindowDimensions)();
637
+ const { width, height } = (0, import_core3.rotateDimensions)(window.width, window.height, rotation);
566
638
  const rawInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
567
- const insets = (0, import_react2.useMemo)(() => rotatedSafeArea ? (0, import_core2.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
639
+ const insets = (0, import_react3.useMemo)(() => rotatedSafeArea ? (0, import_core3.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
568
640
  const cappedWidth = maxContentWidth !== void 0 && width > height ? maxContentWidth : void 0;
569
- const column = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
570
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles7.root, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Portal.Host, { children: column }) : column }) });
641
+ const column = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [styles9.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
642
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_core3.FakeLandscapeView, { rotation, passThrough, style: styles9.root, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Portal.Host, { children: column }) : column }) });
571
643
  }
572
- var styles7 = import_react_native9.StyleSheet.create({
644
+ var styles9 = import_react_native12.StyleSheet.create({
573
645
  // A centred column: full width up to `maxWidth`, so a capped frame sits in the middle of a wider window.
574
646
  column: {
575
647
  alignSelf: "center",
@@ -582,18 +654,18 @@ var styles7 = import_react_native9.StyleSheet.create({
582
654
  });
583
655
 
584
656
  // src/useUpdateConfirmBridge.ts
585
- var import_react3 = require("react");
657
+ var import_react4 = require("react");
586
658
  function useUpdateConfirmBridge() {
587
- const [manifest, setManifest] = (0, import_react3.useState)(null);
588
- const resolveRef = (0, import_react3.useRef)(null);
589
- const onConfirm = (0, import_react3.useCallback)(
659
+ const [manifest, setManifest] = (0, import_react4.useState)(null);
660
+ const resolveRef = (0, import_react4.useRef)(null);
661
+ const onConfirm = (0, import_react4.useCallback)(
590
662
  (next) => new Promise((resolve) => {
591
663
  resolveRef.current = resolve;
592
664
  setManifest(next);
593
665
  }),
594
666
  []
595
667
  );
596
- const respond = (0, import_react3.useCallback)((confirmed) => {
668
+ const respond = (0, import_react4.useCallback)((confirmed) => {
597
669
  setManifest(null);
598
670
  resolveRef.current?.(confirmed);
599
671
  resolveRef.current = null;
@@ -602,20 +674,27 @@ function useUpdateConfirmBridge() {
602
674
  }
603
675
 
604
676
  // src/BaseSettingsDialog.tsx
605
- var import_jsx_runtime9 = require("react/jsx-runtime");
677
+ var import_jsx_runtime11 = require("react/jsx-runtime");
606
678
  function SettingIcon({ source, color, containerColor }) {
607
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Icon, { source, size: 18, color }) });
679
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.View, { style: [styles10.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Icon, { source, size: 18, color }) });
608
680
  }
609
681
  function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
610
- const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
611
- const ambientRotation = (0, import_core3.useRotation)();
682
+ const { colors } = (0, import_auto_paper9.useAutoPaperTheme)();
683
+ const ambientRotation = (0, import_core4.useRotation)();
612
684
  const rotation = rotationOverride ?? ambientRotation;
613
- const isTouchPrimary = (0, import_core3.useIsTouchPrimaryDevice)();
685
+ const window = (0, import_react_native13.useWindowDimensions)();
686
+ const turned = rotation === 90 || rotation === -90;
687
+ const compactHeader = isCompactDialogHeight(turned ? window.width : window.height);
688
+ const insets = (0, import_core4.rotateInsets)((0, import_react_native_safe_area_context2.useSafeAreaInsets)(), rotation);
689
+ const sheetWidth = Math.min(overlayStyles.card.maxWidth, (turned ? window.height : window.width) - 2 * Math.max(insets.left, insets.right, SHEET_GUTTER));
690
+ const isTouchPrimary = (0, import_core4.useIsTouchPrimaryDevice)();
614
691
  const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press2.useHapticSettings)();
615
692
  const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
616
- const sound = (0, import_react4.useContext)(import_feedback_press2.SoundContext);
693
+ const sound = (0, import_react5.useContext)(import_feedback_press2.SoundContext);
617
694
  const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
618
- const [infoMessage, setInfoMessage] = (0, import_react4.useState)(null);
695
+ const { settings: themeSettings, set: setThemeSettings } = (0, import_auto_paper9.useThemeSettings)();
696
+ const expoBlur = (0, import_auto_paper9.useBlurModule)();
697
+ const [infoMessage, setInfoMessage] = (0, import_react5.useState)(null);
619
698
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
620
699
  const { check, checking, updateReady } = (0, import_updater.useUpdater)({
621
700
  autoCheck: false,
@@ -625,112 +704,124 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
625
704
  onInfo: (title, message) => setInfoMessage({ title, message })
626
705
  });
627
706
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
628
- const [opened, setOpened] = (0, import_react4.useState)(visible);
707
+ const [opened, setOpened] = (0, import_react5.useState)(visible);
629
708
  if (visible && !opened) setOpened(true);
630
709
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
631
- const showEdgeGuard = import_react_native10.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
632
- const showHaptics = import_react_native10.Platform.OS !== "web" && !hideHaptics;
710
+ const showEdgeGuard = import_react_native13.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
711
+ const showHaptics = import_react_native13.Platform.OS !== "web" && !hideHaptics;
633
712
  const showSound = !hideSound;
634
713
  const showAppearance = !hideAppearance;
635
- const showUpdateCheck = import_react_native10.Platform.OS !== "web" && !hideUpdateCheck;
714
+ const showBlur = showAppearance && import_react_native13.Platform.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
715
+ const showUpdateCheck = import_react_native13.Platform.OS !== "web" && !hideUpdateCheck;
636
716
  if (!opened) return null;
637
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
638
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: styles8.dialog, children: [
639
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
640
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles8.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { contentContainerStyle: styles8.content, showsVerticalScrollIndicator: false, children: [
641
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleGroup, children: [
642
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles8.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
643
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
644
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
645
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
646
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
647
- ] })
648
- ] }) }),
649
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles8.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
650
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
651
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
652
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
653
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
654
- ] })
655
- ] }) }),
656
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleRow, children: [
657
- showSound && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
658
- import_feedback_press2.TouchableRipple,
659
- {
660
- soundDisabled: true,
661
- onPress: () => {
662
- const enabled = !soundSettings.enabled;
663
- setSoundSettings({ enabled });
664
- if (enabled) sound.selection?.();
665
- },
666
- style: styles8.toggleButtonInRow,
667
- accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
668
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
669
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
670
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
671
- ] })
672
- }
673
- ),
674
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
717
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_auto_paper9.Dialog, { visible, onDismiss, style: [styles10.dialog, { width: sheetWidth }], children: [
719
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_auto_paper9.Dialog.ScrollArea, { style: styles10.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_auto_paper9.FadingScrollView, { contentContainerStyle: styles10.scrollContent, showsVerticalScrollIndicator: false, children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DialogHeader, { icon: "cog", title: "Settings", compact: compactHeader }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.content, children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleGroup, children: [
723
+ showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles10.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
724
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
725
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.flexShrink, children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pin current layout" })
728
+ ] })
729
+ ] }) }),
730
+ showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles10.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
731
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.flexShrink, children: [
733
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
734
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
735
+ ] })
736
+ ] }) }),
737
+ (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleRow, children: [
738
+ showSound && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
739
+ import_feedback_press2.TouchableRipple,
740
+ {
741
+ soundDisabled: true,
742
+ onPress: () => {
743
+ const enabled = !soundSettings.enabled;
744
+ setSoundSettings({ enabled });
745
+ if (enabled) sound.selection?.();
746
+ },
747
+ style: styles10.toggleButtonInRow,
748
+ accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
749
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
750
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
751
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
752
+ ] })
753
+ }
754
+ ),
755
+ showHaptics && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
756
+ import_feedback_press2.TouchableRipple,
757
+ {
758
+ hapticDisabled: true,
759
+ onPress: () => {
760
+ const vibrate = !hapticSettings.vibrate;
761
+ setHapticSettings({ vibrate });
762
+ if (vibrate) forceHapticFeedback();
763
+ },
764
+ style: styles10.toggleButtonInRow,
765
+ accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
766
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
768
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
769
+ ] })
770
+ }
771
+ )
772
+ ] }),
773
+ onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
675
774
  import_feedback_press2.TouchableRipple,
676
775
  {
677
- hapticDisabled: true,
678
776
  onPress: () => {
679
- const vibrate = !hapticSettings.vibrate;
680
- setHapticSettings({ vibrate });
681
- if (vibrate) forceHapticFeedback();
777
+ onDismiss();
778
+ onShowHowToPlay();
682
779
  },
683
- style: styles8.toggleButtonInRow,
684
- accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
685
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
686
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
687
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
780
+ style: styles10.toggleButton,
781
+ accessibilityLabel: "How to Play",
782
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
783
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
784
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.flexShrink, children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
786
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay quick intro" })
787
+ ] })
688
788
  ] })
689
789
  }
690
790
  )
691
791
  ] }),
692
- onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
693
- import_feedback_press2.TouchableRipple,
694
- {
695
- onPress: () => {
696
- onDismiss();
697
- onShowHowToPlay();
698
- },
699
- style: styles8.toggleButton,
700
- accessibilityLabel: "How to Play",
701
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
702
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
703
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
704
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
705
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
706
- ] })
792
+ showAppearance && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.section, children: [
793
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "labelMedium", style: [styles10.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_auto_paper9.AutoAppearancePicker, { showLabels: false }),
795
+ showBlur && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles10.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
796
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
797
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.flexShrink, children: [
798
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" }),
799
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Frost behind dialogs" })
707
800
  ] })
708
- }
709
- )
710
- ] }),
711
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
712
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "labelMedium", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
713
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false })
714
- ] }),
715
- children,
716
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
717
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_paper8.Text, { variant: "labelSmall", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: [
718
- "VERSION ",
719
- version,
720
- updateReady ? " \xB7 UPDATE READY" : ""
801
+ ] }) })
721
802
  ] }),
722
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
803
+ children,
804
+ showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.section, children: [
805
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native_paper9.Text, { variant: "labelMedium", style: [styles10.sectionLabel, { color: colors.onSurfaceVariant }], children: [
806
+ "VERSION ",
807
+ version,
808
+ updateReady ? " \xB7 UPDATE READY" : ""
809
+ ] }),
810
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
811
+ ] })
723
812
  ] })
724
- ] }) })
813
+ ] }) }),
814
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.View, { style: [overlayActionStyles.actions, styles10.footer], children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.Button, { mode: "contained", onPress: onDismiss, style: overlayActionStyles.actionButtonSingle, buttonColor: colors.primary, textColor: colors.onPrimary, children: "Done" }) })
725
815
  ] }),
726
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
727
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
816
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
728
818
  ] }) });
729
819
  }
730
- var styles8 = import_react_native10.StyleSheet.create({
820
+ var SHEET_GUTTER = 24;
821
+ var styles10 = import_react_native13.StyleSheet.create({
822
+ // The rows' sections, 24pt apart.
731
823
  content: {
732
- gap: 24,
733
- paddingVertical: 20
824
+ gap: 24
734
825
  },
735
826
  // Caps the card so it never grows past the screen - without this the dialog just keeps
736
827
  // growing to fit its content and the overflow gets clipped by the screen edge, which is
@@ -742,6 +833,11 @@ var styles8 = import_react_native10.StyleSheet.create({
742
833
  flexShrink: {
743
834
  flexShrink: 1
744
835
  },
836
+ // The overlay cards' 24pt padding, as the sheet's own insets (its scroll area pads 24 sideways).
837
+ footer: {
838
+ paddingBottom: 24,
839
+ paddingHorizontal: 24
840
+ },
745
841
  iconBadge: {
746
842
  alignItems: "center",
747
843
  borderRadius: 10,
@@ -749,9 +845,20 @@ var styles8 = import_react_native10.StyleSheet.create({
749
845
  justifyContent: "center",
750
846
  width: 36
751
847
  },
848
+ // No hairline dividers above and below the scroll area (Paper's MD2-era borders): none of the
849
+ // fleet's other dialogs draws one, so the sheet matches them (Jay, 2026-10-15).
752
850
  scrollArea: {
851
+ borderBottomWidth: 0,
852
+ borderTopWidth: 0,
753
853
  marginBottom: 0
754
854
  },
855
+ // The header and the rows scroll together: the card's 24pt inset above the header, the overlay
856
+ // cards' 16pt gap between it and the rows, and 16pt below the last row before the Done row.
857
+ scrollContent: {
858
+ gap: 16,
859
+ paddingBottom: 16,
860
+ paddingTop: 24
861
+ },
755
862
  section: {
756
863
  gap: 12
757
864
  },
@@ -795,31 +902,31 @@ var styles8 = import_react_native10.StyleSheet.create({
795
902
  });
796
903
 
797
904
  // src/BaseStatsScreen.tsx
798
- var import_auto_paper8 = require("@rific/auto-paper");
905
+ var import_auto_paper10 = require("@rific/auto-paper");
799
906
  var import_feedback_press3 = require("@rific/feedback-press");
800
- var import_core4 = require("@tastic/core");
801
- var import_react5 = require("react");
802
- var import_react_native11 = require("react-native");
803
- var import_react_native_paper9 = require("react-native-paper");
804
- var import_jsx_runtime10 = require("react/jsx-runtime");
907
+ var import_core5 = require("@tastic/core");
908
+ var import_react6 = require("react");
909
+ var import_react_native14 = require("react-native");
910
+ var import_react_native_paper10 = require("react-native-paper");
911
+ var import_jsx_runtime12 = require("react/jsx-runtime");
805
912
  function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", titleVariant = "headlineSmall", onBack, insets, onReset, resetLabel = "Reset All Stats", resetConfirmTitle = "Reset Everything?", resetConfirmBody = "This permanently erases all stats and achievements. This cannot be undone.", fg: fgOverride, bg: bgOverride, children }) {
806
- const { dark, colors } = (0, import_auto_paper8.useAutoPaperTheme)();
807
- const ambientRotation = (0, import_core4.useRotation)();
913
+ const { dark, colors } = (0, import_auto_paper10.useAutoPaperTheme)();
914
+ const ambientRotation = (0, import_core5.useRotation)();
808
915
  const rotation = rotationOverride ?? ambientRotation;
809
- const [confirmResetVisible, setConfirmResetVisible] = (0, import_react5.useState)(false);
916
+ const [confirmResetVisible, setConfirmResetVisible] = (0, import_react6.useState)(false);
810
917
  const showReset = !!onReset;
811
918
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
812
919
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
813
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.container, { backgroundColor: bg }], children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
815
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
816
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper9.Text, { variant: titleVariant, style: [styles9.title, { color: fg }], children: title })
920
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native14.View, { style: [styles11.container, { backgroundColor: bg }], children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native14.View, { style: [styles11.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
922
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
923
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper10.Text, { variant: titleVariant, style: [styles11.title, { color: fg }], children: title })
817
924
  ] }),
818
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.ScrollView, { style: styles9.scrollView, contentContainerStyle: [styles9.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
925
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native14.ScrollView, { style: styles11.scrollView, contentContainerStyle: [styles11.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
819
926
  children,
820
- showReset && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles9.resetButton, children: resetLabel })
927
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles11.resetButton, children: resetLabel })
821
928
  ] }),
822
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
929
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
823
930
  ConfirmDialog,
824
931
  {
825
932
  visible: confirmResetVisible,
@@ -839,7 +946,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
839
946
  )
840
947
  ] });
841
948
  }
842
- var styles9 = import_react_native11.StyleSheet.create({
949
+ var styles11 = import_react_native14.StyleSheet.create({
843
950
  container: {
844
951
  flex: 1
845
952
  },
@@ -870,19 +977,19 @@ var styles9 = import_react_native11.StyleSheet.create({
870
977
  });
871
978
 
872
979
  // src/ContentGutter.tsx
873
- var import_core5 = require("@tastic/core");
874
- var import_react_native12 = require("react-native");
875
- var import_jsx_runtime11 = require("react/jsx-runtime");
980
+ var import_core6 = require("@tastic/core");
981
+ var import_react_native15 = require("react-native");
982
+ var import_jsx_runtime13 = require("react/jsx-runtime");
876
983
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
877
- const { width: windowWidth } = (0, import_core5.useRotatedWindowDimensions)();
878
- const { contentWidth, gutterWidth } = (0, import_core5.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
879
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.row, style], children: [
880
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: leftGutter }),
881
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: { width: contentWidth }, children }),
882
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: rightGutter })
984
+ const { width: windowWidth } = (0, import_core6.useRotatedWindowDimensions)();
985
+ const { contentWidth, gutterWidth } = (0, import_core6.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
986
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native15.View, { style: [styles12.row, style], children: [
987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native15.View, { style: [styles12.gutter, { width: gutterWidth }], children: leftGutter }),
988
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native15.View, { style: { width: contentWidth }, children }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native15.View, { style: [styles12.gutter, { width: gutterWidth }], children: rightGutter })
883
990
  ] });
884
991
  }
885
- var styles10 = import_react_native12.StyleSheet.create({
992
+ var styles12 = import_react_native15.StyleSheet.create({
886
993
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
887
994
  // column instead of clipping cleanly at its own real width.
888
995
  gutter: {
@@ -894,41 +1001,41 @@ var styles10 = import_react_native12.StyleSheet.create({
894
1001
  });
895
1002
 
896
1003
  // src/ControlSchemePicker.tsx
897
- var import_core8 = require("@tastic/core");
898
- var import_react_native17 = require("react-native");
1004
+ var import_core9 = require("@tastic/core");
1005
+ var import_react_native20 = require("react-native");
899
1006
 
900
1007
  // src/SectionedDropdown.tsx
901
- var import_auto_paper9 = require("@rific/auto-paper");
1008
+ var import_auto_paper11 = require("@rific/auto-paper");
902
1009
  var import_feedback_press4 = require("@rific/feedback-press");
903
- var import_core7 = require("@tastic/core");
904
- var import_react_native16 = require("react-native");
905
- var import_react_native_paper10 = require("react-native-paper");
1010
+ var import_core8 = require("@tastic/core");
1011
+ var import_react_native19 = require("react-native");
1012
+ var import_react_native_paper11 = require("react-native-paper");
906
1013
 
907
1014
  // src/PopoverBody.tsx
908
- var import_react_native13 = require("react-native");
909
- var import_jsx_runtime12 = require("react/jsx-runtime");
1015
+ var import_react_native16 = require("react-native");
1016
+ var import_jsx_runtime14 = require("react/jsx-runtime");
910
1017
  var CARET_SIZE = 7;
911
1018
  var CARET_RING_OFFSET = 2;
912
1019
  var CARET_DIP = 1;
913
1020
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
914
1021
  if (!visible) return null;
915
1022
  const above = verticalAlign === "above";
916
- const alignStyle = align === "left" ? styles11.contentLeft : align === "right" ? styles11.contentRight : styles11.contentCenter;
917
- const verticalStyle = above ? styles11.contentAbove : styles11.contentBelow;
1023
+ const alignStyle = align === "left" ? styles13.contentLeft : align === "right" ? styles13.contentRight : styles13.contentCenter;
1024
+ const verticalStyle = above ? styles13.contentAbove : styles13.contentBelow;
918
1025
  const ringSize = CARET_SIZE + caretBorderWidth;
919
1026
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
920
1027
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
921
1028
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
922
1029
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
923
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: [styles11.content, alignStyle, verticalStyle], children: [
1030
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native16.View, { style: [styles13.content, alignStyle, verticalStyle], children: [
924
1031
  children,
925
- caretColor && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
927
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
1032
+ caretColor && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1033
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native16.View, { style: [styles13.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
1034
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native16.View, { style: [styles13.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
928
1035
  ] })
929
1036
  ] });
930
1037
  }
931
- var styles11 = import_react_native13.StyleSheet.create({
1038
+ var styles13 = import_react_native16.StyleSheet.create({
932
1039
  caret: {
933
1040
  borderLeftColor: "transparent",
934
1041
  borderRightColor: "transparent",
@@ -971,11 +1078,11 @@ var styles11 = import_react_native13.StyleSheet.create({
971
1078
  });
972
1079
 
973
1080
  // src/SkiaGate.tsx
974
- var import_react6 = require("react");
975
- var import_jsx_runtime13 = require("react/jsx-runtime");
1081
+ var import_react7 = require("react");
1082
+ var import_jsx_runtime15 = require("react/jsx-runtime");
976
1083
  function SkiaGate({ getComponent, componentProps, fallback = null }) {
977
- const [Component, setComponent] = (0, import_react6.useState)(null);
978
- (0, import_react6.useEffect)(() => {
1084
+ const [Component, setComponent] = (0, import_react7.useState)(null);
1085
+ (0, import_react7.useEffect)(() => {
979
1086
  let cancelled = false;
980
1087
  getComponent().then((mod) => {
981
1088
  if (!cancelled) setComponent(() => mod.default);
@@ -985,19 +1092,19 @@ function SkiaGate({ getComponent, componentProps, fallback = null }) {
985
1092
  };
986
1093
  }, [getComponent]);
987
1094
  if (!Component) return fallback;
988
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Component, { ...componentProps });
1095
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Component, { ...componentProps });
989
1096
  }
990
1097
 
991
1098
  // src/TriggerGaugeHost.tsx
992
- var import_jsx_runtime15 = require("react/jsx-runtime");
1099
+ var import_jsx_runtime17 = require("react/jsx-runtime");
993
1100
  var getTriggerGauge = () => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((mod) => ({ default: mod.TriggerGauge }));
994
1101
  function TriggerGaugeHost(props) {
995
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
1102
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
996
1103
  }
997
1104
 
998
1105
  // src/useAutoAlign.ts
999
- var import_react8 = require("react");
1000
- var import_react_native15 = require("react-native");
1106
+ var import_react9 = require("react");
1107
+ var import_react_native18 = require("react-native");
1001
1108
  var EDGE_MARGIN = 12;
1002
1109
  function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
1003
1110
  if (rotation === 0) return { x, y, width, height };
@@ -1009,18 +1116,18 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
1009
1116
  return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
1010
1117
  }
1011
1118
  function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
1012
- const triggerRef = (0, import_react8.useRef)(null);
1013
- const { width: windowWidth, height: windowHeight } = (0, import_react_native15.useWindowDimensions)();
1014
- const [align, setAlign] = (0, import_react8.useState)("center");
1015
- const [verticalAlign, setVerticalAlign] = (0, import_react8.useState)("below");
1016
- const [maxHeight, setMaxHeight] = (0, import_react8.useState)(contentHeight);
1017
- const [measured, setMeasured] = (0, import_react8.useState)(false);
1018
- const [prevOpen, setPrevOpen] = (0, import_react8.useState)(open);
1119
+ const triggerRef = (0, import_react9.useRef)(null);
1120
+ const { width: windowWidth, height: windowHeight } = (0, import_react_native18.useWindowDimensions)();
1121
+ const [align, setAlign] = (0, import_react9.useState)("center");
1122
+ const [verticalAlign, setVerticalAlign] = (0, import_react9.useState)("below");
1123
+ const [maxHeight, setMaxHeight] = (0, import_react9.useState)(contentHeight);
1124
+ const [measured, setMeasured] = (0, import_react9.useState)(false);
1125
+ const [prevOpen, setPrevOpen] = (0, import_react9.useState)(open);
1019
1126
  if (open !== prevOpen) {
1020
1127
  setPrevOpen(open);
1021
1128
  if (open) setMeasured(false);
1022
1129
  }
1023
- const measure = (0, import_react8.useCallback)(() => {
1130
+ const measure = (0, import_react9.useCallback)(() => {
1024
1131
  triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
1025
1132
  const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
1026
1133
  const centerX = x + triggerWidth / 2;
@@ -1037,14 +1144,14 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
1037
1144
  setMeasured(true);
1038
1145
  });
1039
1146
  }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
1040
- (0, import_react8.useEffect)(() => {
1147
+ (0, import_react9.useEffect)(() => {
1041
1148
  if (open) measure();
1042
1149
  }, [open, measure]);
1043
1150
  return { align, maxHeight, measured, triggerRef, verticalAlign };
1044
1151
  }
1045
1152
 
1046
1153
  // src/SectionedDropdown.tsx
1047
- var import_jsx_runtime16 = require("react/jsx-runtime");
1154
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1048
1155
  var MENU_BORDER_WIDTH = 1;
1049
1156
  var TRIGGER_SIZE = 44;
1050
1157
  var MENU_MIN_WIDTH = 200;
@@ -1056,11 +1163,11 @@ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
1056
1163
  var MENU_DIVIDER_HEIGHT = 9;
1057
1164
  var MENU_VERTICAL_PADDING = 12;
1058
1165
  function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
1059
- const ambientRotation = (0, import_core7.useRotation)();
1166
+ const ambientRotation = (0, import_core8.useRotation)();
1060
1167
  const rotation = rotationOverride ?? ambientRotation;
1061
1168
  const menuBg = dark ? "#000000" : "#FFFFFF";
1062
- const menuBorderColor = (0, import_auto_paper9.getBlendedColor)(mutedColor, menuBg, 0.5);
1063
- const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper9.getColorRoles)(accentColor, menuBg).onColor;
1169
+ const menuBorderColor = (0, import_auto_paper11.getBlendedColor)(mutedColor, menuBg, 0.5);
1170
+ const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper11.getColorRoles)(accentColor, menuBg).onColor;
1064
1171
  const fg = dark ? "#FFFFFF" : "#000000";
1065
1172
  const open = host.openId === id;
1066
1173
  const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
@@ -1094,17 +1201,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1094
1201
  }
1095
1202
  gaugeOffset += section.options.length;
1096
1203
  }
1097
- const anchorStyle = [styles13.anchor, open && styles13.anchorOpen];
1204
+ const anchorStyle = [styles15.anchor, open && styles15.anchorOpen];
1098
1205
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
1099
1206
  const dividerStyle = { backgroundColor: menuBorderColor };
1100
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: anchorStyle, children: [
1101
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { ref: triggerRef, collapsable: false, style: styles13.triggerBox, children: [
1102
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1103
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1207
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: anchorStyle, children: [
1208
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { ref: triggerRef, collapsable: false, style: styles15.triggerBox, children: [
1209
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1210
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1104
1211
  ] }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native16.ScrollView, { style: [styles13.menu, menuStyle], contentContainerStyle: styles13.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { children: [
1106
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native16.View, { style: [styles13.divider, dividerStyle] }),
1107
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1212
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native19.ScrollView, { style: [styles15.menu, menuStyle], contentContainerStyle: styles15.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { children: [
1213
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native19.View, { style: [styles15.divider, dividerStyle] }),
1214
+ section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1108
1215
  SingleSection,
1109
1216
  {
1110
1217
  section,
@@ -1117,7 +1224,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1117
1224
  if (autoDismiss) host.close();
1118
1225
  }
1119
1226
  }
1120
- ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1227
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1121
1228
  ] }, section.id)) }) })
1122
1229
  ] });
1123
1230
  }
@@ -1129,18 +1236,18 @@ function SingleSection({
1129
1236
  labelFontFamily,
1130
1237
  onSelect
1131
1238
  }) {
1132
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: section.options.map((option) => {
1239
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: section.options.map((option) => {
1133
1240
  const selected = option.value === section.value;
1134
1241
  const taken = !selected && option.value === section.takenValue;
1135
1242
  const rowColor = selected ? onAccentColor : mutedColor;
1136
- const itemStyle = [styles13.item, selected && { backgroundColor: accentColor }, taken && styles13.itemTaken];
1243
+ const itemStyle = [styles15.item, selected && { backgroundColor: accentColor }, taken && styles15.itemTaken];
1137
1244
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1138
1245
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1139
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemRow, children: [
1140
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1141
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemLabelColumn, children: [
1142
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1143
- option.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1246
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: styles15.itemRow, children: [
1247
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1248
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: styles15.itemLabelColumn, children: [
1249
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1250
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1144
1251
  ] })
1145
1252
  ] }) }, option.value);
1146
1253
  }) });
@@ -1154,23 +1261,23 @@ function MultiSection({
1154
1261
  allClearLabels
1155
1262
  }) {
1156
1263
  const allSelected = section.value.length === section.options.length;
1157
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1264
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1158
1265
  section.options.map((option, i) => {
1159
1266
  const selected = section.value.includes(option.value);
1160
1267
  const rowColor = selected ? onAccentColor : mutedColor;
1161
1268
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1162
1269
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1163
- const itemStyle = [styles13.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1270
+ const itemStyle = [styles15.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1164
1271
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1165
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemRow, children: [
1166
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1167
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles13.itemLabelFlex, labelStyle], children: option.label })
1272
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: styles15.itemRow, children: [
1273
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Text, { variant: "labelLarge", style: [styles15.itemLabelFlex, labelStyle], children: option.label })
1168
1275
  ] }) }, option.value);
1169
1276
  }),
1170
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles13.item, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles13.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1277
+ section.allClear && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles15.item, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper11.Text, { variant: "labelLarge", style: [styles15.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1171
1278
  ] });
1172
1279
  }
1173
- var styles13 = import_react_native16.StyleSheet.create({
1280
+ var styles15 = import_react_native19.StyleSheet.create({
1174
1281
  allClearLabel: {
1175
1282
  fontWeight: "bold",
1176
1283
  textAlign: "center"
@@ -1187,7 +1294,7 @@ var styles13 = import_react_native16.StyleSheet.create({
1187
1294
  zIndex: 100
1188
1295
  },
1189
1296
  divider: {
1190
- height: import_react_native16.StyleSheet.hairlineWidth,
1297
+ height: import_react_native19.StyleSheet.hairlineWidth,
1191
1298
  marginVertical: 4
1192
1299
  },
1193
1300
  item: {
@@ -1240,24 +1347,24 @@ var styles13 = import_react_native16.StyleSheet.create({
1240
1347
  });
1241
1348
 
1242
1349
  // src/ControlSchemePicker.tsx
1243
- var import_jsx_runtime17 = require("react/jsx-runtime");
1350
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1244
1351
  function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
1245
- const isTouchPrimary = (0, import_core8.useIsTouchPrimaryDevice)();
1246
- if (import_react_native17.Platform.OS !== "web" || isTouchPrimary) return null;
1247
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1352
+ const isTouchPrimary = (0, import_core9.useIsTouchPrimaryDevice)();
1353
+ if (import_react_native20.Platform.OS !== "web" || isTouchPrimary) return null;
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1248
1355
  }
1249
1356
 
1250
1357
  // src/CornerActionButtons.tsx
1251
1358
  var import_feedback_press5 = require("@rific/feedback-press");
1252
- var import_react_native18 = require("react-native");
1253
- var import_jsx_runtime18 = require("react/jsx-runtime");
1359
+ var import_react_native21 = require("react-native");
1360
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1254
1361
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back", hitSlop }) {
1255
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1256
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles14.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
1257
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles14.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
1362
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
1363
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles16.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
1364
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles16.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
1258
1365
  ] });
1259
1366
  }
1260
- var styles14 = import_react_native18.StyleSheet.create({
1367
+ var styles16 = import_react_native21.StyleSheet.create({
1261
1368
  back: {
1262
1369
  position: "absolute"
1263
1370
  },
@@ -1267,22 +1374,22 @@ var styles14 = import_react_native18.StyleSheet.create({
1267
1374
  });
1268
1375
 
1269
1376
  // src/CornerStatusBadges.tsx
1270
- var import_react_native19 = require("react-native");
1271
- var import_react_native_paper11 = require("react-native-paper");
1272
- var import_jsx_runtime19 = require("react/jsx-runtime");
1377
+ var import_react_native22 = require("react-native");
1378
+ var import_react_native_paper12 = require("react-native-paper");
1379
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1273
1380
  var BADGE_SIZE = 30;
1274
1381
  function StatusBadge({ icon }) {
1275
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { style: styles15.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1382
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native22.View, { style: styles17.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1276
1383
  }
1277
1384
  function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
1278
1385
  const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
1279
1386
  const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
1280
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1281
- p1 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { pointerEvents: "none", style: p1OnRightSide ? styles15.bottomRight : styles15.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { icon: p1.icon }) }),
1282
- p2 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { pointerEvents: "none", style: p2OnLeftSide ? styles15.topLeft : styles15.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { icon: p2.icon }) })
1387
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1388
+ p1 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native22.View, { pointerEvents: "none", style: p1OnRightSide ? styles17.bottomRight : styles17.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusBadge, { icon: p1.icon }) }),
1389
+ p2 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native22.View, { pointerEvents: "none", style: p2OnLeftSide ? styles17.topLeft : styles17.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusBadge, { icon: p2.icon }) })
1283
1390
  ] });
1284
1391
  }
1285
- var styles15 = import_react_native19.StyleSheet.create({
1392
+ var styles17 = import_react_native22.StyleSheet.create({
1286
1393
  badge: {
1287
1394
  alignItems: "center",
1288
1395
  backgroundColor: "rgba(0,0,0,0.28)",
@@ -1301,12 +1408,12 @@ var styles15 = import_react_native19.StyleSheet.create({
1301
1408
  });
1302
1409
 
1303
1410
  // src/InlineColorPicker.tsx
1304
- var import_auto_paper10 = require("@rific/auto-paper");
1411
+ var import_auto_paper12 = require("@rific/auto-paper");
1305
1412
  var import_feedback_press6 = require("@rific/feedback-press");
1306
- var import_core9 = require("@tastic/core");
1307
- var import_react_native20 = require("react-native");
1308
- var import_react_native_paper12 = require("react-native-paper");
1309
- var import_jsx_runtime20 = require("react/jsx-runtime");
1413
+ var import_core10 = require("@tastic/core");
1414
+ var import_react_native23 = require("react-native");
1415
+ var import_react_native_paper13 = require("react-native-paper");
1416
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1310
1417
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
1311
1418
  var DEFAULT_SIZE = 48;
1312
1419
  var SWATCH_SIZE = 28;
@@ -1320,18 +1427,18 @@ function widthForColumns(columns) {
1320
1427
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
1321
1428
  }
1322
1429
  function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
1323
- const autoColumns = (0, import_core9.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
1430
+ const autoColumns = (0, import_core10.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
1324
1431
  const resolvedColumns = columns ?? autoColumns;
1325
1432
  const width = widthForColumns(resolvedColumns);
1326
1433
  const rows = Math.ceil(swatchCount / resolvedColumns);
1327
1434
  const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
1328
1435
  return { width, height };
1329
1436
  }
1330
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper10.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1331
- const ambientRotation = (0, import_core9.useRotation)();
1437
+ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper12.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1438
+ const ambientRotation = (0, import_core10.useRotation)();
1332
1439
  const rotation = rotationOverride ?? ambientRotation;
1333
1440
  const menuBg = dark ? "#000000" : "#FFFFFF";
1334
- const { width: windowWidth } = (0, import_react_native20.useWindowDimensions)();
1441
+ const { width: windowWidth } = (0, import_react_native23.useWindowDimensions)();
1335
1442
  const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
1336
1443
  const open = host.openId === id;
1337
1444
  const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
@@ -1340,16 +1447,16 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1340
1447
  const align = forcedAlign ?? placement.align;
1341
1448
  const displayFor = previewValue ?? ((hex) => hex);
1342
1449
  const displayValue = displayFor(value);
1343
- const contrastColor = (0, import_auto_paper10.getContrastColor)(displayValue);
1450
+ const contrastColor = (0, import_auto_paper12.getContrastColor)(displayValue);
1344
1451
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
1345
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: [styles16.anchor, open && styles16.anchorOpen], children: [
1346
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles16.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { ref: triggerRef, collapsable: false, style: styles16.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1347
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.ScrollView, { style: [styles16.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles16.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1452
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native23.View, { style: [styles18.anchor, open && styles18.anchorOpen], children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles18.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native23.View, { ref: triggerRef, collapsable: false, style: styles18.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Text, { style: [styles18.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native23.ScrollView, { style: [styles18.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles18.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1348
1455
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
1349
1456
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
1350
1457
  const swappable = taken && allowSwapTaken;
1351
1458
  const swatchDisplay = displayFor(swatch.value);
1352
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1353
1460
  import_feedback_press6.TouchableRipple,
1354
1461
  {
1355
1462
  disabled: taken && !swappable,
@@ -1358,15 +1465,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1358
1465
  if (autoDismiss) host.close();
1359
1466
  },
1360
1467
  borderless: true,
1361
- style: [styles16.swatch, { backgroundColor: swatchDisplay }, selected && styles16.swatchSelected, taken && !swappable && styles16.swatchTaken],
1362
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "check", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "close", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, {})
1468
+ style: [styles18.swatch, { backgroundColor: swatchDisplay }, selected && styles18.swatchSelected, taken && !swappable && styles18.swatchTaken],
1469
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Icon, { source: "check", size: 16, color: (0, import_auto_paper12.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper12.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Icon, { source: "close", size: 16, color: (0, import_auto_paper12.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native23.View, {})
1363
1470
  },
1364
1471
  swatch.value
1365
1472
  );
1366
1473
  }) }) })
1367
1474
  ] });
1368
1475
  }
1369
- var styles16 = import_react_native20.StyleSheet.create({
1476
+ var styles18 = import_react_native23.StyleSheet.create({
1370
1477
  anchor: {
1371
1478
  position: "relative"
1372
1479
  },
@@ -1438,11 +1545,11 @@ var styles16 = import_react_native20.StyleSheet.create({
1438
1545
  });
1439
1546
 
1440
1547
  // src/LabeledDropdown.tsx
1441
- var import_auto_paper11 = require("@rific/auto-paper");
1548
+ var import_auto_paper13 = require("@rific/auto-paper");
1442
1549
  var import_feedback_press7 = require("@rific/feedback-press");
1443
- var import_react_native21 = require("react-native");
1444
- var import_react_native_paper13 = require("react-native-paper");
1445
- var import_jsx_runtime21 = require("react/jsx-runtime");
1550
+ var import_react_native24 = require("react-native");
1551
+ var import_react_native_paper14 = require("react-native-paper");
1552
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1446
1553
  var TRIGGER_HEIGHT = 28;
1447
1554
  var POPOVER_WIDTH = 180;
1448
1555
  var ROW_HEIGHT = 36;
@@ -1465,22 +1572,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
1465
1572
  onChange(option.value);
1466
1573
  host.close();
1467
1574
  };
1468
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: [styles17.anchor, open && styles17.anchorOpen], children: [
1469
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles17.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { ref: triggerRef, collapsable: false, style: styles17.triggerInner, children: [
1470
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { style: [styles17.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1471
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Icon, { source: "menu-down", size: 16, color })
1575
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native24.View, { style: [styles19.anchor, open && styles19.anchorOpen], children: [
1576
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles19.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native24.View, { ref: triggerRef, collapsable: false, style: styles19.triggerInner, children: [
1577
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper14.Text, { style: [styles19.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1578
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper14.Icon, { source: "menu-down", size: 16, color })
1472
1579
  ] }) }),
1473
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.ScrollView, { style: [styles17.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles17.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1580
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native24.ScrollView, { style: [styles19.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles19.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1474
1581
  const isSelected = option.value === value;
1475
- const onColor = (0, import_auto_paper11.getContrastColor)(color);
1476
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles17.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: styles17.rowInner, children: [
1477
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1478
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { style: [styles17.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1582
+ const onColor = (0, import_auto_paper13.getContrastColor)(color);
1583
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles19.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native24.View, { style: styles19.rowInner, children: [
1584
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper14.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper14.Text, { style: [styles19.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1479
1586
  ] }) }, option.value);
1480
1587
  }) }) })
1481
1588
  ] });
1482
1589
  }
1483
- var styles17 = import_react_native21.StyleSheet.create({
1590
+ var styles19 = import_react_native24.StyleSheet.create({
1484
1591
  anchor: {
1485
1592
  position: "relative"
1486
1593
  },
@@ -1539,21 +1646,21 @@ function loadSkiaWeb() {
1539
1646
 
1540
1647
  // src/PlayerSetupPanel.tsx
1541
1648
  var import_profile2 = require("@tastic/profile");
1542
- var import_react_native23 = require("react-native");
1543
- var import_react_native_paper15 = require("react-native-paper");
1649
+ var import_react_native26 = require("react-native");
1650
+ var import_react_native_paper16 = require("react-native-paper");
1544
1651
 
1545
1652
  // src/ReadyButton.tsx
1546
1653
  var import_feedback_press8 = require("@rific/feedback-press");
1547
- var import_react_native22 = require("react-native");
1548
- var import_react_native_paper14 = require("react-native-paper");
1549
- var import_jsx_runtime22 = require("react/jsx-runtime");
1654
+ var import_react_native25 = require("react-native");
1655
+ var import_react_native_paper15 = require("react-native-paper");
1656
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1550
1657
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
1551
- const readyButtonStyle = [styles18.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1658
+ const readyButtonStyle = [styles20.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1552
1659
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
1553
1660
  const labelColorStyle = { color: ready ? "#000000" : color };
1554
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper14.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native_paper15.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1555
1662
  }
1556
- var styles18 = import_react_native22.StyleSheet.create({
1663
+ var styles20 = import_react_native25.StyleSheet.create({
1557
1664
  readyButton: {
1558
1665
  alignItems: "center",
1559
1666
  borderRadius: 12,
@@ -1566,18 +1673,18 @@ var styles18 = import_react_native22.StyleSheet.create({
1566
1673
  });
1567
1674
 
1568
1675
  // src/usePopoverHost.ts
1569
- var import_react9 = require("react");
1676
+ var import_react10 = require("react");
1570
1677
  function usePopoverHost() {
1571
- const [openId, setOpenId] = (0, import_react9.useState)(null);
1572
- const toggle = (0, import_react9.useCallback)((id) => {
1678
+ const [openId, setOpenId] = (0, import_react10.useState)(null);
1679
+ const toggle = (0, import_react10.useCallback)((id) => {
1573
1680
  setOpenId((prev) => prev === id ? null : id);
1574
1681
  }, []);
1575
- const close = (0, import_react9.useCallback)(() => setOpenId(null), []);
1682
+ const close = (0, import_react10.useCallback)(() => setOpenId(null), []);
1576
1683
  return { openId, toggle, close };
1577
1684
  }
1578
1685
 
1579
1686
  // src/PlayerSetupPanel.tsx
1580
- var import_jsx_runtime23 = require("react/jsx-runtime");
1687
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1581
1688
  function getColorPopoverId(idPrefix) {
1582
1689
  return `${idPrefix}-color`;
1583
1690
  }
@@ -1592,16 +1699,16 @@ function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onCol
1592
1699
  const showProfilePicker = isHuman && profiles !== void 0 && !!onProfileSelect;
1593
1700
  const showCpuDifficulty = !isHuman && cpuDifficulty !== void 0 && cpuDifficultyOptions !== void 0 && !!onCpuDifficultyChange;
1594
1701
  const selectedProfile = profiles?.find((p) => p.id === selectedProfileId) ?? null;
1595
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: [styles19.panel, ownPopoverOpen && styles19.panelOpen], children: [
1596
- showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_profile2.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper15.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1597
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: [styles19.pickerRow, pickerRowPopoverOpen && styles19.pickerRowOpen], children: [
1598
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1702
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native26.View, { style: [styles21.panel, ownPopoverOpen && styles21.panelOpen], children: [
1703
+ showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_profile2.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native_paper16.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1704
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native26.View, { style: [styles21.pickerRow, pickerRowPopoverOpen && styles21.pickerRowOpen], children: [
1705
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1599
1706
  secondPicker
1600
1707
  ] }),
1601
- isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1708
+ isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1602
1709
  ] });
1603
1710
  }
1604
- var styles19 = import_react_native23.StyleSheet.create({
1711
+ var styles21 = import_react_native26.StyleSheet.create({
1605
1712
  panel: {
1606
1713
  alignItems: "center",
1607
1714
  gap: 12
@@ -1633,29 +1740,29 @@ var styles19 = import_react_native23.StyleSheet.create({
1633
1740
  });
1634
1741
 
1635
1742
  // src/PressAwayOverlay.tsx
1636
- var import_react_native24 = require("react-native");
1637
- var import_jsx_runtime24 = require("react/jsx-runtime");
1743
+ var import_react_native27 = require("react-native");
1744
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1638
1745
  function PressAwayOverlay({ active, onPress, style }) {
1639
1746
  if (!active) return null;
1640
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native24.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native24.StyleSheet.absoluteFill, style] });
1747
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native27.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native27.StyleSheet.absoluteFill, style] });
1641
1748
  }
1642
1749
 
1643
1750
  // src/SharedActionBand.tsx
1644
1751
  var import_feedback_press9 = require("@rific/feedback-press");
1645
- var import_react_native25 = require("react-native");
1646
- var import_jsx_runtime25 = require("react/jsx-runtime");
1752
+ var import_react_native28 = require("react-native");
1753
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1647
1754
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1648
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native25.View, { style: [styles20.column, popoverOpen && styles20.columnOpen], children: [
1649
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native25.View, { style: styles20.actionsRow, children: [
1650
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1651
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1652
- onReset && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1653
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1755
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react_native28.View, { style: [styles22.column, popoverOpen && styles22.columnOpen], children: [
1756
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react_native28.View, { style: styles22.actionsRow, children: [
1757
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1758
+ onRandomize && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1759
+ onReset && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1760
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1654
1761
  ] }),
1655
1762
  children
1656
1763
  ] });
1657
1764
  }
1658
- var styles20 = import_react_native25.StyleSheet.create({
1765
+ var styles22 = import_react_native28.StyleSheet.create({
1659
1766
  actionsRow: {
1660
1767
  alignItems: "center",
1661
1768
  flexDirection: "row",
@@ -1671,10 +1778,10 @@ var styles20 = import_react_native25.StyleSheet.create({
1671
1778
  });
1672
1779
 
1673
1780
  // src/StaggeredWord.tsx
1674
- var import_react10 = require("react");
1675
- var import_react_native26 = require("react-native");
1781
+ var import_react11 = require("react");
1782
+ var import_react_native29 = require("react-native");
1676
1783
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
1677
- var import_jsx_runtime26 = require("react/jsx-runtime");
1784
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1678
1785
  var STAGGER_MS = 45;
1679
1786
  var LETTER_DURATION_MS = 320;
1680
1787
  function getStaggeredWordDuration(letterCount) {
@@ -1682,7 +1789,7 @@ function getStaggeredWordDuration(letterCount) {
1682
1789
  }
1683
1790
  function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
1684
1791
  const progress = (0, import_react_native_reanimated2.useSharedValue)(reducedMotion ? 1 : 0);
1685
- (0, import_react10.useEffect)(() => {
1792
+ (0, import_react11.useEffect)(() => {
1686
1793
  if (reducedMotion) return;
1687
1794
  progress.value = (0, import_react_native_reanimated2.withDelay)(index * STAGGER_MS, (0, import_react_native_reanimated2.withTiming)(1, { duration: LETTER_DURATION_MS, easing: import_react_native_reanimated2.Easing.out(import_react_native_reanimated2.Easing.back(1.5)) }));
1688
1795
  }, [reducedMotion]);
@@ -1690,12 +1797,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
1690
1797
  opacity: progress.value,
1691
1798
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
1692
1799
  }));
1693
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1694
1801
  }
1695
1802
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
1696
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.View, { style: [styles21.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1803
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_native29.View, { style: [styles23.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1697
1804
  }
1698
- var styles21 = import_react_native26.StyleSheet.create({
1805
+ var styles23 = import_react_native29.StyleSheet.create({
1699
1806
  row: {
1700
1807
  flexDirection: "row"
1701
1808
  }
@@ -1703,53 +1810,53 @@ var styles21 = import_react_native26.StyleSheet.create({
1703
1810
 
1704
1811
  // src/UpdateDialog.tsx
1705
1812
  var import_updater2 = require("@rific/updater");
1706
- var import_jsx_runtime27 = require("react/jsx-runtime");
1813
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1707
1814
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
1708
1815
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
1709
1816
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
1710
1817
  const date = manifest ? new Date(manifest.createdAt) : null;
1711
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1818
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1712
1819
  }
1713
1820
 
1714
1821
  // src/useQuitConfirmation.ts
1715
- var import_react11 = require("react");
1822
+ var import_react12 = require("react");
1716
1823
  function useQuitConfirmation(hasProgress, onConfirmedBack) {
1717
- const [confirmVisible, setConfirmVisible] = (0, import_react11.useState)(false);
1718
- const hasProgressRef = (0, import_react11.useRef)(hasProgress);
1719
- (0, import_react11.useEffect)(() => {
1824
+ const [confirmVisible, setConfirmVisible] = (0, import_react12.useState)(false);
1825
+ const hasProgressRef = (0, import_react12.useRef)(hasProgress);
1826
+ (0, import_react12.useEffect)(() => {
1720
1827
  hasProgressRef.current = hasProgress;
1721
1828
  });
1722
- const onConfirmedBackRef = (0, import_react11.useRef)(onConfirmedBack);
1723
- (0, import_react11.useEffect)(() => {
1829
+ const onConfirmedBackRef = (0, import_react12.useRef)(onConfirmedBack);
1830
+ (0, import_react12.useEffect)(() => {
1724
1831
  onConfirmedBackRef.current = onConfirmedBack;
1725
1832
  });
1726
- const requestBack = (0, import_react11.useCallback)(() => {
1833
+ const requestBack = (0, import_react12.useCallback)(() => {
1727
1834
  if (hasProgressRef.current()) setConfirmVisible(true);
1728
1835
  else onConfirmedBackRef.current();
1729
1836
  }, []);
1730
- const cancelBack = (0, import_react11.useCallback)(() => setConfirmVisible(false), []);
1837
+ const cancelBack = (0, import_react12.useCallback)(() => setConfirmVisible(false), []);
1731
1838
  return { confirmVisible, requestBack, cancelBack };
1732
1839
  }
1733
1840
 
1734
1841
  // src/useZoneClampedAlign.ts
1735
1842
  var import_split_screen = require("@tastic/split-screen");
1736
- var import_react12 = require("react");
1737
- var import_react_native27 = require("react-native");
1738
- var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
1843
+ var import_react13 = require("react");
1844
+ var import_react_native30 = require("react-native");
1845
+ var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
1739
1846
  var EDGE_MARGIN2 = 12;
1740
1847
  function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1741
1848
  const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
1742
1849
  const zone = (0, import_split_screen.useZoneBounds)();
1743
- const { height: windowHeight } = (0, import_react_native27.useWindowDimensions)();
1744
- const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
1850
+ const { height: windowHeight } = (0, import_react_native30.useWindowDimensions)();
1851
+ const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
1745
1852
  const shouldMeasure = open && auto.measured && zone !== null;
1746
- const [ownBounds, setOwnBounds] = (0, import_react12.useState)(null);
1747
- const [prevShouldMeasure, setPrevShouldMeasure] = (0, import_react12.useState)(shouldMeasure);
1853
+ const [ownBounds, setOwnBounds] = (0, import_react13.useState)(null);
1854
+ const [prevShouldMeasure, setPrevShouldMeasure] = (0, import_react13.useState)(shouldMeasure);
1748
1855
  if (shouldMeasure !== prevShouldMeasure) {
1749
1856
  setPrevShouldMeasure(shouldMeasure);
1750
1857
  setOwnBounds(null);
1751
1858
  }
1752
- (0, import_react12.useEffect)(() => {
1859
+ (0, import_react13.useEffect)(() => {
1753
1860
  if (!shouldMeasure) return;
1754
1861
  auto.triggerRef.current?.measureInWindow((_x, y, _width, height) => {
1755
1862
  const belowShared = zone.zoneSide === "belowShared";
@@ -1777,16 +1884,20 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1777
1884
  ActivityStatSection,
1778
1885
  BaseSettingsDialog,
1779
1886
  BaseStatsScreen,
1887
+ COMPACT_DIALOG_HEIGHT,
1780
1888
  ConfirmDialog,
1781
1889
  ContentGutter,
1782
1890
  ControlSchemePicker,
1783
1891
  CornerActionButtons,
1784
1892
  CornerStatusBadges,
1893
+ DialogHeader,
1785
1894
  InlineColorPicker,
1786
1895
  LABELED_DROPDOWN_POPOVER_WIDTH,
1787
1896
  LOCKED_BADGE_COLOR,
1788
1897
  LabeledDropdown,
1789
1898
  MONO_FONT,
1899
+ OverlayBackdrop,
1900
+ OverlayCard,
1790
1901
  PlayerSetupPanel,
1791
1902
  PopoverBody,
1792
1903
  PressAwayOverlay,
@@ -1804,12 +1915,14 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1804
1915
  getCpuDifficultyPopoverId,
1805
1916
  getInlineColorPickerContentSize,
1806
1917
  getLabeledDropdownContentHeight,
1807
- getOverlayCardColors,
1808
1918
  getStaggeredWordDuration,
1919
+ isCompactDialogHeight,
1809
1920
  loadSkiaWeb,
1810
1921
  overlayActionStyles,
1811
1922
  overlayStyles,
1812
1923
  useAutoAlign,
1924
+ useCompactDialog,
1925
+ useOverlayCardColors,
1813
1926
  usePopoverHost,
1814
1927
  useQuitConfirmation,
1815
1928
  useZoneClampedAlign