@tastic/hud 0.16.0 → 0.17.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.
@@ -40,6 +40,8 @@ __export(chrome_exports, {
40
40
  CornerActionButtons: () => CornerActionButtons,
41
41
  LOCKED_BADGE_COLOR: () => LOCKED_BADGE_COLOR,
42
42
  MONO_FONT: () => MONO_FONT,
43
+ OverlayBackdrop: () => OverlayBackdrop,
44
+ OverlayCard: () => OverlayCard,
43
45
  RotatedFrame: () => RotatedFrame,
44
46
  StaggeredWord: () => StaggeredWord,
45
47
  StatRow: () => StatRow,
@@ -48,7 +50,8 @@ __export(chrome_exports, {
48
50
  getOverlayCardColors: () => getOverlayCardColors,
49
51
  getStaggeredWordDuration: () => getStaggeredWordDuration,
50
52
  overlayActionStyles: () => overlayActionStyles,
51
- overlayStyles: () => overlayStyles
53
+ overlayStyles: () => overlayStyles,
54
+ useOverlayCardColors: () => useOverlayCardColors
52
55
  });
53
56
  module.exports = __toCommonJS(chrome_exports);
54
57
 
@@ -213,19 +216,19 @@ function ActivityStatSection({ stats }) {
213
216
  }
214
217
 
215
218
  // src/BaseSettingsDialog.tsx
216
- var import_auto_paper6 = require("@rific/auto-paper");
219
+ var import_auto_paper7 = require("@rific/auto-paper");
217
220
  var import_feedback_press2 = require("@rific/feedback-press");
218
221
  var import_updater = require("@rific/updater");
219
222
  var import_core3 = require("@tastic/core");
220
223
  var import_react4 = require("react");
221
- var import_react_native9 = require("react-native");
224
+ var import_react_native10 = require("react-native");
222
225
  var import_react_native_paper7 = require("react-native-paper");
223
226
 
224
227
  // src/ConfirmDialog.tsx
225
- var import_auto_paper5 = require("@rific/auto-paper");
228
+ var import_auto_paper6 = require("@rific/auto-paper");
226
229
  var import_feedback_press = require("@rific/feedback-press");
227
230
  var import_core = require("@tastic/core");
228
- var import_react_native7 = require("react-native");
231
+ var import_react_native8 = require("react-native");
229
232
  var import_react_native_paper5 = require("react-native-paper");
230
233
 
231
234
  // src/overlayCard.ts
@@ -300,26 +303,47 @@ var overlayActionStyles = import_react_native6.StyleSheet.create({
300
303
  }
301
304
  });
302
305
 
303
- // src/ConfirmDialog.tsx
306
+ // src/OverlaySurface.tsx
307
+ var import_auto_paper5 = require("@rific/auto-paper");
308
+ var import_react_native7 = require("react-native");
304
309
  var import_jsx_runtime6 = require("react/jsx-runtime");
310
+ function useOverlayCardColors() {
311
+ const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
312
+ return { fg: colors.onSurface, fgMuted: colors.onSurfaceVariant, cardBorder: colors.outlineVariant, backdrop: colors.backdrop };
313
+ }
314
+ function OverlayBackdrop({ children, style }) {
315
+ const { backdrop } = useOverlayCardColors();
316
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
317
+ }
318
+ function OverlayCard({ children, style, ...rest }) {
319
+ const { cardBorder } = useOverlayCardColors();
320
+ const blur = (0, import_auto_paper5.useBlur)();
321
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_auto_paper5.BlurView, { blur, elevation: 3, style: [overlayStyles.card, styles5.card, { borderColor: cardBorder }, style], ...rest, children });
322
+ }
323
+ var styles5 = import_react_native7.StyleSheet.create({
324
+ card: { overflow: "hidden" }
325
+ });
326
+
327
+ // src/ConfirmDialog.tsx
328
+ var import_jsx_runtime7 = require("react/jsx-runtime");
305
329
  function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
306
- const { dark, colors } = (0, import_auto_paper5.useAutoPaperTheme)();
330
+ const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
331
+ const { fg } = useOverlayCardColors();
307
332
  if (!visible) return null;
308
- const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
309
333
  const accent = destructive ? colors.danger : colors.primary;
310
334
  const onAccent = destructive ? colors.onDanger : colors.onPrimary;
311
335
  const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
312
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [overlayStyles.overlay, styles5.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: [overlayStyles.card, styles5.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core.toRotationStyle)(rotation)], children: [
313
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Icon, { source: icon, size: 64, color: accent }),
314
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Text, { variant: "headlineLarge", style: [styles5.title, { color: accent }], children: title }),
315
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Text, { variant: "bodyLarge", style: [styles5.body, { color: fg }], children: message }),
316
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: overlayActionStyles.actions, children: [
317
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
318
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
336
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(OverlayBackdrop, { style: styles6.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(OverlayCard, { style: [styles6.card, (0, import_core.toRotationStyle)(rotation)], children: [
337
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Icon, { source: icon, size: 64, color: accent }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "headlineLarge", style: [styles6.title, { color: accent }], children: title }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "bodyLarge", style: [styles6.body, { color: fg }], children: message }),
340
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: overlayActionStyles.actions, children: [
341
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
319
343
  ] })
320
344
  ] }) }) });
321
345
  }
322
- var styles5 = import_react_native7.StyleSheet.create({
346
+ var styles6 = import_react_native8.StyleSheet.create({
323
347
  body: {
324
348
  textAlign: "center"
325
349
  },
@@ -350,22 +374,22 @@ var styles5 = import_react_native7.StyleSheet.create({
350
374
  // src/RotatedFrame.tsx
351
375
  var import_core2 = require("@tastic/core");
352
376
  var import_react2 = require("react");
353
- var import_react_native8 = require("react-native");
377
+ var import_react_native9 = require("react-native");
354
378
  var import_react_native_paper6 = require("react-native-paper");
355
379
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
356
- var import_jsx_runtime7 = require("react/jsx-runtime");
380
+ var import_jsx_runtime8 = require("react/jsx-runtime");
357
381
  function RotatedFrame({ children, rotation: rotationOverride, rotatedSafeArea = false, portalHost = false, passThrough = false, maxContentWidth }) {
358
382
  const ambientRotation = (0, import_core2.useRotation)();
359
383
  const rotation = rotationOverride ?? ambientRotation;
360
- const window = (0, import_react_native8.useWindowDimensions)();
384
+ const window = (0, import_react_native9.useWindowDimensions)();
361
385
  const { width, height } = (0, import_core2.rotateDimensions)(window.width, window.height, rotation);
362
386
  const rawInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
363
387
  const insets = (0, import_react2.useMemo)(() => rotatedSafeArea ? (0, import_core2.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
364
388
  const cappedWidth = maxContentWidth !== void 0 && width > height ? maxContentWidth : void 0;
365
- const column = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles6.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
366
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles6.root, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Portal.Host, { children: column }) : column }) });
389
+ const column = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
390
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles7.root, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Portal.Host, { children: column }) : column }) });
367
391
  }
368
- var styles6 = import_react_native8.StyleSheet.create({
392
+ var styles7 = import_react_native9.StyleSheet.create({
369
393
  // A centred column: full width up to `maxWidth`, so a capped frame sits in the middle of a wider window.
370
394
  column: {
371
395
  alignSelf: "center",
@@ -398,12 +422,12 @@ function useUpdateConfirmBridge() {
398
422
  }
399
423
 
400
424
  // src/BaseSettingsDialog.tsx
401
- var import_jsx_runtime8 = require("react/jsx-runtime");
425
+ var import_jsx_runtime9 = require("react/jsx-runtime");
402
426
  function SettingIcon({ source, color, containerColor }) {
403
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Icon, { source, size: 18, color }) });
427
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Icon, { source, size: 18, color }) });
404
428
  }
405
429
  function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
406
- const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
430
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
407
431
  const ambientRotation = (0, import_core3.useRotation)();
408
432
  const rotation = rotationOverride ?? ambientRotation;
409
433
  const isTouchPrimary = (0, import_core3.useIsTouchPrimaryDevice)();
@@ -411,6 +435,8 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
411
435
  const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
412
436
  const sound = (0, import_react4.useContext)(import_feedback_press2.SoundContext);
413
437
  const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
438
+ const { settings: themeSettings, set: setThemeSettings } = (0, import_auto_paper7.useThemeSettings)();
439
+ const expoBlur = (0, import_auto_paper7.useBlurModule)();
414
440
  const [infoMessage, setInfoMessage] = (0, import_react4.useState)(null);
415
441
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
416
442
  const { check, checking, updateReady } = (0, import_updater.useUpdater)({
@@ -424,33 +450,34 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
424
450
  const [opened, setOpened] = (0, import_react4.useState)(visible);
425
451
  if (visible && !opened) setOpened(true);
426
452
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
427
- const showEdgeGuard = import_react_native9.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
428
- const showHaptics = import_react_native9.Platform.OS !== "web" && !hideHaptics;
453
+ const showEdgeGuard = import_react_native10.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
454
+ const showHaptics = import_react_native10.Platform.OS !== "web" && !hideHaptics;
429
455
  const showSound = !hideSound;
430
456
  const showAppearance = !hideAppearance;
431
- const showUpdateCheck = import_react_native9.Platform.OS !== "web" && !hideUpdateCheck;
457
+ const showBlur = showAppearance && import_react_native10.Platform.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
458
+ const showUpdateCheck = import_react_native10.Platform.OS !== "web" && !hideUpdateCheck;
432
459
  if (!opened) return null;
433
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
434
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_auto_paper6.Dialog, { visible, onDismiss, style: styles7.dialog, children: [
435
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper6.Dialog.Title, { children: "Settings" }),
436
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper6.Dialog.ScrollArea, { style: styles7.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.ScrollView, { contentContainerStyle: styles7.content, showsVerticalScrollIndicator: false, children: [
437
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleGroup, children: [
438
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles7.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
440
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
441
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
442
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
460
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
461
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: styles8.dialog, children: [
462
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
463
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles8.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { contentContainerStyle: styles8.content, showsVerticalScrollIndicator: false, children: [
464
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleGroup, children: [
465
+ showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles8.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
466
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
467
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
468
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
469
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
443
470
  ] })
444
471
  ] }) }),
445
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles7.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
446
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
447
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
448
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
449
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
472
+ showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles8.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
473
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
474
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
475
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
476
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
450
477
  ] })
451
478
  ] }) }),
452
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleRow, children: [
453
- showSound && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
479
+ (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleRow, children: [
480
+ showSound && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
454
481
  import_feedback_press2.TouchableRipple,
455
482
  {
456
483
  soundDisabled: true,
@@ -459,15 +486,15 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
459
486
  setSoundSettings({ enabled });
460
487
  if (enabled) sound.selection?.();
461
488
  },
462
- style: styles7.toggleButtonInRow,
489
+ style: styles8.toggleButtonInRow,
463
490
  accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
464
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
465
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
466
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
491
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
492
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
493
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
467
494
  ] })
468
495
  }
469
496
  ),
470
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
497
+ showHaptics && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
471
498
  import_feedback_press2.TouchableRipple,
472
499
  {
473
500
  hapticDisabled: true,
@@ -476,54 +503,58 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
476
503
  setHapticSettings({ vibrate });
477
504
  if (vibrate) forceHapticFeedback();
478
505
  },
479
- style: styles7.toggleButtonInRow,
506
+ style: styles8.toggleButtonInRow,
480
507
  accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
481
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
483
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
508
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
509
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
484
511
  ] })
485
512
  }
486
513
  )
487
514
  ] }),
488
- onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
515
+ onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
489
516
  import_feedback_press2.TouchableRipple,
490
517
  {
491
518
  onPress: () => {
492
519
  onDismiss();
493
520
  onShowHowToPlay();
494
521
  },
495
- style: styles7.toggleButton,
522
+ style: styles8.toggleButton,
496
523
  accessibilityLabel: "How to Play",
497
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
498
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
499
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
500
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
501
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
524
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
525
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
526
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
527
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
528
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
502
529
  ] })
503
530
  ] })
504
531
  }
505
532
  )
506
533
  ] }),
507
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
508
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "labelMedium", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
509
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper6.AutoAppearancePicker, { showLabels: false })
534
+ showAppearance && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
535
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "labelMedium", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false }),
537
+ showBlur && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles8.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
538
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
539
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" })
540
+ ] }) })
510
541
  ] }),
511
542
  children,
512
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
513
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_paper7.Text, { variant: "labelSmall", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: [
543
+ showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
544
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_paper7.Text, { variant: "labelSmall", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: [
514
545
  "VERSION ",
515
546
  version,
516
547
  updateReady ? " \xB7 UPDATE READY" : ""
517
548
  ] }),
518
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
549
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
519
550
  ] })
520
551
  ] }) })
521
552
  ] }),
522
- /* @__PURE__ */ (0, import_jsx_runtime8.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) }),
523
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
553
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
554
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
524
555
  ] }) });
525
556
  }
526
- var styles7 = import_react_native9.StyleSheet.create({
557
+ var styles8 = import_react_native10.StyleSheet.create({
527
558
  content: {
528
559
  gap: 24,
529
560
  paddingVertical: 20
@@ -591,31 +622,31 @@ var styles7 = import_react_native9.StyleSheet.create({
591
622
  });
592
623
 
593
624
  // src/BaseStatsScreen.tsx
594
- var import_auto_paper7 = require("@rific/auto-paper");
625
+ var import_auto_paper8 = require("@rific/auto-paper");
595
626
  var import_feedback_press3 = require("@rific/feedback-press");
596
627
  var import_core4 = require("@tastic/core");
597
628
  var import_react5 = require("react");
598
- var import_react_native10 = require("react-native");
629
+ var import_react_native11 = require("react-native");
599
630
  var import_react_native_paper8 = require("react-native-paper");
600
- var import_jsx_runtime9 = require("react/jsx-runtime");
631
+ var import_jsx_runtime10 = require("react/jsx-runtime");
601
632
  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 }) {
602
- const { dark, colors } = (0, import_auto_paper7.useAutoPaperTheme)();
633
+ const { dark, colors } = (0, import_auto_paper8.useAutoPaperTheme)();
603
634
  const ambientRotation = (0, import_core4.useRotation)();
604
635
  const rotation = rotationOverride ?? ambientRotation;
605
636
  const [confirmResetVisible, setConfirmResetVisible] = (0, import_react5.useState)(false);
606
637
  const showReset = !!onReset;
607
638
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
608
639
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
609
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.container, { backgroundColor: bg }], children: [
610
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
611
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
612
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: titleVariant, style: [styles8.title, { color: fg }], children: title })
640
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.container, { backgroundColor: bg }], children: [
641
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
642
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
643
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: titleVariant, style: [styles9.title, { color: fg }], children: title })
613
644
  ] }),
614
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { style: styles8.scrollView, contentContainerStyle: [styles8.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
645
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.ScrollView, { style: styles9.scrollView, contentContainerStyle: [styles9.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
615
646
  children,
616
- showReset && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles8.resetButton, children: resetLabel })
647
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles9.resetButton, children: resetLabel })
617
648
  ] }),
618
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
649
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
619
650
  ConfirmDialog,
620
651
  {
621
652
  visible: confirmResetVisible,
@@ -635,7 +666,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
635
666
  )
636
667
  ] });
637
668
  }
638
- var styles8 = import_react_native10.StyleSheet.create({
669
+ var styles9 = import_react_native11.StyleSheet.create({
639
670
  container: {
640
671
  flex: 1
641
672
  },
@@ -667,18 +698,18 @@ var styles8 = import_react_native10.StyleSheet.create({
667
698
 
668
699
  // src/ContentGutter.tsx
669
700
  var import_core5 = require("@tastic/core");
670
- var import_react_native11 = require("react-native");
671
- var import_jsx_runtime10 = require("react/jsx-runtime");
701
+ var import_react_native12 = require("react-native");
702
+ var import_jsx_runtime11 = require("react/jsx-runtime");
672
703
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
673
704
  const { width: windowWidth } = (0, import_core5.useRotatedWindowDimensions)();
674
705
  const { contentWidth, gutterWidth } = (0, import_core5.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
675
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.row, style], children: [
676
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: leftGutter }),
677
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: { width: contentWidth }, children }),
678
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: rightGutter })
706
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.row, style], children: [
707
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: leftGutter }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: { width: contentWidth }, children }),
709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: rightGutter })
679
710
  ] });
680
711
  }
