diff --git a/catalyst_voices/ios/Flutter/AppFrameworkInfo.plist b/catalyst_voices/ios/Flutter/AppFrameworkInfo.plist
index 4f8d4d2456f..8c6e56146e2 100644
--- a/catalyst_voices/ios/Flutter/AppFrameworkInfo.plist
+++ b/catalyst_voices/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
   <key>CFBundleVersion</key>
   <string>1.0</string>
   <key>MinimumOSVersion</key>
-  <string>11.0</string>
+  <string>12.0</string>
 </dict>
 </plist>
diff --git a/catalyst_voices/ios/Podfile.lock b/catalyst_voices/ios/Podfile.lock
index 21ca313d8b4..01f6fe0819b 100644
--- a/catalyst_voices/ios/Podfile.lock
+++ b/catalyst_voices/ios/Podfile.lock
@@ -30,12 +30,12 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/url_launcher_ios/ios"
 
 SPEC CHECKSUMS:
-  Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
+  Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
   flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
   integration_test: 13825b8a9334a850581300559b8839134b124670
-  path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
-  url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
+  path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
+  url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
 
 PODFILE CHECKSUM: ff9ae414ffbc80ad6f9d2058e299051a15f6eca7
 
-COCOAPODS: 1.14.3
+COCOAPODS: 1.15.0
diff --git a/catalyst_voices/lib/routes/app_router.dart b/catalyst_voices/lib/routes/app_router.dart
index c780dae1b6e..608056d2ab2 100644
--- a/catalyst_voices/lib/routes/app_router.dart
+++ b/catalyst_voices/lib/routes/app_router.dart
@@ -20,10 +20,7 @@ final class AppRouter {
       initialLocation: _isWeb(),
       refreshListenable: AppRouterRefreshStream(authenticationBloc.stream),
       redirect: (context, state) => _guard(authenticationBloc, state),
-      routes: [
-        ...login_route.$appRoutes,
-        ...home_route.$appRoutes,
-      ],
+      routes: _routes(),
     );
   }
 
@@ -52,4 +49,11 @@ final class AppRouter {
       return null;
     }
   }
+
+  static List<RouteBase> _routes() {
+    return [
+      ...login_route.$appRoutes,
+      ...home_route.$appRoutes,
+    ];
+  }
 }
diff --git a/catalyst_voices/packages/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart b/catalyst_voices/packages/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart
index 6d1a1e347cb..5723c64c28a 100644
--- a/catalyst_voices/packages/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart
+++ b/catalyst_voices/packages/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart
@@ -1,3 +1 @@
-class CatalystVoicesShared {
-  const CatalystVoicesShared();
-}
+export 'platform/catalyst_platform.dart';
diff --git a/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/catalyst_platform.dart b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/catalyst_platform.dart
new file mode 100644
index 00000000000..74358e8d27b
--- /dev/null
+++ b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/catalyst_platform.dart
@@ -0,0 +1,5 @@
+library catalyst_platform;
+
+export 'stub_platform.dart'
+    if (dart.library.io) 'io_platform.dart'
+    if (dart.library.html) 'web_platform.dart';
diff --git a/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/io_platform.dart b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/io_platform.dart
new file mode 100644
index 00000000000..bf4faa30aa0
--- /dev/null
+++ b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/io_platform.dart
@@ -0,0 +1,26 @@
+import 'dart:io';
+
+final class CatalystPlatform {
+  static bool get isAndroid => Platform.isAndroid;
+
+  static bool get isDesktop =>
+      Platform.isLinux || Platform.isMacOS || Platform.isWindows;
+
+  static bool get isFuchsia => Platform.isFuchsia;
+
+  static bool get isIOS => Platform.isIOS;
+
+  static bool get isLinux => Platform.isLinux;
+
+  static bool get isMacOS => Platform.isMacOS;
+
+  static bool get isMobile => Platform.isAndroid || Platform.isIOS;
+
+  static bool get isMobileWeb => false;
+
+  static bool get isWeb => false;
+
+  static bool get isWebDesktop => false;
+
+  static bool get isWindows => Platform.isWindows;
+}
diff --git a/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/stub_platform.dart b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/stub_platform.dart
new file mode 100644
index 00000000000..539a794b214
--- /dev/null
+++ b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/stub_platform.dart
@@ -0,0 +1,47 @@
+final class CatalystPlatform {
+  static bool get isAndroid {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isDesktop {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isFuchsia {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isIOS {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isLinux {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isMacOS {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isMobile {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isMobileWeb {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isWeb {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isWebDesktop {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  static bool get isWindows {
+    throw UnimplementedError('Stub CatalystPlatform');
+  }
+
+  const CatalystPlatform._();
+}
diff --git a/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/web_platform.dart b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/web_platform.dart
new file mode 100644
index 00000000000..4f74a8726f2
--- /dev/null
+++ b/catalyst_voices/packages/catalyst_voices_shared/lib/src/platform/web_platform.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/foundation.dart' show kIsWeb;
+import 'package:web/web.dart';
+
+final class CatalystPlatform {
+  static bool get isAndroid => false;
+
+  static bool get isDesktop => false;
+
+  static bool get isFuchsia => false;
+
+  static bool get isIOS => false;
+
+  static bool get isLinux => false;
+
+  static bool get isMacOS => false;
+
+  static bool get isMobile => false;
+
+  static bool get isMobileWeb => _isMobileOS;
+
+  static bool get isWeb => kIsWeb;
+
+  static bool get isWebDesktop => kIsWeb && !_isMobileOS;
+
+  static bool get isWindows => false;
+
+  static bool get _isMobileOS {
+    final userAgent = window.navigator.userAgent.toLowerCase();
+    const mobileIdentifiers = [
+      'android',
+      'ipad',
+      'iphone',
+    ];
+    return mobileIdentifiers.any(userAgent.contains);
+  }
+
+  const CatalystPlatform._();
+}
diff --git a/catalyst_voices/packages/catalyst_voices_shared/pubspec.yaml b/catalyst_voices/packages/catalyst_voices_shared/pubspec.yaml
index e7a366414a6..6885536bc9c 100644
--- a/catalyst_voices/packages/catalyst_voices_shared/pubspec.yaml
+++ b/catalyst_voices/packages/catalyst_voices_shared/pubspec.yaml
@@ -10,6 +10,7 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
+  web: ^0.3.0
 
 dev_dependencies:
    catalyst_analysis: