@tastic/hud 0.17.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_runtime15.jsx)(import_react_native15.View, { style: [styles13.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime15.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_runtime15.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_native15, import_react_native_reanimated, import_jsx_runtime15, 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, styles13;
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_native15 = 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_runtime15 = 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
- styles13 = import_react_native15.StyleSheet.create({
157
+ styles14 = import_react_native17.StyleSheet.create({
158
158
  container: {
159
159
  alignItems: "center",
160
160
  justifyContent: "center",
@@ -173,11 +173,13 @@ __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,
@@ -202,12 +204,13 @@ __export(index_exports, {
202
204
  getCpuDifficultyPopoverId: () => getCpuDifficultyPopoverId,
203
205
  getInlineColorPickerContentSize: () => getInlineColorPickerContentSize,
204
206
  getLabeledDropdownContentHeight: () => getLabeledDropdownContentHeight,
205
- getOverlayCardColors: () => getOverlayCardColors,
206
207
  getStaggeredWordDuration: () => getStaggeredWordDuration,
208
+ isCompactDialogHeight: () => isCompactDialogHeight,
207
209
  loadSkiaWeb: () => loadSkiaWeb,
208
210
  overlayActionStyles: () => overlayActionStyles,
209
211
  overlayStyles: () => overlayStyles,
210
212
  useAutoAlign: () => useAutoAlign,
213
+ useCompactDialog: () => useCompactDialog,
211
214
  useOverlayCardColors: () => useOverlayCardColors,
212
215
  usePopoverHost: () => usePopoverHost,
213
216
  useQuitConfirmation: () => useQuitConfirmation,
@@ -420,39 +423,74 @@ function ActivityStatSection({ stats }) {
420
423
  }
421
424
 
422
425
  // src/BaseSettingsDialog.tsx
423
- var import_auto_paper8 = require("@rific/auto-paper");
426
+ var import_auto_paper9 = require("@rific/auto-paper");
424
427
  var import_feedback_press2 = require("@rific/feedback-press");
425
428
  var import_updater = require("@rific/updater");
426
- var import_core3 = require("@tastic/core");
427
- var import_react4 = require("react");
428
- var import_react_native11 = require("react-native");
429
- 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");
430
434
 
431
435
  // src/ConfirmDialog.tsx
432
- var import_auto_paper7 = require("@rific/auto-paper");
436
+ var import_auto_paper8 = require("@rific/auto-paper");
433
437
  var import_feedback_press = require("@rific/feedback-press");
434
- var import_core = require("@tastic/core");
435
- var import_react_native9 = require("react-native");
436
- 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");
437
441
 
438
- // src/overlayCard.ts
442
+ // src/DialogHeader.tsx
443
+ var import_auto_paper6 = require("@rific/auto-paper");
439
444
  var import_react_native7 = require("react-native");
440
- function getOverlayCardColors(dark) {
441
- return {
442
- fg: dark ? "#FFFFFF" : "#000000",
443
- fgMuted: dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)",
444
- cardBg: dark ? "#111111" : "#F2F2F2",
445
- cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
446
- };
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;
450
+ }
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
+ ] });
447
458
  }
448
- var overlayStyles = import_react_native7.StyleSheet.create({
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({
449
488
  card: {
450
489
  alignItems: "center",
451
- borderRadius: 20,
452
- borderWidth: 1,
490
+ borderRadius: 28,
453
491
  gap: 16,
454
492
  maxWidth: 360,
455
- padding: 32
493
+ padding: 24
456
494
  },
457
495
  overlay: {
458
496
  alignItems: "center",
@@ -465,7 +503,7 @@ var overlayStyles = import_react_native7.StyleSheet.create({
465
503
  top: 0
466
504
  }
467
505
  });
468
- var overlayActionStyles = import_react_native7.StyleSheet.create({
506
+ var overlayActionStyles = import_react_native8.StyleSheet.create({
469
507
  // minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
470
508
  // still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
471
509
  // on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
@@ -508,46 +546,63 @@ var overlayActionStyles = import_react_native7.StyleSheet.create({
508
546
  });
509
547
 
510
548
  // src/OverlaySurface.tsx
511
- var import_auto_paper6 = require("@rific/auto-paper");
512
- var import_react_native8 = require("react-native");
513
- var import_jsx_runtime7 = require("react/jsx-runtime");
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");
514
552
  function useOverlayCardColors() {
515
- const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
553
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
516
554
  return { fg: colors.onSurface, fgMuted: colors.onSurfaceVariant, cardBorder: colors.outlineVariant, backdrop: colors.backdrop };
517
555
  }
518
- function OverlayBackdrop({ children, style }) {
556
+ function OverlayBackdrop({ children, style, onLayout }) {
519
557
  const { backdrop } = useOverlayCardColors();
520
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
558
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { onLayout, style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
521
559
  }
522
560
  function OverlayCard({ children, style, ...rest }) {
523
- const { cardBorder } = useOverlayCardColors();
524
- const blur = (0, import_auto_paper6.useBlur)();
525
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper6.BlurView, { blur, elevation: 3, style: [overlayStyles.card, styles6.card, { borderColor: cardBorder }, style], ...rest, children });
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 });
526
564
  }
527
- var styles6 = import_react_native8.StyleSheet.create({
565
+ var styles7 = import_react_native9.StyleSheet.create({
528
566
  card: { overflow: "hidden" }
529
567
  });
530
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
+
531
586
  // src/ConfirmDialog.tsx
532
- var import_jsx_runtime8 = require("react/jsx-runtime");
587
+ var import_jsx_runtime9 = require("react/jsx-runtime");
533
588
  function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
534
- const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
589
+ const { colors } = (0, import_auto_paper8.useAutoPaperTheme)();
535
590
  const { fg } = useOverlayCardColors();
591
+ const { compact, onLayout } = useCompactDialog(rotation);
536
592
  if (!visible) return null;
537
593
  const accent = destructive ? colors.danger : colors.primary;
538
594
  const onAccent = destructive ? colors.onDanger : colors.onPrimary;
539
595
  const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
540
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OverlayBackdrop, { style: styles7.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(OverlayCard, { style: [styles7.card, (0, import_core.toRotationStyle)(rotation)], children: [
541
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Icon, { source: icon, size: 64, color: accent }),
542
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Text, { variant: "headlineLarge", style: [styles7.title, { color: accent }], children: title }),
543
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: [styles7.body, { color: fg }], children: message }),
544
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: overlayActionStyles.actions, children: [
545
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
546
- /* @__PURE__ */ (0, import_jsx_runtime8.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 })
547
602
  ] })
548
603
  ] }) }) });
549
604
  }
550
- var styles7 = import_react_native9.StyleSheet.create({
605
+ var styles8 = import_react_native11.StyleSheet.create({
551
606
  body: {
552
607
  textAlign: "center"
553
608
  },
@@ -565,35 +620,28 @@ var styles7 = import_react_native9.StyleSheet.create({
565
620
  // screen narrower than maxWidth's own 360.
566
621
  overlay: {
567
622
  paddingHorizontal: 24
568
- },
569
- // textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
570
- // within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
571
- // line inside that block still defaults to left-aligned without this.
572
- title: {
573
- fontWeight: "bold",
574
- textAlign: "center"
575
623
  }
576
624
  });
577
625
 
578
626
  // src/RotatedFrame.tsx
579
- var import_core2 = require("@tastic/core");
580
- var import_react2 = require("react");
581
- var import_react_native10 = require("react-native");
582
- 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");
583
631
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
584
- var import_jsx_runtime9 = require("react/jsx-runtime");
632
+ var import_jsx_runtime10 = require("react/jsx-runtime");
585
633
  function RotatedFrame({ children, rotation: rotationOverride, rotatedSafeArea = false, portalHost = false, passThrough = false, maxContentWidth }) {
586
- const ambientRotation = (0, import_core2.useRotation)();
634
+ const ambientRotation = (0, import_core3.useRotation)();
587
635
  const rotation = rotationOverride ?? ambientRotation;
588
- const window = (0, import_react_native10.useWindowDimensions)();
589
- 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);
590
638
  const rawInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
591
- 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]);
592
640
  const cappedWidth = maxContentWidth !== void 0 && width > height ? maxContentWidth : void 0;
593
- const column = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
594
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles8.root, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime9.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 }) });
595
643
  }