681
- var styles9 = import_react_native11.StyleSheet.create({
712
+ var styles10 = import_react_native12.StyleSheet.create({
682
713
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
683
714
  // column instead of clipping cleanly at its own real width.
684
715
  gutter: {
@@ -691,15 +722,15 @@ var styles9 = import_react_native11.StyleSheet.create({
691
722
 
692
723
  // src/CornerActionButtons.tsx
693
724
  var import_feedback_press4 = require("@rific/feedback-press");
694
- var import_react_native12 = require("react-native");
695
- var import_jsx_runtime11 = require("react/jsx-runtime");
725
+ var import_react_native13 = require("react-native");
726
+ var import_jsx_runtime12 = require("react/jsx-runtime");
696
727
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back", hitSlop }) {
697
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
698
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press4.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles10.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
699
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press4.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles10.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
728
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
729
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press4.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles11.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
730
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press4.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles11.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
700
731
  ] });
701
732
  }
702
- var styles10 = import_react_native12.StyleSheet.create({
733
+ var styles11 = import_react_native13.StyleSheet.create({
703
734
  back: {
704
735
  position: "absolute"
705
736
  },
@@ -710,9 +741,9 @@ var styles10 = import_react_native12.StyleSheet.create({
710
741
 
711
742
  // src/StaggeredWord.tsx
712
743
  var import_react6 = require("react");
713
- var import_react_native13 = require("react-native");
744
+ var import_react_native14 = require("react-native");
714
745
  var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
715
- var import_jsx_runtime12 = require("react/jsx-runtime");
746
+ var import_jsx_runtime13 = require("react/jsx-runtime");
716
747
  var STAGGER_MS = 45;
717
748
  var LETTER_DURATION_MS = 320;
718
749
  function getStaggeredWordDuration(letterCount) {
@@ -728,12 +759,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
728
759
  opacity: progress.value,
729
760
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
730
761
  }));
731
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
762
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_reanimated.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
732
763
  }
733
764
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
734
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
765
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { style: [styles12.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
735
766
  }
736
- var styles11 = import_react_native13.StyleSheet.create({
767
+ var styles12 = import_react_native14.StyleSheet.create({
737
768
  row: {
738
769
  flexDirection: "row"
739
770
  }
@@ -741,12 +772,12 @@ var styles11 = import_react_native13.StyleSheet.create({
741
772
 
742
773
  // src/UpdateDialog.tsx
743
774
  var import_updater2 = require("@rific/updater");
744
- var import_jsx_runtime13 = require("react/jsx-runtime");
775
+ var import_jsx_runtime14 = require("react/jsx-runtime");
745
776
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
746
777
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
747
778
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
748
779
  const date = manifest ? new Date(manifest.createdAt) : null;
749
- return /* @__PURE__ */ (0, import_jsx_runtime13.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) });
780
+ return /* @__PURE__ */ (0, import_jsx_runtime14.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) });
750
781
  }
751
782
  // Annotate the CommonJS export names for ESM import in node:
752
783
  0 && (module.exports = {
@@ -760,6 +791,8 @@ function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onErr
760
791
  CornerActionButtons,
761
792
  LOCKED_BADGE_COLOR,
762
793
  MONO_FONT,
794
+ OverlayBackdrop,
795
+ OverlayCard,
763
796
  RotatedFrame,
764
797
  StaggeredWord,
765
798
  StatRow,
@@ -768,5 +801,6 @@ function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onErr
768
801
  getOverlayCardColors,
769
802
  getStaggeredWordDuration,
770
803
  overlayActionStyles,
771
- overlayStyles
804
+ overlayStyles,
805
+ useOverlayCardColors
772
806
  });
@@ -15,12 +15,15 @@ import {
15
15
  StatSection,
16
16
  UpdateDialog,
17
17
  getStaggeredWordDuration
18
- } from "../chunk-JXRBXQLQ.mjs";
18
+ } from "../chunk-27FIA26F.mjs";
19
19
  import {
20
+ OverlayBackdrop,
21
+ OverlayCard,
20
22
  getOverlayCardColors,
21
23
  overlayActionStyles,
22
- overlayStyles
23
- } from "../chunk-32U2OIRW.mjs";
24
+ overlayStyles,
25
+ useOverlayCardColors
26
+ } from "../chunk-AX4GC5KU.mjs";
24
27
  export {
25
28
  AchievementCatalogSection,
26
29
  AchievementRow,
@@ -32,6 +35,8 @@ export {
32
35
  CornerActionButtons,
33
36
  LOCKED_BADGE_COLOR,
34
37
  MONO_FONT,
38
+ OverlayBackdrop,
39
+ OverlayCard,
35
40
  RotatedFrame,
36
41
  StaggeredWord,
37
42
  StatRow,
@@ -40,5 +45,6 @@ export {
40
45
  getOverlayCardColors,
41
46
  getStaggeredWordDuration,
42
47
  overlayActionStyles,
43
- overlayStyles
48
+ overlayStyles,
49
+ useOverlayCardColors
44
50
  };
@@ -1,8 +1,9 @@
1
1
  import {
2
- getOverlayCardColors,
2
+ OverlayBackdrop,
3
+ OverlayCard,
3
4
  overlayActionStyles,
4
- overlayStyles
5
- } from "./chunk-32U2OIRW.mjs";
5
+ useOverlayCardColors
6
+ } from "./chunk-AX4GC5KU.mjs";
6
7
 
7
8
  // src/AchievementRow.tsx
8
9
  import { useAutoPaperTheme } from "@rific/auto-paper";
@@ -170,13 +171,13 @@ import { StyleSheet as StyleSheet5, View as View4 } from "react-native";
170
171
  import { Icon as Icon2, Portal, Text as Text5 } from "react-native-paper";
171
172
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
172
173
  function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
173
- const { dark, colors } = useAutoPaperTheme5();
174
+ const { colors } = useAutoPaperTheme5();
175
+ const { fg } = useOverlayCardColors();
174
176
  if (!visible) return null;
175
- const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
176
177
  const accent = destructive ? colors.danger : colors.primary;
177
178
  const onAccent = destructive ? colors.onDanger : colors.onPrimary;
178
179
  const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
179
- return /* @__PURE__ */ jsx6(Portal, { children: /* @__PURE__ */ jsx6(View4, { style: [overlayStyles.overlay, styles5.overlay], children: /* @__PURE__ */ jsxs6(View4, { style: [overlayStyles.card, styles5.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle(rotation)], children: [
180
+ return /* @__PURE__ */ jsx6(Portal, { children: /* @__PURE__ */ jsx6(OverlayBackdrop, { style: styles5.overlay, children: /* @__PURE__ */ jsxs6(OverlayCard, { style: [styles5.card, toRotationStyle(rotation)], children: [
180
181
  /* @__PURE__ */ jsx6(Icon2, { source: icon, size: 64, color: accent }),
181
182
  /* @__PURE__ */ jsx6(Text5, { variant: "headlineLarge", style: [styles5.title, { color: accent }], children: title }),
182
183
  /* @__PURE__ */ jsx6(Text5, { variant: "bodyLarge", style: [styles5.body, { color: fg }], children: message }),
@@ -245,7 +246,7 @@ var styles6 = StyleSheet6.create({
245
246
  });
246
247
 
247
248
  // src/BaseSettingsDialog.tsx
248
- import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
249
+ import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme6, useBlurModule, useThemeSettings } from "@rific/auto-paper";
249
250
  import { Button as Button2, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
250
251
  import { useUpdater } from "@rific/updater";
251
252
  import { useIsTouchPrimaryDevice, useRotation as useRotation2 } from "@tastic/core";
@@ -287,6 +288,8 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
287
288
  const { settings: soundSettings, set: setSoundSettings } = useSoundSettings();
288
289
  const sound = useContext(SoundContext);
289
290
  const { forceShort: forceHapticFeedback } = useVibration();
291
+ const { settings: themeSettings, set: setThemeSettings } = useThemeSettings();
292
+ const expoBlur = useBlurModule();
290
293
  const [infoMessage, setInfoMessage] = useState2(null);
291
294
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
292
295
  const { check, checking, updateReady } = useUpdater({
@@ -304,6 +307,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
304
307
  const showHaptics = Platform2.OS !== "web" && !hideHaptics;
305
308
  const showSound = !hideSound;
306
309
  const showAppearance = !hideAppearance;
310
+ const showBlur = showAppearance && Platform2.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
307
311
  const showUpdateCheck = Platform2.OS !== "web" && !hideUpdateCheck;
308
312
  if (!opened) return null;
309
313
  return /* @__PURE__ */ jsx8(Portal3, { children: /* @__PURE__ */ jsxs7(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
@@ -382,7 +386,11 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
382
386
  ] }),
383
387
  showAppearance && /* @__PURE__ */ jsxs7(View6, { style: styles7.section, children: [
384
388
  /* @__PURE__ */ jsx8(Text6, { variant: "labelMedium", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
385
- /* @__PURE__ */ jsx8(AutoAppearancePicker, { showLabels: false })
389
+ /* @__PURE__ */ jsx8(AutoAppearancePicker, { showLabels: false }),
390
+ showBlur && /* @__PURE__ */ jsx8(TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles7.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ jsxs7(View6, { style: styles7.toggleContent, children: [
391
+ /* @__PURE__ */ jsx8(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
392
+ /* @__PURE__ */ jsx8(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" })
393
+ ] }) })
386
394
  ] }),
387
395
  children,
388
396
  showUpdateCheck && /* @__PURE__ */ jsxs7(View6, { style: styles7.section, children: [