596
- var styles8 = import_react_native10.StyleSheet.create({
644
+ var styles9 = import_react_native12.StyleSheet.create({
597
645
  // A centred column: full width up to `maxWidth`, so a capped frame sits in the middle of a wider window.
598
646
  column: {
599
647
  alignSelf: "center",
@@ -606,18 +654,18 @@ var styles8 = import_react_native10.StyleSheet.create({
606
654
  });
607
655
 
608
656
  // src/useUpdateConfirmBridge.ts
609
- var import_react3 = require("react");
657
+ var import_react4 = require("react");
610
658
  function useUpdateConfirmBridge() {
611
- const [manifest, setManifest] = (0, import_react3.useState)(null);
612
- const resolveRef = (0, import_react3.useRef)(null);
613
- 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)(
614
662
  (next) => new Promise((resolve) => {
615
663
  resolveRef.current = resolve;
616
664
  setManifest(next);
617
665
  }),
618
666
  []
619
667
  );
620
- const respond = (0, import_react3.useCallback)((confirmed) => {
668
+ const respond = (0, import_react4.useCallback)((confirmed) => {
621
669
  setManifest(null);
622
670
  resolveRef.current?.(confirmed);
623
671
  resolveRef.current = null;
@@ -626,22 +674,27 @@ function useUpdateConfirmBridge() {
626
674
  }
627
675
 
628
676
  // src/BaseSettingsDialog.tsx
629
- var import_jsx_runtime10 = require("react/jsx-runtime");
677
+ var import_jsx_runtime11 = require("react/jsx-runtime");
630
678
  function SettingIcon({ source, color, containerColor }) {
631
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime10.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 }) });
632
680
  }
633
681
  function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
634
- const { colors } = (0, import_auto_paper8.useAutoPaperTheme)();
635
- const ambientRotation = (0, import_core3.useRotation)();
682
+ const { colors } = (0, import_auto_paper9.useAutoPaperTheme)();
683
+ const ambientRotation = (0, import_core4.useRotation)();
636
684
  const rotation = rotationOverride ?? ambientRotation;
637
- 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)();
638
691
  const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press2.useHapticSettings)();
639
692
  const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
640
- const sound = (0, import_react4.useContext)(import_feedback_press2.SoundContext);
693
+ const sound = (0, import_react5.useContext)(import_feedback_press2.SoundContext);
641
694
  const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
642
- const { settings: themeSettings, set: setThemeSettings } = (0, import_auto_paper8.useThemeSettings)();
643
- const expoBlur = (0, import_auto_paper8.useBlurModule)();
644
- 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);
645
698
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
646
699
  const { check, checking, updateReady } = (0, import_updater.useUpdater)({
647
700
  autoCheck: false,
@@ -651,117 +704,124 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
651
704
  onInfo: (title, message) => setInfoMessage({ title, message })
652
705
  });
653
706
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
654
- const [opened, setOpened] = (0, import_react4.useState)(visible);
707
+ const [opened, setOpened] = (0, import_react5.useState)(visible);
655
708
  if (visible && !opened) setOpened(true);
656
709
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
657
- const showEdgeGuard = import_react_native11.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
658
- const showHaptics = import_react_native11.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;
659
712
  const showSound = !hideSound;
660
713
  const showAppearance = !hideAppearance;
661
- const showBlur = showAppearance && import_react_native11.Platform.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
662
- const showUpdateCheck = import_react_native11.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;
663
716
  if (!opened) return null;
664
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
665
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_auto_paper8.Dialog, { visible, onDismiss, style: styles9.dialog, children: [
666
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper8.Dialog.Title, { children: "Settings" }),
667
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper8.Dialog.ScrollArea, { style: styles9.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.ScrollView, { contentContainerStyle: styles9.content, showsVerticalScrollIndicator: false, children: [
668
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleGroup, children: [
669
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles9.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
670
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
671
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.flexShrink, children: [
672
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
673
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
674
- ] })
675
- ] }) }),
676
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles9.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
677
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
678
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.flexShrink, children: [
679
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
680
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
681
- ] })
682
- ] }) }),
683
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleRow, children: [
684
- showSound && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
685
- import_feedback_press2.TouchableRipple,
686
- {
687
- soundDisabled: true,
688
- onPress: () => {
689
- const enabled = !soundSettings.enabled;
690
- setSoundSettings({ enabled });
691
- if (enabled) sound.selection?.();
692
- },
693
- style: styles9.toggleButtonInRow,
694
- accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
695
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
696
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
697
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
698
- ] })
699
- }
700
- ),
701
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime10.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)(
702
774
  import_feedback_press2.TouchableRipple,
703
775
  {
704
- hapticDisabled: true,
705
776
  onPress: () => {
706
- const vibrate = !hapticSettings.vibrate;
707
- setHapticSettings({ vibrate });
708
- if (vibrate) forceHapticFeedback();
777
+ onDismiss();
778
+ onShowHowToPlay();
709
779
  },
710
- style: styles9.toggleButtonInRow,
711
- accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
712
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
713
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
714
- /* @__PURE__ */ (0, import_jsx_runtime10.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
+ ] })
715
788
  ] })
716
789
  }
717
790
  )
718
791
  ] }),
719
- onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
720
- import_feedback_press2.TouchableRipple,
721
- {
722
- onPress: () => {
723
- onDismiss();
724
- onShowHowToPlay();
725
- },
726
- style: styles9.toggleButton,
727
- accessibilityLabel: "How to Play",
728
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
729
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
730
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.flexShrink, children: [
731
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
732
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
733
- ] })
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" })
734
800
  ] })
735
- }
736
- )
737
- ] }),
738
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.section, children: [
739
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "labelMedium", style: [styles9.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
740
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper8.AutoAppearancePicker, { showLabels: false }),
741
- showBlur && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles9.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.toggleContent, children: [
742
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
743
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" })
744
- ] }) })
745
- ] }),
746
- children,
747
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles9.section, children: [
748
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_paper8.Text, { variant: "labelSmall", style: [styles9.sectionLabel, { color: colors.onSurfaceVariant }], children: [
749
- "VERSION ",
750
- version,
751
- updateReady ? " \xB7 UPDATE READY" : ""
801
+ ] }) })
752
802
  ] }),
753
- /* @__PURE__ */ (0, import_jsx_runtime10.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
+ ] })
754
812
  ] })
755
- ] }) })
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" }) })
756
815
  ] }),
757
- /* @__PURE__ */ (0, import_jsx_runtime10.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) }),
758
- /* @__PURE__ */ (0, import_jsx_runtime10.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) })
759
818
  ] }) });
760
819
  }
761
- var styles9 = import_react_native11.StyleSheet.create({
820
+ var SHEET_GUTTER = 24;
821
+ var styles10 = import_react_native13.StyleSheet.create({
822
+ // The rows' sections, 24pt apart.
762
823
  content: {
763
- gap: 24,
764
- paddingVertical: 20
824
+ gap: 24
765
825
  },
766
826
  // Caps the card so it never grows past the screen - without this the dialog just keeps
767
827
  // growing to fit its content and the overflow gets clipped by the screen edge, which is
@@ -773,6 +833,11 @@ var styles9 = import_react_native11.StyleSheet.create({
773
833
  flexShrink: {
774
834
  flexShrink: 1
775
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
+ },
776
841
  iconBadge: {
777
842
  alignItems: "center",
778
843
  borderRadius: 10,
@@ -780,9 +845,20 @@ var styles9 = import_react_native11.StyleSheet.create({
780
845
  justifyContent: "center",
781
846
  width: 36
782
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).
783
850
  scrollArea: {
851
+ borderBottomWidth: 0,
852
+ borderTopWidth: 0,
784
853
  marginBottom: 0
785
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
+ },
786
862
  section: {
787
863
  gap: 12
788
864
  },
@@ -826,31 +902,31 @@ var styles9 = import_react_native11.StyleSheet.create({
826
902
  });
827
903
 
828
904
  // src/BaseStatsScreen.tsx
829
- var import_auto_paper9 = require("@rific/auto-paper");
905
+ var import_auto_paper10 = require("@rific/auto-paper");
830
906
  var import_feedback_press3 = require("@rific/feedback-press");
831
- var import_core4 = require("@tastic/core");
832
- var import_react5 = require("react");
833
- var import_react_native12 = require("react-native");
834
- var import_react_native_paper9 = require("react-native-paper");
835
- var import_jsx_runtime11 = 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");
836
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 }) {
837
- const { dark, colors } = (0, import_auto_paper9.useAutoPaperTheme)();
838
- const ambientRotation = (0, import_core4.useRotation)();
913
+ const { dark, colors } = (0, import_auto_paper10.useAutoPaperTheme)();
914
+ const ambientRotation = (0, import_core5.useRotation)();
839
915
  const rotation = rotationOverride ?? ambientRotation;
840
- const [confirmResetVisible, setConfirmResetVisible] = (0, import_react5.useState)(false);
916
+ const [confirmResetVisible, setConfirmResetVisible] = (0, import_react6.useState)(false);
841
917
  const showReset = !!onReset;
842
918
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
843
919
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
844
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.container, { backgroundColor: bg }], children: [
845
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
846
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
847
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: titleVariant, style: [styles10.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 })
848
924
  ] }),
849
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.ScrollView, { style: styles10.scrollView, contentContainerStyle: [styles10.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: [
850
926
  children,
851
- showReset && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles10.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 })
852
928
  ] }),
853
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
929
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
854
930
  ConfirmDialog,
855
931
  {
856
932
  visible: confirmResetVisible,
@@ -870,7 +946,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
870
946
  )
871
947
  ] });
872
948
  }
873
- var styles10 = import_react_native12.StyleSheet.create({
949
+ var styles11 = import_react_native14.StyleSheet.create({
874
950
  container: {
875
951
  flex: 1
876
952
  },
@@ -901,19 +977,19 @@ var styles10 = import_react_native12.StyleSheet.create({
901
977
  });
902
978
 
903
979
  // src/ContentGutter.tsx
904
- var import_core5 = require("@tastic/core");
905
- var import_react_native13 = require("react-native");
906
- var import_jsx_runtime12 = 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");
907
983
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
908
- const { width: windowWidth } = (0, import_core5.useRotatedWindowDimensions)();
909
- const { contentWidth, gutterWidth } = (0, import_core5.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
910
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: [styles11.row, style], children: [
911
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.gutter, { width: gutterWidth }], children: leftGutter }),
912
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: { width: contentWidth }, children }),
913
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.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 })
914
990
  ] });
915
991
  }
916
- var styles11 = import_react_native13.StyleSheet.create({
992
+ var styles12 = import_react_native15.StyleSheet.create({
917
993
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
918
994
  // column instead of clipping cleanly at its own real width.
919
995
  gutter: {
@@ -925,41 +1001,41 @@ var styles11 = import_react_native13.StyleSheet.create({
925
1001
  });
926
1002
 
927
1003
  // src/ControlSchemePicker.tsx
928
- var import_core8 = require("@tastic/core");
929
- var import_react_native18 = require("react-native");
1004
+ var import_core9 = require("@tastic/core");
1005
+ var import_react_native20 = require("react-native");
930
1006
 
931
1007
  // src/SectionedDropdown.tsx
932
- var import_auto_paper10 = require("@rific/auto-paper");
1008
+ var import_auto_paper11 = require("@rific/auto-paper");
933
1009
  var import_feedback_press4 = require("@rific/feedback-press");
934
- var import_core7 = require("@tastic/core");
935
- var import_react_native17 = require("react-native");
936
- 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");
937
1013
 
938
1014
  // src/PopoverBody.tsx
939
- var import_react_native14 = require("react-native");
940
- var import_jsx_runtime13 = require("react/jsx-runtime");
1015
+ var import_react_native16 = require("react-native");
1016
+ var import_jsx_runtime14 = require("react/jsx-runtime");
941
1017
  var CARET_SIZE = 7;
942
1018
  var CARET_RING_OFFSET = 2;
943
1019
  var CARET_DIP = 1;
944
1020
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
945
1021
  if (!visible) return null;
946
1022
  const above = verticalAlign === "above";
947
- const alignStyle = align === "left" ? styles12.contentLeft : align === "right" ? styles12.contentRight : styles12.contentCenter;
948
- const verticalStyle = above ? styles12.contentAbove : styles12.contentBelow;
1023
+ const alignStyle = align === "left" ? styles13.contentLeft : align === "right" ? styles13.contentRight : styles13.contentCenter;
1024
+ const verticalStyle = above ? styles13.contentAbove : styles13.contentBelow;
949
1025
  const ringSize = CARET_SIZE + caretBorderWidth;
950
1026
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
951
1027
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
952
1028
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
953
1029
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
954
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: [styles12.content, alignStyle, verticalStyle], children: [
1030
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native16.View, { style: [styles13.content, alignStyle, verticalStyle], children: [
955
1031
  children,
956
- caretColor && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { style: [styles12.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
958
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { style: [styles12.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 }] })
959
1035
  ] })
960
1036
  ] });
961
1037
  }
962
- var styles12 = import_react_native14.StyleSheet.create({
1038
+ var styles13 = import_react_native16.StyleSheet.create({
963
1039
  caret: {
964
1040
  borderLeftColor: "transparent",
965
1041
  borderRightColor: "transparent",
@@ -1002,11 +1078,11 @@ var styles12 = import_react_native14.StyleSheet.create({
1002
1078
  });
1003
1079
 
1004
1080
  // src/SkiaGate.tsx
1005
- var import_react6 = require("react");
1006
- var import_jsx_runtime14 = require("react/jsx-runtime");
1081
+ var import_react7 = require("react");
1082
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1007
1083
  function SkiaGate({ getComponent, componentProps, fallback = null }) {
1008
- const [Component, setComponent] = (0, import_react6.useState)(null);
1009
- (0, import_react6.useEffect)(() => {
1084
+ const [Component, setComponent] = (0, import_react7.useState)(null);
1085
+ (0, import_react7.useEffect)(() => {
1010
1086
  let cancelled = false;
1011
1087
  getComponent().then((mod) => {
1012
1088
  if (!cancelled) setComponent(() => mod.default);
@@ -1016,19 +1092,19 @@ function SkiaGate({ getComponent, componentProps, fallback = null }) {
1016
1092
  };
1017
1093
  }, [getComponent]);
1018
1094
  if (!Component) return fallback;
1019
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Component, { ...componentProps });
1095
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Component, { ...componentProps });
1020
1096
  }
1021
1097
 
1022
1098
  // src/TriggerGaugeHost.tsx
1023
- var import_jsx_runtime16 = require("react/jsx-runtime");
1099
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1024
1100
  var getTriggerGauge = () => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((mod) => ({ default: mod.TriggerGauge }));
1025
1101
  function TriggerGaugeHost(props) {
1026
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
1102
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
1027
1103
  }
1028
1104
 
1029
1105
  // src/useAutoAlign.ts
1030
- var import_react8 = require("react");
1031
- var import_react_native16 = require("react-native");
1106
+ var import_react9 = require("react");
1107
+ var import_react_native18 = require("react-native");
1032
1108
  var EDGE_MARGIN = 12;
1033
1109
  function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
1034
1110
  if (rotation === 0) return { x, y, width, height };
@@ -1040,18 +1116,18 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
1040
1116
  return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
1041
1117
  }
1042
1118
  function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
1043
- const triggerRef = (0, import_react8.useRef)(null);
1044
- const { width: windowWidth, height: windowHeight } = (0, import_react_native16.useWindowDimensions)();
1045
- const [align, setAlign] = (0, import_react8.useState)("center");
1046
- const [verticalAlign, setVerticalAlign] = (0, import_react8.useState)("below");
1047
- const [maxHeight, setMaxHeight] = (0, import_react8.useState)(contentHeight);
1048
- const [measured, setMeasured] = (0, import_react8.useState)(false);
1049
- 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);
1050
1126
  if (open !== prevOpen) {
1051
1127
  setPrevOpen(open);
1052
1128
  if (open) setMeasured(false);
1053
1129
  }
1054
- const measure = (0, import_react8.useCallback)(() => {
1130
+ const measure = (0, import_react9.useCallback)(() => {
1055
1131
  triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
1056
1132
  const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
1057
1133
  const centerX = x + triggerWidth / 2;
@@ -1068,14 +1144,14 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
1068
1144
  setMeasured(true);
1069
1145
  });
1070
1146
  }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
1071
- (0, import_react8.useEffect)(() => {
1147
+ (0, import_react9.useEffect)(() => {
1072
1148
  if (open) measure();
1073
1149
  }, [open, measure]);
1074
1150
  return { align, maxHeight, measured, triggerRef, verticalAlign };
1075
1151
  }
1076
1152
 
1077
1153
  // src/SectionedDropdown.tsx
1078
- var import_jsx_runtime17 = require("react/jsx-runtime");
1154
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1079
1155
  var MENU_BORDER_WIDTH = 1;
1080
1156
  var TRIGGER_SIZE = 44;
1081
1157
  var MENU_MIN_WIDTH = 200;
@@ -1087,11 +1163,11 @@ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
1087
1163
  var MENU_DIVIDER_HEIGHT = 9;
1088
1164
  var MENU_VERTICAL_PADDING = 12;
1089
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" } }) {
1090
- const ambientRotation = (0, import_core7.useRotation)();
1166
+ const ambientRotation = (0, import_core8.useRotation)();
1091
1167
  const rotation = rotationOverride ?? ambientRotation;
1092
1168
  const menuBg = dark ? "#000000" : "#FFFFFF";
1093
- const menuBorderColor = (0, import_auto_paper10.getBlendedColor)(mutedColor, menuBg, 0.5);
1094
- const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper10.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;
1095
1171
  const fg = dark ? "#FFFFFF" : "#000000";
1096
1172
  const open = host.openId === id;
1097
1173
  const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
@@ -1125,17 +1201,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1125
1201
  }
1126
1202
  gaugeOffset += section.options.length;
1127
1203
  }
1128
- const anchorStyle = [styles14.anchor, open && styles14.anchorOpen];
1204
+ const anchorStyle = [styles15.anchor, open && styles15.anchorOpen];
1129
1205
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
1130
1206
  const dividerStyle = { backgroundColor: menuBorderColor };
1131
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { style: anchorStyle, children: [
1132
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { ref: triggerRef, collapsable: false, style: styles14.triggerBox, children: [
1133
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1134
- /* @__PURE__ */ (0, import_jsx_runtime17.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) })
1135
1211
  ] }),
1136
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.ScrollView, { style: [styles14.menu, menuStyle], contentContainerStyle: styles14.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { children: [
1137
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.View, { style: [styles14.divider, dividerStyle] }),
1138
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime17.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)(
1139
1215
  SingleSection,
1140
1216
  {
1141
1217
  section,
@@ -1148,7 +1224,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1148
1224
  if (autoDismiss) host.close();
1149
1225
  }
1150
1226
  }
1151
- ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1227
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1152
1228
  ] }, section.id)) }) })
1153
1229
  ] });
1154
1230
  }
@@ -1160,18 +1236,18 @@ function SingleSection({
1160
1236
  labelFontFamily,
1161
1237
  onSelect
1162
1238
  }) {
1163
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: section.options.map((option) => {
1239
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: section.options.map((option) => {
1164
1240
  const selected = option.value === section.value;
1165
1241
  const taken = !selected && option.value === section.takenValue;
1166
1242
  const rowColor = selected ? onAccentColor : mutedColor;
1167
- const itemStyle = [styles14.item, selected && { backgroundColor: accentColor }, taken && styles14.itemTaken];
1243
+ const itemStyle = [styles15.item, selected && { backgroundColor: accentColor }, taken && styles15.itemTaken];
1168
1244
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1169
1245
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1170
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { style: styles14.itemRow, children: [
1171
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1172
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { style: styles14.itemLabelColumn, children: [
1173
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1174
- option.description && /* @__PURE__ */ (0, import_jsx_runtime17.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 })
1175
1251
  ] })
1176
1252
  ] }) }, option.value);
1177
1253
  }) });
@@ -1185,23 +1261,23 @@ function MultiSection({
1185
1261
  allClearLabels
1186
1262
  }) {
1187
1263
  const allSelected = section.value.length === section.options.length;
1188
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1264
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1189
1265
  section.options.map((option, i) => {
1190
1266
  const selected = section.value.includes(option.value);
1191
1267
  const rowColor = selected ? onAccentColor : mutedColor;
1192
1268
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1193
1269
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1194
- const itemStyle = [styles14.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 }];
1195
1271
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1196
- return /* @__PURE__ */ (0, import_jsx_runtime17.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_runtime17.jsxs)(import_react_native17.View, { style: styles14.itemRow, children: [
1197
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1198
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles14.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 })
1199
1275
  ] }) }, option.value);
1200
1276
  }),
1201
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles14.item, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles14.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 }) })
1202
1278
  ] });
1203
1279
  }
1204
- var styles14 = import_react_native17.StyleSheet.create({
1280
+ var styles15 = import_react_native19.StyleSheet.create({
1205
1281
  allClearLabel: {
1206
1282
  fontWeight: "bold",
1207
1283
  textAlign: "center"
@@ -1218,7 +1294,7 @@ var styles14 = import_react_native17.StyleSheet.create({
1218
1294
  zIndex: 100
1219
1295
  },
1220
1296
  divider: {
1221
- height: import_react_native17.StyleSheet.hairlineWidth,
1297
+ height: import_react_native19.StyleSheet.hairlineWidth,
1222
1298
  marginVertical: 4
1223
1299
  },
1224
1300
  item: {
@@ -1271,24 +1347,24 @@ var styles14 = import_react_native17.StyleSheet.create({
1271
1347
  });
1272
1348
 
1273
1349
  // src/ControlSchemePicker.tsx
1274
- var import_jsx_runtime18 = require("react/jsx-runtime");
1350
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1275
1351
  function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
1276
- const isTouchPrimary = (0, import_core8.useIsTouchPrimaryDevice)();
1277
- if (import_react_native18.Platform.OS !== "web" || isTouchPrimary) return null;
1278
- return /* @__PURE__ */ (0, import_jsx_runtime18.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 });
1279
1355
  }
1280
1356
 
1281
1357
  // src/CornerActionButtons.tsx
1282
1358
  var import_feedback_press5 = require("@rific/feedback-press");
1283
- var import_react_native19 = require("react-native");
1284
- var import_jsx_runtime19 = require("react/jsx-runtime");
1359
+ var import_react_native21 = require("react-native");
1360
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1285
1361
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back", hitSlop }) {
1286
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1287
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles15.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
1288
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles15.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" })
1289
1365
  ] });
1290
1366
  }
1291
- var styles15 = import_react_native19.StyleSheet.create({
1367
+ var styles16 = import_react_native21.StyleSheet.create({
1292
1368
  back: {
1293
1369
  position: "absolute"
1294
1370
  },
@@ -1298,22 +1374,22 @@ var styles15 = import_react_native19.StyleSheet.create({
1298
1374
  });
1299
1375
 
1300
1376
  // src/CornerStatusBadges.tsx
1301
- var import_react_native20 = require("react-native");
1302
- var import_react_native_paper11 = require("react-native-paper");
1303
- var import_jsx_runtime20 = 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");
1304
1380
  var BADGE_SIZE = 30;
1305
1381
  function StatusBadge({ icon }) {
1306
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { style: styles16.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime20.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)" }) });
1307
1383
  }
1308
1384
  function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
1309
1385
  const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
1310
1386
  const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
1311
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
1312
- p1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { pointerEvents: "none", style: p1OnRightSide ? styles16.bottomRight : styles16.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StatusBadge, { icon: p1.icon }) }),
1313
- p2 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { pointerEvents: "none", style: p2OnLeftSide ? styles16.topLeft : styles16.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime20.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 }) })
1314
1390
  ] });
1315
1391
  }
1316
- var styles16 = import_react_native20.StyleSheet.create({
1392
+ var styles17 = import_react_native22.StyleSheet.create({
1317
1393
  badge: {
1318
1394
  alignItems: "center",
1319
1395
  backgroundColor: "rgba(0,0,0,0.28)",
@@ -1332,12 +1408,12 @@ var styles16 = import_react_native20.StyleSheet.create({
1332
1408
  });
1333
1409
 
1334
1410
  // src/InlineColorPicker.tsx
1335
- var import_auto_paper11 = require("@rific/auto-paper");
1411
+ var import_auto_paper12 = require("@rific/auto-paper");
1336
1412
  var import_feedback_press6 = require("@rific/feedback-press");
1337
- var import_core9 = require("@tastic/core");
1338
- var import_react_native21 = require("react-native");
1339
- var import_react_native_paper12 = require("react-native-paper");
1340
- var import_jsx_runtime21 = 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");
1341
1417
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
1342
1418
  var DEFAULT_SIZE = 48;
1343
1419
  var SWATCH_SIZE = 28;
@@ -1351,18 +1427,18 @@ function widthForColumns(columns) {
1351
1427
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
1352
1428
  }
1353
1429
  function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
1354
- 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);
1355
1431
  const resolvedColumns = columns ?? autoColumns;
1356
1432
  const width = widthForColumns(resolvedColumns);
1357
1433
  const rows = Math.ceil(swatchCount / resolvedColumns);
1358
1434
  const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
1359
1435
  return { width, height };
1360
1436
  }
1361
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper11.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1362
- 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)();
1363
1439
  const rotation = rotationOverride ?? ambientRotation;
1364
1440
  const menuBg = dark ? "#000000" : "#FFFFFF";
1365
- const { width: windowWidth } = (0, import_react_native21.useWindowDimensions)();
1441
+ const { width: windowWidth } = (0, import_react_native23.useWindowDimensions)();
1366
1442
  const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
1367
1443
  const open = host.openId === id;
1368
1444
  const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
@@ -1371,16 +1447,16 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1371
1447
  const align = forcedAlign ?? placement.align;
1372
1448
  const displayFor = previewValue ?? ((hex) => hex);
1373
1449
  const displayValue = displayFor(value);
1374
- const contrastColor = (0, import_auto_paper11.getContrastColor)(displayValue);
1450
+ const contrastColor = (0, import_auto_paper12.getContrastColor)(displayValue);
1375
1451
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
1376
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: [styles17.anchor, open && styles17.anchorOpen], children: [
1377
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles17.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.View, { ref: triggerRef, collapsable: false, style: styles17.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Text, { style: [styles17.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1378
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.ScrollView, { style: [styles17.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles17.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) => {
1379
1455
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
1380
1456
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
1381
1457
  const swappable = taken && allowSwapTaken;
1382
1458
  const swatchDisplay = displayFor(swatch.value);
1383
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1384
1460
  import_feedback_press6.TouchableRipple,
1385
1461
  {
1386
1462
  disabled: taken && !swappable,
@@ -1389,15 +1465,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1389
1465
  if (autoDismiss) host.close();
1390
1466
  },
1391
1467
  borderless: true,
1392
- style: [styles17.swatch, { backgroundColor: swatchDisplay }, selected && styles17.swatchSelected, taken && !swappable && styles17.swatchTaken],
1393
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Icon, { source: "check", size: 16, color: (0, import_auto_paper11.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper11.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper12.Icon, { source: "close", size: 16, color: (0, import_auto_paper11.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.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, {})
1394
1470
  },
1395
1471
  swatch.value
1396
1472
  );
1397
1473
  }) }) })
1398
1474
  ] });
1399
1475
  }
1400
- var styles17 = import_react_native21.StyleSheet.create({
1476
+ var styles18 = import_react_native23.StyleSheet.create({
1401
1477
  anchor: {
1402
1478
  position: "relative"
1403
1479
  },
@@ -1469,11 +1545,11 @@ var styles17 = import_react_native21.StyleSheet.create({
1469
1545
  });
1470
1546
 
1471
1547
  // src/LabeledDropdown.tsx
1472
- var import_auto_paper12 = require("@rific/auto-paper");
1548
+ var import_auto_paper13 = require("@rific/auto-paper");
1473
1549
  var import_feedback_press7 = require("@rific/feedback-press");
1474
- var import_react_native22 = require("react-native");
1475
- var import_react_native_paper13 = require("react-native-paper");
1476
- var import_jsx_runtime22 = 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");
1477
1553
  var TRIGGER_HEIGHT = 28;
1478
1554
  var POPOVER_WIDTH = 180;
1479
1555
  var ROW_HEIGHT = 36;
@@ -1496,22 +1572,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
1496
1572
  onChange(option.value);
1497
1573
  host.close();
1498
1574
  };
1499
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: [styles18.anchor, open && styles18.anchorOpen], children: [
1500
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles18.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { ref: triggerRef, collapsable: false, style: styles18.triggerInner, children: [
1501
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Text, { style: [styles18.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1502
- /* @__PURE__ */ (0, import_jsx_runtime22.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 })
1503
1579
  ] }) }),
1504
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native22.ScrollView, { style: [styles18.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles18.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) => {
1505
1581
  const isSelected = option.value === value;
1506
- const onColor = (0, import_auto_paper12.getContrastColor)(color);
1507
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles18.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: styles18.rowInner, children: [
1508
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1509
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper13.Text, { style: [styles18.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 })
1510
1586
  ] }) }, option.value);
1511
1587
  }) }) })
1512
1588
  ] });
1513
1589
  }
1514
- var styles18 = import_react_native22.StyleSheet.create({
1590
+ var styles19 = import_react_native24.StyleSheet.create({
1515
1591
  anchor: {
1516
1592
  position: "relative"
1517
1593
  },
@@ -1570,21 +1646,21 @@ function loadSkiaWeb() {
1570
1646
 
1571
1647
  // src/PlayerSetupPanel.tsx
1572
1648
  var import_profile2 = require("@tastic/profile");
1573
- var import_react_native24 = require("react-native");
1574
- 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");
1575
1651
 
1576
1652
  // src/ReadyButton.tsx
1577
1653
  var import_feedback_press8 = require("@rific/feedback-press");
1578
- var import_react_native23 = require("react-native");
1579
- var import_react_native_paper14 = require("react-native-paper");
1580
- var import_jsx_runtime23 = 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");
1581
1657
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
1582
- const readyButtonStyle = [styles19.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1658
+ const readyButtonStyle = [styles20.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1583
1659
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
1584
1660
  const labelColorStyle = { color: ready ? "#000000" : color };
1585
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime23.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?" }) });
1586
1662
  }
1587
- var styles19 = import_react_native23.StyleSheet.create({
1663
+ var styles20 = import_react_native25.StyleSheet.create({
1588
1664
  readyButton: {
1589
1665
  alignItems: "center",
1590
1666
  borderRadius: 12,
@@ -1597,18 +1673,18 @@ var styles19 = import_react_native23.StyleSheet.create({
1597
1673
  });
1598
1674
 
1599
1675
  // src/usePopoverHost.ts
1600
- var import_react9 = require("react");
1676
+ var import_react10 = require("react");
1601
1677
  function usePopoverHost() {
1602
- const [openId, setOpenId] = (0, import_react9.useState)(null);
1603
- const toggle = (0, import_react9.useCallback)((id) => {
1678
+ const [openId, setOpenId] = (0, import_react10.useState)(null);
1679
+ const toggle = (0, import_react10.useCallback)((id) => {
1604
1680
  setOpenId((prev) => prev === id ? null : id);
1605
1681
  }, []);
1606
- const close = (0, import_react9.useCallback)(() => setOpenId(null), []);
1682
+ const close = (0, import_react10.useCallback)(() => setOpenId(null), []);
1607
1683
  return { openId, toggle, close };
1608
1684
  }
1609
1685
 
1610
1686
  // src/PlayerSetupPanel.tsx
1611
- var import_jsx_runtime24 = require("react/jsx-runtime");
1687
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1612
1688
  function getColorPopoverId(idPrefix) {
1613
1689
  return `${idPrefix}-color`;
1614
1690
  }
@@ -1623,16 +1699,16 @@ function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onCol
1623
1699
  const showProfilePicker = isHuman && profiles !== void 0 && !!onProfileSelect;
1624
1700
  const showCpuDifficulty = !isHuman && cpuDifficulty !== void 0 && cpuDifficultyOptions !== void 0 && !!onCpuDifficultyChange;
1625
1701
  const selectedProfile = profiles?.find((p) => p.id === selectedProfileId) ?? null;
1626
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: [styles20.panel, ownPopoverOpen && styles20.panelOpen], children: [
1627
- showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native_paper15.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1628
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: [styles20.pickerRow, pickerRowPopoverOpen && styles20.pickerRowOpen], children: [
1629
- /* @__PURE__ */ (0, import_jsx_runtime24.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 }),
1630
1706
  secondPicker
1631
1707
  ] }),
1632
- isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1708
+ isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1633
1709
  ] });
1634
1710
  }
1635
- var styles20 = import_react_native24.StyleSheet.create({
1711
+ var styles21 = import_react_native26.StyleSheet.create({
1636
1712
  panel: {
1637
1713
  alignItems: "center",
1638
1714
  gap: 12
@@ -1664,29 +1740,29 @@ var styles20 = import_react_native24.StyleSheet.create({
1664
1740
  });
1665
1741
 
1666
1742
  // src/PressAwayOverlay.tsx
1667
- var import_react_native25 = require("react-native");
1668
- var import_jsx_runtime25 = require("react/jsx-runtime");
1743
+ var import_react_native27 = require("react-native");
1744
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1669
1745
  function PressAwayOverlay({ active, onPress, style }) {
1670
1746
  if (!active) return null;
1671
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native25.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] });
1672
1748
  }
1673
1749
 
1674
1750
  // src/SharedActionBand.tsx
1675
1751
  var import_feedback_press9 = require("@rific/feedback-press");
1676
- var import_react_native26 = require("react-native");
1677
- var import_jsx_runtime26 = require("react/jsx-runtime");
1752
+ var import_react_native28 = require("react-native");
1753
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1678
1754
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1679
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_native26.View, { style: [styles21.column, popoverOpen && styles21.columnOpen], children: [
1680
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_native26.View, { style: styles21.actionsRow, children: [
1681
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1682
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1683
- onReset && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1684
- /* @__PURE__ */ (0, import_jsx_runtime26.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" })
1685
1761
  ] }),
1686
1762
  children
1687
1763
  ] });
1688
1764
  }
1689
- var styles21 = import_react_native26.StyleSheet.create({
1765
+ var styles22 = import_react_native28.StyleSheet.create({
1690
1766
  actionsRow: {
1691
1767
  alignItems: "center",
1692
1768
  flexDirection: "row",
@@ -1702,10 +1778,10 @@ var styles21 = import_react_native26.StyleSheet.create({
1702
1778
  });
1703
1779
 
1704
1780
  // src/StaggeredWord.tsx
1705
- var import_react10 = require("react");
1706
- var import_react_native27 = require("react-native");
1781
+ var import_react11 = require("react");
1782
+ var import_react_native29 = require("react-native");
1707
1783
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
1708
- var import_jsx_runtime27 = require("react/jsx-runtime");
1784
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1709
1785
  var STAGGER_MS = 45;
1710
1786
  var LETTER_DURATION_MS = 320;
1711
1787
  function getStaggeredWordDuration(letterCount) {
@@ -1713,7 +1789,7 @@ function getStaggeredWordDuration(letterCount) {
1713
1789
  }
1714
1790
  function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
1715
1791
  const progress = (0, import_react_native_reanimated2.useSharedValue)(reducedMotion ? 1 : 0);
1716
- (0, import_react10.useEffect)(() => {
1792
+ (0, import_react11.useEffect)(() => {
1717
1793
  if (reducedMotion) return;
1718
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)) }));
1719
1795
  }, [reducedMotion]);
@@ -1721,12 +1797,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
1721
1797
  opacity: progress.value,
1722
1798
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
1723
1799
  }));
1724
- return /* @__PURE__ */ (0, import_jsx_runtime27.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 });
1725
1801
  }
1726
1802
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
1727
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_native27.View, { style: [styles22.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime27.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)) });
1728
1804
  }
1729
- var styles22 = import_react_native27.StyleSheet.create({
1805
+ var styles23 = import_react_native29.StyleSheet.create({
1730
1806
  row: {
1731
1807
  flexDirection: "row"
1732
1808
  }
@@ -1734,53 +1810,53 @@ var styles22 = import_react_native27.StyleSheet.create({
1734
1810
 
1735
1811
  // src/UpdateDialog.tsx
1736
1812
  var import_updater2 = require("@rific/updater");
1737
- var import_jsx_runtime28 = require("react/jsx-runtime");
1813
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1738
1814
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
1739
1815
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
1740
1816
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
1741
1817
  const date = manifest ? new Date(manifest.createdAt) : null;
1742
- return /* @__PURE__ */ (0, import_jsx_runtime28.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) });
1743
1819
  }
1744
1820
 
1745
1821
  // src/useQuitConfirmation.ts
1746
- var import_react11 = require("react");
1822
+ var import_react12 = require("react");
1747
1823
  function useQuitConfirmation(hasProgress, onConfirmedBack) {
1748
- const [confirmVisible, setConfirmVisible] = (0, import_react11.useState)(false);
1749
- const hasProgressRef = (0, import_react11.useRef)(hasProgress);
1750
- (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)(() => {
1751
1827
  hasProgressRef.current = hasProgress;
1752
1828
  });
1753
- const onConfirmedBackRef = (0, import_react11.useRef)(onConfirmedBack);
1754
- (0, import_react11.useEffect)(() => {
1829
+ const onConfirmedBackRef = (0, import_react12.useRef)(onConfirmedBack);
1830
+ (0, import_react12.useEffect)(() => {
1755
1831
  onConfirmedBackRef.current = onConfirmedBack;
1756
1832
  });
1757
- const requestBack = (0, import_react11.useCallback)(() => {
1833
+ const requestBack = (0, import_react12.useCallback)(() => {
1758
1834
  if (hasProgressRef.current()) setConfirmVisible(true);
1759
1835
  else onConfirmedBackRef.current();
1760
1836
  }, []);
1761
- const cancelBack = (0, import_react11.useCallback)(() => setConfirmVisible(false), []);
1837
+ const cancelBack = (0, import_react12.useCallback)(() => setConfirmVisible(false), []);
1762
1838
  return { confirmVisible, requestBack, cancelBack };
1763
1839
  }
1764
1840
 
1765
1841
  // src/useZoneClampedAlign.ts
1766
1842
  var import_split_screen = require("@tastic/split-screen");
1767
- var import_react12 = require("react");
1768
- var import_react_native28 = require("react-native");
1769
- 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");
1770
1846
  var EDGE_MARGIN2 = 12;
1771
1847
  function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1772
1848
  const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
1773
1849
  const zone = (0, import_split_screen.useZoneBounds)();
1774
- const { height: windowHeight } = (0, import_react_native28.useWindowDimensions)();
1775
- 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)();
1776
1852
  const shouldMeasure = open && auto.measured && zone !== null;
1777
- const [ownBounds, setOwnBounds] = (0, import_react12.useState)(null);
1778
- 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);
1779
1855
  if (shouldMeasure !== prevShouldMeasure) {
1780
1856
  setPrevShouldMeasure(shouldMeasure);
1781
1857
  setOwnBounds(null);
1782
1858
  }
1783
- (0, import_react12.useEffect)(() => {
1859
+ (0, import_react13.useEffect)(() => {
1784
1860
  if (!shouldMeasure) return;
1785
1861
  auto.triggerRef.current?.measureInWindow((_x, y, _width, height) => {
1786
1862
  const belowShared = zone.zoneSide === "belowShared";
@@ -1808,11 +1884,13 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1808
1884
  ActivityStatSection,
1809
1885
  BaseSettingsDialog,
1810
1886
  BaseStatsScreen,
1887
+ COMPACT_DIALOG_HEIGHT,
1811
1888
  ConfirmDialog,
1812
1889
  ContentGutter,
1813
1890
  ControlSchemePicker,
1814
1891
  CornerActionButtons,
1815
1892
  CornerStatusBadges,
1893
+ DialogHeader,
1816
1894
  InlineColorPicker,
1817
1895
  LABELED_DROPDOWN_POPOVER_WIDTH,
1818
1896
  LOCKED_BADGE_COLOR,
@@ -1837,12 +1915,13 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1837
1915
  getCpuDifficultyPopoverId,
1838
1916
  getInlineColorPickerContentSize,
1839
1917
  getLabeledDropdownContentHeight,
1840
- getOverlayCardColors,
1841
1918
  getStaggeredWordDuration,
1919
+ isCompactDialogHeight,
1842
1920
  loadSkiaWeb,
1843
1921
  overlayActionStyles,
1844
1922
  overlayStyles,
1845
1923
  useAutoAlign,
1924
+ useCompactDialog,
1846
1925
  useOverlayCardColors,
1847
1926
  usePopoverHost,
1848
1927
  useQuitConfirmation,