about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alf/atoms.ts31
-rw-r--r--src/components/Dialog/index.tsx61
-rw-r--r--src/components/Dialog/index.web.tsx38
-rw-r--r--src/components/InterestTabs.tsx390
-rw-r--r--src/components/LoggedOutCTA.tsx6
-rw-r--r--src/components/ProgressGuide/FollowDialog.tsx146
-rw-r--r--src/components/Toast/Toast.tsx91
-rw-r--r--src/components/Toast/index.e2e.tsx8
-rw-r--r--src/components/Toast/index.tsx40
-rw-r--r--src/components/Toast/index.web.tsx30
-rw-r--r--src/components/dialogs/StarterPackDialog.tsx46
-rw-r--r--src/components/forms/Toggle.tsx6
-rw-r--r--src/env/common.ts6
-rw-r--r--src/lib/constants.ts13
-rw-r--r--src/lib/hooks/useDraggableScrollView.ts6
-rw-r--r--src/lib/icons.tsx4
-rw-r--r--src/lib/statsig/gates.ts2
-rw-r--r--src/locale/locales/en/messages.po1356
-rw-r--r--src/logger/metrics.ts19
-rw-r--r--src/screens/Login/ForgotPasswordForm.tsx6
-rw-r--r--src/screens/Login/SetNewPasswordForm.tsx4
-rw-r--r--src/screens/Onboarding/Layout.tsx126
-rw-r--r--src/screens/Onboarding/StepFinished.tsx292
-rw-r--r--src/screens/Onboarding/StepInterests/index.tsx11
-rw-r--r--src/screens/Onboarding/StepProfile/index.tsx2
-rw-r--r--src/screens/Onboarding/StepSuggestedAccounts/index.tsx356
-rw-r--r--src/screens/Onboarding/index.tsx49
-rw-r--r--src/screens/Onboarding/state.ts58
-rw-r--r--src/screens/Onboarding/util.ts14
-rw-r--r--src/screens/Profile/Header/SuggestedFollows.tsx3
-rw-r--r--src/screens/Search/Explore.tsx2
-rw-r--r--src/screens/Search/modules/ExploreSuggestedAccounts.tsx74
-rw-r--r--src/screens/Search/util/useSuggestedUsers.ts9
-rw-r--r--src/state/messages/convo/agent.ts2
-rw-r--r--src/state/messages/events/agent.ts2
-rw-r--r--src/state/modals/index.tsx5
-rw-r--r--src/state/queries/handle-availability.ts7
-rw-r--r--src/state/queries/messages/accept-conversation.ts7
-rw-r--r--src/state/queries/messages/const.ts5
-rw-r--r--src/state/queries/messages/conversation.ts8
-rw-r--r--src/state/queries/messages/get-convo-availability.ts2
-rw-r--r--src/state/queries/messages/get-convo-for-members.ts4
-rw-r--r--src/state/queries/messages/leave-conversation.ts7
-rw-r--r--src/state/queries/messages/list-conversations.tsx2
-rw-r--r--src/state/queries/messages/mute-conversation.ts14
-rw-r--r--src/state/queries/messages/update-all-read.ts4
-rw-r--r--src/state/queries/service.ts5
-rw-r--r--src/state/queries/trending/useGetSuggestedUsersQuery.ts9
-rw-r--r--src/state/session/agent.ts44
-rw-r--r--src/view/com/composer/Composer.tsx13
-rw-r--r--src/view/com/composer/select-language/SelectLangBtn.tsx133
-rw-r--r--src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx382
-rw-r--r--src/view/com/modals/DeleteAccount.tsx2
-rw-r--r--src/view/com/modals/Modal.tsx4
-rw-r--r--src/view/com/modals/Modal.web.tsx3
-rw-r--r--src/view/com/modals/lang-settings/PostLanguagesSettings.tsx145
-rw-r--r--src/view/com/notifications/NotificationFeedItem.tsx2
-rw-r--r--src/view/com/util/forms/DropdownButton.tsx397
-rw-r--r--src/view/screens/Debug.tsx51
-rw-r--r--src/view/screens/Storybook/Toasts.tsx80
60 files changed, 2752 insertions, 1892 deletions
diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts
index 5b7c5c87e..ae88f457d 100644
--- a/src/alf/atoms.ts
+++ b/src/alf/atoms.ts
@@ -70,9 +70,21 @@ export const atoms = {
   overflow_visible: {
     overflow: 'visible',
   },
+  overflow_x_visible: {
+    overflowX: 'visible',
+  },
+  overflow_y_visible: {
+    overflowY: 'visible',
+  },
   overflow_hidden: {
     overflow: 'hidden',
   },
+  overflow_x_hidden: {
+    overflowX: 'hidden',
+  },
+  overflow_y_hidden: {
+    overflowY: 'hidden',
+  },
   /**
    * @platform web
    */
@@ -363,6 +375,14 @@ export const atoms = {
   border_r_0: {
     borderRightWidth: 0,
   },
+  border_x_0: {
+    borderLeftWidth: 0,
+    borderRightWidth: 0,
+  },
+  border_y_0: {
+    borderTopWidth: 0,
+    borderBottomWidth: 0,
+  },
   border: {
     borderWidth: StyleSheet.hairlineWidth,
   },
@@ -378,6 +398,14 @@ export const atoms = {
   border_r: {
     borderRightWidth: StyleSheet.hairlineWidth,
   },
+  border_x: {
+    borderLeftWidth: StyleSheet.hairlineWidth,
+    borderRightWidth: StyleSheet.hairlineWidth,
+  },
+  border_y: {
+    borderTopWidth: StyleSheet.hairlineWidth,
+    borderBottomWidth: StyleSheet.hairlineWidth,
+  },
   border_transparent: {
     borderColor: 'transparent',
   },
@@ -988,6 +1016,9 @@ export const atoms = {
   block: web({
     display: 'block',
   }),
+  contents: web({
+    display: 'contents',
+  }),
 
   /*
    * Transition
diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx
index 4795385ee..de8287a53 100644
--- a/src/components/Dialog/index.tsx
+++ b/src/components/Dialog/index.tsx
@@ -12,9 +12,13 @@ import {
 import {
   KeyboardAwareScrollView,
   useKeyboardHandler,
+  useReanimatedKeyboardAnimation,
 } from 'react-native-keyboard-controller'
-import {runOnJS} from 'react-native-reanimated'
-import {type ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes'
+import Animated, {
+  runOnJS,
+  type ScrollEvent,
+  useAnimatedStyle,
+} from 'react-native-reanimated'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
@@ -26,7 +30,7 @@ import {isAndroid, isIOS} from '#/platform/detection'
 import {useA11y} from '#/state/a11y'
 import {useDialogStateControlContext} from '#/state/dialogs'
 import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
-import {atoms as a, tokens, useTheme} from '#/alf'
+import {atoms as a, ios, platform, tokens, useTheme} from '#/alf'
 import {useThemeName} from '#/alf/util/useColorModeTheme'
 import {Context, useDialogContext} from '#/components/Dialog/context'
 import {
@@ -256,6 +260,7 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
           contentContainerStyle,
         ]}
         ref={ref}
+        showsVerticalScrollIndicator={isAndroid ? false : undefined}
         {...props}
         bounces={nativeSnapPoint === BottomSheetSnapPoint.Full}
         bottomOffset={30}
@@ -275,12 +280,15 @@ export const InnerFlatList = React.forwardRef<
   ListProps<any> & {
     webInnerStyle?: StyleProp<ViewStyle>
     webInnerContentContainerStyle?: StyleProp<ViewStyle>
+    footer?: React.ReactNode
   }
->(function InnerFlatList({style, ...props}, ref) {
+>(function InnerFlatList({footer, style, ...props}, ref) {
   const insets = useSafeAreaInsets()
   const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
 
-  const onScroll = (e: ReanimatedScrollEvent) => {
+  useEnableKeyboardController(isIOS)
+
+  const onScroll = (e: ScrollEvent) => {
     'worklet'
     if (!isAndroid) {
       return
@@ -300,13 +308,54 @@ export const InnerFlatList = React.forwardRef<
         bounces={nativeSnapPoint === BottomSheetSnapPoint.Full}
         ListFooterComponent={<View style={{height: insets.bottom + 100}} />}
         ref={ref}
+        showsVerticalScrollIndicator={isAndroid ? false : undefined}
         {...props}
-        style={[style]}
+        style={[a.h_full, style]}
       />
+      {footer}
     </ScrollProvider>
   )
 })
 
+export function FlatListFooter({children}: {children: React.ReactNode}) {
+  const t = useTheme()
+  const {top, bottom} = useSafeAreaInsets()
+  const {height} = useReanimatedKeyboardAnimation()
+
+  const animatedStyle = useAnimatedStyle(() => {
+    if (!isIOS) return {}
+    return {
+      transform: [{translateY: Math.min(0, height.get() + bottom - 10)}],
+    }
+  })
+
+  return (
+    <Animated.View
+      style={[
+        a.absolute,
+        a.bottom_0,
+        a.w_full,
+        a.z_10,
+        a.border_t,
+        t.atoms.bg,
+        t.atoms.border_contrast_low,
+        a.px_lg,
+        a.pt_md,
+        {
+          paddingBottom: platform({
+            ios: tokens.space.md + bottom,
+            android: tokens.space.md + bottom + top,
+          }),
+        },
+        // TODO: had to admit defeat here, but we should
+        // try and get this to work for Android as well -sfn
+        ios(animatedStyle),
+      ]}>
+      {children}
+    </Animated.View>
+  )
+}
+
 export function Handle({difference = false}: {difference?: boolean}) {
   const t = useTheme()
   const {_} = useLingui()
diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx
index 7e10dfadc..1d62cbfdc 100644
--- a/src/components/Dialog/index.web.tsx
+++ b/src/components/Dialog/index.web.tsx
@@ -33,6 +33,9 @@ export * from '#/components/Dialog/types'
 export * from '#/components/Dialog/utils'
 export {Input} from '#/components/forms/TextField'
 
+// 100 minus 10vh of paddingVertical
+export const WEB_DIALOG_HEIGHT = '80vh'
+
 const stopPropagation = (e: any) => e.stopPropagation()
 const preventDefault = (e: any) => e.preventDefault()
 
@@ -215,9 +218,17 @@ export const InnerFlatList = React.forwardRef<
   FlatListProps<any> & {label: string} & {
     webInnerStyle?: StyleProp<ViewStyle>
     webInnerContentContainerStyle?: StyleProp<ViewStyle>
+    footer?: React.ReactNode
   }
 >(function InnerFlatList(
-  {label, style, webInnerStyle, webInnerContentContainerStyle, ...props},
+  {
+    label,
+    style,
+    webInnerStyle,
+    webInnerContentContainerStyle,
+    footer,
+    ...props
+  },
   ref,
 ) {
   const {gtMobile} = useBreakpoints()
@@ -227,8 +238,7 @@ export const InnerFlatList = React.forwardRef<
       style={[
         a.overflow_hidden,
         a.px_0,
-        // 100 minus 10vh of paddingVertical
-        web({maxHeight: '80vh'}),
+        web({maxHeight: WEB_DIALOG_HEIGHT}),
         webInnerStyle,
       ]}
       contentContainerStyle={[a.h_full, a.px_0, webInnerContentContainerStyle]}>
@@ -237,10 +247,32 @@ export const InnerFlatList = React.forwardRef<
         style={[a.h_full, gtMobile ? a.px_2xl : a.px_xl, flatten(style)]}
         {...props}
       />
+      {footer}
     </Inner>
   )
 })
 
+export function FlatListFooter({children}: {children: React.ReactNode}) {
+  const t = useTheme()
+
+  return (
+    <View
+      style={[
+        a.absolute,
+        a.bottom_0,
+        a.w_full,
+        a.z_10,
+        t.atoms.bg,
+        a.border_t,
+        t.atoms.border_contrast_low,
+        a.px_lg,
+        a.py_md,
+      ]}>
+      {children}
+    </View>
+  )
+}
+
 export function Close() {
   const {_} = useLingui()
   const {close} = React.useContext(Context)
diff --git a/src/components/InterestTabs.tsx b/src/components/InterestTabs.tsx
new file mode 100644
index 000000000..b61157ed8
--- /dev/null
+++ b/src/components/InterestTabs.tsx
@@ -0,0 +1,390 @@
+import {useEffect, useRef, useState} from 'react'
+import {
+  type ScrollView,
+  type StyleProp,
+  View,
+  type ViewStyle,
+} from 'react-native'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
+import {isWeb} from '#/platform/detection'
+import {DraggableScrollView} from '#/view/com/pager/DraggableScrollView'
+import {atoms as a, tokens, useTheme, web} from '#/alf'
+import {transparentifyColor} from '#/alf/util/colorGeneration'
+import {Button, ButtonIcon} from '#/components/Button'
+import {
+  ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft,
+  ArrowRight_Stroke2_Corner0_Rounded as ArrowRight,
+} from '#/components/icons/Arrow'
+import {Text} from '#/components/Typography'
+
+/**
+ * Tab component that automatically scrolls the selected tab into view - used for interests
+ * in the Find Follows dialog, Explore screen, etc.
+ */
+export function InterestTabs({
+  onSelectTab,
+  interests,
+  selectedInterest,
+  disabled,
+  interestsDisplayNames,
+  TabComponent = Tab,
+  contentContainerStyle,
+  gutterWidth = tokens.space.lg,
+}: {
+  onSelectTab: (tab: string) => void
+  interests: string[]
+  selectedInterest: string
+  interestsDisplayNames: Record<string, string>
+  /** still allows changing tab, but removes the active state from the selected tab */
+  disabled?: boolean
+  TabComponent?: React.ComponentType<React.ComponentProps<typeof Tab>>
+  contentContainerStyle?: StyleProp<ViewStyle>
+  gutterWidth?: number
+}) {
+  const t = useTheme()
+  const {_} = useLingui()
+  const listRef = useRef<ScrollView>(null)
+  const [totalWidth, setTotalWidth] = useState(0)
+  const [scrollX, setScrollX] = useState(0)
+  const [contentWidth, setContentWidth] = useState(0)
+  const pendingTabOffsets = useRef<{x: number; width: number}[]>([])
+  const [tabOffsets, setTabOffsets] = useState<{x: number; width: number}[]>([])
+
+  const onInitialLayout = useNonReactiveCallback(() => {
+    const index = interests.indexOf(selectedInterest)
+    scrollIntoViewIfNeeded(index)
+  })
+
+  useEffect(() => {
+    if (tabOffsets) {
+      onInitialLayout()
+    }
+  }, [tabOffsets, onInitialLayout])
+
+  function scrollIntoViewIfNeeded(index: number) {
+    const btnLayout = tabOffsets[index]
+    if (!btnLayout) return
+    listRef.current?.scrollTo({
+      // centered
+      x: btnLayout.x - (totalWidth / 2 - btnLayout.width / 2),
+      animated: true,
+    })
+  }
+
+  function handleSelectTab(index: number) {
+    const tab = interests[index]
+    onSelectTab(tab)
+    scrollIntoViewIfNeeded(index)
+  }
+
+  function handleTabLayout(index: number, x: number, width: number) {
+    if (!tabOffsets.length) {
+      pendingTabOffsets.current[index] = {x, width}
+      if (pendingTabOffsets.current.length === interests.length) {
+        setTabOffsets(pendingTabOffsets.current)
+      }
+    }
+  }
+
+  const canScrollLeft = scrollX > 0
+  const canScrollRight = scrollX < contentWidth - totalWidth
+
+  const cleanupRef = useRef<(() => void) | null>(null)
+
+  function scrollLeft() {
+    if (isContinuouslyScrollingRef.current) {
+      return
+    }
+    if (listRef.current && canScrollLeft) {
+      const newScrollX = Math.max(0, scrollX - 200)
+      listRef.current.scrollTo({x: newScrollX, animated: true})
+    }
+  }
+
+  function scrollRight() {
+    if (isContinuouslyScrollingRef.current) {
+      return
+    }
+    if (listRef.current && canScrollRight) {
+      const maxScroll = contentWidth - totalWidth
+      const newScrollX = Math.min(maxScroll, scrollX + 200)
+      listRef.current.scrollTo({x: newScrollX, animated: true})
+    }
+  }
+
+  const isContinuouslyScrollingRef = useRef(false)
+
+  function startContinuousScroll(direction: 'left' | 'right') {
+    // Clear any existing continuous scroll
+    if (cleanupRef.current) {
+      cleanupRef.current()
+    }
+
+    let holdTimeout: NodeJS.Timeout | null = null
+    let animationFrame: number | null = null
+    let isActive = true
+    isContinuouslyScrollingRef.current = false
+
+    const cleanup = () => {
+      isActive = false
+      if (holdTimeout) clearTimeout(holdTimeout)
+      if (animationFrame) cancelAnimationFrame(animationFrame)
+      cleanupRef.current = null
+      // Reset flag after a delay to prevent onPress from firing
+      setTimeout(() => {
+        isContinuouslyScrollingRef.current = false
+      }, 100)
+    }
+
+    cleanupRef.current = cleanup
+
+    // Start continuous scrolling after hold delay
+    holdTimeout = setTimeout(() => {
+      if (!isActive) return
+
+      isContinuouslyScrollingRef.current = true
+      let currentScrollPosition = scrollX
+
+      const scroll = () => {
+        if (!isActive || !listRef.current) return
+
+        const scrollAmount = 3
+        const maxScroll = contentWidth - totalWidth
+
+        let newScrollX: number
+        let canContinue = false
+
+        if (direction === 'left' && currentScrollPosition > 0) {
+          newScrollX = Math.max(0, currentScrollPosition - scrollAmount)
+          canContinue = newScrollX > 0
+        } else if (direction === 'right' && currentScrollPosition < maxScroll) {
+          newScrollX = Math.min(maxScroll, currentScrollPosition + scrollAmount)
+          canContinue = newScrollX < maxScroll
+        } else {
+          return
+        }
+
+        currentScrollPosition = newScrollX
+        listRef.current.scrollTo({x: newScrollX, animated: false})
+
+        if (canContinue && isActive) {
+          animationFrame = requestAnimationFrame(scroll)
+        }
+      }
+
+      scroll()
+    }, 500)
+  }
+
+  function stopContinuousScroll() {
+    if (cleanupRef.current) {
+      cleanupRef.current()
+    }
+  }
+
+  useEffect(() => {
+    return () => {
+      if (cleanupRef.current) {
+        cleanupRef.current()
+      }
+    }
+  }, [])
+
+  return (
+    <View style={[a.relative, a.flex_row]}>
+      <DraggableScrollView
+        ref={listRef}
+        contentContainerStyle={[
+          a.gap_sm,
+          {paddingHorizontal: gutterWidth},
+          contentContainerStyle,
+        ]}
+        showsHorizontalScrollIndicator={false}
+        decelerationRate="fast"
+        snapToOffsets={
+          tabOffsets.length === interests.length
+            ? tabOffsets.map(o => o.x - tokens.space.xl)
+            : undefined
+        }
+        onLayout={evt => setTotalWidth(evt.nativeEvent.layout.width)}
+        onContentSizeChange={width => setContentWidth(width)}
+        onScroll={evt => {
+          const newScrollX = evt.nativeEvent.contentOffset.x
+          setScrollX(newScrollX)
+        }}
+        scrollEventThrottle={16}>
+        {interests.map((interest, i) => {
+          const active = interest === selectedInterest && !disabled
+          return (
+            <TabComponent
+              key={interest}
+              onSelectTab={handleSelectTab}
+              active={active}
+              index={i}
+              interest={interest}
+              interestsDisplayName={interestsDisplayNames[interest]}
+              onLayout={handleTabLayout}
+            />
+          )
+        })}
+      </DraggableScrollView>
+      {isWeb && canScrollLeft && (
+        <View
+          style={[
+            a.absolute,
+            a.top_0,
+            a.left_0,
+            a.bottom_0,
+            a.justify_center,
+            {paddingLeft: gutterWidth},
+            a.pr_md,
+            a.z_10,
+            web({
+              background: `linear-gradient(to right,  ${t.atoms.bg.backgroundColor} 0%, ${t.atoms.bg.backgroundColor} 70%, ${transparentifyColor(t.atoms.bg.backgroundColor, 0)} 100%)`,
+            }),
+          ]}>
+          <Button
+            label={_(msg`Scroll left`)}
+            onPress={scrollLeft}
+            onPressIn={() => startContinuousScroll('left')}
+            onPressOut={stopContinuousScroll}
+            color="secondary"
+            size="small"
+            style={[
+              a.border,
+              t.atoms.border_contrast_low,
+              t.atoms.bg,
+              a.h_full,
+              {aspectRatio: 1},
+              a.rounded_full,
+            ]}>
+            <ButtonIcon icon={ArrowLeft} />
+          </Button>
+        </View>
+      )}
+      {isWeb && canScrollRight && (
+        <View
+          style={[
+            a.absolute,
+            a.top_0,
+            a.right_0,
+            a.bottom_0,
+            a.justify_center,
+            {paddingRight: gutterWidth},
+            a.pl_md,
+            a.z_10,
+            web({
+              background: `linear-gradient(to left, ${t.atoms.bg.backgroundColor} 0%, ${t.atoms.bg.backgroundColor} 70%, ${transparentifyColor(t.atoms.bg.backgroundColor, 0)} 100%)`,
+            }),
+          ]}>
+          <Button
+            label={_(msg`Scroll right`)}
+            onPress={scrollRight}
+            onPressIn={() => startContinuousScroll('right')}
+            onPressOut={stopContinuousScroll}
+            color="secondary"
+            size="small"
+            style={[
+              a.border,
+              t.atoms.border_contrast_low,
+              t.atoms.bg,
+              a.h_full,
+              {aspectRatio: 1},
+              a.rounded_full,
+            ]}>
+            <ButtonIcon icon={ArrowRight} />
+          </Button>
+        </View>
+      )}
+    </View>
+  )
+}
+
+function Tab({
+  onSelectTab,
+  interest,
+  active,
+  index,
+  interestsDisplayName,
+  onLayout,
+}: {
+  onSelectTab: (index: number) => void
+  interest: string
+  active: boolean
+  index: number
+  interestsDisplayName: string
+  onLayout: (index: number, x: number, width: number) => void
+}) {
+  const t = useTheme()
+  const {_} = useLingui()
+  const label = active
+    ? _(
+        msg({
+          message: `"${interestsDisplayName}" category (active)`,
+          comment:
+            'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is currently selected.',
+        }),
+      )
+    : _(
+        msg({
+          message: `Select "${interestsDisplayName}" category`,
+          comment:
+            'Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is not currently active and can be selected.',
+        }),
+      )
+
+  return (
+    <View
+      key={interest}
+      onLayout={e =>
+        onLayout(index, e.nativeEvent.layout.x, e.nativeEvent.layout.width)
+      }>
+      <Button
+        label={label}
+        onPress={() => onSelectTab(index)}
+        // disable focus ring, we handle it
+        style={web({outline: 'none'})}>
+        {({hovered, pressed, focused}) => (
+          <View
+            style={[
+              a.rounded_full,
+              a.px_lg,
+              a.py_sm,
+              a.border,
+              active || hovered || pressed
+                ? [t.atoms.bg_contrast_25, t.atoms.border_contrast_medium]
+                : focused
+                  ? {
+                      borderColor: t.palette.primary_300,
+                      backgroundColor: t.palette.primary_25,
+                    }
+                  : [t.atoms.bg, t.atoms.border_contrast_low],
+            ]}>
+            <Text
+              style={[
+                a.font_medium,
+                active || hovered || pressed
+                  ? t.atoms.text
+                  : t.atoms.text_contrast_medium,
+              ]}>
+              {interestsDisplayName}
+            </Text>
+          </View>
+        )}
+      </Button>
+    </View>
+  )
+}
+
+export function boostInterests(boosts?: string[]) {
+  return (_a: string, _b: string) => {
+    const indexA = boosts?.indexOf(_a) ?? -1
+    const indexB = boosts?.indexOf(_b) ?? -1
+    const rankA = indexA === -1 ? Infinity : indexA
+    const rankB = indexB === -1 ? Infinity : indexB
+    return rankA - rankB
+  }
+}
diff --git a/src/components/LoggedOutCTA.tsx b/src/components/LoggedOutCTA.tsx
index 7ec8c2264..0bafbd45f 100644
--- a/src/components/LoggedOutCTA.tsx
+++ b/src/components/LoggedOutCTA.tsx
@@ -1,5 +1,6 @@
 import {View, type ViewStyle} from 'react-native'
-import {Trans} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 import {type Gate} from '#/lib/statsig/gates'
 import {useGate} from '#/lib/statsig/statsig'
@@ -21,6 +22,7 @@ export function LoggedOutCTA({style, gateName}: LoggedOutCTAProps) {
   const {requestSwitchToAccount} = useLoggedOutViewControls()
   const gate = useGate()
   const t = useTheme()
+  const {_} = useLingui()
 
   // Only show for logged-out users on web
   if (hasSession || !isWeb) {
@@ -66,7 +68,7 @@ export function LoggedOutCTA({style, gateName}: LoggedOutCTAProps) {
           onPress={() => {
             requestSwitchToAccount({requestedAccount: 'new'})
           }}
-          label="Create account"
+          label={_(msg`Create account`)}
           size="small"
           variant="solid"
           color="primary">
diff --git a/src/components/ProgressGuide/FollowDialog.tsx b/src/components/ProgressGuide/FollowDialog.tsx
index 20ebb0abf..a2ec4df13 100644
--- a/src/components/ProgressGuide/FollowDialog.tsx
+++ b/src/components/ProgressGuide/FollowDialog.tsx
@@ -1,17 +1,9 @@
 import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'
-import {
-  ScrollView,
-  type StyleProp,
-  TextInput,
-  useWindowDimensions,
-  View,
-  type ViewStyle,
-} from 'react-native'
+import {TextInput, useWindowDimensions, View} from 'react-native'
 import {type ModerationOpts} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
-import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
 import {logEvent} from '#/lib/statsig/statsig'
 import {isWeb} from '#/platform/detection'
 import {useModerationOpts} from '#/state/preferences/moderation-opts'
@@ -28,7 +20,6 @@ import {
 import {
   atoms as a,
   native,
-  tokens,
   useBreakpoints,
   useTheme,
   type ViewStyleProp,
@@ -40,6 +31,7 @@ import {useInteractionState} from '#/components/hooks/useInteractionState'
 import {MagnifyingGlass2_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass2'
 import {PersonGroup_Stroke2_Corner2_Rounded as PersonGroupIcon} from '#/components/icons/Person'
 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
+import {boostInterests, InterestTabs} from '#/components/InterestTabs'
 import * as ProfileCard from '#/components/ProfileCard'
 import {Text} from '#/components/Typography'
 import type * as bsky from '#/types/bsky'
@@ -337,12 +329,13 @@ let Header = ({
           }}
           onEscape={control.close}
         />
-        <Tabs
+        <InterestTabs
           onSelectTab={onSelectTab}
           interests={interests}
           selectedInterest={selectedInterest}
-          hasSearchText={!!searchText}
+          disabled={!!searchText}
           interestsDisplayNames={interestsDisplayNames}
+          TabComponent={Tab}
         />
       </View>
     </View>
@@ -403,99 +396,6 @@ function HeaderTop({guide}: {guide: Follow10ProgressGuide}) {
   )
 }
 
-let Tabs = ({
-  onSelectTab,
-  interests,
-  selectedInterest,
-  hasSearchText,
-  interestsDisplayNames,
-  TabComponent = Tab,
-  contentContainerStyle,
-}: {
-  onSelectTab: (tab: string) => void
-  interests: string[]
-  selectedInterest: string
-  hasSearchText: boolean
-  interestsDisplayNames: Record<string, string>
-  TabComponent?: React.ComponentType<React.ComponentProps<typeof Tab>>
-  contentContainerStyle?: StyleProp<ViewStyle>
-}): React.ReactNode => {
-  const listRef = useRef<ScrollView>(null)
-  const [totalWidth, setTotalWidth] = useState(0)
-  const pendingTabOffsets = useRef<{x: number; width: number}[]>([])
-  const [tabOffsets, setTabOffsets] = useState<{x: number; width: number}[]>([])
-
-  const onInitialLayout = useNonReactiveCallback(() => {
-    const index = interests.indexOf(selectedInterest)
-    scrollIntoViewIfNeeded(index)
-  })
-
-  useEffect(() => {
-    if (tabOffsets) {
-      onInitialLayout()
-    }
-  }, [tabOffsets, onInitialLayout])
-
-  function scrollIntoViewIfNeeded(index: number) {
-    const btnLayout = tabOffsets[index]
-    if (!btnLayout) return
-    listRef.current?.scrollTo({
-      // centered
-      x: btnLayout.x - (totalWidth / 2 - btnLayout.width / 2),
-      animated: true,
-    })
-  }
-
-  function handleSelectTab(index: number) {
-    const tab = interests[index]
-    onSelectTab(tab)
-    scrollIntoViewIfNeeded(index)
-  }
-
-  function handleTabLayout(index: number, x: number, width: number) {
-    if (!tabOffsets.length) {
-      pendingTabOffsets.current[index] = {x, width}
-      if (pendingTabOffsets.current.length === interests.length) {
-        setTabOffsets(pendingTabOffsets.current)
-      }
-    }
-  }
-
-  return (
-    <ScrollView
-      ref={listRef}
-      horizontal
-      contentContainerStyle={[a.gap_sm, a.px_lg, contentContainerStyle]}
-      showsHorizontalScrollIndicator={false}
-      decelerationRate="fast"
-      snapToOffsets={
-        tabOffsets.length === interests.length
-          ? tabOffsets.map(o => o.x - tokens.space.xl)
-          : undefined
-      }
-      onLayout={evt => setTotalWidth(evt.nativeEvent.layout.width)}
-      scrollEventThrottle={200} // big throttle
-    >
-      {interests.map((interest, i) => {
-        const active = interest === selectedInterest && !hasSearchText
-        return (
-          <TabComponent
-            key={interest}
-            onSelectTab={handleSelectTab}
-            active={active}
-            index={i}
-            interest={interest}
-            interestsDisplayName={interestsDisplayNames[interest]}
-            onLayout={handleTabLayout}
-          />
-        )
-      })}
-    </ScrollView>
-  )
-}
-Tabs = memo(Tabs)
-export {Tabs}
-
 let Tab = ({
   onSelectTab,
   interest,
@@ -513,24 +413,36 @@ let Tab = ({
 }): React.ReactNode => {
   const t = useTheme()
   const {_} = useLingui()
-  const activeText = active ? _(msg` (active)`) : ''
+  const label = active
+    ? _(
+        msg({
+          message: `Search for "${interestsDisplayName}" (active)`,
+          comment:
+            'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.',
+        }),
+      )
+    : _(
+        msg({
+          message: `Search for "${interestsDisplayName}`,
+          comment:
+            'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.',
+        }),
+      )
   return (
     <View
       key={interest}
       onLayout={e =>
         onLayout(index, e.nativeEvent.layout.x, e.nativeEvent.layout.width)
       }>
-      <Button
-        label={_(msg`Search for "${interestsDisplayName}"${activeText}`)}
-        onPress={() => onSelectTab(index)}>
-        {({hovered, pressed, focused}) => (
+      <Button label={label} onPress={() => onSelectTab(index)}>
+        {({hovered, pressed}) => (
           <View
             style={[
               a.rounded_full,
               a.px_lg,
               a.py_sm,
               a.border,
-              active || hovered || pressed || focused
+              active || hovered || pressed
                 ? [
                     t.atoms.bg_contrast_25,
                     {borderColor: t.atoms.bg_contrast_25.backgroundColor},
@@ -540,7 +452,7 @@ let Tab = ({
             <Text
               style={[
                 a.font_medium,
-                active || hovered || pressed || focused
+                active || hovered || pressed
                   ? t.atoms.text
                   : t.atoms.text_contrast_medium,
               ]}>
@@ -759,13 +671,3 @@ function Empty({message}: {message: string}) {
     </View>
   )
 }
-
-export function boostInterests(boosts?: string[]) {
-  return (_a: string, _b: string) => {
-    const indexA = boosts?.indexOf(_a) ?? -1
-    const indexB = boosts?.indexOf(_b) ?? -1
-    const rankA = indexA === -1 ? Infinity : indexA
-    const rankB = indexB === -1 ? Infinity : indexB
-    return rankA - rankB
-  }
-}
diff --git a/src/components/Toast/Toast.tsx b/src/components/Toast/Toast.tsx
index 53d5e5115..ac5bc4889 100644
--- a/src/components/Toast/Toast.tsx
+++ b/src/components/Toast/Toast.tsx
@@ -16,19 +16,6 @@ import {dismiss} from '#/components/Toast/sonner'
 import {type ToastType} from '#/components/Toast/types'
 import {Text as BaseText} from '#/components/Typography'
 
-type ToastConfigContextType = {
-  id: string
-}
-
-type ToastThemeContextType = {
-  type: ToastType
-}
-
-export type ToastComponentProps = {
-  type?: ToastType
-  content: string
-}
-
 export const ICONS = {
   default: CircleCheck,
   success: CircleCheck,
@@ -37,81 +24,67 @@ export const ICONS = {
   info: CircleInfo,
 }
 
-const ToastConfigContext = createContext<ToastConfigContextType>({
+const ToastConfigContext = createContext<{
+  id: string
+  type: ToastType
+}>({
   id: '',
+  type: 'default',
 })
 ToastConfigContext.displayName = 'ToastConfigContext'
 
 export function ToastConfigProvider({
   children,
   id,
+  type,
 }: {
   children: React.ReactNode
   id: string
+  type: ToastType
 }) {
   return (
-    <ToastConfigContext.Provider value={useMemo(() => ({id}), [id])}>
+    <ToastConfigContext.Provider
+      value={useMemo(() => ({id, type}), [id, type])}>
       {children}
     </ToastConfigContext.Provider>
   )
 }
 
-const ToastThemeContext = createContext<ToastThemeContextType>({
-  type: 'default',
-})
-ToastThemeContext.displayName = 'ToastThemeContext'
-
-export function Default({type = 'default', content}: ToastComponentProps) {
-  return (
-    <Outer type={type}>
-      <Icon />
-      <Text>{content}</Text>
-    </Outer>
-  )
-}
-
-export function Outer({
-  children,
-  type = 'default',
-}: {
-  children: React.ReactNode
-  type?: ToastType
-}) {
+export function Outer({children}: {children: React.ReactNode}) {
   const t = useTheme()
+  const {type} = useContext(ToastConfigContext)
   const styles = useToastStyles({type})
 
   return (
-    <ToastThemeContext.Provider value={useMemo(() => ({type}), [type])}>
-      <View
-        style={[
-          a.flex_1,
-          a.p_lg,
-          a.rounded_md,
-          a.border,
-          a.flex_row,
-          a.gap_sm,
-          t.atoms.shadow_sm,
-          {
-            paddingVertical: 14, // 16 seems too big
-            backgroundColor: styles.backgroundColor,
-            borderColor: styles.borderColor,
-          },
-        ]}>
-        {children}
-      </View>
-    </ToastThemeContext.Provider>
+    <View
+      style={[
+        a.flex_1,
+        a.p_lg,
+        a.rounded_md,
+        a.border,
+        a.flex_row,
+        a.gap_sm,
+        t.atoms.shadow_sm,
+        {
+          paddingVertical: 14, // 16 seems too big
+          backgroundColor: styles.backgroundColor,
+          borderColor: styles.borderColor,
+        },
+      ]}>
+      {children}
+    </View>
   )
 }
 
 export function Icon({icon}: {icon?: React.ComponentType<SVGIconProps>}) {
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const styles = useToastStyles({type})
   const IconComponent = icon || ICONS[type]
   return <IconComponent size="md" fill={styles.iconColor} />
 }
 
 export function Text({children}: {children: React.ReactNode}) {
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const {textColor} = useToastStyles({type})
   const {fontScaleCompensation} = useToastFontScaleCompensation()
   return (
@@ -142,12 +115,12 @@ export function Text({children}: {children: React.ReactNode}) {
 
 export function Action(
   props: Omit<ButtonProps, UninheritableButtonProps | 'children'> & {
-    children: string
+    children: React.ReactNode
   },
 ) {
   const t = useTheme()
   const {fontScaleCompensation} = useToastFontScaleCompensation()
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const {id} = useContext(ToastConfigContext)
   const styles = useMemo(() => {
     const base = {
diff --git a/src/components/Toast/index.e2e.tsx b/src/components/Toast/index.e2e.tsx
index 357bd8dda..a4056323d 100644
--- a/src/components/Toast/index.e2e.tsx
+++ b/src/components/Toast/index.e2e.tsx
@@ -1,3 +1,11 @@
+export const DURATION = 0
+
+export const Action = () => null
+export const Icon = () => null
+export const Outer = () => null
+export const Text = () => null
+export const ToastConfigProvider = () => null
+
 export function ToastOutlet() {
   return null
 }
diff --git a/src/components/Toast/index.tsx b/src/components/Toast/index.tsx
index 0d1c661d2..d70a8ad16 100644
--- a/src/components/Toast/index.tsx
+++ b/src/components/Toast/index.tsx
@@ -6,15 +6,15 @@ import {toast as sonner, Toaster} from 'sonner-native'
 import {atoms as a} from '#/alf'
 import {DURATION} from '#/components/Toast/const'
 import {
-  Default as DefaultToast,
+  Icon as ToastIcon,
   Outer as BaseOuter,
-  type ToastComponentProps,
+  Text as ToastText,
   ToastConfigProvider,
 } from '#/components/Toast/Toast'
 import {type BaseToastOptions} from '#/components/Toast/types'
 
 export {DURATION} from '#/components/Toast/const'
-export {Action, Icon, Text} from '#/components/Toast/Toast'
+export {Action, Icon, Text, ToastConfigProvider} from '#/components/Toast/Toast'
 export {type ToastType} from '#/components/Toast/types'
 
 /**
@@ -25,27 +25,10 @@ export function ToastOutlet() {
   return <Toaster pauseWhenPageIsHidden gap={a.gap_sm.gap} />
 }
 
-/**
- * The toast UI component
- */
-export function Default({type, content}: ToastComponentProps) {
+export function Outer({children}: {children: React.ReactNode}) {
   return (
     <View style={[a.px_xl, a.w_full]}>
-      <DefaultToast content={content} type={type} />
-    </View>
-  )
-}
-
-export function Outer({
-  children,
-  type = 'default',
-}: {
-  children: React.ReactNode
-  type?: ToastComponentProps['type']
-}) {
-  return (
-    <View style={[a.px_xl, a.w_full]}>
-      <BaseOuter type={type}>{children}</BaseOuter>
+      <BaseOuter>{children}</BaseOuter>
     </View>
   )
 }
@@ -60,14 +43,17 @@ export const api = sonner
  */
 export function show(
   content: React.ReactNode,
-  {type, ...options}: BaseToastOptions = {},
+  {type = 'default', ...options}: BaseToastOptions = {},
 ) {
   const id = nanoid()
 
   if (typeof content === 'string') {
     sonner.custom(
-      <ToastConfigProvider id={id}>
-        <Default content={content} type={type} />
+      <ToastConfigProvider id={id} type={type}>
+        <Outer>
+          <ToastIcon />
+          <ToastText>{content}</ToastText>
+        </Outer>
       </ToastConfigProvider>,
       {
         ...options,
@@ -77,7 +63,9 @@ export function show(
     )
   } else if (React.isValidElement(content)) {
     sonner.custom(
-      <ToastConfigProvider id={id}>{content}</ToastConfigProvider>,
+      <ToastConfigProvider id={id} type={type}>
+        {content}
+      </ToastConfigProvider>,
       {
         ...options,
         id,
diff --git a/src/components/Toast/index.web.tsx b/src/components/Toast/index.web.tsx
index c4db20dca..8b2028db9 100644
--- a/src/components/Toast/index.web.tsx
+++ b/src/components/Toast/index.web.tsx
@@ -5,7 +5,9 @@ import {toast as sonner, Toaster} from 'sonner'
 import {atoms as a} from '#/alf'
 import {DURATION} from '#/components/Toast/const'
 import {
-  Default as DefaultToast,
+  Icon as ToastIcon,
+  Outer as ToastOuter,
+  Text as ToastText,
   ToastConfigProvider,
 } from '#/components/Toast/Toast'
 import {type BaseToastOptions} from '#/components/Toast/types'
@@ -39,14 +41,17 @@ export const api = sonner
  */
 export function show(
   content: React.ReactNode,
-  {type, ...options}: BaseToastOptions = {},
+  {type = 'default', ...options}: BaseToastOptions = {},
 ) {
   const id = nanoid()
 
   if (typeof content === 'string') {
     sonner(
-      <ToastConfigProvider id={id}>
-        <DefaultToast content={content} type={type} />
+      <ToastConfigProvider id={id} type={type}>
+        <ToastOuter>
+          <ToastIcon />
+          <ToastText>{content}</ToastText>
+        </ToastOuter>
       </ToastConfigProvider>,
       {
         ...options,
@@ -56,12 +61,17 @@ export function show(
       },
     )
   } else if (React.isValidElement(content)) {
-    sonner(<ToastConfigProvider id={id}>{content}</ToastConfigProvider>, {
-      ...options,
-      unstyled: true, // required on web
-      id,
-      duration: options?.duration ?? DURATION,
-    })
+    sonner(
+      <ToastConfigProvider id={id} type={type}>
+        {content}
+      </ToastConfigProvider>,
+      {
+        ...options,
+        unstyled: true, // required on web
+        id,
+        duration: options?.duration ?? DURATION,
+      },
+    )
   } else {
     throw new Error(
       `Toast can be a string or a React element, got ${typeof content}`,
diff --git a/src/components/dialogs/StarterPackDialog.tsx b/src/components/dialogs/StarterPackDialog.tsx
index ec041d401..c4b8a72c4 100644
--- a/src/components/dialogs/StarterPackDialog.tsx
+++ b/src/components/dialogs/StarterPackDialog.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import {useCallback, useState} from 'react'
 import {View} from 'react-native'
 import {
   type AppBskyGraphGetStarterPacksWithMembership,
@@ -22,16 +22,16 @@ import {
 } from '#/state/queries/list-memberships'
 import * as Toast from '#/view/com/util/Toast'
 import {atoms as a, useTheme} from '#/alf'
+import {AvatarStack} from '#/components/AvatarStack'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import * as Dialog from '#/components/Dialog'
 import {Divider} from '#/components/Divider'
+import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
+import {StarterPack} from '#/components/icons/StarterPack'
+import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
 import {Loader} from '#/components/Loader'
 import {Text} from '#/components/Typography'
 import * as bsky from '#/types/bsky'
-import {AvatarStack} from '../AvatarStack'
-import {PlusLarge_Stroke2_Corner0_Rounded} from '../icons/Plus'
-import {StarterPack} from '../icons/StarterPack'
-import {TimesLarge_Stroke2_Corner0_Rounded} from '../icons/Times'
 
 type StarterPackWithMembership =
   AppBskyGraphGetStarterPacksWithMembership.StarterPackWithMembership
@@ -51,7 +51,7 @@ export function StarterPackDialog({
   const navigation = useNavigation<NavigationProp>()
   const requireEmailVerification = useRequireEmailVerification()
 
-  const navToWizard = React.useCallback(() => {
+  const navToWizard = useCallback(() => {
     control.close()
     navigation.navigate('StarterPackWizard', {
       fromDialog: true,
@@ -91,7 +91,6 @@ function Empty({onStartWizard}: {onStartWizard: () => void}) {
   const {_} = useLingui()
   const t = useTheme()
 
-  isWeb
   return (
     <View style={[a.gap_2xl, {paddingTop: isWeb ? 100 : 64}]}>
       <View style={[a.gap_xs, a.align_center]}>
@@ -115,7 +114,7 @@ function Empty({onStartWizard}: {onStartWizard: () => void}) {
               Create
             </Trans>
           </ButtonText>
-          <ButtonIcon icon={PlusLarge_Stroke2_Corner0_Rounded} />
+          <ButtonIcon icon={PlusIcon} />
         </Button>
       </View>
     </View>
@@ -134,7 +133,6 @@ function StarterPackList({
   enabled?: boolean
 }) {
   const {_} = useLingui()
-  const t = useTheme()
 
   const {
     data,
@@ -149,7 +147,7 @@ function StarterPackList({
   const membershipItems =
     data?.pages.flatMap(page => page.starterPacksWithMembership) || []
 
-  const _onRefresh = React.useCallback(async () => {
+  const _onRefresh = useCallback(async () => {
     try {
       await refetch()
     } catch (err) {
@@ -157,7 +155,7 @@ function StarterPackList({
     }
   }, [refetch])
 
-  const _onEndReached = React.useCallback(async () => {
+  const _onEndReached = useCallback(async () => {
     if (isFetchingNextPage || !hasNextPage || isError) return
     try {
       await fetchNextPage()
@@ -166,25 +164,17 @@ function StarterPackList({
     }
   }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
 
-  const renderItem = React.useCallback(
+  const renderItem = useCallback(
     ({item}: {item: StarterPackWithMembership}) => (
       <StarterPackItem starterPackWithMembership={item} targetDid={targetDid} />
     ),
     [targetDid],
   )
 
-  const onClose = React.useCallback(() => {
+  const onClose = useCallback(() => {
     control.close()
   }, [control])
 
-  const XIcon = React.useMemo(() => {
-    return (
-      <TimesLarge_Stroke2_Corner0_Rounded
-        fill={t.atoms.text_contrast_medium.color}
-      />
-    )
-  }, [t])
-
   const listHeader = (
     <>
       <View
@@ -196,8 +186,14 @@ function StarterPackList({
         <Text style={[a.text_lg, a.font_bold]}>
           <Trans>Add to starter packs</Trans>
         </Text>
-        <Button label={_(msg`Close`)} onPress={onClose}>
-          <ButtonIcon icon={() => XIcon} />
+        <Button
+          label={_(msg`Close`)}
+          onPress={onClose}
+          variant="ghost"
+          color="secondary"
+          size="small"
+          shape="round">
+          <ButtonIcon icon={XIcon} />
         </Button>
       </View>
       {membershipItems.length > 0 && (
@@ -217,7 +213,7 @@ function StarterPackList({
                   Create
                 </Trans>
               </ButtonText>
-              <ButtonIcon icon={PlusLarge_Stroke2_Corner0_Rounded} />
+              <ButtonIcon icon={PlusIcon} />
             </Button>
           </View>
           <Divider />
@@ -268,7 +264,7 @@ function StarterPackItem({
   const starterPack = starterPackWithMembership.starterPack
   const isInPack = !!starterPackWithMembership.listItem
 
-  const [isPendingRefresh, setIsPendingRefresh] = React.useState(false)
+  const [isPendingRefresh, setIsPendingRefresh] = useState(false)
 
   const {mutate: addMembership} = useListMembershipAddMutation({
     onSuccess: () => {
diff --git a/src/components/forms/Toggle.tsx b/src/components/forms/Toggle.tsx
index 9c3564aa5..bb9fde2e1 100644
--- a/src/components/forms/Toggle.tsx
+++ b/src/components/forms/Toggle.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {Pressable, View, type ViewStyle} from 'react-native'
+import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
 import Animated, {LinearTransition} from 'react-native-reanimated'
 
 import {HITSLOP_10} from '#/lib/constants'
@@ -59,6 +59,7 @@ export type GroupProps = React.PropsWithChildren<{
   disabled?: boolean
   onChange: (value: string[]) => void
   label: string
+  style?: StyleProp<ViewStyle>
 }>
 
 export type ItemProps = ViewStyleProp & {
@@ -84,6 +85,7 @@ export function Group({
   type = 'checkbox',
   maxSelections,
   label,
+  style,
 }: GroupProps) {
   const groupRole = type === 'radio' ? 'radiogroup' : undefined
   const values = type === 'radio' ? providedValues.slice(0, 1) : providedValues
@@ -136,7 +138,7 @@ export function Group({
   return (
     <GroupContext.Provider value={context}>
       <View
-        style={[a.w_full]}
+        style={[a.w_full, style]}
         role={groupRole}
         {...(groupRole === 'radiogroup'
           ? {
diff --git a/src/env/common.ts b/src/env/common.ts
index fbf477726..69451fd7e 100644
--- a/src/env/common.ts
+++ b/src/env/common.ts
@@ -63,6 +63,12 @@ export const LOG_LEVEL = (process.env.EXPO_PUBLIC_LOG_LEVEL || 'info') as
 export const LOG_DEBUG: string = process.env.EXPO_PUBLIC_LOG_DEBUG || ''
 
 /**
+ * The DID of the Bluesky appview to proxy to
+ */
+export const BLUESKY_PROXY_DID: Did =
+  process.env.EXPO_PUBLIC_BLUESKY_PROXY_DID || 'did:web:api.bsky.app'
+
+/**
  * The DID of the chat service to proxy to
  */
 export const CHAT_PROXY_DID: Did =
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index d81b68db6..727d4b052 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -1,6 +1,9 @@
 import {type Insets, Platform} from 'react-native'
 import {type AppBskyActorDefs} from '@atproto/api'
 
+import {type ProxyHeaderValue} from '#/state/session/agent'
+import {BLUESKY_PROXY_DID, CHAT_PROXY_DID} from '#/env'
+
 export const LOCAL_DEV_SERVICE =
   Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583'
 export const STAGING_SERVICE = 'https://staging.bsky.dev'
@@ -211,6 +214,16 @@ export const PUBLIC_STAGING_APPVIEW_DID = 'did:web:api.staging.bsky.dev'
 
 export const DEV_ENV_APPVIEW = `http://localhost:2584` // always the same
 
+export const BLUESKY_PROXY_HEADER: ProxyHeaderValue = `${BLUESKY_PROXY_DID}#bsky_appview`
+
+export const BLUESKY_SERVICE_HEADERS = {
+  'atproto-proxy': BLUESKY_PROXY_HEADER,
+}
+
+export const DM_SERVICE_HEADERS = {
+  'atproto-proxy': `${CHAT_PROXY_DID}#bsky_chat`,
+}
+
 export const webLinks = {
   tos: `https://bsky.social/about/support/tos`,
   privacy: `https://bsky.social/about/support/privacy-policy`,
diff --git a/src/lib/hooks/useDraggableScrollView.ts b/src/lib/hooks/useDraggableScrollView.ts
index 05fda9a9f..d4d35ccda 100644
--- a/src/lib/hooks/useDraggableScrollView.ts
+++ b/src/lib/hooks/useDraggableScrollView.ts
@@ -20,9 +20,6 @@ export function useDraggableScroll<Scrollable extends ScrollView = ScrollView>({
       return
     }
     const slider = ref.current as unknown as HTMLDivElement
-    if (!slider) {
-      return
-    }
     let isDragging = false
     let isMouseDown = false
     let startX = 0
@@ -61,6 +58,9 @@ export function useDraggableScroll<Scrollable extends ScrollView = ScrollView>({
       e.preventDefault()
       const walk = x - startX
       slider.scrollLeft = scrollLeft - walk
+
+      if (slider.contains(document.activeElement))
+        (document.activeElement as HTMLElement)?.blur?.()
     }
 
     slider.addEventListener('mousedown', mouseDown)
diff --git a/src/lib/icons.tsx b/src/lib/icons.tsx
index 6e0be9d0a..4bea1ebef 100644
--- a/src/lib/icons.tsx
+++ b/src/lib/icons.tsx
@@ -7,17 +7,19 @@ export function MagnifyingGlassIcon({
   style,
   size,
   strokeWidth = 2,
+  color = 'currentColor',
 }: {
   style?: StyleProp<ViewStyle>
   size?: string | number
   strokeWidth?: number
+  color?: string
 }) {
   return (
     <Svg
       fill="none"
       viewBox="0 0 24 24"
       strokeWidth={strokeWidth}
-      stroke="currentColor"
+      stroke={color}
       width={size || 24}
       height={size || 24}
       style={style}>
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index 114048ab7..391314162 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -9,6 +9,8 @@ export type Gate =
   | 'explore_show_suggested_feeds'
   | 'old_postonboarding'
   | 'onboarding_add_video_feed'
+  | 'onboarding_suggested_accounts'
+  | 'onboarding_value_prop'
   | 'post_follow_profile_suggested_accounts'
   | 'remove_show_latest_button'
   | 'test_gate_1'
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index a6c98211c..c48ea6c64 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -13,16 +13,16 @@ msgstr ""
 "Language-Team: \n"
 "Plural-Forms: \n"
 
-#: src/components/ProgressGuide/FollowDialog.tsx:516
-#: src/screens/Search/modules/ExploreSuggestedAccounts.tsx:127
-msgid "(active)"
+#. Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is currently selected.
+#: src/components/InterestTabs.tsx:325
+msgid "\"{interestsDisplayName}\" category (active)"
 msgstr ""
 
 #: src/screens/Messages/components/ChatListItem.tsx:160
 msgid "(contains embedded content)"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:69
+#: src/screens/Settings/AccountSettings.tsx:71
 msgid "(no email)"
 msgstr ""
 
@@ -95,8 +95,7 @@ msgstr ""
 msgid "{0, plural, one {following} other {following}}"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:469
-#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:473
 msgid "{0, plural, one {like} other {likes}}"
 msgstr ""
 
@@ -104,13 +103,11 @@ msgstr ""
 msgid "{0, plural, one {post} other {posts}}"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:453
-#: src/view/com/post-thread/PostThreadItem.tsx:522
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:457
 msgid "{0, plural, one {quote} other {quotes}}"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:435
-#: src/view/com/post-thread/PostThreadItem.tsx:504
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:439
 msgid "{0, plural, one {repost} other {reposts}}"
 msgstr ""
 
@@ -123,6 +120,10 @@ msgstr ""
 msgid "{0, plural, other {# people have}} used this starter pack!"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:370
+msgid "{0, plural, other {+# more}}"
+msgstr ""
+
 #. Pattern: {wordValue} in tags
 #: src/components/dialogs/MutedWords.tsx:475
 msgid "{0} <0>in <1>tags</1></0>"
@@ -211,20 +212,20 @@ msgstr ""
 msgid "{0}s"
 msgstr ""
 
-#: src/view/shell/desktop/LeftNav.tsx:402
+#: src/view/shell/desktop/LeftNav.tsx:454
 msgid "{count, plural, one {# unread item} other {# unread items}}"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:386
+#: src/screens/Profile/Header/EditProfileDialog.tsx:380
 msgid "{DESCRIPTION_MAX_GRAPHEMES, plural, other {Description is too long. The maximum number of characters is #.}}"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:340
+#: src/screens/Profile/Header/EditProfileDialog.tsx:334
 msgid "{DISPLAY_NAME_MAX_GRAPHEMES, plural, other {Display name is too long. The maximum number of characters is #.}}"
 msgstr ""
 
-#: src/lib/generate-starterpack.ts:111
-#: src/screens/StarterPack/Wizard/index.tsx:184
+#: src/lib/generate-starterpack.ts:104
+#: src/screens/StarterPack/Wizard/index.tsx:201
 msgid "{displayName}'s Starter Pack"
 msgstr ""
 
@@ -453,12 +454,12 @@ msgstr ""
 msgid "+{computedTotal}"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:488
+#: src/screens/StarterPack/Wizard/index.tsx:524
 msgctxt "profiles"
 msgid "<0>{0}, </0><1>{1}, </1>and {2, plural, one {# other} other {# others}} are included in your starter pack"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:541
+#: src/screens/StarterPack/Wizard/index.tsx:577
 msgctxt "feeds"
 msgid "<0>{0}, </0><1>{1}, </1>and {2, plural, one {# other} other {# others}} are included in your starter pack"
 msgstr ""
@@ -471,11 +472,12 @@ msgstr ""
 msgid "<0>{0}</0> {1, plural, one {following} other {following}}"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:529
+#: src/screens/StarterPack/Wizard/index.tsx:511
+#: src/screens/StarterPack/Wizard/index.tsx:565
 msgid "<0>{0}</0> and<1> </1><2>{1} </2>are included in your starter pack"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:522
+#: src/screens/StarterPack/Wizard/index.tsx:558
 msgid "<0>{0}</0> is included in your starter pack"
 msgstr ""
 
@@ -491,7 +493,7 @@ msgstr ""
 msgid "<0>Sign in</0><1> or </1><2>create an account</2><3> </3><4>to search for news, sports, politics, and everything else happening on Bluesky.</4>"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:479
+#: src/screens/StarterPack/Wizard/index.tsx:502
 msgid "<0>You</0> and<1> </1><2>{0} </2>are included in your starter pack"
 msgstr ""
 
@@ -515,6 +517,10 @@ msgstr ""
 msgid "7 days"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:341
+msgid "A collection of popular feeds you can find on Bluesky, including News, Booksky, Game Dev, Blacksky, and Fountain Pens"
+msgstr ""
+
 #. If last message does not contain text, fall back to "{user} reacted to {a message}"
 #: src/screens/Messages/components/ChatListItem.tsx:210
 msgid "a message"
@@ -565,26 +571,26 @@ msgstr ""
 
 #: src/Navigation.tsx:398
 #: src/screens/Login/LoginForm.tsx:194
-#: src/screens/Settings/AccountSettings.tsx:49
+#: src/screens/Settings/AccountSettings.tsx:51
 #: src/screens/Settings/Settings.tsx:174
 #: src/screens/Settings/Settings.tsx:177
 msgid "Account"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:357
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:361
 #: src/screens/Messages/components/RequestButtons.tsx:91
-#: src/view/com/profile/ProfileMenu.tsx:158
+#: src/view/com/profile/ProfileMenu.tsx:161
 msgctxt "toast"
 msgid "Account blocked"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:171
+#: src/view/com/profile/ProfileMenu.tsx:174
 msgctxt "toast"
 msgid "Account followed"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:380
-#: src/view/com/profile/ProfileMenu.tsx:134
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:384
+#: src/view/com/profile/ProfileMenu.tsx:137
 msgctxt "toast"
 msgid "Account muted"
 msgstr ""
@@ -607,18 +613,18 @@ msgid "Account removed from quick access"
 msgstr ""
 
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:132
-#: src/view/com/profile/ProfileMenu.tsx:148
+#: src/view/com/profile/ProfileMenu.tsx:151
 msgctxt "toast"
 msgid "Account unblocked"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:183
+#: src/view/com/profile/ProfileMenu.tsx:186
 msgctxt "toast"
 msgid "Account unfollowed"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:370
-#: src/view/com/profile/ProfileMenu.tsx:124
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:374
+#: src/view/com/profile/ProfileMenu.tsx:127
 msgctxt "toast"
 msgid "Account unmuted"
 msgstr ""
@@ -639,11 +645,13 @@ msgstr ""
 
 #: src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx:169
 #: src/components/dialogs/MutedWords.tsx:328
+#: src/components/dialogs/StarterPackDialog.tsx:384
+#: src/components/dialogs/StarterPackDialog.tsx:390
 #: src/view/com/modals/UserAddRemoveLists.tsx:235
 msgid "Add"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:572
+#: src/screens/StarterPack/Wizard/index.tsx:608
 msgid "Add {0} more to continue"
 msgstr ""
 
@@ -686,12 +694,12 @@ msgstr ""
 
 #: src/screens/Settings/Settings.tsx:564
 #: src/screens/Settings/Settings.tsx:567
-#: src/view/shell/desktop/LeftNav.tsx:259
-#: src/view/shell/desktop/LeftNav.tsx:263
+#: src/view/shell/desktop/LeftNav.tsx:261
+#: src/view/shell/desktop/LeftNav.tsx:265
 msgid "Add another account"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:788
+#: src/view/com/composer/Composer.tsx:810
 msgid "Add another post"
 msgstr ""
 
@@ -709,7 +717,7 @@ msgstr ""
 msgid "Add emoji reaction"
 msgstr ""
 
-#. Accessibility label for button in composer to add photos or a video to a post
+#. Accessibility label for button in composer to add images, a video, or a GIF to a post
 #: src/view/com/composer/SelectMediaButton.tsx:482
 msgid "Add media to post"
 msgstr ""
@@ -727,7 +735,7 @@ msgstr ""
 msgid "Add muted words and tags"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1421
+#: src/view/com/composer/Composer.tsx:1443
 msgid "Add new post"
 msgstr ""
 
@@ -748,7 +756,7 @@ msgstr ""
 msgid "Add recommended feeds"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:510
+#: src/screens/StarterPack/Wizard/index.tsx:546
 msgid "Add some feeds to your starter pack!"
 msgstr ""
 
@@ -764,11 +772,17 @@ msgstr ""
 msgid "Add this feed to your feeds"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:305
-#: src/view/com/profile/ProfileMenu.tsx:308
+#: src/view/com/profile/ProfileMenu.tsx:317
+#: src/view/com/profile/ProfileMenu.tsx:320
 msgid "Add to lists"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:187
+#: src/view/com/profile/ProfileMenu.tsx:308
+#: src/view/com/profile/ProfileMenu.tsx:311
+msgid "Add to starter packs"
+msgstr ""
+
 #: src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx:156
 msgid "Add user to list"
 msgstr ""
@@ -778,6 +792,10 @@ msgstr ""
 msgid "Added to list"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:271
+msgid "Added to starter pack"
+msgstr ""
+
 #: src/components/ageAssurance/AgeAssuranceAppealDialog.tsx:112
 msgid "Additional details (limit 1000 characters)"
 msgstr ""
@@ -835,6 +853,8 @@ msgstr ""
 msgid "alice@example.com"
 msgstr ""
 
+#. the default tab in the interests tab bar
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:154
 #: src/view/screens/Notifications.tsx:88
 msgid "All"
 msgstr ""
@@ -846,6 +866,7 @@ msgstr ""
 #: src/screens/Search/components/SearchLanguageDropdown.tsx:64
 #: src/screens/Search/components/SearchLanguageDropdown.tsx:99
 #: src/screens/Search/components/SearchLanguageDropdown.tsx:101
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:280
 msgid "All languages"
 msgstr ""
 
@@ -881,7 +902,8 @@ msgid "Allows access to direct messages"
 msgstr ""
 
 #: src/screens/Login/ForgotPasswordForm.tsx:171
-#: src/view/com/modals/ChangePassword.tsx:182
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:235
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:241
 msgid "Already have a code?"
 msgstr ""
 
@@ -923,6 +945,7 @@ msgid "An email has been sent to {0}. It includes a confirmation code which you
 msgstr ""
 
 #: src/components/dialogs/GifSelect.tsx:264
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:362
 msgid "An error has occurred"
 msgstr ""
 
@@ -934,6 +957,10 @@ msgstr ""
 msgid "An error occurred while compressing the video."
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:176
+msgid "An error occurred while fetching suggested accounts."
+msgstr ""
+
 #: src/state/queries/explore-feed-previews.tsx:173
 msgid "An error occurred while fetching the feed."
 msgstr ""
@@ -963,6 +990,10 @@ msgstr ""
 msgid "An error occurred while uploading the video."
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:359
+msgid "An illustration of several Bluesky posts alongside repost, like, and comment icons"
+msgstr ""
+
 #: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:84
 #: src/components/verification/VerifierDialog.tsx:86
 msgid "An illustration showing that Bluesky selects trusted verifiers, and trusted verifiers in turn verify individual user accounts."
@@ -994,7 +1025,7 @@ msgstr ""
 msgid "An mockup of a iPhone showing the Bluesky app open to the profile of a verified user with a blue checkmark next to their display name."
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:185
+#: src/screens/Onboarding/StepInterests/index.tsx:194
 msgid "an unknown error occurred"
 msgstr ""
 
@@ -1007,8 +1038,8 @@ msgstr ""
 msgid "and"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:29
-#: src/screens/Onboarding/state.ts:97
+#: src/screens/Onboarding/index.tsx:43
+#: src/screens/Onboarding/state.ts:102
 msgid "Animals"
 msgstr ""
 
@@ -1130,15 +1161,12 @@ msgstr ""
 msgid "Apply Pull Request"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:639
-#: src/view/com/post-thread/PostThreadItem.tsx:954
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:643
 msgid "Archived from {0}"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:608
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:647
-#: src/view/com/post-thread/PostThreadItem.tsx:923
-#: src/view/com/post-thread/PostThreadItem.tsx:962
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:612
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:651
 msgid "Archived post"
 msgstr ""
 
@@ -1154,7 +1182,7 @@ msgstr ""
 msgid "Are you sure you want to delete this starter pack?"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:87
+#: src/screens/Profile/Header/EditProfileDialog.tsx:81
 msgid "Are you sure you want to discard your changes?"
 msgstr ""
 
@@ -1170,11 +1198,11 @@ msgstr ""
 msgid "Are you sure you want to remove this from your feeds?"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:737
+#: src/view/com/composer/Composer.tsx:759
 msgid "Are you sure you'd like to discard this draft?"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:927
+#: src/view/com/composer/Composer.tsx:949
 msgid "Are you sure you'd like to discard this post?"
 msgstr ""
 
@@ -1186,8 +1214,8 @@ msgstr ""
 msgid "Are you writing in <0>{suggestedLanguageName}</0>?"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:23
-#: src/screens/Onboarding/state.ts:98
+#: src/screens/Onboarding/index.tsx:37
+#: src/screens/Onboarding/state.ts:103
 msgid "Art"
 msgstr ""
 
@@ -1199,11 +1227,15 @@ msgstr ""
 msgid "As a small team, we cannot justify building the expensive infrastructure this requirement demands while legal challenges to this law are pending."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:491
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:493
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:497
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:499
 msgid "Assign topic for algo"
 msgstr ""
 
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:208
+msgid "At least 8 characters"
+msgstr ""
+
 #: src/screens/Settings/AppIconSettings/useAppIconSets.ts:58
 msgctxt "Name of app icon variant"
 msgid "Aurora"
@@ -1232,8 +1264,10 @@ msgstr ""
 #: src/screens/Messages/components/ChatDisabled.tsx:133
 #: src/screens/Messages/components/ChatDisabled.tsx:134
 #: src/screens/Profile/Header/Shell.tsx:158
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:271
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:280
 #: src/screens/Signup/BackNextButtons.tsx:41
-#: src/screens/StarterPack/Wizard/index.tsx:303
+#: src/screens/StarterPack/Wizard/index.tsx:323
 msgid "Back"
 msgstr ""
 
@@ -1250,6 +1284,7 @@ msgstr ""
 msgid "Before creating a post or replying, you must first verify your email."
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:71
 #: src/components/StarterPack/ProfileStarterPacks.tsx:235
 #: src/components/StarterPack/ProfileStarterPacks.tsx:245
 msgid "Before creating a starter pack, you must first verify your email."
@@ -1283,29 +1318,29 @@ msgid "Begin the age assurance process by completing the fields below."
 msgstr ""
 
 #: src/components/dialogs/BirthDateSettings.tsx:103
-#: src/screens/Settings/AccountSettings.tsx:140
+#: src/screens/Settings/AccountSettings.tsx:142
 msgid "Birthday"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:753
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:760
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:328
-#: src/view/com/profile/ProfileMenu.tsx:473
+#: src/view/com/profile/ProfileMenu.tsx:490
 msgid "Block"
 msgstr ""
 
 #: src/components/dms/ConvoMenu.tsx:247
 #: src/components/dms/ConvoMenu.tsx:250
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:638
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:640
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:645
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:647
 #: src/screens/Messages/components/RequestButtons.tsx:144
 #: src/screens/Messages/components/RequestButtons.tsx:146
-#: src/view/com/profile/ProfileMenu.tsx:384
-#: src/view/com/profile/ProfileMenu.tsx:391
+#: src/view/com/profile/ProfileMenu.tsx:396
+#: src/view/com/profile/ProfileMenu.tsx:403
 msgid "Block account"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:748
-#: src/view/com/profile/ProfileMenu.tsx:456
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:755
+#: src/view/com/profile/ProfileMenu.tsx:473
 msgid "Block Account?"
 msgstr ""
 
@@ -1355,8 +1390,8 @@ msgstr ""
 msgid "Blocked Accounts"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:750
-#: src/view/com/profile/ProfileMenu.tsx:468
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:757
+#: src/view/com/profile/ProfileMenu.tsx:485
 msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
@@ -1364,10 +1399,6 @@ msgstr ""
 msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours."
 msgstr ""
 
-#: src/view/com/post-thread/PostThread.tsx:489
-msgid "Blocked post."
-msgstr ""
-
 #: src/screens/Profile/Sections/Labels.tsx:203
 msgid "Blocking does not prevent this labeler from placing labels on your account."
 msgstr ""
@@ -1376,7 +1407,7 @@ msgstr ""
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:465
+#: src/view/com/profile/ProfileMenu.tsx:482
 msgid "Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you."
 msgstr ""
 
@@ -1389,8 +1420,7 @@ msgstr ""
 msgid "Bluesky"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:664
-#: src/view/com/post-thread/PostThreadItem.tsx:979
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:668
 msgid "Bluesky cannot confirm the authenticity of the claimed date."
 msgstr ""
 
@@ -1452,25 +1482,25 @@ msgstr ""
 msgid "Blur images and filter from feeds"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:30
-#: src/screens/Onboarding/state.ts:99
+#: src/screens/Onboarding/index.tsx:44
+#: src/screens/Onboarding/state.ts:104
 msgid "Books"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:428
+#: src/components/FeedInterstitials.tsx:431
 msgid "Browse more accounts on the Explore page"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:556
+#: src/components/FeedInterstitials.tsx:559
 msgid "Browse more feeds on the Explore page"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:537
 #: src/components/FeedInterstitials.tsx:540
+#: src/components/FeedInterstitials.tsx:543
 msgid "Browse more suggestions"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:565
+#: src/components/FeedInterstitials.tsx:568
 msgid "Browse more suggestions on the Explore page"
 msgstr ""
 
@@ -1556,22 +1586,22 @@ msgstr ""
 #: src/components/Prompt.tsx:144
 #: src/components/Prompt.tsx:146
 #: src/screens/Deactivated.tsx:158
-#: src/screens/Profile/Header/EditProfileDialog.tsx:226
-#: src/screens/Profile/Header/EditProfileDialog.tsx:234
+#: src/screens/Profile/Header/EditProfileDialog.tsx:220
+#: src/screens/Profile/Header/EditProfileDialog.tsx:228
 #: src/screens/Search/Shell.tsx:349
 #: src/screens/Settings/AppIconSettings/index.tsx:44
 #: src/screens/Settings/AppIconSettings/index.tsx:225
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:78
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:85
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:246
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:252
 #: src/screens/Settings/Settings.tsx:289
 #: src/screens/Takendown.tsx:99
 #: src/screens/Takendown.tsx:102
-#: src/view/com/composer/Composer.tsx:982
-#: src/view/com/composer/Composer.tsx:993
+#: src/view/com/composer/Composer.tsx:1004
+#: src/view/com/composer/Composer.tsx:1015
 #: src/view/com/composer/photos/EditImageDialog.web.tsx:43
 #: src/view/com/composer/photos/EditImageDialog.web.tsx:52
-#: src/view/com/modals/ChangePassword.tsx:279
-#: src/view/com/modals/ChangePassword.tsx:282
 #: src/view/com/modals/CreateOrEditList.tsx:333
 #: src/view/com/modals/CropImage.web.tsx:97
 #: src/view/shell/desktop/LeftNav.tsx:212
@@ -1648,8 +1678,13 @@ msgstr ""
 msgid "Change moderation service"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:153
-msgid "Change Password"
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:260
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:266
+msgid "Change password"
+msgstr ""
+
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:164
+msgid "Change password dialog"
 msgstr ""
 
 #: src/view/com/composer/select-language/SuggestedLanguage.tsx:98
@@ -1660,6 +1695,10 @@ msgstr ""
 msgid "Change report reason"
 msgstr ""
 
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:57
+msgid "Change your password"
+msgstr ""
+
 #: src/screens/Settings/AppIconSettings/index.tsx:216
 msgid "Changes app icon"
 msgstr ""
@@ -1676,7 +1715,7 @@ msgstr ""
 #: src/lib/hooks/useNotificationHandler.ts:99
 #: src/Navigation.tsx:548
 #: src/view/shell/bottom-bar/BottomBar.tsx:221
-#: src/view/shell/desktop/LeftNav.tsx:554
+#: src/view/shell/desktop/LeftNav.tsx:606
 #: src/view/shell/Drawer.tsx:455
 msgid "Chat"
 msgstr ""
@@ -1750,7 +1789,7 @@ msgstr ""
 msgid "Choose domain verification method"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:200
+#: src/screens/StarterPack/Wizard/index.tsx:217
 msgid "Choose Feeds"
 msgstr ""
 
@@ -1758,11 +1797,15 @@ msgstr ""
 msgid "Choose for me"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:196
+#: src/screens/StarterPack/Wizard/index.tsx:213
 msgid "Choose People"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:298
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:226
+msgid "Choose Post Languages"
+msgstr ""
+
+#: src/screens/Onboarding/StepFinished.tsx:575
 msgid "Choose the algorithms that power your custom feeds."
 msgstr ""
 
@@ -1835,7 +1878,7 @@ msgstr ""
 msgid "Click to retry failed message"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:32
+#: src/screens/Onboarding/index.tsx:46
 msgid "Climate"
 msgstr ""
 
@@ -1853,6 +1896,7 @@ msgstr ""
 #: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:178
 #: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:187
 #: src/components/dialogs/SearchablePeopleList.tsx:295
+#: src/components/dialogs/StarterPackDialog.tsx:190
 #: src/components/dms/EmojiPopup.android.tsx:58
 #: src/components/dms/ReportDialog.tsx:381
 #: src/components/dms/ReportDialog.tsx:390
@@ -1861,22 +1905,23 @@ msgstr ""
 #: src/components/NewskieDialog.tsx:146
 #: src/components/NewskieDialog.tsx:153
 #: src/components/Post/Embed/ExternalEmbed/Gif.tsx:197
-#: src/components/ProgressGuide/FollowDialog.tsx:386
-#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:123
-#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:129
+#: src/components/ProgressGuide/FollowDialog.tsx:379
+#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:118
+#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:124
 #: src/components/verification/VerificationsDialog.tsx:144
 #: src/components/verification/VerifierDialog.tsx:144
 #: src/components/WhoCanReply.tsx:202
 #: src/components/WhoCanReply.tsx:209
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:286
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:291
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:377
 #: src/view/com/feeds/MissingFeed.tsx:208
 #: src/view/com/feeds/MissingFeed.tsx:215
-#: src/view/com/modals/ChangePassword.tsx:279
-#: src/view/com/modals/ChangePassword.tsx:282
 msgid "Close"
 msgstr ""
 
-#: src/components/Dialog/index.web.tsx:111
-#: src/components/Dialog/index.web.tsx:259
+#: src/components/Dialog/index.web.tsx:118
+#: src/components/Dialog/index.web.tsx:295
 msgid "Close active dialog"
 msgstr ""
 
@@ -1893,6 +1938,9 @@ msgstr ""
 #: src/components/dialogs/GifSelect.tsx:274
 #: src/components/verification/VerificationsDialog.tsx:136
 #: src/components/verification/VerifierDialog.tsx:136
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:246
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:340
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:372
 msgid "Close dialog"
 msgstr ""
 
@@ -1931,7 +1979,7 @@ msgstr ""
 msgid "Closes password update alert"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:990
+#: src/view/com/composer/Composer.tsx:1012
 msgid "Closes post composer and discards post draft"
 msgstr ""
 
@@ -1961,13 +2009,13 @@ msgstr ""
 msgid "Color theme"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:38
-#: src/screens/Onboarding/state.ts:100
+#: src/screens/Onboarding/index.tsx:52
+#: src/screens/Onboarding/state.ts:105
 msgid "Comedy"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:24
-#: src/screens/Onboarding/state.ts:101
+#: src/screens/Onboarding/index.tsx:38
+#: src/screens/Onboarding/state.ts:106
 msgid "Comics"
 msgstr ""
 
@@ -1977,7 +2025,8 @@ msgstr ""
 msgid "Community Guidelines"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:311
+#: src/screens/Onboarding/StepFinished.tsx:473
+#: src/screens/Onboarding/StepFinished.tsx:587
 msgid "Complete onboarding and start using your account"
 msgstr ""
 
@@ -1985,19 +2034,19 @@ msgstr ""
 msgid "Complete the challenge"
 msgstr ""
 
-#: src/view/shell/desktop/LeftNav.tsx:519
+#: src/view/shell/desktop/LeftNav.tsx:571
 msgid "Compose new post"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:891
+#: src/view/com/composer/Composer.tsx:913
 msgid "Compose posts up to {0, plural, other {# characters}} in length"
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadComposePrompt.tsx:62
+#: src/screens/PostThread/components/ThreadComposePrompt.tsx:62
 msgid "Compose reply"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1815
+#: src/view/com/composer/Composer.tsx:1837
 msgid "Compressing video..."
 msgstr ""
 
@@ -2034,6 +2083,8 @@ msgstr ""
 
 #: src/components/dialogs/EmailDialog/components/TokenField.tsx:36
 #: src/screens/Login/LoginForm.tsx:274
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:186
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:190
 #: src/screens/Settings/components/DisableEmail2FADialog.tsx:144
 #: src/screens/Settings/components/DisableEmail2FADialog.tsx:150
 #: src/view/com/modals/DeleteAccount.tsx:220
@@ -2117,8 +2168,9 @@ msgstr ""
 
 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:162
 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:170
-#: src/screens/Onboarding/StepInterests/index.tsx:244
+#: src/screens/Onboarding/StepInterests/index.tsx:253
 #: src/screens/Onboarding/StepProfile/index.tsx:277
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:246
 msgid "Continue"
 msgstr ""
 
@@ -2131,12 +2183,12 @@ msgid "Continue thread"
 msgstr ""
 
 #: src/screens/PostThread/components/ThreadItemReadMoreUp.tsx:63
-#: src/view/com/post-thread/PostThreadLoadMore.tsx:60
 msgid "Continue thread..."
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:241
+#: src/screens/Onboarding/StepInterests/index.tsx:250
 #: src/screens/Onboarding/StepProfile/index.tsx:274
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:243
 #: src/screens/Signup/BackNextButtons.tsx:60
 msgid "Continue to next step"
 msgstr ""
@@ -2155,7 +2207,7 @@ msgstr ""
 msgid "Conversation deleted"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:41
+#: src/screens/Onboarding/index.tsx:55
 msgid "Cooking"
 msgstr ""
 
@@ -2194,8 +2246,8 @@ msgstr ""
 msgid "Copy App Password"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:421
-#: src/view/com/profile/ProfileMenu.tsx:424
+#: src/view/com/profile/ProfileMenu.tsx:433
+#: src/view/com/profile/ProfileMenu.tsx:436
 msgid "Copy at:// URI"
 msgstr ""
 
@@ -2210,8 +2262,8 @@ msgid "Copy code"
 msgstr ""
 
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:491
-#: src/view/com/profile/ProfileMenu.tsx:430
-#: src/view/com/profile/ProfileMenu.tsx:433
+#: src/view/com/profile/ProfileMenu.tsx:442
+#: src/view/com/profile/ProfileMenu.tsx:445
 msgid "Copy DID"
 msgstr ""
 
@@ -2239,8 +2291,8 @@ msgstr ""
 msgid "Copy link to post"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:243
-#: src/view/com/profile/ProfileMenu.tsx:254
+#: src/view/com/profile/ProfileMenu.tsx:246
+#: src/view/com/profile/ProfileMenu.tsx:257
 msgid "Copy link to profile"
 msgstr ""
 
@@ -2258,8 +2310,8 @@ msgstr ""
 msgid "Copy post at:// URI"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:448
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:450
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:452
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:454
 msgid "Copy post text"
 msgstr ""
 
@@ -2319,6 +2371,10 @@ msgstr ""
 msgid "Could not update notification settings"
 msgstr ""
 
+#. Text on button to create a new starter pack
+#. Text on button to create a new starter pack
+#: src/components/dialogs/StarterPackDialog.tsx:113
+#: src/components/dialogs/StarterPackDialog.tsx:212
 #: src/components/StarterPack/ProfileStarterPacks.tsx:300
 msgid "Create"
 msgstr ""
@@ -2337,6 +2393,8 @@ msgstr ""
 msgid "Create a starter pack for me"
 msgstr ""
 
+#: src/components/LoggedOutCTA.tsx:71
+#: src/components/LoggedOutCTA.tsx:76
 #: src/view/com/auth/SplashScreen.tsx:55
 #: src/view/com/auth/SplashScreen.web.tsx:117
 #: src/view/shell/bottom-bar/BottomBar.tsx:345
@@ -2381,6 +2439,11 @@ msgstr ""
 msgid "Create report for {0}"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:108
+#: src/components/dialogs/StarterPackDialog.tsx:207
+msgid "Create starter pack"
+msgstr ""
+
 #: src/screens/Settings/AppPasswords.tsx:174
 msgid "Created {0}"
 msgstr ""
@@ -2389,8 +2452,8 @@ msgstr ""
 msgid "Creator has been blocked"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:26
-#: src/screens/Onboarding/state.ts:102
+#: src/screens/Onboarding/index.tsx:40
+#: src/screens/Onboarding/state.ts:107
 msgid "Culture"
 msgstr ""
 
@@ -2407,7 +2470,7 @@ msgstr ""
 msgid "Customize who can interact with this post."
 msgstr ""
 
-#: src/screens/Onboarding/Layout.tsx:56
+#: src/screens/Onboarding/Layout.tsx:61
 msgid "Customizes your Bluesky experience"
 msgstr ""
 
@@ -2423,7 +2486,7 @@ msgctxt "Name of app icon variant"
 msgid "Dark"
 msgstr ""
 
-#: src/view/screens/Debug.tsx:69
+#: src/view/screens/Debug.tsx:68
 msgid "Dark mode"
 msgstr ""
 
@@ -2435,8 +2498,8 @@ msgstr ""
 msgid "Date of birth"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:159
-#: src/screens/Settings/AccountSettings.tsx:164
+#: src/screens/Settings/AccountSettings.tsx:161
+#: src/screens/Settings/AccountSettings.tsx:166
 #: src/screens/Settings/components/DeactivateAccountDialog.tsx:73
 msgid "Deactivate account"
 msgstr ""
@@ -2445,7 +2508,7 @@ msgstr ""
 msgid "Debug Moderation"
 msgstr ""
 
-#: src/view/screens/Debug.tsx:89
+#: src/view/screens/Debug.tsx:88
 msgid "Debug panel"
 msgstr ""
 
@@ -2458,7 +2521,7 @@ msgid "Default icons"
 msgstr ""
 
 #: src/components/dms/MessageContextMenu.tsx:185
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:697
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:704
 #: src/screens/Messages/components/ChatStatusInfo.tsx:55
 #: src/screens/Settings/AppPasswords.tsx:212
 #: src/screens/StarterPack/StarterPackScreen.tsx:599
@@ -2468,8 +2531,8 @@ msgstr ""
 msgid "Delete"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:169
-#: src/screens/Settings/AccountSettings.tsx:174
+#: src/screens/Settings/AccountSettings.tsx:171
+#: src/screens/Settings/AccountSettings.tsx:176
 msgid "Delete account"
 msgstr ""
 
@@ -2525,9 +2588,9 @@ msgstr ""
 msgid "Delete my account"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:678
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:680
-#: src/view/com/composer/Composer.tsx:901
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:685
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:687
+#: src/view/com/composer/Composer.tsx:923
 msgid "Delete post"
 msgstr ""
 
@@ -2544,7 +2607,7 @@ msgstr ""
 msgid "Delete this list?"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:692
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:699
 msgid "Delete this post?"
 msgstr ""
 
@@ -2564,11 +2627,7 @@ msgstr ""
 msgid "Deleted list"
 msgstr ""
 
-#: src/view/com/post-thread/PostThread.tsx:475
-msgid "Deleted post."
-msgstr ""
-
-#: src/screens/Profile/Header/EditProfileDialog.tsx:366
+#: src/screens/Profile/Header/EditProfileDialog.tsx:360
 #: src/view/com/modals/CreateOrEditList.tsx:278
 #: src/view/com/modals/CreateOrEditList.tsx:299
 msgid "Description"
@@ -2579,12 +2638,12 @@ msgstr ""
 msgid "Descriptive alt text"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:582
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:592
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:589
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:599
 msgid "Detach quote"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:728
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:735
 msgid "Detach quote post?"
 msgstr ""
 
@@ -2642,21 +2701,21 @@ msgstr ""
 msgid "Disabled"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:89
-#: src/view/com/composer/Composer.tsx:739
-#: src/view/com/composer/Composer.tsx:934
+#: src/screens/Profile/Header/EditProfileDialog.tsx:83
+#: src/view/com/composer/Composer.tsx:761
+#: src/view/com/composer/Composer.tsx:956
 msgid "Discard"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:86
+#: src/screens/Profile/Header/EditProfileDialog.tsx:80
 msgid "Discard changes?"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:736
+#: src/view/com/composer/Composer.tsx:758
 msgid "Discard draft?"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:926
+#: src/view/com/composer/Composer.tsx:948
 msgid "Discard post?"
 msgstr ""
 
@@ -2665,24 +2724,21 @@ msgstr ""
 msgid "Discourage apps from showing my account to logged-out users"
 msgstr ""
 
-#: src/screens/Search/Explore.tsx:434
-msgid "Discover Feeds"
-msgstr ""
-
 #: src/view/com/posts/FollowingEmptyState.tsx:70
 #: src/view/com/posts/FollowingEndOfFeed.tsx:71
 msgid "Discover new custom feeds"
 msgstr ""
 
+#: src/screens/Search/Explore.tsx:434
 #: src/view/screens/Feeds.tsx:730
 msgid "Discover New Feeds"
 msgstr ""
 
-#: src/components/Dialog/index.tsx:321
+#: src/components/Dialog/index.tsx:370
 msgid "Dismiss"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1739
+#: src/view/com/composer/Composer.tsx:1761
 msgid "Dismiss error"
 msgstr ""
 
@@ -2703,12 +2759,16 @@ msgstr ""
 msgid "Display larger alt text badges"
 msgstr ""
 
+#: src/screens/Profile/Header/EditProfileDialog.tsx:315
 #: src/screens/Profile/Header/EditProfileDialog.tsx:321
-#: src/screens/Profile/Header/EditProfileDialog.tsx:327
-#: src/screens/Profile/Header/EditProfileDialog.tsx:373
+#: src/screens/Profile/Header/EditProfileDialog.tsx:367
 msgid "Display name"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:347
+msgid "Ditch the trolls and clickbait. Find real people and conversations that matter to you."
+msgstr ""
+
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:392
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:394
 msgid "DNS Panel"
@@ -2758,6 +2818,7 @@ msgstr ""
 #: src/view/com/auth/server-input/index.tsx:233
 #: src/view/com/composer/labels/LabelsBtn.tsx:223
 #: src/view/com/composer/labels/LabelsBtn.tsx:230
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:345
 #: src/view/com/composer/videos/SubtitleDialog.tsx:168
 #: src/view/com/composer/videos/SubtitleDialog.tsx:178
 #: src/view/com/modals/CropImage.web.tsx:112
@@ -2780,11 +2841,11 @@ msgstr ""
 msgid "Double tap or long press the message to add a reaction"
 msgstr ""
 
-#: src/components/Dialog/index.tsx:322
+#: src/components/Dialog/index.tsx:371
 msgid "Double tap to close the dialog"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:1081
+#: src/screens/VideoFeed/index.tsx:1084
 msgid "Double tap to like"
 msgstr ""
 
@@ -2809,7 +2870,7 @@ msgstr ""
 msgid "e.g. alice"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:328
+#: src/screens/Profile/Header/EditProfileDialog.tsx:322
 msgid "e.g. Alice Lastname"
 msgstr ""
 
@@ -2841,11 +2902,11 @@ msgstr ""
 msgid "Each code works once. You'll receive more invite codes periodically."
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:143
+#: src/screens/Settings/AccountSettings.tsx:145
 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:249
 #: src/screens/StarterPack/StarterPackScreen.tsx:588
-#: src/screens/StarterPack/Wizard/index.tsx:319
-#: src/screens/StarterPack/Wizard/index.tsx:324
+#: src/screens/StarterPack/Wizard/index.tsx:339
+#: src/screens/StarterPack/Wizard/index.tsx:344
 msgid "Edit"
 msgstr ""
 
@@ -2860,7 +2921,7 @@ msgstr ""
 msgid "Edit avatar"
 msgstr ""
 
-#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:117
+#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:112
 msgid "Edit Feeds"
 msgstr ""
 
@@ -2870,8 +2931,8 @@ msgstr ""
 msgid "Edit image"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:659
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:672
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:666
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:679
 msgid "Edit interaction settings"
 msgstr ""
 
@@ -2884,8 +2945,8 @@ msgstr ""
 msgid "Edit list details"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:317
-#: src/view/com/profile/ProfileMenu.tsx:323
+#: src/view/com/profile/ProfileMenu.tsx:329
+#: src/view/com/profile/ProfileMenu.tsx:335
 msgid "Edit live status"
 msgstr ""
 
@@ -2902,7 +2963,7 @@ msgstr ""
 msgid "Edit notifications from {0}"
 msgstr ""
 
-#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:115
+#: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:110
 msgid "Edit People"
 msgstr ""
 
@@ -2911,8 +2972,8 @@ msgstr ""
 msgid "Edit post interaction settings"
 msgstr ""
 
+#: src/screens/Profile/Header/EditProfileDialog.tsx:270
 #: src/screens/Profile/Header/EditProfileDialog.tsx:276
-#: src/screens/Profile/Header/EditProfileDialog.tsx:282
 #: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:183
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:190
 msgid "Edit profile"
@@ -2939,8 +3000,8 @@ msgstr ""
 msgid "Edit your starter pack"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:31
-#: src/screens/Onboarding/state.ts:104
+#: src/screens/Onboarding/index.tsx:45
+#: src/screens/Onboarding/state.ts:109
 msgid "Education"
 msgstr ""
 
@@ -2948,7 +3009,7 @@ msgstr ""
 msgid "Either the creator of this list has blocked you or you have blocked the creator."
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:64
+#: src/screens/Settings/AccountSettings.tsx:66
 #: src/screens/Signup/StepInfo/index.tsx:197
 msgid "Email"
 msgstr ""
@@ -3080,6 +3141,7 @@ msgstr ""
 
 #: src/components/dialogs/EmailDialog/screens/Manage2FA/Disable.tsx:201
 #: src/components/dialogs/EmailDialog/screens/Verify.tsx:320
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:63
 msgid "Enter code"
 msgstr ""
 
@@ -3087,10 +3149,6 @@ msgstr ""
 msgid "Enter fullscreen"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:165
-msgid "Enter the code you received to change your password."
-msgstr ""
-
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:370
 msgid "Enter the domain you want to use"
 msgstr ""
@@ -3128,7 +3186,7 @@ msgstr ""
 msgid "Entertainment"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1824
+#: src/view/com/composer/Composer.tsx:1846
 #: src/view/com/util/error/ErrorScreen.tsx:42
 msgid "Error"
 msgstr ""
@@ -3153,7 +3211,7 @@ msgstr ""
 msgid "Error receiving captcha response."
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:183
+#: src/screens/Onboarding/StepInterests/index.tsx:192
 msgid "Error:"
 msgstr ""
 
@@ -3235,7 +3293,7 @@ msgstr ""
 msgid "Expand post text"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:966
+#: src/screens/VideoFeed/index.tsx:969
 msgid "Expands or collapses post text"
 msgstr ""
 
@@ -3244,7 +3302,6 @@ msgid "Expected uri to resolve to a record"
 msgstr ""
 
 #: src/screens/Settings/FollowingFeedPreferences.tsx:126
-#: src/screens/Settings/ThreadPreferences.tsx:271
 msgid "Experimental"
 msgstr ""
 
@@ -3276,13 +3333,13 @@ msgstr ""
 
 #: src/Navigation.tsx:750
 #: src/screens/Search/Shell.tsx:307
-#: src/view/shell/desktop/LeftNav.tsx:636
+#: src/view/shell/desktop/LeftNav.tsx:688
 #: src/view/shell/Drawer.tsx:403
 msgid "Explore"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:150
-#: src/screens/Settings/AccountSettings.tsx:154
+#: src/screens/Settings/AccountSettings.tsx:152
+#: src/screens/Settings/AccountSettings.tsx:156
 msgid "Export my data"
 msgstr ""
 
@@ -3320,6 +3377,10 @@ msgstr ""
 msgid "Failed to add emoji reaction"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:283
+msgid "Failed to add to starter pack"
+msgstr ""
+
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:587
 msgid "Failed to change handle. Please try again."
 msgstr ""
@@ -3332,8 +3393,8 @@ msgstr ""
 msgid "Failed to create conversation"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:239
-#: src/screens/StarterPack/Wizard/index.tsx:247
+#: src/screens/StarterPack/Wizard/index.tsx:262
+#: src/screens/StarterPack/Wizard/index.tsx:270
 msgid "Failed to create starter pack"
 msgstr ""
 
@@ -3359,6 +3420,10 @@ msgstr ""
 msgid "Failed to delete starter pack"
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:126
+msgid "Failed to follow all suggested accounts, please try again"
+msgstr ""
+
 #: src/screens/Messages/ChatList.tsx:270
 #: src/screens/Messages/Inbox.tsx:208
 msgid "Failed to load conversations"
@@ -3422,6 +3487,10 @@ msgstr ""
 msgid "Failed to remove emoji reaction"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:302
+msgid "Failed to remove from starter pack"
+msgstr ""
+
 #: src/components/verification/VerificationRemovePrompt.tsx:34
 msgid "Failed to remove verification"
 msgstr ""
@@ -3522,16 +3591,16 @@ msgstr ""
 msgid "Feed unavailable"
 msgstr ""
 
-#: src/view/shell/desktop/RightNav.tsx:102
-#: src/view/shell/desktop/RightNav.tsx:103
+#: src/view/shell/desktop/RightNav.tsx:106
+#: src/view/shell/desktop/RightNav.tsx:107
 #: src/view/shell/Drawer.tsx:357
 msgid "Feedback"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:269
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:285
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:270
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:288
 msgctxt "toast"
-msgid "Feedback sent!"
+msgid "Feedback sent to feed operator"
 msgstr ""
 
 #: src/Navigation.tsx:573
@@ -3540,7 +3609,7 @@ msgstr ""
 #: src/view/screens/Feeds.tsx:511
 #: src/view/screens/Profile.tsx:230
 #: src/view/screens/SavedFeeds.tsx:104
-#: src/view/shell/desktop/LeftNav.tsx:674
+#: src/view/shell/desktop/LeftNav.tsx:726
 #: src/view/shell/Drawer.tsx:519
 msgid "Feeds"
 msgstr ""
@@ -3587,7 +3656,8 @@ msgstr ""
 msgid "Filter who you receive notifications from"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:314
+#: src/screens/Onboarding/StepFinished.tsx:479
+#: src/screens/Onboarding/StepFinished.tsx:590
 msgid "Finalizing"
 msgstr ""
 
@@ -3597,9 +3667,9 @@ msgstr ""
 msgid "Find accounts to follow"
 msgstr ""
 
-#: src/components/ProgressGuide/FollowDialog.tsx:77
-#: src/components/ProgressGuide/FollowDialog.tsx:87
-#: src/components/ProgressGuide/FollowDialog.tsx:374
+#: src/components/ProgressGuide/FollowDialog.tsx:69
+#: src/components/ProgressGuide/FollowDialog.tsx:79
+#: src/components/ProgressGuide/FollowDialog.tsx:367
 msgid "Find people to follow"
 msgstr ""
 
@@ -3607,11 +3677,15 @@ msgstr ""
 msgid "Find posts, users, and feeds on Bluesky"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:201
+#: src/screens/Onboarding/StepFinished.tsx:345
+msgid "Find your people"
+msgstr ""
+
+#: src/screens/StarterPack/Wizard/index.tsx:218
 msgid "Finish"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:35
+#: src/screens/Onboarding/index.tsx:49
 msgid "Fitness"
 msgstr ""
 
@@ -3630,7 +3704,7 @@ msgctxt "Name of app icon variant"
 msgid "Flat White"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:294
+#: src/screens/Onboarding/StepFinished.tsx:571
 msgid "Flexible"
 msgstr ""
 
@@ -3638,9 +3712,9 @@ msgstr ""
 #: src/components/ProfileCard.tsx:524
 #: src/components/ProfileHoverCard/index.web.tsx:496
 #: src/components/ProfileHoverCard/index.web.tsx:507
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:131
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:252
-#: src/screens/VideoFeed/index.tsx:851
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:131
+#: src/screens/VideoFeed/index.tsx:854
 msgid "Follow"
 msgstr ""
 
@@ -3649,12 +3723,12 @@ msgctxt "action"
 msgid "Follow"
 msgstr ""
 
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:113
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:237
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:113
 msgid "Follow {0}"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:828
+#: src/screens/VideoFeed/index.tsx:831
 msgid "Follow {handle}"
 msgstr ""
 
@@ -3667,20 +3741,25 @@ msgstr ""
 msgid "Follow 7 accounts"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:284
-#: src/view/com/profile/ProfileMenu.tsx:295
+#: src/view/com/profile/ProfileMenu.tsx:287
+#: src/view/com/profile/ProfileMenu.tsx:298
 msgid "Follow account"
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:235
 #: src/screens/StarterPack/StarterPackScreen.tsx:438
 #: src/screens/StarterPack/StarterPackScreen.tsx:446
 msgid "Follow all"
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:232
+msgid "Follow all accounts"
+msgstr ""
+
 #. User is not following this account, click to follow back
 #: src/components/ProfileCard.tsx:518
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:129
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:250
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:129
 msgid "Follow back"
 msgstr ""
 
@@ -3689,6 +3768,10 @@ msgctxt "action"
 msgid "Follow back"
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:121
+msgid "Followed all accounts!"
+msgstr ""
+
 #: src/components/KnownFollowers.tsx:238
 msgid "Followed by <0>{0}</0>"
 msgstr ""
@@ -3718,9 +3801,9 @@ msgstr ""
 #: src/components/ProfileCard.tsx:511
 #: src/components/ProfileHoverCard/index.web.tsx:495
 #: src/components/ProfileHoverCard/index.web.tsx:506
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:134
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:248
-#: src/screens/VideoFeed/index.tsx:849
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:134
+#: src/screens/VideoFeed/index.tsx:852
 msgid "Following"
 msgstr ""
 
@@ -3735,7 +3818,7 @@ msgstr ""
 msgid "Following {0}"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:827
+#: src/screens/VideoFeed/index.tsx:830
 msgid "Following {handle}"
 msgstr ""
 
@@ -3765,8 +3848,8 @@ msgstr ""
 msgid "Font size"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:40
-#: src/screens/Onboarding/state.ts:105
+#: src/screens/Onboarding/index.tsx:54
+#: src/screens/Onboarding/state.ts:110
 msgid "Food"
 msgstr ""
 
@@ -3786,6 +3869,7 @@ msgstr ""
 msgid "For the best experience, we recommend using the theme font."
 msgstr ""
 
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:293
 #: src/screens/Search/modules/ExploreSuggestedAccounts.tsx:94
 msgid "For You"
 msgstr ""
@@ -3794,6 +3878,10 @@ msgstr ""
 msgid "Forever"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:354
+msgid "Forget the noise"
+msgstr ""
+
 #: src/screens/Login/index.tsx:153
 #: src/screens/Login/index.tsx:168
 msgid "Forgot Password"
@@ -3807,6 +3895,10 @@ msgstr ""
 msgid "Forgot?"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:336
+msgid "Free your feed"
+msgstr ""
+
 #: src/components/moderation/ReportDialog/utils/useReportOptions.ts:54
 #: src/lib/moderation/useReportOptions.ts:54
 msgid "Frequently Posts Unwanted Content"
@@ -3919,8 +4011,8 @@ msgstr ""
 #: src/screens/Messages/Inbox.tsx:249
 #: src/screens/Profile/ProfileFeed/index.tsx:92
 #: src/screens/VideoFeed/components/Header.tsx:163
-#: src/screens/VideoFeed/index.tsx:1142
-#: src/screens/VideoFeed/index.tsx:1146
+#: src/screens/VideoFeed/index.tsx:1145
+#: src/screens/VideoFeed/index.tsx:1149
 #: src/view/com/auth/LoggedOut.tsx:72
 #: src/view/screens/NotFound.tsx:57
 #: src/view/screens/ProfileList.tsx:1038
@@ -3941,8 +4033,8 @@ msgstr ""
 #: src/components/dms/ReportDialog.tsx:192
 #: src/components/ReportDialog/SelectReportOptionView.tsx:78
 #: src/components/ReportDialog/SubmitView.tsx:110
-#: src/screens/Onboarding/Layout.tsx:99
-#: src/screens/Onboarding/Layout.tsx:188
+#: src/screens/Onboarding/Layout.tsx:121
+#: src/screens/Onboarding/Layout.tsx:214
 #: src/screens/Signup/BackNextButtons.tsx:35
 msgid "Go back to previous step"
 msgstr ""
@@ -3955,8 +4047,8 @@ msgstr ""
 msgid "Go Home"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:318
-#: src/view/com/profile/ProfileMenu.tsx:325
+#: src/view/com/profile/ProfileMenu.tsx:330
+#: src/view/com/profile/ProfileMenu.tsx:337
 msgid "Go live"
 msgstr ""
 
@@ -3987,11 +4079,12 @@ msgid "Go to conversation with {0}"
 msgstr ""
 
 #: src/screens/Login/ForgotPasswordForm.tsx:165
-#: src/view/com/modals/ChangePassword.tsx:179
 msgid "Go to next"
 msgstr ""
 
 #: src/components/dms/ConvoMenu.tsx:227
+#: src/view/shell/desktop/LeftNav.tsx:316
+#: src/view/shell/desktop/LeftNav.tsx:322
 msgid "Go to profile"
 msgstr ""
 
@@ -4011,8 +4104,8 @@ msgstr ""
 msgid "Half way there!"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:128
-#: src/screens/Settings/AccountSettings.tsx:133
+#: src/screens/Settings/AccountSettings.tsx:130
+#: src/screens/Settings/AccountSettings.tsx:135
 msgid "Handle"
 msgstr ""
 
@@ -4057,8 +4150,8 @@ msgstr ""
 
 #: src/screens/Settings/Settings.tsx:236
 #: src/screens/Settings/Settings.tsx:240
-#: src/view/shell/desktop/RightNav.tsx:120
-#: src/view/shell/desktop/RightNav.tsx:121
+#: src/view/shell/desktop/RightNav.tsx:124
+#: src/view/shell/desktop/RightNav.tsx:125
 #: src/view/shell/Drawer.tsx:370
 msgid "Help"
 msgstr ""
@@ -4081,7 +4174,7 @@ msgstr ""
 msgid "Hidden"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:625
+#: src/screens/VideoFeed/index.tsx:628
 msgid "Hidden by your moderation settings."
 msgstr ""
 
@@ -4094,12 +4187,12 @@ msgstr ""
 #: src/components/moderation/ContentHider.tsx:203
 #: src/components/moderation/LabelPreference.tsx:141
 #: src/components/moderation/PostHider.tsx:134
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:708
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:715
 #: src/lib/moderation/useLabelBehaviorDescription.ts:15
 #: src/lib/moderation/useLabelBehaviorDescription.ts:20
 #: src/lib/moderation/useLabelBehaviorDescription.ts:25
 #: src/lib/moderation/useLabelBehaviorDescription.ts:30
-#: src/view/shell/desktop/SidebarTrendingTopics.tsx:110
+#: src/view/shell/desktop/SidebarTrendingTopics.tsx:111
 msgid "Hide"
 msgstr ""
 
@@ -4112,18 +4205,18 @@ msgstr ""
 msgid "Hide customization options"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:539
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:545
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:546
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:552
 msgid "Hide post for me"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:556
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:566
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:563
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:573
 msgid "Hide reply for everyone"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:538
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:544
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:545
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:551
 msgid "Hide reply for me"
 msgstr ""
 
@@ -4131,12 +4224,12 @@ msgstr ""
 msgid "Hide this card"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:703
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:710
 msgid "Hide this post?"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:703
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:738
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:710
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:745
 msgid "Hide this reply?"
 msgstr ""
 
@@ -4146,7 +4239,7 @@ msgid "Hide trending topics"
 msgstr ""
 
 #: src/components/interstitials/Trending.tsx:129
-#: src/view/shell/desktop/SidebarTrendingTopics.tsx:108
+#: src/view/shell/desktop/SidebarTrendingTopics.tsx:109
 msgid "Hide trending topics?"
 msgstr ""
 
@@ -4203,7 +4296,7 @@ msgstr ""
 #: src/Navigation.tsx:745
 #: src/Navigation.tsx:765
 #: src/view/shell/bottom-bar/BottomBar.tsx:178
-#: src/view/shell/desktop/LeftNav.tsx:618
+#: src/view/shell/desktop/LeftNav.tsx:670
 #: src/view/shell/Drawer.tsx:429
 msgid "Home"
 msgstr ""
@@ -4221,13 +4314,6 @@ msgstr ""
 msgid "Hot"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:201
-#: src/screens/Settings/ThreadPreferences.tsx:204
-#: src/view/com/post-thread/PostThread.tsx:680
-#: src/view/com/post-thread/PostThread.tsx:685
-msgid "Hot replies first"
-msgstr ""
-
 #: src/components/dialogs/InAppBrowserConsent.tsx:62
 #: src/components/dialogs/InAppBrowserConsent.tsx:66
 msgid "How should we open this link?"
@@ -4268,7 +4354,7 @@ msgstr ""
 msgid "If you need to update your email, <0>click here</0>."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:694
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:701
 msgid "If you remove this post, you won't be able to recover it."
 msgstr ""
 
@@ -4276,7 +4362,7 @@ msgstr ""
 msgid "If you update your email address, email 2FA will be disabled."
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:160
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:59
 msgid "If you want to change your password, we will send you a code to verify that this is your account."
 msgstr ""
 
@@ -4411,10 +4497,6 @@ msgstr ""
 msgid "Invalid handle. Please try a different one."
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadItem.tsx:348
-msgid "Invalid or unsupported post record"
-msgstr ""
-
 #: src/components/moderation/ReportDialog/index.tsx:73
 msgid "Invalid report subject"
 msgstr ""
@@ -4459,11 +4541,15 @@ msgstr ""
 msgid "It's correct"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:474
+#: src/screens/StarterPack/Wizard/index.tsx:491
+msgid "It's just <0>{0} </0>right now! Add more people to your starter pack by searching above."
+msgstr ""
+
+#: src/screens/StarterPack/Wizard/index.tsx:486
 msgid "It's just you right now! Add more people to your starter pack by searching above."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1758
+#: src/view/com/composer/Composer.tsx:1780
 msgid "Job ID: {0}"
 msgstr ""
 
@@ -4472,6 +4558,7 @@ msgstr ""
 msgid "Jobs"
 msgstr ""
 
+#: src/components/LoggedOutCTA.tsx:54
 #: src/screens/StarterPack/StarterPackLandingScreen.tsx:205
 #: src/screens/StarterPack/StarterPackLandingScreen.tsx:211
 #: src/screens/StarterPack/StarterPackScreen.tsx:466
@@ -4484,8 +4571,8 @@ msgstr ""
 msgid "Join the conversation"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:21
-#: src/screens/Onboarding/state.ts:107
+#: src/screens/Onboarding/index.tsx:35
+#: src/screens/Onboarding/state.ts:112
 msgid "Journalism"
 msgstr ""
 
@@ -4534,10 +4621,6 @@ msgstr ""
 msgid "Labels on your content"
 msgstr ""
 
-#: src/view/com/composer/select-language/SelectLangBtn.tsx:107
-msgid "Language selection"
-msgstr ""
-
 #: src/Navigation.tsx:217
 msgid "Language Settings"
 msgstr ""
@@ -4573,7 +4656,7 @@ msgstr ""
 #: src/components/verification/VerificationsDialog.tsx:165
 #: src/components/verification/VerifierDialog.tsx:132
 #: src/screens/Moderation/VerificationSettings.tsx:47
-#: src/screens/Profile/Header/EditProfileDialog.tsx:356
+#: src/screens/Profile/Header/EditProfileDialog.tsx:350
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:212
 msgid "Learn more"
 msgstr ""
@@ -4673,7 +4756,8 @@ msgstr ""
 msgid "Let's get your password reset!"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:314
+#: src/screens/Onboarding/StepFinished.tsx:481
+#: src/screens/Onboarding/StepFinished.tsx:590
 msgid "Let's go!"
 msgstr ""
 
@@ -4758,15 +4842,12 @@ msgstr ""
 msgid "Likes of your reposts notifications"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:462
-#: src/view/com/post-thread/PostThreadItem.tsx:243
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:466
 msgid "Likes on this post"
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:47
 #: src/screens/PostThread/components/HeaderDropdown.tsx:52
-#: src/view/com/post-thread/PostThread.tsx:654
-#: src/view/com/post-thread/PostThread.tsx:659
 msgid "Linear"
 msgstr ""
 
@@ -4836,7 +4917,7 @@ msgstr ""
 #: src/view/screens/Lists.tsx:65
 #: src/view/screens/Profile.tsx:224
 #: src/view/screens/Profile.tsx:232
-#: src/view/shell/desktop/LeftNav.tsx:692
+#: src/view/shell/desktop/LeftNav.tsx:744
 #: src/view/shell/Drawer.tsx:534
 msgid "Lists"
 msgstr ""
@@ -4893,11 +4974,11 @@ msgstr ""
 msgid "Logged-out visibility"
 msgstr ""
 
-#: src/view/shell/desktop/RightNav.tsx:130
+#: src/view/shell/desktop/RightNav.tsx:134
 msgid "Logo by @sawaratsuki.bsky.social"
 msgstr ""
 
-#: src/view/shell/desktop/RightNav.tsx:127
+#: src/view/shell/desktop/RightNav.tsx:131
 #: src/view/shell/Drawer.tsx:672
 msgid "Logo by <0>@sawaratsuki.bsky.social</0>"
 msgstr ""
@@ -5117,36 +5198,22 @@ msgstr ""
 msgid "Moderator has chosen to set a general warning on the content."
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadItem.tsx:728
-msgid "More"
-msgstr ""
-
-#: src/view/shell/desktop/Feeds.tsx:102
-#: src/view/shell/desktop/Feeds.tsx:105
+#: src/view/shell/desktop/Feeds.tsx:108
+#: src/view/shell/desktop/Feeds.tsx:118
 msgid "More feeds"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:220
-#: src/view/com/profile/ProfileMenu.tsx:226
+#: src/view/com/profile/ProfileMenu.tsx:223
+#: src/view/com/profile/ProfileMenu.tsx:229
 #: src/view/screens/ProfileList.tsx:750
 msgid "More options"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:228
-msgid "Most-liked first"
-msgstr ""
-
-#: src/screens/Settings/ThreadPreferences.tsx:225
-#: src/view/com/post-thread/PostThread.tsx:710
-#: src/view/com/post-thread/PostThread.tsx:715
-msgid "Most-liked replies first"
-msgstr ""
-
-#: src/screens/Onboarding/state.ts:108
+#: src/screens/Onboarding/state.ts:113
 msgid "Movies"
 msgstr ""
 
-#: src/screens/Onboarding/state.ts:109
+#: src/screens/Onboarding/state.ts:114
 msgid "Music"
 msgstr ""
 
@@ -5161,10 +5228,10 @@ msgstr ""
 msgid "Mute {tag}"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:621
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:627
-#: src/view/com/profile/ProfileMenu.tsx:363
-#: src/view/com/profile/ProfileMenu.tsx:370
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:628
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:634
+#: src/view/com/profile/ProfileMenu.tsx:375
+#: src/view/com/profile/ProfileMenu.tsx:382
 msgid "Mute account"
 msgstr ""
 
@@ -5213,13 +5280,13 @@ msgstr ""
 msgid "Mute this word until you unmute it"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:505
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:509
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:512
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:516
 msgid "Mute thread"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:519
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:521
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:526
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:528
 msgid "Mute words & tags"
 msgstr ""
 
@@ -5276,8 +5343,8 @@ msgstr ""
 msgid "Name or Description Violates Community Standards"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:22
-#: src/screens/Onboarding/state.ts:110
+#: src/screens/Onboarding/index.tsx:36
+#: src/screens/Onboarding/state.ts:115
 msgid "Nature"
 msgstr ""
 
@@ -5292,7 +5359,6 @@ msgstr ""
 
 #: src/screens/Login/ForgotPasswordForm.tsx:166
 #: src/screens/Login/LoginForm.tsx:344
-#: src/view/com/modals/ChangePassword.tsx:180
 msgid "Navigates to the next screen"
 msgstr ""
 
@@ -5309,7 +5375,7 @@ msgstr ""
 msgid "Need to report a copyright violation?"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:282
+#: src/screens/Onboarding/StepFinished.tsx:559
 msgid "Never lose access to your followers or data."
 msgstr ""
 
@@ -5380,14 +5446,11 @@ msgid "New Moderation List"
 msgstr ""
 
 #: src/screens/Login/SetNewPasswordForm.tsx:141
-#: src/view/com/modals/ChangePassword.tsx:224
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:203
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:207
 msgid "New password"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:229
-msgid "New Password"
-msgstr ""
-
 #: src/screens/Profile/ProfileFeed/index.tsx:241
 #: src/view/screens/Feeds.tsx:552
 #: src/view/screens/Notifications.tsx:167
@@ -5402,7 +5465,7 @@ msgctxt "action"
 msgid "New post"
 msgstr ""
 
-#: src/view/shell/desktop/LeftNav.tsx:527
+#: src/view/shell/desktop/LeftNav.tsx:579
 msgctxt "action"
 msgid "New Post"
 msgstr ""
@@ -5415,6 +5478,10 @@ msgstr ""
 msgid "New posts from {firstAuthorName} and {additionalAuthorsCount, plural, one {{formattedAuthorsCount} other} other {{formattedAuthorsCount} others}}"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:204
+msgid "New starter pack"
+msgstr ""
+
 #: src/components/NewskieDialog.tsx:83
 msgid "New user info dialog"
 msgstr ""
@@ -5425,17 +5492,13 @@ msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:93
 #: src/screens/PostThread/components/HeaderDropdown.tsx:98
-#: src/screens/Settings/ThreadPreferences.tsx:96
-#: src/screens/Settings/ThreadPreferences.tsx:99
-#: src/screens/Settings/ThreadPreferences.tsx:217
-#: src/screens/Settings/ThreadPreferences.tsx:220
-#: src/view/com/post-thread/PostThread.tsx:700
-#: src/view/com/post-thread/PostThread.tsx:705
+#: src/screens/Settings/ThreadPreferences.tsx:80
+#: src/screens/Settings/ThreadPreferences.tsx:83
 msgid "Newest replies first"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:20
-#: src/screens/Onboarding/state.ts:111
+#: src/screens/Onboarding/index.tsx:34
+#: src/screens/Onboarding/state.ts:116
 #: src/screens/Search/modules/ExploreTrendingTopics.tsx:238
 msgid "News"
 msgstr ""
@@ -5446,15 +5509,15 @@ msgstr ""
 #: src/screens/Login/LoginForm.tsx:350
 #: src/screens/Login/SetNewPasswordForm.tsx:182
 #: src/screens/Login/SetNewPasswordForm.tsx:188
+#: src/screens/Onboarding/StepFinished.tsx:474
+#: src/screens/Onboarding/StepFinished.tsx:483
 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:157
 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:165
 #: src/screens/Signup/BackNextButtons.tsx:67
-#: src/screens/StarterPack/Wizard/index.tsx:193
-#: src/screens/StarterPack/Wizard/index.tsx:197
-#: src/screens/StarterPack/Wizard/index.tsx:376
-#: src/screens/StarterPack/Wizard/index.tsx:383
-#: src/view/com/modals/ChangePassword.tsx:265
-#: src/view/com/modals/ChangePassword.tsx:267
+#: src/screens/StarterPack/Wizard/index.tsx:210
+#: src/screens/StarterPack/Wizard/index.tsx:214
+#: src/screens/StarterPack/Wizard/index.tsx:392
+#: src/screens/StarterPack/Wizard/index.tsx:399
 msgid "Next"
 msgstr ""
 
@@ -5467,6 +5530,10 @@ msgstr ""
 msgid "Next image"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:356
+msgid "No ads, no invasive tracking, no engagement traps. Bluesky respects your time and attention."
+msgstr ""
+
 #: src/screens/Settings/AppPasswords.tsx:108
 msgid "No app passwords yet"
 msgstr ""
@@ -5506,6 +5573,10 @@ msgstr ""
 msgid "No messages yet"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:338
+msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you."
+msgstr ""
+
 #: src/view/com/notifications/NotificationFeed.tsx:122
 msgid "No notifications yet!"
 msgstr ""
@@ -5544,7 +5615,7 @@ msgid "No result"
 msgstr ""
 
 #: src/components/dialogs/SearchablePeopleList.tsx:223
-#: src/components/ProgressGuide/FollowDialog.tsx:212
+#: src/components/ProgressGuide/FollowDialog.tsx:204
 msgid "No results"
 msgstr ""
 
@@ -5617,7 +5688,7 @@ msgstr ""
 msgid "Not Found"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:480
+#: src/view/com/profile/ProfileMenu.tsx:497
 msgid "Note about sharing"
 msgstr ""
 
@@ -5665,7 +5736,7 @@ msgstr ""
 #: src/screens/Settings/Settings.tsx:199
 #: src/view/screens/Notifications.tsx:130
 #: src/view/shell/bottom-bar/BottomBar.tsx:252
-#: src/view/shell/desktop/LeftNav.tsx:655
+#: src/view/shell/desktop/LeftNav.tsx:707
 #: src/view/shell/Drawer.tsx:482
 msgid "Notifications"
 msgstr ""
@@ -5698,6 +5769,7 @@ msgid "Off"
 msgstr ""
 
 #: src/components/dialogs/GifSelect.tsx:267
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:365
 #: src/view/com/util/ErrorBoundary.tsx:57
 msgid "Oh no!"
 msgstr ""
@@ -5715,19 +5787,14 @@ msgid "OK"
 msgstr ""
 
 #: src/screens/Login/PasswordUpdatedForm.tsx:37
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:669
-#: src/view/com/post-thread/PostThreadItem.tsx:984
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:673
 msgid "Okay"
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:83
 #: src/screens/PostThread/components/HeaderDropdown.tsx:88
-#: src/screens/Settings/ThreadPreferences.tsx:88
-#: src/screens/Settings/ThreadPreferences.tsx:91
-#: src/screens/Settings/ThreadPreferences.tsx:209
-#: src/screens/Settings/ThreadPreferences.tsx:212
-#: src/view/com/post-thread/PostThread.tsx:690
-#: src/view/com/post-thread/PostThread.tsx:695
+#: src/screens/Settings/ThreadPreferences.tsx:72
+#: src/screens/Settings/ThreadPreferences.tsx:75
 msgid "Oldest replies first"
 msgstr ""
 
@@ -5739,11 +5806,11 @@ msgstr ""
 msgid "Onboarding reset"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:354
+#: src/view/com/composer/Composer.tsx:358
 msgid "One or more GIFs is missing alt text."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:351
+#: src/view/com/composer/Composer.tsx:355
 msgid "One or more images is missing alt text."
 msgstr ""
 
@@ -5752,10 +5819,10 @@ msgid "One or more of your selected files are not supported."
 msgstr ""
 
 #: src/view/com/composer/SelectMediaButton.tsx:413
-msgid "One or more of your selected files is too large. Maximum size is 100 MB."
+msgid "One or more of your selected files are too large. Maximum size is 100 MB."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:361
+#: src/view/com/composer/Composer.tsx:365
 msgid "One or more videos is missing alt text."
 msgstr ""
 
@@ -5794,7 +5861,7 @@ msgstr ""
 msgid "Oops!"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:278
+#: src/screens/Onboarding/StepFinished.tsx:555
 msgid "Open"
 msgstr ""
 
@@ -5812,7 +5879,7 @@ msgid "Open drawer menu"
 msgstr ""
 
 #: src/screens/Messages/components/MessageInput.web.tsx:181
-#: src/view/com/composer/Composer.tsx:1406
+#: src/view/com/composer/Composer.tsx:1428
 msgid "Open emoji picker"
 msgstr ""
 
@@ -5875,10 +5942,6 @@ msgstr ""
 msgid "Open system log"
 msgstr ""
 
-#: src/view/com/util/forms/DropdownButton.tsx:167
-msgid "Opens {numItems} options"
-msgstr ""
-
 #: src/view/com/composer/labels/LabelsBtn.tsx:62
 msgid "Opens a dialog to add a content warning to your post"
 msgstr ""
@@ -5903,25 +5966,20 @@ msgstr ""
 msgid "Opens captions and alt text dialog"
 msgstr ""
 
-#: src/screens/Settings/AccountSettings.tsx:129
+#: src/screens/Settings/AccountSettings.tsx:131
 msgid "Opens change handle dialog"
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadComposePrompt.tsx:63
+#: src/screens/PostThread/components/ThreadComposePrompt.tsx:63
 msgid "Opens composer"
 msgstr ""
 
-#. Accessibility hint on web for button in composer to add images, a video, or a GIF to a post. Maximum number of images that can be selected is currently 4 but may change.
-#: src/view/com/composer/SelectMediaButton.tsx:501
+#. Accessibility hint for button in composer to add images, a video, or a GIF to a post. Maximum number of images that can be selected is currently 4 but may change.
+#: src/view/com/composer/SelectMediaButton.tsx:488
 msgid "Opens device gallery to select up to {MAX_IMAGES, plural, other {# images}}, or a single video or GIF."
 msgstr ""
 
-#. Accessibility hint on native for button in composer to add images or a video to a post. Maximum number of images that can be selected is currently 4 but may change.
-#: src/view/com/composer/SelectMediaButton.tsx:490
-msgid "Opens device gallery to select up to {MAX_IMAGES, plural, other {# images}}, or a single video."
-msgstr ""
-
-#: src/view/com/composer/Composer.tsx:1407
+#: src/view/com/composer/Composer.tsx:1429
 msgid "Opens emoji picker"
 msgstr ""
 
@@ -5959,6 +6017,10 @@ msgstr ""
 msgid "Opens password reset form"
 msgstr ""
 
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:58
+msgid "Opens post language settings"
+msgstr ""
+
 #: src/view/com/notifications/NotificationFeedItem.tsx:906
 #: src/view/com/util/UserAvatar.tsx:594
 msgid "Opens this profile"
@@ -6011,10 +6073,6 @@ msgstr ""
 msgid "Other account"
 msgstr ""
 
-#: src/view/com/composer/select-language/SelectLangBtn.tsx:93
-msgid "Other..."
-msgstr ""
-
 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:50
 msgid "Our blog post"
 msgstr ""
@@ -6037,19 +6095,19 @@ msgid "Page Not Found"
 msgstr ""
 
 #: src/screens/Login/LoginForm.tsx:228
-#: src/screens/Settings/AccountSettings.tsx:119
-#: src/screens/Settings/AccountSettings.tsx:123
+#: src/screens/Settings/AccountSettings.tsx:121
+#: src/screens/Settings/AccountSettings.tsx:125
 #: src/screens/Signup/StepInfo/index.tsx:232
 #: src/view/com/modals/DeleteAccount.tsx:239
 #: src/view/com/modals/DeleteAccount.tsx:246
 msgid "Password"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:154
-msgid "Password Changed"
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:69
+msgid "Password changed"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:99
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:124
 msgid "Password must be at least 8 characters long."
 msgstr ""
 
@@ -6098,12 +6156,12 @@ msgstr ""
 msgid "Person toggle"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:28
-#: src/screens/Onboarding/state.ts:112
+#: src/screens/Onboarding/index.tsx:42
+#: src/screens/Onboarding/state.ts:117
 msgid "Pets"
 msgstr ""
 
-#: src/screens/Onboarding/state.ts:113
+#: src/screens/Onboarding/state.ts:118
 msgid "Photography"
 msgstr ""
 
@@ -6128,8 +6186,8 @@ msgstr ""
 msgid "Pin to Home"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:416
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:423
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:420
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:427
 msgid "Pin to your profile"
 msgstr ""
 
@@ -6219,7 +6277,7 @@ msgstr ""
 msgid "Please enter a password."
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:94
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:119
 msgid "Please enter a password. It must be at least 8 characters long."
 msgstr ""
 
@@ -6250,6 +6308,10 @@ msgstr ""
 msgid "Please enter the code we sent to <0>{0}</0> below."
 msgstr ""
 
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:65
+msgid "Please enter the code you received and the new password you would like to use."
+msgstr ""
+
 #: src/components/dialogs/EmailDialog/screens/Update.tsx:247
 msgid "Please enter the security code we sent to your previous email address."
 msgstr ""
@@ -6321,8 +6383,8 @@ msgstr ""
 msgid "Please write your message below:"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:34
-#: src/screens/Onboarding/state.ts:114
+#: src/screens/Onboarding/index.tsx:48
+#: src/screens/Onboarding/state.ts:119
 #: src/screens/Search/modules/ExploreTrendingTopics.tsx:232
 msgid "Politics"
 msgstr ""
@@ -6331,18 +6393,17 @@ msgstr ""
 msgid "Porn"
 msgstr ""
 
-#: src/screens/PostThread/index.tsx:496
-#: src/view/com/post-thread/PostThread.tsx:562
+#: src/screens/PostThread/index.tsx:502
 msgctxt "description"
 msgid "Post"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1053
+#: src/view/com/composer/Composer.tsx:1075
 msgctxt "action"
 msgid "Post"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1051
+#: src/view/com/composer/Composer.tsx:1073
 msgctxt "action"
 msgid "Post All"
 msgstr ""
@@ -6351,10 +6412,6 @@ msgstr ""
 msgid "Post blocked"
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadItem.tsx:235
-msgid "Post by {0}"
-msgstr ""
-
 #: src/Navigation.tsx:263
 #: src/Navigation.tsx:270
 #: src/Navigation.tsx:277
@@ -6371,17 +6428,13 @@ msgstr ""
 msgid "Post failed to upload. Please check your Internet connection and try again."
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:132
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:133
 #: src/screens/PostThread/components/ThreadItemPost.tsx:110
 #: src/screens/PostThread/components/ThreadItemTreePost.tsx:107
-#: src/screens/VideoFeed/index.tsx:529
+#: src/screens/VideoFeed/index.tsx:532
 msgid "Post has been deleted"
 msgstr ""
 
-#: src/view/com/post-thread/PostThread.tsx:271
-msgid "Post hidden"
-msgstr ""
-
 #: src/components/moderation/ModerationDetailsDialog.tsx:107
 #: src/lib/moderation/useModerationCauseDescription.ts:106
 msgid "Post Hidden by Muted Word"
@@ -6401,18 +6454,13 @@ msgstr ""
 msgid "Post Interaction Settings"
 msgstr ""
 
-#: src/view/com/composer/select-language/SelectLangBtn.tsx:89
-msgid "Post language"
-msgstr ""
-
-#: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:77
-msgid "Post Languages"
+#. Accessibility label for button that opens dialog to choose post language settings
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:53
+msgid "Post language selection"
 msgstr ""
 
 #: src/screens/PostThread/components/ThreadError.tsx:32
 #: src/screens/PostThread/components/ThreadItemPostTombstone.tsx:25
-#: src/view/com/post-thread/PostThread.tsx:266
-#: src/view/com/post-thread/PostThread.tsx:278
 msgid "Post not found"
 msgstr ""
 
@@ -6478,15 +6526,13 @@ msgstr ""
 msgid "Primary Language"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:110
-#: src/screens/Settings/ThreadPreferences.tsx:115
-#: src/screens/Settings/ThreadPreferences.tsx:246
-#: src/screens/Settings/ThreadPreferences.tsx:251
+#: src/screens/Settings/ThreadPreferences.tsx:94
+#: src/screens/Settings/ThreadPreferences.tsx:99
 msgid "Prioritize your Follows"
 msgstr ""
 
-#: src/view/shell/desktop/RightNav.tsx:110
-#: src/view/shell/desktop/RightNav.tsx:111
+#: src/view/shell/desktop/RightNav.tsx:114
+#: src/view/shell/desktop/RightNav.tsx:115
 msgid "Privacy"
 msgstr ""
 
@@ -6517,7 +6563,7 @@ msgstr ""
 msgid "Privacy Policy"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1821
+#: src/view/com/composer/Composer.tsx:1843
 msgid "Processing video..."
 msgstr ""
 
@@ -6526,24 +6572,24 @@ msgstr ""
 msgid "Processing..."
 msgstr ""
 
-#: src/view/screens/DebugMod.tsx:927
+#: src/view/screens/DebugMod.tsx:934
 #: src/view/screens/Profile.tsx:364
 msgid "profile"
 msgstr ""
 
 #: src/view/shell/bottom-bar/BottomBar.tsx:316
-#: src/view/shell/desktop/LeftNav.tsx:710
+#: src/view/shell/desktop/LeftNav.tsx:762
 #: src/view/shell/Drawer.tsx:76
 #: src/view/shell/Drawer.tsx:559
 msgid "Profile"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:197
+#: src/screens/Profile/Header/EditProfileDialog.tsx:191
 msgctxt "toast"
 msgid "Profile updated"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:264
+#: src/screens/Onboarding/StepFinished.tsx:541
 msgid "Public"
 msgstr ""
 
@@ -6556,22 +6602,22 @@ msgid "Public, sharable lists which can be used to drive feeds."
 msgstr ""
 
 #. Accessibility label for button to publish a single post
-#: src/view/com/composer/Composer.tsx:1033
+#: src/view/com/composer/Composer.tsx:1055
 msgid "Publish post"
 msgstr ""
 
 #. Accessibility label for button to publish multiple posts in a thread
-#: src/view/com/composer/Composer.tsx:1026
+#: src/view/com/composer/Composer.tsx:1048
 msgid "Publish posts"
 msgstr ""
 
 #. Accessibility label for button to publish multiple replies in a thread
-#: src/view/com/composer/Composer.tsx:1011
+#: src/view/com/composer/Composer.tsx:1033
 msgid "Publish replies"
 msgstr ""
 
 #. Accessibility label for button to publish a single reply
-#: src/view/com/composer/Composer.tsx:1018
+#: src/view/com/composer/Composer.tsx:1040
 msgid "Publish reply"
 msgstr ""
 
@@ -6614,11 +6660,11 @@ msgstr ""
 msgid "Quote post"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:304
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:308
 msgid "Quote post was re-attached"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:303
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:307
 msgid "Quote post was successfully detached"
 msgstr ""
 
@@ -6640,24 +6686,16 @@ msgstr ""
 msgid "Quotes"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:446
-#: src/view/com/post-thread/PostThreadItem.tsx:269
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:450
 msgid "Quotes of this post"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:233
-#: src/screens/Settings/ThreadPreferences.tsx:236
-#: src/view/com/post-thread/PostThread.tsx:720
-#: src/view/com/post-thread/PostThread.tsx:725
-msgid "Random (aka \"Poster's Roulette\")"
-msgstr ""
-
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:600
 msgid "Rate limit exceeded – you've tried to change your handle too many times in a short period. Please wait a minute before trying again."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:581
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:591
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:588
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:598
 msgid "Re-attach quote"
 msgstr ""
 
@@ -6678,11 +6716,11 @@ msgstr ""
 msgid "Read blog post"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:967
+#: src/screens/VideoFeed/index.tsx:970
 msgid "Read less"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:967
+#: src/screens/VideoFeed/index.tsx:970
 msgid "Read more"
 msgstr ""
 
@@ -6730,6 +6768,10 @@ msgstr ""
 msgid "Recent Searches"
 msgstr ""
 
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:274
+msgid "Recently used"
+msgstr ""
+
 #: src/screens/Search/modules/ExploreRecommendations.tsx:54
 msgid "Recommended"
 msgstr ""
@@ -6754,6 +6796,8 @@ msgstr ""
 
 #: src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx:171
 #: src/components/dialogs/MutedWords.tsx:438
+#: src/components/dialogs/StarterPackDialog.tsx:384
+#: src/components/dialogs/StarterPackDialog.tsx:390
 #: src/components/FeedCard.tsx:343
 #: src/components/StarterPack/Wizard/WizardListCard.tsx:104
 #: src/components/StarterPack/Wizard/WizardListCard.tsx:111
@@ -6860,8 +6904,8 @@ msgstr ""
 
 #: src/components/verification/VerificationRemovePrompt.tsx:46
 #: src/components/verification/VerificationsDialog.tsx:247
-#: src/view/com/profile/ProfileMenu.tsx:336
-#: src/view/com/profile/ProfileMenu.tsx:339
+#: src/view/com/profile/ProfileMenu.tsx:348
+#: src/view/com/profile/ProfileMenu.tsx:351
 msgid "Remove verification"
 msgstr ""
 
@@ -6886,6 +6930,10 @@ msgstr ""
 msgid "Removed from saved feeds"
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:290
+msgid "Removed from starter pack"
+msgstr ""
+
 #: src/screens/Profile/components/ProfileFeedHeader.tsx:122
 #: src/view/com/posts/FeedShutdownMsg.tsx:44
 #: src/view/screens/ProfileList.tsx:392
@@ -6939,7 +6987,7 @@ msgstr ""
 msgid "Replies to this post are disabled."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1049
+#: src/view/com/composer/Composer.tsx:1071
 msgctxt "action"
 msgid "Reply"
 msgstr ""
@@ -6972,16 +7020,15 @@ msgid "Reply settings are chosen by the author of the thread"
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:69
-#: src/view/com/post-thread/PostThread.tsx:676
 msgid "Reply sorting"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:335
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:339
 msgctxt "toast"
 msgid "Reply visibility updated"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:334
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:338
 msgid "Reply was successfully hidden"
 msgstr ""
 
@@ -6991,8 +7038,8 @@ msgstr ""
 msgid "Report"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:403
-#: src/view/com/profile/ProfileMenu.tsx:406
+#: src/view/com/profile/ProfileMenu.tsx:415
+#: src/view/com/profile/ProfileMenu.tsx:418
 msgid "Report account"
 msgstr ""
 
@@ -7023,8 +7070,8 @@ msgstr ""
 msgid "Report message"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:647
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:649
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:654
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:656
 msgid "Report post"
 msgstr ""
 
@@ -7120,8 +7167,7 @@ msgstr ""
 msgid "Reposts"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:428
-#: src/view/com/post-thread/PostThreadItem.tsx:248
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:432
 msgid "Reposts of this post"
 msgstr ""
 
@@ -7135,9 +7181,9 @@ msgstr ""
 msgid "Reposts of your reposts notifications"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:253
-#: src/view/com/modals/ChangePassword.tsx:255
-msgid "Request Code"
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:224
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:230
+msgid "Request code"
 msgstr ""
 
 #: src/screens/Settings/AccessibilitySettings.tsx:58
@@ -7180,14 +7226,9 @@ msgid "Reset activity subscription nudge"
 msgstr ""
 
 #: src/screens/Login/SetNewPasswordForm.tsx:116
-#: src/view/com/modals/ChangePassword.tsx:197
 msgid "Reset code"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:204
-msgid "Reset Code"
-msgstr ""
-
 #: src/screens/Settings/Settings.tsx:467
 #: src/screens/Settings/Settings.tsx:469
 msgid "Reset onboarding state"
@@ -7218,8 +7259,10 @@ msgstr ""
 #: src/screens/Messages/ChatList.tsx:280
 #: src/screens/Messages/components/MessageListError.tsx:25
 #: src/screens/Messages/Inbox.tsx:218
-#: src/screens/Onboarding/StepInterests/index.tsx:217
-#: src/screens/Onboarding/StepInterests/index.tsx:220
+#: src/screens/Onboarding/StepInterests/index.tsx:226
+#: src/screens/Onboarding/StepInterests/index.tsx:229
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:209
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:212
 #: src/screens/PostThread/components/ThreadError.tsx:75
 #: src/screens/PostThread/components/ThreadError.tsx:81
 #: src/screens/Signup/BackNextButtons.tsx:53
@@ -7244,13 +7287,13 @@ msgstr ""
 
 #: src/screens/Profile/ProfileFeed/index.tsx:93
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:559
-#: src/screens/VideoFeed/index.tsx:1143
+#: src/screens/VideoFeed/index.tsx:1146
 #: src/view/screens/NotFound.tsx:60
 #: src/view/screens/ProfileList.tsx:1039
 msgid "Returns to previous page"
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:304
+#: src/screens/StarterPack/Wizard/index.tsx:324
 msgid "Returns to the previous step"
 msgstr ""
 
@@ -7260,8 +7303,8 @@ msgstr ""
 #: src/components/live/EditLiveDialog.tsx:216
 #: src/components/live/EditLiveDialog.tsx:223
 #: src/components/StarterPack/QrCodeDialog.tsx:192
-#: src/screens/Profile/Header/EditProfileDialog.tsx:244
-#: src/screens/Profile/Header/EditProfileDialog.tsx:258
+#: src/screens/Profile/Header/EditProfileDialog.tsx:238
+#: src/screens/Profile/Header/EditProfileDialog.tsx:252
 #: src/screens/Settings/components/ChangeHandleDialog.tsx:262
 #: src/view/com/composer/GifAltText.tsx:193
 #: src/view/com/composer/GifAltText.tsx:202
@@ -7333,11 +7376,19 @@ msgstr ""
 msgid "Say hello!"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:33
-#: src/screens/Onboarding/state.ts:115
+#: src/screens/Onboarding/index.tsx:47
+#: src/screens/Onboarding/state.ts:120
 msgid "Science"
 msgstr ""
 
+#: src/components/InterestTabs.tsx:250
+msgid "Scroll left"
+msgstr ""
+
+#: src/components/InterestTabs.tsx:284
+msgid "Scroll right"
+msgstr ""
+
 #: src/view/screens/ProfileList.tsx:996
 msgid "Scroll to top"
 msgstr ""
@@ -7356,7 +7407,7 @@ msgstr ""
 msgid "Search @{0}'s posts"
 msgstr ""
 
-#: src/components/ProgressGuide/FollowDialog.tsx:683
+#: src/components/ProgressGuide/FollowDialog.tsx:595
 msgid "Search by name or interest"
 msgstr ""
 
@@ -7364,9 +7415,14 @@ msgstr ""
 msgid "Search feeds"
 msgstr ""
 
-#: src/components/ProgressGuide/FollowDialog.tsx:524
-#: src/screens/Search/modules/ExploreSuggestedAccounts.tsx:135
-msgid "Search for \"{interestsDisplayName}\"{activeText}"
+#. Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.
+#: src/components/ProgressGuide/FollowDialog.tsx:425
+msgid "Search for \"{interestsDisplayName}"
+msgstr ""
+
+#. Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.
+#: src/components/ProgressGuide/FollowDialog.tsx:418
+msgid "Search for \"{interestsDisplayName}\" (active)"
 msgstr ""
 
 #: src/view/shell/desktop/Search.tsx:131
@@ -7377,7 +7433,7 @@ msgstr ""
 msgid "Search for \"{searchText}\""
 msgstr ""
 
-#: src/screens/StarterPack/Wizard/index.tsx:513
+#: src/screens/StarterPack/Wizard/index.tsx:549
 msgid "Search for feeds that you want to suggest to others."
 msgstr ""
 
@@ -7401,17 +7457,22 @@ msgstr ""
 msgid "Search is currently unavailable when logged out"
 msgstr ""
 
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:257
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:258
+msgid "Search languages"
+msgstr ""
+
 #: src/screens/Profile/ProfileSearch.tsx:36
 msgid "Search my posts"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:263
 #: src/view/com/profile/ProfileMenu.tsx:266
+#: src/view/com/profile/ProfileMenu.tsx:269
 msgid "Search posts"
 msgstr ""
 
 #: src/components/dialogs/SearchablePeopleList.tsx:534
-#: src/components/ProgressGuide/FollowDialog.tsx:702
+#: src/components/ProgressGuide/FollowDialog.tsx:614
 msgid "Search profiles"
 msgstr ""
 
@@ -7424,7 +7485,7 @@ msgid "Search..."
 msgstr ""
 
 #: src/components/dialogs/SearchablePeopleList.tsx:535
-#: src/components/ProgressGuide/FollowDialog.tsx:703
+#: src/components/ProgressGuide/FollowDialog.tsx:615
 msgid "Searches for profiles"
 msgstr ""
 
@@ -7452,15 +7513,12 @@ msgstr ""
 msgid "See jobs at Bluesky"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:393
+#: src/components/FeedInterstitials.tsx:394
+#: src/components/FeedInterstitials.tsx:445
 msgid "See more"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:437
-msgid "See more accounts you might like"
-msgstr ""
-
-#: src/components/FeedInterstitials.tsx:391
+#: src/components/FeedInterstitials.tsx:392
 msgid "See more suggested profiles on the Explore page"
 msgstr ""
 
@@ -7472,6 +7530,11 @@ msgstr ""
 msgid "Seek slider. Use the arrow keys to seek forwards and backwards, and space to play/pause"
 msgstr ""
 
+#. Accessibility label for a category (e.g. Art, Video Games, Sports, etc.) that shows suggested accounts for the user to follow. The tab is not currently active and can be selected.
+#: src/components/InterestTabs.tsx:332
+msgid "Select \"{interestsDisplayName}\" category"
+msgstr ""
+
 #. Accessibility label for a username suggestion in the account creation flow
 #: src/screens/Signup/StepHandle/HandleSuggestions.tsx:42
 msgid "Select {0}"
@@ -7539,6 +7602,7 @@ msgid "Select language..."
 msgstr ""
 
 #: src/screens/Settings/LanguageSettings.tsx:178
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:290
 msgid "Select languages"
 msgstr ""
 
@@ -7567,6 +7631,10 @@ msgstr ""
 msgid "Select the moderation service(s) to report to"
 msgstr ""
 
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:236
+msgid "Select up to 3 languages used in this post"
+msgstr ""
+
 #: src/components/dialogs/MutedWords.tsx:242
 msgid "Select what content this mute word should apply to."
 msgstr ""
@@ -7583,7 +7651,7 @@ msgstr ""
 msgid "Select your date of birth"
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:192
+#: src/screens/Onboarding/StepInterests/index.tsx:201
 #: src/screens/Settings/InterestsSettings.tsx:161
 msgid "Select your interests from the options below"
 msgstr ""
@@ -7600,10 +7668,6 @@ msgstr ""
 msgid "Selecting multiple media types is not supported."
 msgstr ""
 
-#: src/view/com/util/forms/DropdownButton.tsx:302
-msgid "Selects option {0} of {numItems}"
-msgstr ""
-
 #: src/components/dms/ChatEmptyPill.tsx:38
 msgid "Send a neat website!"
 msgstr ""
@@ -7685,7 +7749,7 @@ msgstr ""
 msgid "Set new password"
 msgstr ""
 
-#: src/screens/Onboarding/Layout.tsx:47
+#: src/screens/Onboarding/Layout.tsx:50
 msgid "Set up your account"
 msgstr ""
 
@@ -7695,7 +7759,7 @@ msgstr ""
 
 #: src/Navigation.tsx:212
 #: src/screens/Settings/Settings.tsx:99
-#: src/view/shell/desktop/LeftNav.tsx:728
+#: src/view/shell/desktop/LeftNav.tsx:780
 #: src/view/shell/Drawer.tsx:572
 msgid "Settings"
 msgstr ""
@@ -7778,7 +7842,7 @@ msgstr ""
 msgid "Share a fun fact!"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:485
+#: src/view/com/profile/ProfileMenu.tsx:502
 msgid "Share anyway"
 msgstr ""
 
@@ -7824,8 +7888,8 @@ msgstr ""
 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:120
 #: src/screens/StarterPack/StarterPackScreen.tsx:611
 #: src/screens/StarterPack/StarterPackScreen.tsx:619
-#: src/view/com/profile/ProfileMenu.tsx:243
-#: src/view/com/profile/ProfileMenu.tsx:256
+#: src/view/com/profile/ProfileMenu.tsx:246
+#: src/view/com/profile/ProfileMenu.tsx:259
 msgid "Share via..."
 msgstr ""
 
@@ -7850,8 +7914,8 @@ msgstr ""
 #: src/components/moderation/ScreenHider.tsx:172
 #: src/components/moderation/ScreenHider.tsx:175
 #: src/screens/List/ListHiddenScreen.tsx:190
-#: src/screens/VideoFeed/index.tsx:628
-#: src/screens/VideoFeed/index.tsx:634
+#: src/screens/VideoFeed/index.tsx:631
+#: src/screens/VideoFeed/index.tsx:637
 msgid "Show anyway"
 msgstr ""
 
@@ -7868,12 +7932,8 @@ msgstr ""
 msgid "Show customization options"
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadShowHiddenReplies.tsx:22
-msgid "Show hidden replies"
-msgstr ""
-
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:479
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:481
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:483
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:485
 msgid "Show less like this"
 msgstr ""
 
@@ -7885,8 +7945,8 @@ msgstr ""
 msgid "Show More"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:471
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:473
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:475
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:477
 msgid "Show more like this"
 msgstr ""
 
@@ -7894,11 +7954,7 @@ msgstr ""
 msgid "Show more replies"
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadShowHiddenReplies.tsx:22
-msgid "Show muted replies"
-msgstr ""
-
-#: src/screens/Settings/ThreadPreferences.tsx:143
+#: src/screens/Settings/ThreadPreferences.tsx:127
 msgid "Show post replies in a threaded tree view"
 msgstr ""
 
@@ -7913,21 +7969,15 @@ msgid "Show replies"
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:43
-#: src/view/com/post-thread/PostThread.tsx:650
 msgid "Show replies as"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:285
-msgid "Show replies as threaded"
-msgstr ""
-
-#: src/screens/Settings/ThreadPreferences.tsx:120
-#: src/screens/Settings/ThreadPreferences.tsx:260
+#: src/screens/Settings/ThreadPreferences.tsx:104
 msgid "Show replies by people you follow before all other replies"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:555
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:565
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:562
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:572
 msgid "Show reply for everyone"
 msgstr ""
 
@@ -7949,8 +7999,7 @@ msgstr ""
 msgid "Show warning and filter from feeds"
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:610
-#: src/view/com/post-thread/PostThreadItem.tsx:925
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:614
 msgid "Shows information about when this post was created"
 msgstr ""
 
@@ -8007,8 +8056,8 @@ msgstr ""
 msgid "Sign in to Bluesky or create a new account"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:457
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:459
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:461
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:463
 msgid "Sign in to view post"
 msgstr ""
 
@@ -8019,8 +8068,8 @@ msgstr ""
 #: src/screens/SignupQueued.tsx:96
 #: src/screens/Takendown.tsx:85
 #: src/view/shell/desktop/LeftNav.tsx:211
-#: src/view/shell/desktop/LeftNav.tsx:266
-#: src/view/shell/desktop/LeftNav.tsx:269
+#: src/view/shell/desktop/LeftNav.tsx:268
+#: src/view/shell/desktop/LeftNav.tsx:271
 msgid "Sign out"
 msgstr ""
 
@@ -8043,16 +8092,25 @@ msgstr ""
 msgid "Signed in as @{0}"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:386
+#: src/components/FeedInterstitials.tsx:387
 msgid "Similar accounts"
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:231
-#: src/screens/StarterPack/Wizard/index.tsx:201
+#: src/screens/Onboarding/StepFinished.tsx:380
+#: src/screens/Onboarding/StepFinished.tsx:462
+#: src/screens/Onboarding/StepInterests/index.tsx:240
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:222
+#: src/screens/StarterPack/Wizard/index.tsx:218
 msgid "Skip"
 msgstr ""
 
-#: src/screens/Onboarding/StepInterests/index.tsx:228
+#: src/screens/Onboarding/StepFinished.tsx:373
+#: src/screens/Onboarding/StepFinished.tsx:459
+msgid "Skip introduction and start using your account"
+msgstr ""
+
+#: src/screens/Onboarding/StepInterests/index.tsx:237
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:219
 msgid "Skip this flow"
 msgstr ""
 
@@ -8064,8 +8122,8 @@ msgstr ""
 msgid "Snoozes the reminder"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:37
-#: src/screens/Onboarding/state.ts:103
+#: src/screens/Onboarding/index.tsx:51
+#: src/screens/Onboarding/state.ts:108
 msgid "Software Dev"
 msgstr ""
 
@@ -8073,7 +8131,7 @@ msgstr ""
 msgid "Some of your verifications are invalid."
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:519
+#: src/components/FeedInterstitials.tsx:522
 msgid "Some other feeds you might like"
 msgstr ""
 
@@ -8131,18 +8189,15 @@ msgstr ""
 msgid "Sorry! Your session expired. Please sign in again."
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:68
-#: src/screens/Settings/ThreadPreferences.tsx:189
+#: src/screens/Settings/ThreadPreferences.tsx:52
 msgid "Sort replies"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:75
-#: src/screens/Settings/ThreadPreferences.tsx:196
+#: src/screens/Settings/ThreadPreferences.tsx:59
 msgid "Sort replies by"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:72
-#: src/screens/Settings/ThreadPreferences.tsx:193
+#: src/screens/Settings/ThreadPreferences.tsx:56
 msgid "Sort replies to the same post by:"
 msgstr ""
 
@@ -8163,8 +8218,8 @@ msgstr ""
 msgid "Spam; excessive mentions or replies"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:27
-#: src/screens/Onboarding/state.ts:116
+#: src/screens/Onboarding/index.tsx:41
+#: src/screens/Onboarding/state.ts:121
 #: src/screens/Search/modules/ExploreTrendingTopics.tsx:230
 msgid "Sports"
 msgstr ""
@@ -8193,7 +8248,7 @@ msgstr ""
 
 #: src/Navigation.tsx:578
 #: src/Navigation.tsx:583
-#: src/screens/StarterPack/Wizard/index.tsx:192
+#: src/screens/StarterPack/Wizard/index.tsx:209
 msgid "Starter Pack"
 msgstr ""
 
@@ -8305,7 +8360,9 @@ msgstr ""
 msgid "Suggested Accounts"
 msgstr ""
 
-#: src/components/FeedInterstitials.tsx:384
+#. Accounts suggested to the user for them to follow
+#: src/components/FeedInterstitials.tsx:385
+#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:137
 msgid "Suggested for you"
 msgstr ""
 
@@ -8333,7 +8390,7 @@ msgstr ""
 #: src/screens/Settings/Settings.tsx:123
 #: src/screens/Settings/Settings.tsx:137
 #: src/screens/Settings/Settings.tsx:604
-#: src/view/shell/desktop/LeftNav.tsx:245
+#: src/view/shell/desktop/LeftNav.tsx:246
 msgid "Switch account"
 msgstr ""
 
@@ -8346,7 +8403,7 @@ msgstr ""
 msgid "Switch accounts"
 msgstr ""
 
-#: src/view/shell/desktop/LeftNav.tsx:293
+#: src/view/shell/desktop/LeftNav.tsx:345
 msgid "Switch to {0}"
 msgstr ""
 
@@ -8402,8 +8459,8 @@ msgstr ""
 msgid "Teach our algorithm what you like"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:36
-#: src/screens/Onboarding/state.ts:117
+#: src/screens/Onboarding/index.tsx:50
+#: src/screens/Onboarding/state.ts:122
 msgid "Tech"
 msgstr ""
 
@@ -8411,7 +8468,7 @@ msgstr ""
 msgid "Tell a joke!"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:374
+#: src/screens/Profile/Header/EditProfileDialog.tsx:368
 msgid "Tell us a bit about yourself"
 msgstr ""
 
@@ -8419,8 +8476,8 @@ msgstr ""
 msgid "Tell us a little more"
 msgstr ""
 
-#: src/view/shell/desktop/RightNav.tsx:116
-#: src/view/shell/desktop/RightNav.tsx:117
+#: src/view/shell/desktop/RightNav.tsx:120
+#: src/view/shell/desktop/RightNav.tsx:121
 msgid "Terms"
 msgstr ""
 
@@ -8479,8 +8536,8 @@ msgstr ""
 #: src/screens/StarterPack/StarterPackScreen.tsx:111
 #: src/screens/StarterPack/StarterPackScreen.tsx:155
 #: src/screens/StarterPack/StarterPackScreen.tsx:156
-#: src/screens/StarterPack/Wizard/index.tsx:110
-#: src/screens/StarterPack/Wizard/index.tsx:120
+#: src/screens/StarterPack/Wizard/index.tsx:117
+#: src/screens/StarterPack/Wizard/index.tsx:127
 msgid "That starter pack could not be found."
 msgstr ""
 
@@ -8492,12 +8549,12 @@ msgstr ""
 msgid "That's all, folks!"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:1115
+#: src/screens/VideoFeed/index.tsx:1118
 msgid "That's everything!"
 msgstr ""
 
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:324
-#: src/view/com/profile/ProfileMenu.tsx:461
+#: src/view/com/profile/ProfileMenu.tsx:478
 msgid "The account will be able to interact with you after unblocking."
 msgstr ""
 
@@ -8559,9 +8616,8 @@ msgstr ""
 msgid "The laws in your location require you to verify you're an adult to access certain features. Tap to learn more."
 msgstr ""
 
-#: src/view/com/post-thread/PostThread.tsx:267
-#: src/view/com/post-thread/PostThread.tsx:279
-msgid "The post may have been deleted."
+#: src/components/LoggedOutCTA.tsx:63
+msgid "The open social network."
 msgstr ""
 
 #: src/view/screens/PrivacyPolicy.tsx:35
@@ -8663,20 +8719,20 @@ msgstr ""
 msgid "There was an issue updating your feeds, please check your internet connection and try again."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:361
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:374
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:384
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:365
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:378
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:388
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:90
+#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:101
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:101
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:123
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:136
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:90
-#: src/view/com/post-thread/PostThreadFollowBtn.tsx:101
-#: src/view/com/profile/ProfileMenu.tsx:128
-#: src/view/com/profile/ProfileMenu.tsx:138
-#: src/view/com/profile/ProfileMenu.tsx:152
-#: src/view/com/profile/ProfileMenu.tsx:162
-#: src/view/com/profile/ProfileMenu.tsx:175
-#: src/view/com/profile/ProfileMenu.tsx:187
+#: src/view/com/profile/ProfileMenu.tsx:131
+#: src/view/com/profile/ProfileMenu.tsx:141
+#: src/view/com/profile/ProfileMenu.tsx:155
+#: src/view/com/profile/ProfileMenu.tsx:165
+#: src/view/com/profile/ProfileMenu.tsx:178
+#: src/view/com/profile/ProfileMenu.tsx:190
 msgid "There was an issue! {0}"
 msgstr ""
 
@@ -8692,6 +8748,7 @@ msgid "There was an issue. Please check your internet connection and try again."
 msgstr ""
 
 #: src/components/dialogs/GifSelect.tsx:269
+#: src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx:367
 #: src/view/com/util/ErrorBoundary.tsx:59
 msgid "There was an unexpected issue in the application. Please let us know if this happened to you!"
 msgstr ""
@@ -8740,6 +8797,10 @@ msgstr ""
 msgid "This chat was disconnected"
 msgstr ""
 
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:144
+msgid "This confirmation code is not valid. Please try again."
+msgstr ""
+
 #: src/lib/moderation/useGlobalLabelStrings.ts:19
 msgid "This content has been hidden by the moderators."
 msgstr ""
@@ -8848,8 +8909,7 @@ msgstr ""
 msgid "This moderation service is unavailable. See below for more details. If this issue persists, contact us."
 msgstr ""
 
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:650
-#: src/view/com/post-thread/PostThreadItem.tsx:965
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:654
 msgid "This post claims to have been created on <0>{0}</0>, but was first seen by Bluesky on <1>{1}</1>."
 msgstr ""
 
@@ -8857,27 +8917,23 @@ msgstr ""
 msgid "This post has an unknown type of threadgate on it. Your app may be out of date."
 msgstr ""
 
-#: src/view/com/post-thread/PostThreadItem.tsx:171
-msgid "This post has been deleted."
-msgstr ""
-
 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:140
 msgid "This post is only visible to logged-in users."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:705
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:712
 msgid "This post will be hidden from feeds and threads. This cannot be undone."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:470
+#: src/view/com/composer/Composer.tsx:474
 msgid "This post's author has disabled quote posts."
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:482
+#: src/view/com/profile/ProfileMenu.tsx:499
 msgid "This profile is only visible to logged-in users. It won't be visible to people who aren't signed in."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:740
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:747
 msgid "This reply will be sorted into a hidden section at the bottom of your thread and will mute notifications for subsequent replies - both for yourself and others."
 msgstr ""
 
@@ -8938,14 +8994,12 @@ msgstr ""
 msgid "This will remove @{0} from the quick access list."
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:730
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:737
 msgid "This will remove your post from this quote post for all users, and replace it with a placeholder."
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:23
 #: src/screens/PostThread/components/HeaderDropdown.tsx:26
-#: src/view/com/post-thread/PostThread.tsx:634
-#: src/view/com/post-thread/PostThread.tsx:637
 msgid "Thread options"
 msgstr ""
 
@@ -8954,22 +9008,15 @@ msgstr ""
 msgid "Thread preferences"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:58
-#: src/screens/Settings/ThreadPreferences.tsx:179
+#: src/screens/Settings/ThreadPreferences.tsx:42
 msgid "Thread Preferences"
 msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:57
 #: src/screens/PostThread/components/HeaderDropdown.tsx:62
-#: src/view/com/post-thread/PostThread.tsx:664
-#: src/view/com/post-thread/PostThread.tsx:669
 msgid "Threaded"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:276
-msgid "Threaded mode"
-msgstr ""
-
 #: src/Navigation.tsx:368
 msgid "Threads Preferences"
 msgstr ""
@@ -8999,10 +9046,6 @@ msgstr ""
 msgid "Today"
 msgstr ""
 
-#: src/view/com/util/forms/DropdownButton.tsx:263
-msgid "Toggle dropdown"
-msgstr ""
-
 #: src/screens/Moderation/index.tsx:403
 msgid "Toggle to enable or disable adult content"
 msgstr ""
@@ -9019,8 +9062,8 @@ msgstr ""
 
 #: src/screens/PostThread/components/HeaderDropdown.tsx:73
 #: src/screens/PostThread/components/HeaderDropdown.tsx:78
-#: src/screens/Settings/ThreadPreferences.tsx:80
-#: src/screens/Settings/ThreadPreferences.tsx:83
+#: src/screens/Settings/ThreadPreferences.tsx:64
+#: src/screens/Settings/ThreadPreferences.tsx:67
 msgid "Top replies first"
 msgstr ""
 
@@ -9030,17 +9073,15 @@ msgstr ""
 
 #: src/components/dms/MessageContextMenu.tsx:137
 #: src/components/dms/MessageContextMenu.tsx:139
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:440
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:442
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:572
-#: src/screens/PostThread/components/ThreadItemAnchor.tsx:575
-#: src/view/com/post-thread/PostThreadItem.tsx:887
-#: src/view/com/post-thread/PostThreadItem.tsx:890
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:444
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:446
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:576
+#: src/screens/PostThread/components/ThreadItemAnchor.tsx:579
 msgid "Translate"
 msgstr ""
 
-#: src/screens/Settings/ThreadPreferences.tsx:131
-#: src/screens/Settings/ThreadPreferences.tsx:136
+#: src/screens/Settings/ThreadPreferences.tsx:115
+#: src/screens/Settings/ThreadPreferences.tsx:120
 msgid "Tree view"
 msgstr ""
 
@@ -9061,7 +9102,7 @@ msgctxt "action"
 msgid "Try again"
 msgstr ""
 
-#: src/screens/Onboarding/state.ts:118
+#: src/screens/Onboarding/state.ts:123
 msgid "TV"
 msgstr ""
 
@@ -9082,13 +9123,16 @@ msgstr ""
 msgid "Unable to connect. Please check your internet connection and try again."
 msgstr ""
 
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:95
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:140
+msgid "Unable to contact your service. Please check your internet connection and try again."
+msgstr ""
+
 #: src/screens/Login/ForgotPasswordForm.tsx:68
 #: src/screens/Login/index.tsx:79
 #: src/screens/Login/LoginForm.tsx:169
 #: src/screens/Login/SetNewPasswordForm.tsx:81
 #: src/screens/Signup/index.tsx:76
-#: src/view/com/modals/ChangePassword.tsx:71
-#: src/view/com/modals/ChangePassword.tsx:117
 msgid "Unable to contact your service. Please check your Internet connection."
 msgstr ""
 
@@ -9118,7 +9162,7 @@ msgstr ""
 #: src/components/dms/MessagesListBlockedFooter.tsx:119
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:208
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:328
-#: src/view/com/profile/ProfileMenu.tsx:473
+#: src/view/com/profile/ProfileMenu.tsx:490
 #: src/view/screens/ProfileList.tsx:723
 msgid "Unblock"
 msgstr ""
@@ -9130,13 +9174,13 @@ msgstr ""
 
 #: src/components/dms/ConvoMenu.tsx:247
 #: src/components/dms/ConvoMenu.tsx:250
-#: src/view/com/profile/ProfileMenu.tsx:383
-#: src/view/com/profile/ProfileMenu.tsx:389
+#: src/view/com/profile/ProfileMenu.tsx:395
+#: src/view/com/profile/ProfileMenu.tsx:401
 msgid "Unblock account"
 msgstr ""
 
 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:322
-#: src/view/com/profile/ProfileMenu.tsx:455
+#: src/view/com/profile/ProfileMenu.tsx:472
 msgid "Unblock Account?"
 msgstr ""
 
@@ -9163,12 +9207,12 @@ msgstr ""
 msgid "Unfollow {0}"
 msgstr ""
 
-#: src/view/com/profile/ProfileMenu.tsx:283
-#: src/view/com/profile/ProfileMenu.tsx:293
+#: src/view/com/profile/ProfileMenu.tsx:286
+#: src/view/com/profile/ProfileMenu.tsx:296
 msgid "Unfollow account"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:832
+#: src/screens/VideoFeed/index.tsx:835
 msgid "Unfollows the user"
 msgstr ""
 
@@ -9208,10 +9252,10 @@ msgstr ""
 msgid "Unmute {tag}"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:620
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:626
-#: src/view/com/profile/ProfileMenu.tsx:362
-#: src/view/com/profile/ProfileMenu.tsx:368
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:627
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:633
+#: src/view/com/profile/ProfileMenu.tsx:374
+#: src/view/com/profile/ProfileMenu.tsx:380
 msgid "Unmute account"
 msgstr ""
 
@@ -9223,8 +9267,8 @@ msgstr ""
 msgid "Unmute list"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:505
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:509
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:512
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:516
 msgid "Unmute thread"
 msgstr ""
 
@@ -9250,8 +9294,8 @@ msgstr ""
 msgid "Unpin from home"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:415
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:422
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:419
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:426
 msgid "Unpin from profile"
 msgstr ""
 
@@ -9289,7 +9333,7 @@ msgstr ""
 msgid "Unsubscribed from list"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:829
+#: src/view/com/composer/Composer.tsx:851
 msgid "Unsupported video type: {mimeType}"
 msgstr ""
 
@@ -9311,8 +9355,8 @@ msgstr ""
 
 #: src/components/dialogs/EmailDialog/screens/Update.tsx:300
 #: src/components/dialogs/EmailDialog/screens/Update.tsx:312
-#: src/screens/Settings/AccountSettings.tsx:105
-#: src/screens/Settings/AccountSettings.tsx:113
+#: src/screens/Settings/AccountSettings.tsx:107
+#: src/screens/Settings/AccountSettings.tsx:115
 msgid "Update email"
 msgstr ""
 
@@ -9325,12 +9369,12 @@ msgstr ""
 msgid "Update your email"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:308
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:312
 msgctxt "toast"
 msgid "Updating quote attachment failed"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:339
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:343
 msgctxt "toast"
 msgid "Updating reply visibility failed"
 msgstr ""
@@ -9375,7 +9419,7 @@ msgstr ""
 msgid "Uploading link thumbnail..."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1818
+#: src/view/com/composer/Composer.tsx:1840
 msgid "Uploading video..."
 msgstr ""
 
@@ -9530,8 +9574,8 @@ msgstr ""
 
 #: src/components/verification/VerificationCreatePrompt.tsx:84
 #: src/components/verification/VerificationCreatePrompt.tsx:86
-#: src/view/com/profile/ProfileMenu.tsx:346
-#: src/view/com/profile/ProfileMenu.tsx:349
+#: src/view/com/profile/ProfileMenu.tsx:358
+#: src/view/com/profile/ProfileMenu.tsx:361
 msgid "Verify account"
 msgstr ""
 
@@ -9580,8 +9624,8 @@ msgid "Verify your age"
 msgstr ""
 
 #: src/components/dialogs/EmailDialog/screens/Verify.tsx:211
-#: src/screens/Settings/AccountSettings.tsx:79
-#: src/screens/Settings/AccountSettings.tsx:99
+#: src/screens/Settings/AccountSettings.tsx:81
+#: src/screens/Settings/AccountSettings.tsx:101
 msgid "Verify your email"
 msgstr ""
 
@@ -9615,17 +9659,17 @@ msgstr ""
 msgid "Video from {0}: {text}"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:39
-#: src/screens/Onboarding/state.ts:106
+#: src/screens/Onboarding/index.tsx:53
+#: src/screens/Onboarding/state.ts:111
 #: src/screens/Search/modules/ExploreTrendingTopics.tsx:234
 msgid "Video Games"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:1073
+#: src/screens/VideoFeed/index.tsx:1076
 msgid "Video is paused"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:1073
+#: src/screens/VideoFeed/index.tsx:1076
 msgid "Video is playing"
 msgstr ""
 
@@ -9637,7 +9681,7 @@ msgstr ""
 msgid "Video settings"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:1828
+#: src/view/com/composer/Composer.tsx:1850
 msgid "Video uploaded"
 msgstr ""
 
@@ -9653,6 +9697,11 @@ msgstr ""
 msgid "Videos must be less than 3 minutes long."
 msgstr ""
 
+#: src/view/com/composer/Composer.tsx:545
+msgctxt "Action to view the post the user just created"
+msgid "View"
+msgstr ""
+
 #: src/screens/Profile/Header/Shell.tsx:229
 msgid "View {0}'s avatar"
 msgstr ""
@@ -9660,7 +9709,7 @@ msgstr ""
 #: src/components/ProfileCard.tsx:124
 #: src/screens/Profile/components/ProfileFeedHeader.tsx:454
 #: src/screens/Search/components/SearchProfileCard.tsx:36
-#: src/screens/VideoFeed/index.tsx:791
+#: src/screens/VideoFeed/index.tsx:794
 #: src/view/com/notifications/NotificationFeedItem.tsx:599
 msgid "View {0}'s profile"
 msgstr ""
@@ -9682,8 +9731,8 @@ msgid "View debug entry"
 msgstr ""
 
 #: src/components/ReportDialog/SelectReportOptionView.tsx:137
-#: src/screens/VideoFeed/index.tsx:656
-#: src/screens/VideoFeed/index.tsx:674
+#: src/screens/VideoFeed/index.tsx:659
+#: src/screens/VideoFeed/index.tsx:677
 msgid "View details"
 msgstr ""
 
@@ -9710,6 +9759,10 @@ msgstr ""
 msgid "View more trending videos"
 msgstr ""
 
+#: src/view/com/composer/Composer.tsx:540
+msgid "View post"
+msgstr ""
+
 #: src/components/ProfileHoverCard/index.web.tsx:466
 #: src/components/ProfileHoverCard/index.web.tsx:486
 #: src/components/ProfileHoverCard/index.web.tsx:513
@@ -9837,7 +9890,7 @@ msgstr ""
 msgid "We have sent another verification email to <0>{0}</0>."
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:256
+#: src/screens/Onboarding/StepFinished.tsx:533
 msgid "We hope you have a wonderful time. Remember, Bluesky is:"
 msgstr ""
 
@@ -9902,7 +9955,7 @@ msgid "We're having issues initializing the age assurance process for your accou
 msgstr ""
 
 #: src/components/dialogs/SearchablePeopleList.tsx:107
-#: src/components/ProgressGuide/FollowDialog.tsx:172
+#: src/components/ProgressGuide/FollowDialog.tsx:164
 msgid "We're having network issues, try again"
 msgstr ""
 
@@ -9926,7 +9979,7 @@ msgstr ""
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:467
+#: src/view/com/composer/Composer.tsx:471
 msgid "We're sorry! The post you are replying to has been deleted."
 msgstr ""
 
@@ -9977,7 +10030,7 @@ msgstr ""
 
 #: src/view/com/auth/SplashScreen.tsx:38
 #: src/view/com/auth/SplashScreen.web.tsx:99
-#: src/view/com/composer/Composer.tsx:789
+#: src/view/com/composer/Composer.tsx:811
 msgid "What's up?"
 msgstr ""
 
@@ -9985,10 +10038,6 @@ msgstr ""
 msgid "When you tap on a check, you’ll see which organizations have granted verification."
 msgstr ""
 
-#: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:80
-msgid "Which languages are used in this post?"
-msgstr ""
-
 #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:79
 msgid "Which languages would you like to see in your algorithmic feeds?"
 msgstr ""
@@ -10059,17 +10108,17 @@ msgstr ""
 msgid "Write a message"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:889
+#: src/view/com/composer/Composer.tsx:911
 msgid "Write post"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:787
-#: src/view/com/post-thread/PostThreadComposePrompt.tsx:90
+#: src/screens/PostThread/components/ThreadComposePrompt.tsx:90
+#: src/view/com/composer/Composer.tsx:809
 msgid "Write your reply"
 msgstr ""
 
-#: src/screens/Onboarding/index.tsx:25
-#: src/screens/Onboarding/state.ts:119
+#: src/screens/Onboarding/index.tsx:39
+#: src/screens/Onboarding/state.ts:124
 msgid "Writers"
 msgstr ""
 
@@ -10095,11 +10144,11 @@ msgstr ""
 msgid "Yes, delete this starter pack"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:733
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:740
 msgid "Yes, detach"
 msgstr ""
 
-#: src/components/PostControls/PostMenu/PostMenuItems.tsx:743
+#: src/components/PostControls/PostMenu/PostMenuItems.tsx:750
 msgid "Yes, hide"
 msgstr ""
 
@@ -10164,7 +10213,7 @@ msgstr ""
 msgid "You are verified"
 msgstr ""
 
-#: src/screens/Profile/Header/EditProfileDialog.tsx:352
+#: src/screens/Profile/Header/EditProfileDialog.tsx:346
 msgid "You are verified. You will lose your verification status if you change your display name. <0>Learn more.</0>"
 msgstr ""
 
@@ -10225,7 +10274,7 @@ msgstr ""
 
 #: src/components/interstitials/Trending.tsx:130
 #: src/components/interstitials/TrendingVideos.tsx:137
-#: src/view/shell/desktop/SidebarTrendingTopics.tsx:109
+#: src/view/shell/desktop/SidebarTrendingTopics.tsx:110
 msgid "You can update this later from your settings."
 msgstr ""
 
@@ -10253,10 +10302,6 @@ msgstr ""
 msgid "You don't have any saved feeds."
 msgstr ""
 
-#: src/view/com/post-thread/PostThread.tsx:273
-msgid "You have blocked the author or you have been blocked by the author."
-msgstr ""
-
 #: src/components/dms/MessagesListBlockedFooter.tsx:66
 msgid "You have blocked this user"
 msgstr ""
@@ -10273,8 +10318,7 @@ msgstr ""
 
 #: src/screens/Login/SetNewPasswordForm.tsx:49
 #: src/screens/Login/SetNewPasswordForm.tsx:95
-#: src/view/com/modals/ChangePassword.tsx:87
-#: src/view/com/modals/ChangePassword.tsx:133
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:112
 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX."
 msgstr ""
 
@@ -10308,6 +10352,10 @@ msgstr ""
 msgid "You have no lists."
 msgstr ""
 
+#: src/components/dialogs/StarterPackDialog.tsx:102
+msgid "You have no starter packs."
+msgstr ""
+
 #: src/view/screens/ModerationBlockedAccounts.tsx:164
 msgid "You have not blocked any accounts yet. To block an account, go to their profile and select \"Block account\" from the menu on their account."
 msgstr ""
@@ -10475,7 +10523,7 @@ msgstr ""
 msgid "You're in line"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:253
+#: src/screens/Onboarding/StepFinished.tsx:530
 msgid "You're ready to go!"
 msgstr ""
 
@@ -10517,7 +10565,7 @@ msgstr ""
 msgid "You've reached your daily limit for video uploads (too many videos)"
 msgstr ""
 
-#: src/screens/VideoFeed/index.tsx:1124
+#: src/screens/VideoFeed/index.tsx:1127
 msgid "You've run out of videos to watch. Maybe it's a good time to take a break?"
 msgstr ""
 
@@ -10580,9 +10628,9 @@ msgid "Your email"
 msgstr ""
 
 #: src/screens/Login/ForgotPasswordForm.tsx:51
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:81
 #: src/screens/Signup/state.ts:271
 #: src/screens/Signup/StepInfo/index.tsx:101
-#: src/view/com/modals/ChangePassword.tsx:55
 msgid "Your email appears to be invalid."
 msgstr ""
 
@@ -10627,23 +10675,23 @@ msgstr ""
 msgid "Your muted words"
 msgstr ""
 
-#: src/view/com/modals/ChangePassword.tsx:169
-msgid "Your password has been changed successfully!"
+#: src/screens/Settings/components/ChangePasswordDialog.tsx:71
+msgid "Your password has been changed successfully! Please use your new password when you sign in to Bluesky from now on."
 msgstr ""
 
 #: src/screens/Signup/StepInfo/index.tsx:130
 msgid "Your password must be at least 8 characters long."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:529
-msgid "Your post has been published"
+#: src/view/com/composer/Composer.tsx:536
+msgid "Your post was sent"
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:526
-msgid "Your posts have been published"
+#: src/view/com/composer/Composer.tsx:533
+msgid "Your posts were sent"
 msgstr ""
 
-#: src/screens/Onboarding/StepFinished.tsx:268
+#: src/screens/Onboarding/StepFinished.tsx:545
 msgid "Your posts, likes, and blocks are public. Mutes are private."
 msgstr ""
 
@@ -10651,12 +10699,20 @@ msgstr ""
 msgid "Your preferred language"
 msgstr ""
 
+#: src/screens/Onboarding/StepFinished.tsx:422
+msgid "Your profile picture"
+msgstr ""
+
+#: src/screens/Onboarding/StepFinished.tsx:350
+msgid "Your profile picture surrounded by concentric circles of other users' profile pictures"
+msgstr ""
+
 #: src/screens/Settings/components/DeactivateAccountDialog.tsx:75
 msgid "Your profile, posts, feeds, and lists will no longer be visible to other Bluesky users. You can reactivate your account at any time by logging in."
 msgstr ""
 
-#: src/view/com/composer/Composer.tsx:528
-msgid "Your reply has been published"
+#: src/view/com/composer/Composer.tsx:535
+msgid "Your reply was sent"
 msgstr ""
 
 #: src/components/moderation/ReportDialog/index.tsx:394
diff --git a/src/logger/metrics.ts b/src/logger/metrics.ts
index e51905f84..1cb4eb9d3 100644
--- a/src/logger/metrics.ts
+++ b/src/logger/metrics.ts
@@ -90,6 +90,13 @@ export type MetricEvents = {
     selectedInterests: string[]
     selectedInterestsLength: number
   }
+  'onboarding:suggestedAccounts:tabPressed': {
+    tab: string
+  }
+  'onboarding:suggestedAccounts:followAllPressed': {
+    tab: string
+    numAccounts: number
+  }
   'onboarding:suggestedAccounts:nextPressed': {
     selectedAccountsLength: number
     skipped: boolean
@@ -118,6 +125,9 @@ export type MetricEvents = {
   'onboarding:finished:avatarResult': {
     avatarResult: 'default' | 'created' | 'uploaded'
   }
+  'onboarding:valueProp:stepOne:nextPressed': {}
+  'onboarding:valueProp:stepTwo:nextPressed': {}
+  'onboarding:valueProp:skipPressed': {}
   'home:feedDisplayed': {
     feedUrl: string
     feedType: string
@@ -242,6 +252,7 @@ export type MetricEvents = {
       | 'PostOnboardingFindFollows'
       | 'ImmersiveVideo'
       | 'ExploreSuggestedAccounts'
+      | 'OnboardingSuggestedAccounts'
   }
   'suggestedUser:follow': {
     logContext:
@@ -249,12 +260,17 @@ export type MetricEvents = {
       | 'InterstitialDiscover'
       | 'InterstitialProfile'
       | 'Profile'
+      | 'Onboarding'
     location: 'Card' | 'Profile'
     recId?: number
     position: number
   }
   'suggestedUser:press': {
-    logContext: 'Explore' | 'InterstitialDiscover' | 'InterstitialProfile'
+    logContext:
+      | 'Explore'
+      | 'InterstitialDiscover'
+      | 'InterstitialProfile'
+      | 'Onboarding'
     recId?: number
     position: number
   }
@@ -280,6 +296,7 @@ export type MetricEvents = {
       | 'PostOnboardingFindFollows'
       | 'ImmersiveVideo'
       | 'ExploreSuggestedAccounts'
+      | 'OnboardingSuggestedAccounts'
   }
   'chat:create': {
     logContext: 'ProfileHeader' | 'NewChatDialog' | 'SendViaChatDialog'
diff --git a/src/screens/Login/ForgotPasswordForm.tsx b/src/screens/Login/ForgotPasswordForm.tsx
index e8582f46f..d3b5a4f10 100644
--- a/src/screens/Login/ForgotPasswordForm.tsx
+++ b/src/screens/Login/ForgotPasswordForm.tsx
@@ -1,7 +1,6 @@
 import React, {useState} from 'react'
 import {ActivityIndicator, Keyboard, View} from 'react-native'
-import {ComAtprotoServerDescribeServer} from '@atproto/api'
-import {BskyAgent} from '@atproto/api'
+import {type ComAtprotoServerDescribeServer} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import * as EmailValidator from 'email-validator'
@@ -9,6 +8,7 @@ import * as EmailValidator from 'email-validator'
 import {isNetworkError} from '#/lib/strings/errors'
 import {cleanError} from '#/lib/strings/errors'
 import {logger} from '#/logger'
+import {Agent} from '#/state/session/agent'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
 import {FormError} from '#/components/forms/FormError'
@@ -55,7 +55,7 @@ export const ForgotPasswordForm = ({
     setIsProcessing(true)
 
     try {
-      const agent = new BskyAgent({service: serviceUrl})
+      const agent = new Agent(null, {service: serviceUrl})
       await agent.com.atproto.server.requestPasswordReset({email})
       onEmailSent()
     } catch (e: any) {
diff --git a/src/screens/Login/SetNewPasswordForm.tsx b/src/screens/Login/SetNewPasswordForm.tsx
index d2fa0f9c1..be72b558b 100644
--- a/src/screens/Login/SetNewPasswordForm.tsx
+++ b/src/screens/Login/SetNewPasswordForm.tsx
@@ -1,6 +1,5 @@
 import {useState} from 'react'
 import {ActivityIndicator, View} from 'react-native'
-import {BskyAgent} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -9,6 +8,7 @@ import {isNetworkError} from '#/lib/strings/errors'
 import {cleanError} from '#/lib/strings/errors'
 import {checkAndFormatResetCode} from '#/lib/strings/password'
 import {logger} from '#/logger'
+import {Agent} from '#/state/session/agent'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
 import {FormError} from '#/components/forms/FormError'
@@ -63,7 +63,7 @@ export const SetNewPasswordForm = ({
     setIsProcessing(true)
 
     try {
-      const agent = new BskyAgent({service: serviceUrl})
+      const agent = new Agent(null, {service: serviceUrl})
       await agent.com.atproto.server.resetPassword({
         token: formattedCode,
         password,
diff --git a/src/screens/Onboarding/Layout.tsx b/src/screens/Onboarding/Layout.tsx
index 16c37358f..6394d9c96 100644
--- a/src/screens/Onboarding/Layout.tsx
+++ b/src/screens/Onboarding/Layout.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {useState} from 'react'
 import {ScrollView, View} from 'react-native'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {msg} from '@lingui/macro'
@@ -11,20 +11,23 @@ import {
   atoms as a,
   flatten,
   native,
-  TextStyleProp,
+  type TextStyleProp,
+  tokens,
   useBreakpoints,
   useTheme,
   web,
 } from '#/alf'
 import {leading} from '#/alf/typography'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
-import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
+import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow'
+import {HEADER_SLOT_SIZE} from '#/components/Layout'
 import {createPortalGroup} from '#/components/Portal'
 import {P, Text} from '#/components/Typography'
 
-const COL_WIDTH = 420
+const ONBOARDING_COL_WIDTH = 420
 
 export const OnboardingControls = createPortalGroup()
+export const OnboardingHeaderSlot = createPortalGroup()
 
 export function Layout({children}: React.PropsWithChildren<{}>) {
   const {_} = useLingui()
@@ -46,6 +49,8 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
   const paddingTop = gtMobile ? a.py_5xl : a.py_lg
   const dialogLabel = _(msg`Set up your account`)
 
+  const [footerHeight, setFooterHeight] = useState(0)
+
   return (
     <View
       aria-modal
@@ -62,45 +67,67 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
         t.atoms.bg,
       ]}>
       {__DEV__ && (
-        <View style={[a.absolute, a.p_xl, a.z_10, {right: 0, top: insets.top}]}>
-          <Button
-            variant="ghost"
-            color="negative"
-            size="small"
-            onPress={() => onboardDispatch({type: 'skip'})}
-            // DEV ONLY
-            label="Clear onboarding state">
-            <ButtonText>Clear</ButtonText>
-          </Button>
-        </View>
+        <Button
+          variant="ghost"
+          color="negative"
+          size="tiny"
+          onPress={() => onboardDispatch({type: 'skip'})}
+          // DEV ONLY
+          label="Clear onboarding state"
+          style={[
+            a.absolute,
+            a.z_10,
+            {
+              left: '50%',
+              top: insets.top + 2,
+              transform: [{translateX: '-50%'}],
+            },
+          ]}>
+          <ButtonText>[DEV] Clear</ButtonText>
+        </Button>
       )}
 
-      {!gtMobile && state.hasPrev && (
+      {!gtMobile && (
         <View
+          pointerEvents="box-none"
           style={[
             web(a.fixed),
             native(a.absolute),
+            a.left_0,
+            a.right_0,
             a.flex_row,
             a.w_full,
             a.justify_center,
             a.z_20,
             a.px_xl,
-            {
-              top: paddingTop.paddingTop + insets.top - 1,
-            },
+            {top: paddingTop.paddingTop + insets.top - 1},
           ]}>
-          <View style={[a.w_full, a.align_start, {maxWidth: COL_WIDTH}]}>
-            <Button
-              key={state.activeStep} // remove focus state on nav
-              variant="ghost"
-              color="secondary"
-              size="small"
-              shape="round"
-              label={_(msg`Go back to previous step`)}
-              style={[a.absolute]}
-              onPress={() => dispatch({type: 'prev'})}>
-              <ButtonIcon icon={ChevronLeft} />
-            </Button>
+          <View
+            pointerEvents="box-none"
+            style={[
+              a.w_full,
+              a.align_start,
+              a.flex_row,
+              a.justify_between,
+              {maxWidth: ONBOARDING_COL_WIDTH},
+            ]}>
+            {state.hasPrev ? (
+              <Button
+                key={state.activeStep} // remove focus state on nav
+                color="secondary"
+                variant="ghost"
+                shape="square"
+                size="small"
+                label={_(msg`Go back to previous step`)}
+                onPress={() => dispatch({type: 'prev'})}
+                style={[a.bg_transparent]}>
+                <ButtonIcon icon={ArrowLeft} size="lg" />
+              </Button>
+            ) : (
+              <View />
+            )}
+
+            <OnboardingHeaderSlot.Outlet />
           </View>
         </View>
       )}
@@ -109,22 +136,24 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
         ref={scrollview}
         style={[a.h_full, a.w_full, {paddingTop: insets.top}]}
         contentContainerStyle={{borderWidth: 0}}
-        // @ts-ignore web only --prf
+        scrollIndicatorInsets={{bottom: footerHeight - insets.bottom}}
+        // @ts-expect-error web only --prf
         dataSet={{'stable-gutters': 1}}>
         <View
           style={[a.flex_row, a.justify_center, gtMobile ? a.px_5xl : a.px_xl]}>
-          <View style={[a.flex_1, {maxWidth: COL_WIDTH}]}>
+          <View style={[a.flex_1, {maxWidth: ONBOARDING_COL_WIDTH}]}>
             <View style={[a.w_full, a.align_center, paddingTop]}>
               <View
                 style={[
                   a.flex_row,
                   a.gap_sm,
                   a.w_full,
-                  {paddingTop: 17, maxWidth: '60%'},
+                  a.align_center,
+                  {height: HEADER_SLOT_SIZE, maxWidth: '60%'},
                 ]}>
                 {Array(state.totalSteps)
                   .fill(0)
-                  .map((_, i) => (
+                  .map((__, i) => (
                     <View
                       key={i}
                       style={[
@@ -144,19 +173,16 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
               </View>
             </View>
 
-            <View
-              style={[a.w_full, a.mb_5xl, {paddingTop: gtMobile ? 20 : 40}]}>
-              {children}
-            </View>
+            <View style={[a.w_full, a.mb_5xl, a.pt_md]}>{children}</View>
 
-            <View style={{height: 400}} />
+            <View style={{height: 100 + footerHeight}} />
           </View>
         </View>
       </ScrollView>
 
       <View
+        onLayout={evt => setFooterHeight(evt.nativeEvent.layout.height)}
         style={[
-          // @ts-ignore web only -prf
           isWeb ? a.fixed : a.absolute,
           {bottom: 0, left: 0, right: 0},
           t.atoms.bg,
@@ -167,30 +193,30 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
           isWeb
             ? a.py_2xl
             : {
-                paddingTop: a.pt_lg.paddingTop,
-                paddingBottom: insets.bottom + 10,
+                paddingTop: tokens.space.md,
+                paddingBottom: insets.bottom + tokens.space.md,
               },
         ]}>
         <View
           style={[
             a.w_full,
-            {maxWidth: COL_WIDTH},
-            gtMobile && [a.flex_row, a.justify_between],
+            {maxWidth: ONBOARDING_COL_WIDTH},
+            gtMobile && [a.flex_row, a.justify_between, a.align_center],
           ]}>
           {gtMobile &&
             (state.hasPrev ? (
               <Button
                 key={state.activeStep} // remove focus state on nav
-                variant="solid"
                 color="secondary"
-                size="large"
-                shape="round"
+                variant="ghost"
+                shape="square"
+                size="small"
                 label={_(msg`Go back to previous step`)}
                 onPress={() => dispatch({type: 'prev'})}>
-                <ButtonIcon icon={ChevronLeft} />
+                <ButtonIcon icon={ArrowLeft} size="lg" />
               </Button>
             ) : (
-              <View style={{height: 54}} />
+              <View style={{height: 33}} />
             ))}
           <OnboardingControls.Outlet />
         </View>
diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx
index 54d282a5e..f8040f3a5 100644
--- a/src/screens/Onboarding/StepFinished.tsx
+++ b/src/screens/Onboarding/StepFinished.tsx
@@ -1,5 +1,12 @@
-import React from 'react'
+import {useCallback, useContext, useState} from 'react'
 import {View} from 'react-native'
+import Animated, {
+  Easing,
+  LayoutAnimationConfig,
+  SlideInRight,
+  SlideOutLeft,
+} from 'react-native-reanimated'
+import {Image} from 'expo-image'
 import {
   type AppBskyActorDefs,
   type AppBskyActorProfile,
@@ -22,6 +29,7 @@ import {
 import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
 import {logEvent, useGate} from '#/lib/statsig/statsig'
 import {logger} from '#/logger'
+import {isNative} from '#/platform/detection'
 import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs'
 import {getAllListMembers} from '#/state/queries/list-members'
 import {preferencesQueryKey} from '#/state/queries/preferences'
@@ -36,13 +44,22 @@ import {
 import {
   DescriptionText,
   OnboardingControls,
+  OnboardingHeaderSlot,
   TitleText,
 } from '#/screens/Onboarding/Layout'
-import {Context} from '#/screens/Onboarding/state'
+import {Context, type OnboardingState} from '#/screens/Onboarding/state'
 import {bulkWriteFollows} from '#/screens/Onboarding/util'
-import {atoms as a, useTheme} from '#/alf'
+import {
+  atoms as a,
+  native,
+  platform,
+  tokens,
+  useBreakpoints,
+  useTheme,
+} from '#/alf'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import {IconCircle} from '#/components/IconCircle'
+import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow'
 import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
 import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
 import {News2_Stroke2_Corner0_Rounded as News} from '#/components/icons/News2'
@@ -53,10 +70,9 @@ import * as bsky from '#/types/bsky'
 
 export function StepFinished() {
   const {_} = useLingui()
-  const t = useTheme()
-  const {state, dispatch} = React.useContext(Context)
+  const {state, dispatch} = useContext(Context)
   const onboardDispatch = useOnboardingDispatch()
-  const [saving, setSaving] = React.useState(false)
+  const [saving, setSaving] = useState(false)
   const queryClient = useQueryClient()
   const agent = useAgent()
   const requestNotificationsPermission = useRequestNotificationsPermission()
@@ -66,7 +82,7 @@ export function StepFinished() {
   const {startProgressGuide} = useProgressGuideControls()
   const gate = useGate()
 
-  const finishOnboarding = React.useCallback(async () => {
+  const finishOnboarding = useCallback(async () => {
     setSaving(true)
 
     let starterPack: AppBskyGraphDefs.StarterPackView | undefined
@@ -245,6 +261,267 @@ export function StepFinished() {
     gate,
   ])
 
+  return state.experiments?.onboarding_value_prop ? (
+    <ValueProposition
+      finishOnboarding={finishOnboarding}
+      saving={saving}
+      state={state}
+    />
+  ) : (
+    <LegacyFinalStep
+      finishOnboarding={finishOnboarding}
+      saving={saving}
+      state={state}
+    />
+  )
+}
+
+const PROP_1 = {
+  light: platform({
+    native: require('../../../assets/images/onboarding/value_prop_1_light.webp'),
+    web: require('../../../assets/images/onboarding/value_prop_1_light_borderless.webp'),
+  }),
+  dim: platform({
+    native: require('../../../assets/images/onboarding/value_prop_1_dim.webp'),
+    web: require('../../../assets/images/onboarding/value_prop_1_dim_borderless.webp'),
+  }),
+  dark: platform({
+    native: require('../../../assets/images/onboarding/value_prop_1_dark.webp'),
+    web: require('../../../assets/images/onboarding/value_prop_1_dark_borderless.webp'),
+  }),
+} as const
+
+const PROP_2 = {
+  light: require('../../../assets/images/onboarding/value_prop_2_light.webp'),
+  dim: require('../../../assets/images/onboarding/value_prop_2_dim.webp'),
+  dark: require('../../../assets/images/onboarding/value_prop_2_dark.webp'),
+} as const
+
+const PROP_3 = {
+  light: require('../../../assets/images/onboarding/value_prop_3_light.webp'),
+  dim: require('../../../assets/images/onboarding/value_prop_3_dim.webp'),
+  dark: require('../../../assets/images/onboarding/value_prop_3_dark.webp'),
+} as const
+
+function ValueProposition({
+  finishOnboarding,
+  saving,
+  state,
+}: {
+  finishOnboarding: () => void
+  saving: boolean
+  state: OnboardingState
+}) {
+  const [subStep, setSubStep] = useState<0 | 1 | 2>(0)
+  const t = useTheme()
+  const {_} = useLingui()
+  const {gtMobile} = useBreakpoints()
+
+  const image = [PROP_1[t.name], PROP_2[t.name], PROP_3[t.name]][subStep]
+
+  const onPress = () => {
+    if (subStep === 2) {
+      finishOnboarding() // has its own metrics
+    } else if (subStep === 1) {
+      setSubStep(2)
+      logger.metric('onboarding:valueProp:stepTwo:nextPressed', {})
+    } else if (subStep === 0) {
+      setSubStep(1)
+      logger.metric('onboarding:valueProp:stepOne:nextPressed', {})
+    }
+  }
+
+  const {title, description, alt} = [
+    {
+      title: _(msg`Free your feed`),
+      description: _(
+        msg`No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you.`,
+      ),
+      alt: _(
+        msg`A collection of popular feeds you can find on Bluesky, including News, Booksky, Game Dev, Blacksky, and Fountain Pens`,
+      ),
+    },
+    {
+      title: _(msg`Find your people`),
+      description: _(
+        msg`Ditch the trolls and clickbait. Find real people and conversations that matter to you.`,
+      ),
+      alt: _(
+        msg`Your profile picture surrounded by concentric circles of other users' profile pictures`,
+      ),
+    },
+    {
+      title: _(msg`Forget the noise`),
+      description: _(
+        msg`No ads, no invasive tracking, no engagement traps. Bluesky respects your time and attention.`,
+      ),
+      alt: _(
+        msg`An illustration of several Bluesky posts alongside repost, like, and comment icons`,
+      ),
+    },
+  ][subStep]
+
+  return (
+    <>
+      {!gtMobile && (
+        <OnboardingHeaderSlot.Portal>
+          <Button
+            disabled={saving}
+            variant="ghost"
+            color="secondary"
+            size="small"
+            label={_(msg`Skip introduction and start using your account`)}
+            onPress={() => {
+              logger.metric('onboarding:valueProp:skipPressed', {})
+              finishOnboarding()
+            }}
+            style={[a.bg_transparent]}>
+            <ButtonText>
+              <Trans>Skip</Trans>
+            </ButtonText>
+          </Button>
+        </OnboardingHeaderSlot.Portal>
+      )}
+
+      <LayoutAnimationConfig skipEntering skipExiting>
+        <Animated.View
+          key={subStep}
+          entering={native(
+            SlideInRight.easing(Easing.out(Easing.exp)).duration(500),
+          )}
+          exiting={native(
+            SlideOutLeft.easing(Easing.out(Easing.exp)).duration(500),
+          )}>
+          <View
+            style={[
+              a.relative,
+              a.align_center,
+              a.justify_center,
+              isNative && {marginHorizontal: tokens.space.xl * -1},
+              a.pointer_events_none,
+            ]}>
+            <Image
+              source={image}
+              style={[a.w_full, {aspectRatio: 1}]}
+              alt={alt}
+              accessibilityIgnoresInvertColors={false} // I guess we do need it to blend into the background
+            />
+            {subStep === 1 && (
+              <Image
+                source={state.profileStepResults.imageUri}
+                style={[
+                  a.z_10,
+                  a.absolute,
+                  a.rounded_full,
+                  {
+                    width: `${(80 / 393) * 100}%`,
+                    height: `${(80 / 393) * 100}%`,
+                  },
+                ]}
+                accessibilityIgnoresInvertColors
+                alt={_(msg`Your profile picture`)}
+              />
+            )}
+          </View>
+
+          <View style={[a.mt_4xl, a.gap_2xl, a.align_center]}>
+            <View style={[a.flex_row, a.gap_sm]}>
+              <Dot active={subStep === 0} />
+              <Dot active={subStep === 1} />
+              <Dot active={subStep === 2} />
+            </View>
+
+            <View style={[a.gap_sm]}>
+              <Text style={[a.font_heavy, a.text_3xl, a.text_center]}>
+                {title}
+              </Text>
+              <Text
+                style={[
+                  t.atoms.text_contrast_medium,
+                  a.text_md,
+                  a.leading_snug,
+                  a.text_center,
+                ]}>
+                {description}
+              </Text>
+            </View>
+          </View>
+        </Animated.View>
+      </LayoutAnimationConfig>
+
+      <OnboardingControls.Portal>
+        <View style={gtMobile && [a.gap_md, a.flex_row]}>
+          {gtMobile && (
+            <Button
+              disabled={saving}
+              color="secondary"
+              size="large"
+              label={_(msg`Skip introduction and start using your account`)}
+              onPress={() => finishOnboarding()}>
+              <ButtonText>
+                <Trans>Skip</Trans>
+              </ButtonText>
+            </Button>
+          )}
+          <Button
+            disabled={saving}
+            key={state.activeStep} // remove focus state on nav
+            color="primary"
+            size="large"
+            label={
+              subStep === 2
+                ? _(msg`Complete onboarding and start using your account`)
+                : _(msg`Next`)
+            }
+            onPress={onPress}>
+            <ButtonText>
+              {saving ? (
+                <Trans>Finalizing</Trans>
+              ) : subStep === 2 ? (
+                <Trans>Let's go!</Trans>
+              ) : (
+                <Trans>Next</Trans>
+              )}
+            </ButtonText>
+            {subStep === 2 && (
+              <ButtonIcon icon={saving ? Loader : ArrowRight} />
+            )}
+          </Button>
+        </View>
+      </OnboardingControls.Portal>
+    </>
+  )
+}
+
+function Dot({active}: {active: boolean}) {
+  const t = useTheme()
+  const {_} = useLingui()
+
+  return (
+    <View
+      style={[
+        a.rounded_full,
+        {width: 8, height: 8},
+        active
+          ? {backgroundColor: t.palette.primary_500}
+          : t.atoms.bg_contrast_50,
+      ]}
+    />
+  )
+}
+
+function LegacyFinalStep({
+  finishOnboarding,
+  saving,
+  state,
+}: {
+  finishOnboarding: () => void
+  saving: boolean
+  state: OnboardingState
+}) {
+  const t = useTheme()
+  const {_} = useLingui()
+
   return (
     <View style={[a.align_start]}>
       <IconCircle icon={Check} style={[a.mb_2xl]} />
@@ -305,7 +582,6 @@ export function StepFinished() {
         <Button
           disabled={saving}
           key={state.activeStep} // remove focus state on nav
-          variant="solid"
           color="primary"
           size="large"
           label={_(msg`Complete onboarding and start using your account`)}
diff --git a/src/screens/Onboarding/StepInterests/index.tsx b/src/screens/Onboarding/StepInterests/index.tsx
index 2a121cac6..3bde22136 100644
--- a/src/screens/Onboarding/StepInterests/index.tsx
+++ b/src/screens/Onboarding/StepInterests/index.tsx
@@ -160,7 +160,16 @@ export function StepInterests() {
 
       <View style={[a.w_full, a.pt_2xl]}>
         {isLoading ? (
-          <Loader size="xl" />
+          <View
+            style={[
+              a.flex_1,
+              a.mt_md,
+              a.align_center,
+              a.justify_center,
+              {minHeight: 400},
+            ]}>
+            <Loader size="xl" />
+          </View>
         ) : isError || !data ? (
           <View
             style={[
diff --git a/src/screens/Onboarding/StepProfile/index.tsx b/src/screens/Onboarding/StepProfile/index.tsx
index 30da5cbb5..fd5f9b6fb 100644
--- a/src/screens/Onboarding/StepProfile/index.tsx
+++ b/src/screens/Onboarding/StepProfile/index.tsx
@@ -266,7 +266,7 @@ export function StepProfile() {
         </View>
 
         <OnboardingControls.Portal>
-          <View style={[a.gap_md, gtMobile && {flexDirection: 'row-reverse'}]}>
+          <View style={[a.gap_md, gtMobile && a.flex_row_reverse]}>
             <Button
               variant="solid"
               color="primary"
diff --git a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx
new file mode 100644
index 000000000..5a9d3464c
--- /dev/null
+++ b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx
@@ -0,0 +1,356 @@
+import {useCallback, useContext, useMemo, useState} from 'react'
+import {View} from 'react-native'
+import {type ModerationOpts} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useMutation, useQueryClient} from '@tanstack/react-query'
+import * as bcp47Match from 'bcp-47-match'
+
+import {wait} from '#/lib/async/wait'
+import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
+import {logger} from '#/logger'
+import {isWeb} from '#/platform/detection'
+import {updateProfileShadow} from '#/state/cache/profile-shadow'
+import {useLanguagePrefs} from '#/state/preferences'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {useAgent, useSession} from '#/state/session'
+import {useOnboardingDispatch} from '#/state/shell'
+import {OnboardingControls} from '#/screens/Onboarding/Layout'
+import {
+  Context,
+  popularInterests,
+  useInterestsDisplayNames,
+} from '#/screens/Onboarding/state'
+import {useSuggestedUsers} from '#/screens/Search/util/useSuggestedUsers'
+import {atoms as a, tokens, useBreakpoints, useTheme} from '#/alf'
+import {Admonition} from '#/components/Admonition'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as ArrowRotateCounterClockwiseIcon} from '#/components/icons/ArrowRotateCounterClockwise'
+import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
+import {boostInterests, InterestTabs} from '#/components/InterestTabs'
+import {Loader} from '#/components/Loader'
+import * as ProfileCard from '#/components/ProfileCard'
+import * as toast from '#/components/Toast'
+import {Text} from '#/components/Typography'
+import type * as bsky from '#/types/bsky'
+import {bulkWriteFollows} from '../util'
+
+export function StepSuggestedAccounts() {
+  const {_} = useLingui()
+  const t = useTheme()
+  const {gtMobile} = useBreakpoints()
+  const moderationOpts = useModerationOpts()
+  const agent = useAgent()
+  const {currentAccount} = useSession()
+  const queryClient = useQueryClient()
+
+  const {state, dispatch} = useContext(Context)
+  const onboardDispatch = useOnboardingDispatch()
+
+  const [selectedInterest, setSelectedInterest] = useState<string | null>(null)
+  // keeping track of who was followed via the follow all button
+  // so we can enable/disable the button without having to dig through the shadow cache
+  const [followedUsers, setFollowedUsers] = useState<string[]>([])
+
+  /*
+   * Special language handling copied wholesale from the Explore screen
+   */
+  const {contentLanguages} = useLanguagePrefs()
+  const useFullExperience = useMemo(() => {
+    if (contentLanguages.length === 0) return true
+    return bcp47Match.basicFilter('en', contentLanguages).length > 0
+  }, [contentLanguages])
+  const interestsDisplayNames = useInterestsDisplayNames()
+  const interests = Object.keys(interestsDisplayNames)
+    .sort(boostInterests(popularInterests))
+    .sort(boostInterests(state.interestsStepResults.selectedInterests))
+  const {
+    data: suggestedUsers,
+    isLoading,
+    error,
+    isRefetching,
+    refetch,
+  } = useSuggestedUsers({
+    category: selectedInterest || (useFullExperience ? null : interests[0]),
+    search: !useFullExperience,
+    overrideInterests: state.interestsStepResults.selectedInterests,
+  })
+
+  const isError = !!error
+
+  const skipOnboarding = useCallback(() => {
+    onboardDispatch({type: 'finish'})
+    dispatch({type: 'finish'})
+  }, [onboardDispatch, dispatch])
+
+  const followableDids =
+    suggestedUsers?.actors
+      .filter(
+        user =>
+          user.did !== currentAccount?.did &&
+          !isBlockedOrBlocking(user) &&
+          !isMuted(user) &&
+          !user.viewer?.following &&
+          !followedUsers.includes(user.did),
+      )
+      .map(user => user.did) ?? []
+
+  const {mutate: followAll, isPending: isFollowingAll} = useMutation({
+    onMutate: () => {
+      logger.metric('onboarding:suggestedAccounts:followAllPressed', {
+        tab: selectedInterest ?? 'all',
+        numAccounts: followableDids.length,
+      })
+    },
+    mutationFn: async () => {
+      for (const did of followableDids) {
+        updateProfileShadow(queryClient, did, {
+          followingUri: 'pending',
+        })
+      }
+      const uris = await wait(1e3, bulkWriteFollows(agent, followableDids))
+      for (const did of followableDids) {
+        const uri = uris.get(did)
+        updateProfileShadow(queryClient, did, {
+          followingUri: uri,
+        })
+      }
+      return followableDids
+    },
+    onSuccess: newlyFollowed => {
+      toast.show(_(msg`Followed all accounts!`), {type: 'success'})
+      setFollowedUsers(followed => [...followed, ...newlyFollowed])
+    },
+    onError: () => {
+      toast.show(
+        _(msg`Failed to follow all suggested accounts, please try again`),
+        {type: 'error'},
+      )
+    },
+  })
+
+  const canFollowAll = followableDids.length > 0 && !isFollowingAll
+
+  return (
+    <View style={[a.align_start]} testID="onboardingInterests">
+      <Text style={[a.font_heavy, a.text_3xl]}>
+        <Trans comment="Accounts suggested to the user for them to follow">
+          Suggested for you
+        </Trans>
+      </Text>
+
+      <View
+        style={[
+          a.overflow_hidden,
+          a.mt_lg,
+          isWeb ? a.max_w_full : {marginHorizontal: tokens.space.xl * -1},
+          a.flex_1,
+          a.justify_start,
+        ]}>
+        <TabBar
+          selectedInterest={selectedInterest}
+          onSelectInterest={setSelectedInterest}
+          defaultTabLabel={_(
+            msg({
+              message: 'All',
+              comment: 'the default tab in the interests tab bar',
+            }),
+          )}
+          selectedInterests={state.interestsStepResults.selectedInterests}
+        />
+
+        {isLoading || !moderationOpts ? (
+          <View
+            style={[
+              a.flex_1,
+              a.mt_md,
+              a.align_center,
+              a.justify_center,
+              {minHeight: 400},
+            ]}>
+            <Loader size="xl" />
+          </View>
+        ) : isError ? (
+          <View style={[a.flex_1, a.px_xl, a.pt_5xl]}>
+            <Admonition type="error">
+              <Trans>
+                An error occurred while fetching suggested accounts.
+              </Trans>
+            </Admonition>
+          </View>
+        ) : (
+          <View
+            style={[
+              a.flex_1,
+              a.mt_md,
+              a.border_y,
+              t.atoms.border_contrast_low,
+              isWeb && [a.border_x, a.rounded_sm, a.overflow_hidden],
+            ]}>
+            {suggestedUsers?.actors.map((user, index) => (
+              <SuggestedProfileCard
+                key={user.did}
+                profile={user}
+                moderationOpts={moderationOpts}
+                position={index}
+              />
+            ))}
+          </View>
+        )}
+      </View>
+
+      <OnboardingControls.Portal>
+        {isError ? (
+          <View style={[a.gap_md, gtMobile ? a.flex_row : a.flex_col]}>
+            <Button
+              disabled={isRefetching}
+              color="secondary"
+              size="large"
+              label={_(msg`Retry`)}
+              onPress={() => refetch()}>
+              <ButtonText>
+                <Trans>Retry</Trans>
+              </ButtonText>
+              <ButtonIcon icon={ArrowRotateCounterClockwiseIcon} />
+            </Button>
+            <Button
+              color="secondary"
+              size="large"
+              label={_(msg`Skip this flow`)}
+              onPress={skipOnboarding}>
+              <ButtonText>
+                <Trans>Skip</Trans>
+              </ButtonText>
+            </Button>
+          </View>
+        ) : (
+          <View style={[a.gap_md, gtMobile ? a.flex_row : a.flex_col]}>
+            <Button
+              disabled={!canFollowAll}
+              color="secondary"
+              size="large"
+              label={_(msg`Follow all accounts`)}
+              onPress={() => followAll()}>
+              <ButtonText>
+                <Trans>Follow all</Trans>
+              </ButtonText>
+              <ButtonIcon icon={isFollowingAll ? Loader : PlusIcon} />
+            </Button>
+            <Button
+              disabled={isFollowingAll}
+              color="primary"
+              size="large"
+              label={_(msg`Continue to next step`)}
+              onPress={() => dispatch({type: 'next'})}>
+              <ButtonText>
+                <Trans>Continue</Trans>
+              </ButtonText>
+            </Button>
+          </View>
+        )}
+      </OnboardingControls.Portal>
+    </View>
+  )
+}
+
+function TabBar({
+  selectedInterest,
+  onSelectInterest,
+  selectedInterests,
+  hideDefaultTab,
+  defaultTabLabel,
+}: {
+  selectedInterest: string | null
+  onSelectInterest: (interest: string | null) => void
+  selectedInterests: string[]
+  hideDefaultTab?: boolean
+  defaultTabLabel?: string
+}) {
+  const {_} = useLingui()
+  const interestsDisplayNames = useInterestsDisplayNames()
+  const interests = Object.keys(interestsDisplayNames)
+    .sort(boostInterests(popularInterests))
+    .sort(boostInterests(selectedInterests))
+
+  return (
+    <InterestTabs
+      interests={hideDefaultTab ? interests : ['all', ...interests]}
+      selectedInterest={
+        selectedInterest || (hideDefaultTab ? interests[0] : 'all')
+      }
+      onSelectTab={tab => {
+        logger.metric(
+          'onboarding:suggestedAccounts:tabPressed',
+          {tab: tab},
+          {statsig: true},
+        )
+        onSelectInterest(tab === 'all' ? null : tab)
+      }}
+      interestsDisplayNames={
+        hideDefaultTab
+          ? interestsDisplayNames
+          : {
+              all: defaultTabLabel || _(msg`For You`),
+              ...interestsDisplayNames,
+            }
+      }
+      gutterWidth={isWeb ? 0 : tokens.space.xl}
+    />
+  )
+}
+
+function SuggestedProfileCard({
+  profile,
+  moderationOpts,
+  position,
+}: {
+  profile: bsky.profile.AnyProfileView
+  moderationOpts: ModerationOpts
+  position: number
+}) {
+  const t = useTheme()
+  return (
+    <View
+      style={[
+        a.flex_1,
+        a.w_full,
+        a.py_lg,
+        a.px_xl,
+        position !== 0 && a.border_t,
+        t.atoms.border_contrast_low,
+      ]}>
+      <ProfileCard.Outer>
+        <ProfileCard.Header>
+          <ProfileCard.Avatar
+            profile={profile}
+            moderationOpts={moderationOpts}
+            disabledPreview
+          />
+          <ProfileCard.NameAndHandle
+            profile={profile}
+            moderationOpts={moderationOpts}
+          />
+          <ProfileCard.FollowButton
+            profile={profile}
+            moderationOpts={moderationOpts}
+            withIcon={false}
+            logContext="OnboardingSuggestedAccounts"
+            onFollow={() => {
+              logger.metric(
+                'suggestedUser:follow',
+                {
+                  logContext: 'Onboarding',
+                  location: 'Card',
+                  recId: undefined,
+                  position,
+                },
+                {statsig: true},
+              )
+            }}
+          />
+        </ProfileCard.Header>
+        <ProfileCard.Description profile={profile} numberOfLines={3} />
+      </ProfileCard.Outer>
+    </View>
+  )
+}
diff --git a/src/screens/Onboarding/index.tsx b/src/screens/Onboarding/index.tsx
index a5c423ca1..2291e5e4f 100644
--- a/src/screens/Onboarding/index.tsx
+++ b/src/screens/Onboarding/index.tsx
@@ -1,21 +1,35 @@
-import React from 'react'
+import {useMemo, useReducer} from 'react'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
-import {Layout, OnboardingControls} from '#/screens/Onboarding/Layout'
+import {useGate} from '#/lib/statsig/statsig'
+import {
+  Layout,
+  OnboardingControls,
+  OnboardingHeaderSlot,
+} from '#/screens/Onboarding/Layout'
 import {Context, initialState, reducer} from '#/screens/Onboarding/state'
 import {StepFinished} from '#/screens/Onboarding/StepFinished'
 import {StepInterests} from '#/screens/Onboarding/StepInterests'
 import {StepProfile} from '#/screens/Onboarding/StepProfile'
 import {Portal} from '#/components/Portal'
+import {StepSuggestedAccounts} from './StepSuggestedAccounts'
 
 export function Onboarding() {
   const {_} = useLingui()
-  const [state, dispatch] = React.useReducer(reducer, {
+  const gate = useGate()
+  const showValueProp = gate('onboarding_value_prop')
+  const showSuggestedAccounts = gate('onboarding_suggested_accounts')
+  const [state, dispatch] = useReducer(reducer, {
     ...initialState,
+    totalSteps: showSuggestedAccounts ? 4 : 3,
+    experiments: {
+      onboarding_suggested_accounts: showSuggestedAccounts,
+      onboarding_value_prop: showValueProp,
+    },
   })
 
-  const interestsDisplayNames = React.useMemo(() => {
+  const interestsDisplayNames = useMemo(() => {
     return {
       news: _(msg`News`),
       journalism: _(msg`Journalism`),
@@ -45,17 +59,22 @@ export function Onboarding() {
   return (
     <Portal>
       <OnboardingControls.Provider>
-        <Context.Provider
-          value={React.useMemo(
-            () => ({state, dispatch, interestsDisplayNames}),
-            [state, dispatch, interestsDisplayNames],
-          )}>
-          <Layout>
-            {state.activeStep === 'profile' && <StepProfile />}
-            {state.activeStep === 'interests' && <StepInterests />}
-            {state.activeStep === 'finished' && <StepFinished />}
-          </Layout>
-        </Context.Provider>
+        <OnboardingHeaderSlot.Provider>
+          <Context.Provider
+            value={useMemo(
+              () => ({state, dispatch, interestsDisplayNames}),
+              [state, dispatch, interestsDisplayNames],
+            )}>
+            <Layout>
+              {state.activeStep === 'profile' && <StepProfile />}
+              {state.activeStep === 'interests' && <StepInterests />}
+              {state.activeStep === 'suggested-accounts' && (
+                <StepSuggestedAccounts />
+              )}
+              {state.activeStep === 'finished' && <StepFinished />}
+            </Layout>
+          </Context.Provider>
+        </OnboardingHeaderSlot.Provider>
       </OnboardingControls.Provider>
     </Portal>
   )
diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts
index cbb466245..31f6eb039 100644
--- a/src/screens/Onboarding/state.ts
+++ b/src/screens/Onboarding/state.ts
@@ -11,7 +11,7 @@ import {
 export type OnboardingState = {
   hasPrev: boolean
   totalSteps: number
-  activeStep: 'profile' | 'interests' | 'finished'
+  activeStep: 'profile' | 'interests' | 'suggested-accounts' | 'finished'
   activeStepIndex: number
 
   interestsStepResults: {
@@ -34,6 +34,11 @@ export type OnboardingState = {
       backgroundColor: AvatarColor
     }
   }
+
+  experiments?: {
+    onboarding_suggested_accounts?: boolean
+    onboarding_value_prop?: boolean
+  }
 }
 
 export type OnboardingAction =
@@ -160,22 +165,49 @@ export function reducer(
 
   switch (a.type) {
     case 'next': {
-      if (s.activeStep === 'profile') {
-        next.activeStep = 'interests'
-        next.activeStepIndex = 2
-      } else if (s.activeStep === 'interests') {
-        next.activeStep = 'finished'
-        next.activeStepIndex = 3
+      if (s.experiments?.onboarding_suggested_accounts) {
+        if (s.activeStep === 'profile') {
+          next.activeStep = 'interests'
+          next.activeStepIndex = 2
+        } else if (s.activeStep === 'interests') {
+          next.activeStep = 'suggested-accounts'
+          next.activeStepIndex = 3
+        }
+        if (s.activeStep === 'suggested-accounts') {
+          next.activeStep = 'finished'
+          next.activeStepIndex = 4
+        }
+      } else {
+        if (s.activeStep === 'profile') {
+          next.activeStep = 'interests'
+          next.activeStepIndex = 2
+        } else if (s.activeStep === 'interests') {
+          next.activeStep = 'finished'
+          next.activeStepIndex = 3
+        }
       }
       break
     }
     case 'prev': {
-      if (s.activeStep === 'interests') {
-        next.activeStep = 'profile'
-        next.activeStepIndex = 1
-      } else if (s.activeStep === 'finished') {
-        next.activeStep = 'interests'
-        next.activeStepIndex = 2
+      if (s.experiments?.onboarding_suggested_accounts) {
+        if (s.activeStep === 'interests') {
+          next.activeStep = 'profile'
+          next.activeStepIndex = 1
+        } else if (s.activeStep === 'suggested-accounts') {
+          next.activeStep = 'interests'
+          next.activeStepIndex = 2
+        } else if (s.activeStep === 'finished') {
+          next.activeStep = 'suggested-accounts'
+          next.activeStepIndex = 3
+        }
+      } else {
+        if (s.activeStep === 'interests') {
+          next.activeStep = 'profile'
+          next.activeStepIndex = 1
+        } else if (s.activeStep === 'finished') {
+          next.activeStep = 'interests'
+          next.activeStepIndex = 2
+        }
       }
       break
     }
diff --git a/src/screens/Onboarding/util.ts b/src/screens/Onboarding/util.ts
index d14c9562e..b08f0408e 100644
--- a/src/screens/Onboarding/util.ts
+++ b/src/screens/Onboarding/util.ts
@@ -1,9 +1,9 @@
 import {
-  $Typed,
-  AppBskyGraphFollow,
-  AppBskyGraphGetFollows,
-  BskyAgent,
-  ComAtprotoRepoApplyWrites,
+  type $Typed,
+  type AppBskyGraphFollow,
+  type AppBskyGraphGetFollows,
+  type BskyAgent,
+  type ComAtprotoRepoApplyWrites,
 } from '@atproto/api'
 import {TID} from '@atproto/common-web'
 import chunk from 'lodash.chunk'
@@ -42,10 +42,10 @@ export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) {
   }
   await whenFollowsIndexed(agent, session.did, res => !!res.data.follows.length)
 
-  const followUris = new Map()
+  const followUris = new Map<string, string>()
   for (const r of followWrites) {
     followUris.set(
-      r.value.subject,
+      r.value.subject as string,
       `at://${session.did}/app.bsky.graph.follow/${r.rkey}`,
     )
   }
diff --git a/src/screens/Profile/Header/SuggestedFollows.tsx b/src/screens/Profile/Header/SuggestedFollows.tsx
index d005d888e..58a507e08 100644
--- a/src/screens/Profile/Header/SuggestedFollows.tsx
+++ b/src/screens/Profile/Header/SuggestedFollows.tsx
@@ -28,7 +28,6 @@ export function AnimatedProfileHeaderSuggestedFollows({
   actorDid: string
 }) {
   const gate = useGate()
-  if (!gate('post_follow_profile_suggested_accounts')) return null
 
   /* NOTE (caidanw):
    * Android does not work well with this feature yet.
@@ -37,6 +36,8 @@ export function AnimatedProfileHeaderSuggestedFollows({
    **/
   if (isAndroid) return null
 
+  if (!gate('post_follow_profile_suggested_accounts')) return null
+
   return (
     <AccordionAnimation isExpanded={isExpanded}>
       <ProfileHeaderSuggestedFollows actorDid={actorDid} />
diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx
index baf69cd7f..cefe68b01 100644
--- a/src/screens/Search/Explore.tsx
+++ b/src/screens/Search/Explore.tsx
@@ -66,9 +66,9 @@ import {
 import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle'
 import {StarterPack} from '#/components/icons/StarterPack'
 import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle'
+import {boostInterests} from '#/components/InterestTabs'
 import {Loader} from '#/components/Loader'
 import * as ProfileCard from '#/components/ProfileCard'
-import {boostInterests} from '#/components/ProgressGuide/FollowDialog'
 import {SubtleHover} from '#/components/SubtleHover'
 import {Text} from '#/components/Typography'
 import * as ModuleHeader from './components/ModuleHeader'
diff --git a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx
index fd37544f4..71bfd6547 100644
--- a/src/screens/Search/modules/ExploreSuggestedAccounts.tsx
+++ b/src/screens/Search/modules/ExploreSuggestedAccounts.tsx
@@ -14,11 +14,9 @@ import {
 } from '#/screens/Onboarding/state'
 import {useTheme} from '#/alf'
 import {atoms as a} from '#/alf'
-import {Button} from '#/components/Button'
+import {boostInterests, InterestTabs} from '#/components/InterestTabs'
 import * as ProfileCard from '#/components/ProfileCard'
-import {boostInterests, Tabs} from '#/components/ProgressGuide/FollowDialog'
 import {SubtleHover} from '#/components/SubtleHover'
-import {Text} from '#/components/Typography'
 import type * as bsky from '#/types/bsky'
 
 export function useLoadEnoughProfiles({
@@ -59,10 +57,12 @@ export function SuggestedAccountsTabBar({
   selectedInterest,
   onSelectInterest,
   hideDefaultTab,
+  defaultTabLabel,
 }: {
   selectedInterest: string | null
   onSelectInterest: (interest: string | null) => void
   hideDefaultTab?: boolean
+  defaultTabLabel?: string
 }) {
   const {_} = useLingui()
   const interestsDisplayNames = useInterestsDisplayNames()
@@ -71,9 +71,10 @@ export function SuggestedAccountsTabBar({
   const interests = Object.keys(interestsDisplayNames)
     .sort(boostInterests(popularInterests))
     .sort(boostInterests(personalizedInterests))
+
   return (
     <BlockDrawerGesture>
-      <Tabs
+      <InterestTabs
         interests={hideDefaultTab ? interests : ['all', ...interests]}
         selectedInterest={
           selectedInterest || (hideDefaultTab ? interests[0] : 'all')
@@ -86,82 +87,19 @@ export function SuggestedAccountsTabBar({
           )
           onSelectInterest(tab === 'all' ? null : tab)
         }}
-        hasSearchText={false}
         interestsDisplayNames={
           hideDefaultTab
             ? interestsDisplayNames
             : {
-                all: _(msg`For You`),
+                all: defaultTabLabel || _(msg`For You`),
                 ...interestsDisplayNames,
               }
         }
-        TabComponent={Tab}
-        contentContainerStyle={[
-          {
-            // visual alignment
-            paddingLeft: a.px_md.paddingLeft,
-          },
-        ]}
       />
     </BlockDrawerGesture>
   )
 }
 
-let Tab = ({
-  onSelectTab,
-  interest,
-  active,
-  index,
-  interestsDisplayName,
-  onLayout,
-}: {
-  onSelectTab: (index: number) => void
-  interest: string
-  active: boolean
-  index: number
-  interestsDisplayName: string
-  onLayout: (index: number, x: number, width: number) => void
-}): React.ReactNode => {
-  const t = useTheme()
-  const {_} = useLingui()
-  const activeText = active ? _(msg` (active)`) : ''
-  return (
-    <View
-      key={interest}
-      onLayout={e =>
-        onLayout(index, e.nativeEvent.layout.x, e.nativeEvent.layout.width)
-      }>
-      <Button
-        label={_(msg`Search for "${interestsDisplayName}"${activeText}`)}
-        onPress={() => onSelectTab(index)}>
-        {({hovered, pressed, focused}) => (
-          <View
-            style={[
-              a.rounded_full,
-              a.px_lg,
-              a.py_sm,
-              a.border,
-              active || hovered || pressed || focused
-                ? [t.atoms.bg_contrast_25, t.atoms.border_contrast_medium]
-                : [t.atoms.bg, t.atoms.border_contrast_low],
-            ]}>
-            <Text
-              style={[
-                a.font_medium,
-                active || hovered || pressed || focused
-                  ? t.atoms.text
-                  : t.atoms.text_contrast_medium,
-              ]}>
-              {interestsDisplayName}
-            </Text>
-          </View>
-        )}
-      </Button>
-    </View>
-  )
-}
-Tab = memo(Tab)
-
 /**
  * Profile card for suggested accounts. Note: border is on the bottom edge
  */
diff --git a/src/screens/Search/util/useSuggestedUsers.ts b/src/screens/Search/util/useSuggestedUsers.ts
index aa29dad8c..9ca2c558a 100644
--- a/src/screens/Search/util/useSuggestedUsers.ts
+++ b/src/screens/Search/util/useSuggestedUsers.ts
@@ -11,6 +11,7 @@ import {useInterestsDisplayNames} from '#/screens/Onboarding/state'
 export function useSuggestedUsers({
   category = null,
   search = false,
+  overrideInterests,
 }: {
   category?: string | null
   /**
@@ -18,11 +19,17 @@ export function useSuggestedUsers({
    * based on the user's "app language setting
    */
   search?: boolean
+  /**
+   * In onboarding, interests haven't been saved to prefs yet, so we need to
+   * pass them down through here
+   */
+  overrideInterests?: string[]
 }) {
   const interestsDisplayNames = useInterestsDisplayNames()
   const curated = useGetSuggestedUsersQuery({
     enabled: !search,
     category,
+    overrideInterests,
   })
   const searched = useActorSearchPaginated({
     enabled: !!search,
@@ -43,6 +50,7 @@ export function useSuggestedUsers({
         isLoading: searched.isLoading,
         error: searched.error,
         isRefetching: searched.isRefetching,
+        refetch: searched.refetch,
       }
     } else {
       return {
@@ -50,6 +58,7 @@ export function useSuggestedUsers({
         isLoading: curated.isLoading,
         error: curated.error,
         isRefetching: curated.isRefetching,
+        refetch: curated.refetch,
       }
     }
   }, [curated, searched, search])
diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts
index 2ad4c592e..168002b1f 100644
--- a/src/state/messages/convo/agent.ts
+++ b/src/state/messages/convo/agent.ts
@@ -10,6 +10,7 @@ import EventEmitter from 'eventemitter3'
 import {nanoid} from 'nanoid/non-secure'
 
 import {networkRetry} from '#/lib/async/retry'
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {isNetworkError} from '#/lib/strings/errors'
 import {Logger} from '#/logger'
 import {isNative} from '#/platform/detection'
@@ -33,7 +34,6 @@ import {
 } from '#/state/messages/convo/types'
 import {type MessagesEventBus} from '#/state/messages/events/agent'
 import {type MessagesEventBusError} from '#/state/messages/events/types'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 
 const logger = Logger.create(Logger.Context.ConversationAgent)
 
diff --git a/src/state/messages/events/agent.ts b/src/state/messages/events/agent.ts
index fb3047bf6..e54ea1c77 100644
--- a/src/state/messages/events/agent.ts
+++ b/src/state/messages/events/agent.ts
@@ -3,6 +3,7 @@ import EventEmitter from 'eventemitter3'
 import {nanoid} from 'nanoid/non-secure'
 
 import {networkRetry} from '#/lib/async/retry'
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {isNetworkError} from '#/lib/strings/errors'
 import {Logger} from '#/logger'
 import {
@@ -17,7 +18,6 @@ import {
   type MessagesEventBusParams,
   MessagesEventBusStatus,
 } from '#/state/messages/events/types'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 
 const logger = Logger.create(Logger.Context.DMsAgent)
 
diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx
index 3ebbd1732..c6070e97b 100644
--- a/src/state/modals/index.tsx
+++ b/src/state/modals/index.tsx
@@ -35,10 +35,6 @@ export interface ContentLanguagesSettingsModal {
   name: 'content-languages-settings'
 }
 
-export interface PostLanguagesSettingsModal {
-  name: 'post-languages-settings'
-}
-
 /**
  * @deprecated DO NOT ADD NEW MODALS
  */
@@ -48,7 +44,6 @@ export type Modal =
 
   // Curation
   | ContentLanguagesSettingsModal
-  | PostLanguagesSettingsModal
 
   // Lists
   | CreateOrEditListModal
diff --git a/src/state/queries/handle-availability.ts b/src/state/queries/handle-availability.ts
index 9391f5d09..06fc6eebb 100644
--- a/src/state/queries/handle-availability.ts
+++ b/src/state/queries/handle-availability.ts
@@ -1,4 +1,4 @@
-import {Agent, ComAtprotoTempCheckHandleAvailability} from '@atproto/api'
+import {ComAtprotoTempCheckHandleAvailability} from '@atproto/api'
 import {useQuery} from '@tanstack/react-query'
 
 import {
@@ -10,6 +10,7 @@ import {createFullHandle} from '#/lib/strings/handles'
 import {logger} from '#/logger'
 import {useDebouncedValue} from '#/components/live/utils'
 import * as bsky from '#/types/bsky'
+import {Agent} from '../session/agent'
 
 export const RQKEY_handleAvailability = (
   handle: string,
@@ -74,7 +75,7 @@ export async function checkHandleAvailability(
   },
 ) {
   if (serviceDid === BSKY_SERVICE_DID) {
-    const agent = new Agent({service: BSKY_SERVICE})
+    const agent = new Agent(null, {service: BSKY_SERVICE})
     // entryway has a special API for handle availability
     const {data} = await agent.com.atproto.temp.checkHandleAvailability({
       handle,
@@ -109,7 +110,7 @@ export async function checkHandleAvailability(
     }
   } else {
     // 3rd party PDSes won't have this API so just try and resolve the handle
-    const agent = new Agent({service: PUBLIC_BSKY_SERVICE})
+    const agent = new Agent(null, {service: PUBLIC_BSKY_SERVICE})
     try {
       const res = await agent.resolveHandle({
         handle,
diff --git a/src/state/queries/messages/accept-conversation.ts b/src/state/queries/messages/accept-conversation.ts
index 82acb33c8..0c06055b5 100644
--- a/src/state/queries/messages/accept-conversation.ts
+++ b/src/state/queries/messages/accept-conversation.ts
@@ -1,9 +1,12 @@
-import {ChatBskyConvoAcceptConvo, ChatBskyConvoListConvos} from '@atproto/api'
+import {
+  type ChatBskyConvoAcceptConvo,
+  type ChatBskyConvoListConvos,
+} from '@atproto/api'
 import {useMutation, useQueryClient} from '@tanstack/react-query'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {logger} from '#/logger'
 import {useAgent} from '#/state/session'
-import {DM_SERVICE_HEADERS} from './const'
 import {
   RQKEY as CONVO_LIST_KEY,
   RQKEY_ROOT as CONVO_LIST_ROOT_KEY,
diff --git a/src/state/queries/messages/const.ts b/src/state/queries/messages/const.ts
deleted file mode 100644
index 1c5519a63..000000000
--- a/src/state/queries/messages/const.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import {CHAT_PROXY_DID} from '#/env'
-
-export const DM_SERVICE_HEADERS = {
-  'atproto-proxy': `${CHAT_PROXY_DID}#bsky_chat`,
-}
diff --git a/src/state/queries/messages/conversation.ts b/src/state/queries/messages/conversation.ts
index de5a90571..393bf9e52 100644
--- a/src/state/queries/messages/conversation.ts
+++ b/src/state/queries/messages/conversation.ts
@@ -1,17 +1,17 @@
-import {ChatBskyConvoDefs} from '@atproto/api'
+import {type ChatBskyConvoDefs} from '@atproto/api'
 import {
-  QueryClient,
+  type QueryClient,
   useMutation,
   useQuery,
   useQueryClient,
 } from '@tanstack/react-query'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {STALE} from '#/state/queries'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useOnMarkAsRead} from '#/state/queries/messages/list-conversations'
 import {useAgent} from '#/state/session'
 import {
-  ConvoListQueryData,
+  type ConvoListQueryData,
   getConvoFromQueryData,
   RQKEY_ROOT as LIST_CONVOS_KEY,
 } from './list-conversations'
diff --git a/src/state/queries/messages/get-convo-availability.ts b/src/state/queries/messages/get-convo-availability.ts
index f545c3bba..2392edb09 100644
--- a/src/state/queries/messages/get-convo-availability.ts
+++ b/src/state/queries/messages/get-convo-availability.ts
@@ -1,6 +1,6 @@
 import {useQuery} from '@tanstack/react-query'
 
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {useAgent} from '#/state/session'
 import {STALE} from '..'
 
diff --git a/src/state/queries/messages/get-convo-for-members.ts b/src/state/queries/messages/get-convo-for-members.ts
index 3f45c2328..58c1ab524 100644
--- a/src/state/queries/messages/get-convo-for-members.ts
+++ b/src/state/queries/messages/get-convo-for-members.ts
@@ -1,8 +1,8 @@
-import {ChatBskyConvoGetConvoForMembers} from '@atproto/api'
+import {type ChatBskyConvoGetConvoForMembers} from '@atproto/api'
 import {useMutation, useQueryClient} from '@tanstack/react-query'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {logger} from '#/logger'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useAgent} from '#/state/session'
 import {precacheConvoQuery} from './conversation'
 
diff --git a/src/state/queries/messages/leave-conversation.ts b/src/state/queries/messages/leave-conversation.ts
index b17e515be..986351a07 100644
--- a/src/state/queries/messages/leave-conversation.ts
+++ b/src/state/queries/messages/leave-conversation.ts
@@ -1,13 +1,16 @@
 import {useMemo} from 'react'
-import {ChatBskyConvoLeaveConvo, ChatBskyConvoListConvos} from '@atproto/api'
+import {
+  type ChatBskyConvoLeaveConvo,
+  type ChatBskyConvoListConvos,
+} from '@atproto/api'
 import {
   useMutation,
   useMutationState,
   useQueryClient,
 } from '@tanstack/react-query'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {logger} from '#/logger'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useAgent} from '#/state/session'
 import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
 
diff --git a/src/state/queries/messages/list-conversations.tsx b/src/state/queries/messages/list-conversations.tsx
index 3f8252519..c5457d1cb 100644
--- a/src/state/queries/messages/list-conversations.tsx
+++ b/src/state/queries/messages/list-conversations.tsx
@@ -13,10 +13,10 @@ import {
 } from '@tanstack/react-query'
 import throttle from 'lodash.throttle'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {useCurrentConvoId} from '#/state/messages/current-convo-id'
 import {useMessagesEventBus} from '#/state/messages/events'
 import {useModerationOpts} from '#/state/preferences/moderation-opts'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useAgent, useSession} from '#/state/session'
 import {useLeftConvos} from './leave-conversation'
 
diff --git a/src/state/queries/messages/mute-conversation.ts b/src/state/queries/messages/mute-conversation.ts
index da9644145..d668e36cb 100644
--- a/src/state/queries/messages/mute-conversation.ts
+++ b/src/state/queries/messages/mute-conversation.ts
@@ -1,11 +1,15 @@
 import {
-  ChatBskyConvoDefs,
-  ChatBskyConvoListConvos,
-  ChatBskyConvoMuteConvo,
+  type ChatBskyConvoDefs,
+  type ChatBskyConvoListConvos,
+  type ChatBskyConvoMuteConvo,
 } from '@atproto/api'
-import {InfiniteData, useMutation, useQueryClient} from '@tanstack/react-query'
+import {
+  type InfiniteData,
+  useMutation,
+  useQueryClient,
+} from '@tanstack/react-query'
 
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {useAgent} from '#/state/session'
 import {RQKEY as CONVO_KEY} from './conversation'
 import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
diff --git a/src/state/queries/messages/update-all-read.ts b/src/state/queries/messages/update-all-read.ts
index 72fa65ee6..3d0fd3a45 100644
--- a/src/state/queries/messages/update-all-read.ts
+++ b/src/state/queries/messages/update-all-read.ts
@@ -1,8 +1,8 @@
-import {ChatBskyConvoListConvos} from '@atproto/api'
+import {type ChatBskyConvoListConvos} from '@atproto/api'
 import {useMutation, useQueryClient} from '@tanstack/react-query'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {logger} from '#/logger'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useAgent} from '#/state/session'
 import {RQKEY as CONVO_LIST_KEY} from './list-conversations'
 
diff --git a/src/state/queries/service.ts b/src/state/queries/service.ts
index 6bfd0b011..e9661db9e 100644
--- a/src/state/queries/service.ts
+++ b/src/state/queries/service.ts
@@ -1,6 +1,7 @@
-import {BskyAgent} from '@atproto/api'
 import {useQuery} from '@tanstack/react-query'
 
+import {Agent} from '../session/agent'
+
 const RQKEY_ROOT = 'service'
 export const RQKEY = (serviceUrl: string) => [RQKEY_ROOT, serviceUrl]
 
@@ -8,7 +9,7 @@ export function useServiceQuery(serviceUrl: string) {
   return useQuery({
     queryKey: RQKEY(serviceUrl),
     queryFn: async () => {
-      const agent = new BskyAgent({service: serviceUrl})
+      const agent = new Agent(null, {service: serviceUrl})
       const res = await agent.com.atproto.server.describeServer()
       return res.data
     },
diff --git a/src/state/queries/trending/useGetSuggestedUsersQuery.ts b/src/state/queries/trending/useGetSuggestedUsersQuery.ts
index 05cc4d74d..898029398 100644
--- a/src/state/queries/trending/useGetSuggestedUsersQuery.ts
+++ b/src/state/queries/trending/useGetSuggestedUsersQuery.ts
@@ -17,6 +17,7 @@ export type QueryProps = {
   category?: string | null
   limit?: number
   enabled?: boolean
+  overrideInterests?: string[]
 }
 
 export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users'
@@ -24,6 +25,7 @@ export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [
   getSuggestedUsersQueryKeyRoot,
   props.category,
   props.limit,
+  props.overrideInterests?.join(','),
 ]
 
 export function useGetSuggestedUsersQuery(props: QueryProps) {
@@ -36,6 +38,7 @@ export function useGetSuggestedUsersQuery(props: QueryProps) {
     queryKey: createGetSuggestedUsersQueryKey(props),
     queryFn: async () => {
       const contentLangs = getContentLanguages().join(',')
+      const interests = aggregateUserInterests(preferences)
       const {data} = await agent.app.bsky.unspecced.getSuggestedUsers(
         {
           category: props.category ?? undefined,
@@ -43,7 +46,11 @@ export function useGetSuggestedUsersQuery(props: QueryProps) {
         },
         {
           headers: {
-            ...createBskyTopicsHeader(aggregateUserInterests(preferences)),
+            ...createBskyTopicsHeader(
+              props.overrideInterests && props.overrideInterests.length > 0
+                ? props.overrideInterests.join(',')
+                : interests,
+            ),
             'Accept-Language': contentLangs,
           },
         },
diff --git a/src/state/session/agent.ts b/src/state/session/agent.ts
index 531e285ab..d063a09a2 100644
--- a/src/state/session/agent.ts
+++ b/src/state/session/agent.ts
@@ -1,8 +1,19 @@
-import {AtpSessionData, AtpSessionEvent, BskyAgent} from '@atproto/api'
+import {
+  Agent as BaseAgent,
+  type AtprotoServiceType,
+  type AtpSessionData,
+  type AtpSessionEvent,
+  BskyAgent,
+  type Did,
+} from '@atproto/api'
+import {type FetchHandler} from '@atproto/api/dist/agent'
+import {type SessionManager} from '@atproto/api/dist/session-manager'
 import {TID} from '@atproto/common-web'
+import {type FetchHandlerOptions} from '@atproto/xrpc'
 
 import {networkRetry} from '#/lib/async/retry'
 import {
+  BLUESKY_PROXY_HEADER,
   BSKY_SERVICE,
   DISCOVER_SAVED_FEED,
   IS_PROD_SERVICE,
@@ -19,12 +30,17 @@ import {
   configureModerationForAccount,
   configureModerationForGuest,
 } from './moderation'
-import {SessionAccount} from './types'
+import {type SessionAccount} from './types'
 import {isSessionExpired, isSignupQueued} from './util'
 
+export type ProxyHeaderValue = `${Did}#${AtprotoServiceType}`
+
 export function createPublicAgent() {
   configureModerationForGuest() // Side effect but only relevant for tests
-  return new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
+
+  const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
+  agent.configureProxy(BLUESKY_PROXY_HEADER)
+  return agent
 }
 
 export async function createAgentAndResume(
@@ -61,6 +77,8 @@ export async function createAgentAndResume(
     }
   }
 
+  agent.configureProxy(BLUESKY_PROXY_HEADER)
+
   return agent.prepare(gates, moderation, onSessionChange)
 }
 
@@ -93,6 +111,9 @@ export async function createAgentAndLogin(
   const account = agentToSessionAccountOrThrow(agent)
   const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
   const moderation = configureModerationForAccount(agent, account)
+
+  agent.configureProxy(BLUESKY_PROXY_HEADER)
+
   return agent.prepare(gates, moderation, onSessionChange)
 }
 
@@ -180,6 +201,8 @@ export async function createAgentAndCreateAccount(
     logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`})
   }
 
+  agent.configureProxy(BLUESKY_PROXY_HEADER)
+
   return agent.prepare(gates, moderation, onSessionChange)
 }
 
@@ -234,7 +257,22 @@ export function sessionAccountToSession(
   }
 }
 
+export class Agent extends BaseAgent {
+  constructor(
+    proxyHeader: ProxyHeaderValue | null,
+    options: SessionManager | FetchHandler | FetchHandlerOptions,
+  ) {
+    super(options)
+    if (proxyHeader) {
+      this.configureProxy(proxyHeader)
+    }
+  }
+}
+
 // Not exported. Use factories above to create it.
+// WARN: In the factories above, we _manually set a proxy header_ for the agent after we do whatever it is we are supposed to do.
+// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it
+// feels safer to just let those run as-is and set the header afterward.
 let realFetch = globalThis.fetch
 class BskyAppAgent extends BskyAgent {
   persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined =
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 7d4eb8ca7..b533510ec 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -110,7 +110,7 @@ import {LabelsBtn} from '#/view/com/composer/labels/LabelsBtn'
 import {Gallery} from '#/view/com/composer/photos/Gallery'
 import {OpenCameraBtn} from '#/view/com/composer/photos/OpenCameraBtn'
 import {SelectGifBtn} from '#/view/com/composer/photos/SelectGifBtn'
-import {SelectLangBtn} from '#/view/com/composer/select-language/SelectLangBtn'
+import {SelectPostLanguagesBtn} from '#/view/com/composer/select-language/SelectPostLanguagesDialog'
 import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage'
 // TODO: Prevent naming components that coincide with RN primitives
 // due to linting false positives
@@ -126,7 +126,6 @@ import {Text} from '#/view/com/util/text/Text'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, native, useTheme, web} from '#/alf'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
-import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheckIcon} from '#/components/icons/CircleCheck'
 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
 import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
@@ -527,8 +526,8 @@ export const ComposePost = ({
     }
     onClose()
     Toast.show(
-      <Toast.Outer type="success">
-        <Toast.Icon icon={CircleCheckIcon} />
+      <Toast.Outer>
+        <Toast.Icon />
         <Toast.Text>
           {thread.posts.length > 1
             ? _(msg`Your posts were sent`)
@@ -543,7 +542,9 @@ export const ComposePost = ({
               const {host: name, rkey} = new AtUri(postUri)
               navigation.navigate('PostThread', {name, rkey})
             }}>
-            View
+            <Trans context="Action to view the post the user just created">
+              View
+            </Trans>
           </Toast.Action>
         )}
       </Toast.Outer>,
@@ -1452,7 +1453,7 @@ function ComposerFooter({
             />
           </Button>
         )}
-        <SelectLangBtn />
+        <SelectPostLanguagesBtn />
         <CharProgress
           count={post.shortenedGraphemeLength}
           style={{width: 65}}
diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx
deleted file mode 100644
index f487b1244..000000000
--- a/src/view/com/composer/select-language/SelectLangBtn.tsx
+++ /dev/null
@@ -1,133 +0,0 @@
-import {useCallback, useMemo} from 'react'
-import {Keyboard, StyleSheet} from 'react-native'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {isNative} from '#/platform/detection'
-import {useModalControls} from '#/state/modals'
-import {
-  hasPostLanguage,
-  toPostLanguages,
-  useLanguagePrefs,
-  useLanguagePrefsApi,
-} from '#/state/preferences/languages'
-import {
-  DropdownButton,
-  DropdownItem,
-  DropdownItemButton,
-} from '#/view/com/util/forms/DropdownButton'
-import {Text} from '#/view/com/util/text/Text'
-import {codeToLanguageName} from '../../../../locale/helpers'
-
-export function SelectLangBtn() {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const {openModal} = useModalControls()
-  const langPrefs = useLanguagePrefs()
-  const setLangPrefs = useLanguagePrefsApi()
-
-  const onPressMore = useCallback(async () => {
-    if (isNative) {
-      if (Keyboard.isVisible()) {
-        Keyboard.dismiss()
-      }
-    }
-    openModal({name: 'post-languages-settings'})
-  }, [openModal])
-
-  const postLanguagesPref = toPostLanguages(langPrefs.postLanguage)
-  const items: DropdownItem[] = useMemo(() => {
-    let arr: DropdownItemButton[] = []
-
-    function add(commaSeparatedLangCodes: string) {
-      const langCodes = commaSeparatedLangCodes.split(',')
-      const langName = langCodes
-        .map(code => codeToLanguageName(code, langPrefs.appLanguage))
-        .join(' + ')
-
-      /*
-       * Filter out any duplicates
-       */
-      if (arr.find((item: DropdownItemButton) => item.label === langName)) {
-        return
-      }
-
-      arr.push({
-        icon:
-          langCodes.every(code =>
-            hasPostLanguage(langPrefs.postLanguage, code),
-          ) && langCodes.length === postLanguagesPref.length
-            ? ['fas', 'circle-dot']
-            : ['far', 'circle'],
-        label: langName,
-        onPress() {
-          setLangPrefs.setPostLanguage(commaSeparatedLangCodes)
-        },
-      })
-    }
-
-    if (postLanguagesPref.length) {
-      /*
-       * Re-join here after sanitization bc postLanguageHistory is an array of
-       * comma-separated strings too
-       */
-      add(langPrefs.postLanguage)
-    }
-
-    // comma-separted strings of lang codes that have been used in the past
-    for (const lang of langPrefs.postLanguageHistory) {
-      add(lang)
-    }
-
-    return [
-      {heading: true, label: _(msg`Post language`)},
-      ...arr.slice(0, 6),
-      {sep: true},
-      {
-        label: _(msg`Other...`),
-        onPress: onPressMore,
-      },
-    ]
-  }, [onPressMore, langPrefs, setLangPrefs, postLanguagesPref, _])
-
-  return (
-    <DropdownButton
-      type="bare"
-      testID="selectLangBtn"
-      items={items}
-      openUpwards
-      style={styles.button}
-      hitSlop={LANG_DROPDOWN_HITSLOP}
-      accessibilityLabel={_(msg`Language selection`)}
-      accessibilityHint="">
-      {postLanguagesPref.length > 0 ? (
-        <Text type="lg-bold" style={[pal.link, styles.label]} numberOfLines={1}>
-          {postLanguagesPref
-            .map(lang => codeToLanguageName(lang, langPrefs.appLanguage))
-            .join(', ')}
-        </Text>
-      ) : (
-        <FontAwesomeIcon
-          icon="language"
-          style={pal.link as FontAwesomeIconStyle}
-          size={26}
-        />
-      )}
-    </DropdownButton>
-  )
-}
-
-const styles = StyleSheet.create({
-  button: {
-    marginHorizontal: 15,
-  },
-  label: {
-    maxWidth: 100,
-  },
-})
diff --git a/src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx b/src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx
new file mode 100644
index 000000000..c8ecc2b89
--- /dev/null
+++ b/src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx
@@ -0,0 +1,382 @@
+import {useCallback, useMemo, useState} from 'react'
+import {Keyboard, useWindowDimensions, View} from 'react-native'
+import {useSafeAreaInsets} from 'react-native-safe-area-context'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants'
+import {languageName} from '#/locale/helpers'
+import {codeToLanguageName} from '#/locale/helpers'
+import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages'
+import {isNative, isWeb} from '#/platform/detection'
+import {
+  toPostLanguages,
+  useLanguagePrefs,
+  useLanguagePrefsApi,
+} from '#/state/preferences/languages'
+import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
+import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
+import {atoms as a, useTheme, web} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import * as Dialog from '#/components/Dialog'
+import {SearchInput} from '#/components/forms/SearchInput'
+import * as Toggle from '#/components/forms/Toggle'
+import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
+import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
+import {Text} from '#/components/Typography'
+
+export function SelectPostLanguagesBtn() {
+  const {_} = useLingui()
+  const langPrefs = useLanguagePrefs()
+  const t = useTheme()
+  const control = Dialog.useDialogControl()
+
+  const onPressMore = useCallback(async () => {
+    if (isNative) {
+      if (Keyboard.isVisible()) {
+        Keyboard.dismiss()
+      }
+    }
+    control.open()
+  }, [control])
+
+  const postLanguagesPref = toPostLanguages(langPrefs.postLanguage)
+
+  return (
+    <>
+      <Button
+        testID="selectLangBtn"
+        onPress={onPressMore}
+        size="small"
+        hitSlop={LANG_DROPDOWN_HITSLOP}
+        label={_(
+          msg({
+            message: `Post language selection`,
+            comment: `Accessibility label for button that opens dialog to choose post language settings`,
+          }),
+        )}
+        accessibilityHint={_(msg`Opens post language settings`)}
+        style={[a.mx_md]}>
+        {({pressed, hovered, focused}) => {
+          const color =
+            pressed || hovered || focused
+              ? t.palette.primary_300
+              : t.palette.primary_500
+          if (postLanguagesPref.length > 0) {
+            return (
+              <Text
+                style={[
+                  {color},
+                  a.font_bold,
+                  a.text_sm,
+                  a.leading_snug,
+                  {maxWidth: 100},
+                ]}
+                numberOfLines={1}>
+                {postLanguagesPref
+                  .map(lang => codeToLanguageName(lang, langPrefs.appLanguage))
+                  .join(', ')}
+              </Text>
+            )
+          } else {
+            return <GlobeIcon size="xs" style={{color}} />
+          }
+        }}
+      </Button>
+
+      <LanguageDialog control={control} />
+    </>
+  )
+}
+
+function LanguageDialog({control}: {control: Dialog.DialogControlProps}) {
+  const {height} = useWindowDimensions()
+  const insets = useSafeAreaInsets()
+
+  const renderErrorBoundary = useCallback(
+    (error: any) => <DialogError details={String(error)} />,
+    [],
+  )
+
+  return (
+    <Dialog.Outer
+      control={control}
+      nativeOptions={{minHeight: height - insets.top}}>
+      <Dialog.Handle />
+      <ErrorBoundary renderError={renderErrorBoundary}>
+        <PostLanguagesSettingsDialogInner />
+      </ErrorBoundary>
+    </Dialog.Outer>
+  )
+}
+
+export function PostLanguagesSettingsDialogInner() {
+  const control = Dialog.useDialogContext()
+  const [headerHeight, setHeaderHeight] = useState(0)
+
+  const allowedLanguages = useMemo(() => {
+    const uniqueLanguagesMap = LANGUAGES.filter(lang => !!lang.code2).reduce(
+      (acc, lang) => {
+        acc[lang.code2] = lang
+        return acc
+      },
+      {} as Record<string, Language>,
+    )
+
+    return Object.values(uniqueLanguagesMap)
+  }, [])
+
+  const langPrefs = useLanguagePrefs()
+  const [checkedLanguagesCode2, setCheckedLanguagesCode2] = useState<string[]>(
+    langPrefs.postLanguage.split(',') || [langPrefs.primaryLanguage],
+  )
+  const [search, setSearch] = useState('')
+
+  const setLangPrefs = useLanguagePrefsApi()
+  const t = useTheme()
+  const {_} = useLingui()
+
+  const handleClose = () => {
+    control.close(() => {
+      let langsString = checkedLanguagesCode2.join(',')
+      if (!langsString) {
+        langsString = langPrefs.primaryLanguage
+      }
+      setLangPrefs.setPostLanguage(langsString)
+    })
+  }
+
+  // NOTE(@elijaharita): Displayed languages are split into 3 lists for
+  // ordering.
+  const displayedLanguages = useMemo(() => {
+    function mapCode2List(code2List: string[]) {
+      return code2List.map(code2 => LANGUAGES_MAP_CODE2[code2]).filter(Boolean)
+    }
+
+    // NOTE(@elijaharita): Get recent language codes and map them to language
+    // objects. Both the user account's saved language history and the current
+    // checked languages are displayed here.
+    const recentLanguagesCode2 =
+      Array.from(
+        new Set([...checkedLanguagesCode2, ...langPrefs.postLanguageHistory]),
+      ).slice(0, 5) || []
+    const recentLanguages = mapCode2List(recentLanguagesCode2)
+
+    // NOTE(@elijaharita): helper functions
+    const matchesSearch = (lang: Language) =>
+      lang.name.toLowerCase().includes(search.toLowerCase())
+    const isChecked = (lang: Language) =>
+      checkedLanguagesCode2.includes(lang.code2)
+    const isInRecents = (lang: Language) =>
+      recentLanguagesCode2.includes(lang.code2)
+
+    const checkedRecent = recentLanguages.filter(isChecked)
+
+    if (search) {
+      // NOTE(@elijaharita): if a search is active, we ALWAYS show checked
+      // items, as well as any items that match the search.
+      const uncheckedRecent = recentLanguages
+        .filter(lang => !isChecked(lang))
+        .filter(matchesSearch)
+      const unchecked = allowedLanguages.filter(lang => !isChecked(lang))
+      const all = unchecked
+        .filter(matchesSearch)
+        .filter(lang => !isInRecents(lang))
+
+      return {
+        all,
+        checkedRecent,
+        uncheckedRecent,
+      }
+    } else {
+      // NOTE(@elijaharita): if no search is active, we show everything.
+      const uncheckedRecent = recentLanguages.filter(lang => !isChecked(lang))
+      const all = allowedLanguages
+        .filter(lang => !recentLanguagesCode2.includes(lang.code2))
+        .filter(lang => !isInRecents(lang))
+
+      return {
+        all,
+        checkedRecent,
+        uncheckedRecent,
+      }
+    }
+  }, [
+    allowedLanguages,
+    search,
+    langPrefs.postLanguageHistory,
+    checkedLanguagesCode2,
+  ])
+
+  const listHeader = (
+    <View
+      style={[a.pb_xs, t.atoms.bg, isNative && a.pt_2xl]}
+      onLayout={evt => setHeaderHeight(evt.nativeEvent.layout.height)}>
+      <View style={[a.flex_row, a.w_full, a.justify_between]}>
+        <View>
+          <Text
+            nativeID="dialog-title"
+            style={[
+              t.atoms.text,
+              a.text_left,
+              a.font_bold,
+              a.text_xl,
+              a.mb_sm,
+            ]}>
+            <Trans>Choose Post Languages</Trans>
+          </Text>
+          <Text
+            nativeID="dialog-description"
+            style={[
+              t.atoms.text_contrast_medium,
+              a.text_left,
+              a.text_md,
+              a.mb_lg,
+            ]}>
+            <Trans>Select up to 3 languages used in this post</Trans>
+          </Text>
+        </View>
+
+        {isWeb && (
+          <Button
+            variant="ghost"
+            size="small"
+            color="secondary"
+            shape="round"
+            label={_(msg`Close dialog`)}
+            onPress={handleClose}>
+            <ButtonIcon icon={XIcon} />
+          </Button>
+        )}
+      </View>
+
+      <View style={[a.w_full, a.flex_row, a.align_stretch, a.gap_xs, a.pb_0]}>
+        <SearchInput
+          value={search}
+          onChangeText={setSearch}
+          placeholder={_(msg`Search languages`)}
+          label={_(msg`Search languages`)}
+          maxLength={50}
+          onClearText={() => setSearch('')}
+        />
+      </View>
+    </View>
+  )
+
+  const isCheckedRecentEmpty =
+    displayedLanguages.checkedRecent.length > 0 ||
+    displayedLanguages.uncheckedRecent.length > 0
+
+  const isDisplayedLanguagesEmpty = displayedLanguages.all.length === 0
+
+  const flatListData = [
+    ...(isCheckedRecentEmpty
+      ? [{type: 'header', label: _(msg`Recently used`)}]
+      : []),
+    ...displayedLanguages.checkedRecent.map(lang => ({type: 'item', lang})),
+    ...displayedLanguages.uncheckedRecent.map(lang => ({type: 'item', lang})),
+    ...(isDisplayedLanguagesEmpty
+      ? []
+      : [{type: 'header', label: _(msg`All languages`)}]),
+    ...displayedLanguages.all.map(lang => ({type: 'item', lang})),
+  ]
+
+  return (
+    <Toggle.Group
+      values={checkedLanguagesCode2}
+      onChange={setCheckedLanguagesCode2}
+      type="checkbox"
+      maxSelections={3}
+      label={_(msg`Select languages`)}
+      style={web([a.contents])}>
+      <Dialog.InnerFlatList
+        data={flatListData}
+        ListHeaderComponent={listHeader}
+        stickyHeaderIndices={[0]}
+        contentContainerStyle={[a.gap_0]}
+        style={[isNative && a.px_lg, web({paddingBottom: 120})]}
+        scrollIndicatorInsets={{top: headerHeight}}
+        renderItem={({item, index}) => {
+          if (item.type === 'header') {
+            return (
+              <Text
+                key={index}
+                style={[
+                  a.px_0,
+                  a.py_md,
+                  a.font_bold,
+                  a.text_xs,
+                  t.atoms.text_contrast_low,
+                  a.pt_3xl,
+                ]}>
+                {item.label}
+              </Text>
+            )
+          }
+          const lang = item.lang
+
+          return (
+            <Toggle.Item
+              key={lang.code2}
+              name={lang.code2}
+              label={languageName(lang, langPrefs.appLanguage)}
+              style={[
+                t.atoms.border_contrast_low,
+                a.border_b,
+                a.rounded_0,
+                a.px_0,
+                a.py_md,
+              ]}>
+              <Toggle.LabelText style={[a.flex_1]}>
+                {languageName(lang, langPrefs.appLanguage)}
+              </Toggle.LabelText>
+              <Toggle.Checkbox />
+            </Toggle.Item>
+          )
+        }}
+        footer={
+          <Dialog.FlatListFooter>
+            <Button
+              label={_(msg`Close dialog`)}
+              onPress={handleClose}
+              color="primary"
+              size="large">
+              <ButtonText>
+                <Trans>Done</Trans>
+              </ButtonText>
+            </Button>
+          </Dialog.FlatListFooter>
+        }
+      />
+    </Toggle.Group>
+  )
+}
+
+function DialogError({details}: {details?: string}) {
+  const {_} = useLingui()
+  const control = Dialog.useDialogContext()
+
+  return (
+    <Dialog.ScrollableInner
+      style={a.gap_md}
+      label={_(msg`An error has occurred`)}>
+      <Dialog.Close />
+      <ErrorScreen
+        title={_(msg`Oh no!`)}
+        message={_(
+          msg`There was an unexpected issue in the application. Please let us know if this happened to you!`,
+        )}
+        details={details}
+      />
+      <Button
+        label={_(msg`Close dialog`)}
+        onPress={() => control.close()}
+        color="primary"
+        size="large">
+        <ButtonText>
+          <Trans>Close</Trans>
+        </ButtonText>
+      </Button>
+    </Dialog.ScrollableInner>
+  )
+}
diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx
index 5e188ee06..80ff15768 100644
--- a/src/view/com/modals/DeleteAccount.tsx
+++ b/src/view/com/modals/DeleteAccount.tsx
@@ -10,6 +10,7 @@ import {LinearGradient} from 'expo-linear-gradient'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {cleanError} from '#/lib/strings/errors'
@@ -17,7 +18,6 @@ import {colors, gradients, s} from '#/lib/styles'
 import {useTheme} from '#/lib/ThemeContext'
 import {isAndroid, isWeb} from '#/platform/detection'
 import {useModalControls} from '#/state/modals'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {useAgent, useSession, useSessionApi} from '#/state/session'
 import {atoms as a, useTheme as useNewTheme} from '#/alf'
 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index c3628f939..79971e660 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -11,7 +11,6 @@ import * as CreateOrEditListModal from './CreateOrEditList'
 import * as DeleteAccountModal from './DeleteAccount'
 import * as InviteCodesModal from './InviteCodes'
 import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
-import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
 import * as UserAddRemoveListsModal from './UserAddRemoveLists'
 
 const DEFAULT_SNAPPOINTS = ['90%']
@@ -60,9 +59,6 @@ export function ModalsContainer() {
   } else if (activeModal?.name === 'content-languages-settings') {
     snapPoints = ContentLanguagesSettingsModal.snapPoints
     element = <ContentLanguagesSettingsModal.Component />
-  } else if (activeModal?.name === 'post-languages-settings') {
-    snapPoints = PostLanguagesSettingsModal.snapPoints
-    element = <PostLanguagesSettingsModal.Component />
   } else {
     return null
   }
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 08f0e2f85..d0799a390 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -10,7 +10,6 @@ import * as CreateOrEditListModal from './CreateOrEditList'
 import * as DeleteAccountModal from './DeleteAccount'
 import * as InviteCodesModal from './InviteCodes'
 import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
-import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
 import * as UserAddRemoveLists from './UserAddRemoveLists'
 
 export function ModalsContainer() {
@@ -59,8 +58,6 @@ function Modal({modal}: {modal: ModalIface}) {
     element = <InviteCodesModal.Component />
   } else if (modal.name === 'content-languages-settings') {
     element = <ContentLanguagesSettingsModal.Component />
-  } else if (modal.name === 'post-languages-settings') {
-    element = <PostLanguagesSettingsModal.Component />
   } else {
     return null
   }
diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
deleted file mode 100644
index 8c2969674..000000000
--- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
-import {Trans} from '@lingui/macro'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {deviceLanguageCodes} from '#/locale/deviceLocales'
-import {languageName} from '#/locale/helpers'
-import {useModalControls} from '#/state/modals'
-import {
-  hasPostLanguage,
-  useLanguagePrefs,
-  useLanguagePrefsApi,
-} from '#/state/preferences/languages'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
-import {Text} from '../../util/text/Text'
-import {ScrollView} from '../util'
-import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
-
-export const snapPoints = ['100%']
-
-export function Component() {
-  const {closeModal} = useModalControls()
-  const langPrefs = useLanguagePrefs()
-  const setLangPrefs = useLanguagePrefsApi()
-  const pal = usePalette('default')
-  const {isMobile} = useWebMediaQueries()
-  const onPressDone = React.useCallback(() => {
-    closeModal()
-  }, [closeModal])
-
-  const languages = React.useMemo(() => {
-    const langs = LANGUAGES.filter(
-      lang =>
-        !!lang.code2.trim() &&
-        LANGUAGES_MAP_CODE2[lang.code2].code3 === lang.code3,
-    )
-    // sort so that device & selected languages are on top, then alphabetically
-    langs.sort((a, b) => {
-      const hasA =
-        hasPostLanguage(langPrefs.postLanguage, a.code2) ||
-        deviceLanguageCodes.includes(a.code2)
-      const hasB =
-        hasPostLanguage(langPrefs.postLanguage, b.code2) ||
-        deviceLanguageCodes.includes(b.code2)
-      if (hasA === hasB) return a.name.localeCompare(b.name)
-      if (hasA) return -1
-      return 1
-    })
-    return langs
-  }, [langPrefs])
-
-  const onPress = React.useCallback(
-    (code2: string) => {
-      setLangPrefs.togglePostLanguage(code2)
-    },
-    [setLangPrefs],
-  )
-
-  return (
-    <View
-      testID="postLanguagesModal"
-      style={[
-        pal.view,
-        styles.container,
-        // @ts-ignore vh is on web only
-        isMobile
-          ? {
-              paddingTop: 20,
-            }
-          : {
-              maxHeight: '90vh',
-            },
-      ]}>
-      <Text style={[pal.text, styles.title]}>
-        <Trans>Post Languages</Trans>
-      </Text>
-      <Text style={[pal.text, styles.description]}>
-        <Trans>Which languages are used in this post?</Trans>
-      </Text>
-      <ScrollView style={styles.scrollContainer}>
-        {languages.map(lang => {
-          const isSelected = hasPostLanguage(langPrefs.postLanguage, lang.code2)
-
-          // enforce a max of 3 selections for post languages
-          let isDisabled = false
-          if (langPrefs.postLanguage.split(',').length >= 3 && !isSelected) {
-            isDisabled = true
-          }
-
-          return (
-            <ToggleButton
-              key={lang.code2}
-              label={languageName(lang, langPrefs.appLanguage)}
-              isSelected={isSelected}
-              onPress={() => (isDisabled ? undefined : onPress(lang.code2))}
-              style={[
-                pal.border,
-                styles.languageToggle,
-                isDisabled && styles.dimmed,
-              ]}
-            />
-          )
-        })}
-        <View
-          style={{
-            height: isMobile ? 60 : 0,
-          }}
-        />
-      </ScrollView>
-      <ConfirmLanguagesButton onPress={onPressDone} />
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-  },
-  title: {
-    textAlign: 'center',
-    fontWeight: '600',
-    fontSize: 24,
-    marginBottom: 12,
-  },
-  description: {
-    textAlign: 'center',
-    paddingHorizontal: 16,
-    marginBottom: 10,
-  },
-  scrollContainer: {
-    flex: 1,
-    paddingHorizontal: 10,
-  },
-  languageToggle: {
-    borderTopWidth: 1,
-    borderRadius: 0,
-    paddingHorizontal: 6,
-    paddingVertical: 12,
-  },
-  dimmed: {
-    opacity: 0.5,
-  },
-})
diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx
index dc048bd26..ce774e888 100644
--- a/src/view/com/notifications/NotificationFeedItem.tsx
+++ b/src/view/com/notifications/NotificationFeedItem.tsx
@@ -31,6 +31,7 @@ import {useNavigation} from '@react-navigation/native'
 import {useQueryClient} from '@tanstack/react-query'
 
 import {MAX_POST_LINES} from '#/lib/constants'
+import {DM_SERVICE_HEADERS} from '#/lib/constants'
 import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {makeProfileLink} from '#/lib/routes/links'
@@ -41,7 +42,6 @@ import {sanitizeHandle} from '#/lib/strings/handles'
 import {niceDate} from '#/lib/strings/time'
 import {s} from '#/lib/styles'
 import {logger} from '#/logger'
-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
 import {type FeedNotification} from '#/state/queries/notifications/feed'
 import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
 import {useAgent} from '#/state/session'
diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx
deleted file mode 100644
index e20dadb49..000000000
--- a/src/view/com/util/forms/DropdownButton.tsx
+++ /dev/null
@@ -1,397 +0,0 @@
-import {type PropsWithChildren} from 'react'
-import {useMemo, useRef} from 'react'
-import {
-  Dimensions,
-  type GestureResponderEvent,
-  type Insets,
-  type StyleProp,
-  StyleSheet,
-  TouchableOpacity,
-  TouchableWithoutFeedback,
-  useWindowDimensions,
-  View,
-  type ViewStyle,
-} from 'react-native'
-import Animated, {FadeIn, FadeInDown, FadeInUp} from 'react-native-reanimated'
-import RootSiblings from 'react-native-root-siblings'
-import {type IconProp} from '@fortawesome/fontawesome-svg-core'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import type React from 'react'
-
-import {HITSLOP_10} from '#/lib/constants'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {colors} from '#/lib/styles'
-import {useTheme} from '#/lib/ThemeContext'
-import {isWeb} from '#/platform/detection'
-import {native} from '#/alf'
-import {FullWindowOverlay} from '#/components/FullWindowOverlay'
-import {Text} from '../text/Text'
-import {Button, type ButtonType} from './Button'
-
-const ESTIMATED_BTN_HEIGHT = 50
-const ESTIMATED_SEP_HEIGHT = 16
-const ESTIMATED_HEADING_HEIGHT = 60
-
-export interface DropdownItemButton {
-  testID?: string
-  icon?: IconProp
-  label: string
-  onPress: () => void
-}
-export interface DropdownItemSeparator {
-  sep: true
-}
-export interface DropdownItemHeading {
-  heading: true
-  label: string
-}
-export type DropdownItem =
-  | DropdownItemButton
-  | DropdownItemSeparator
-  | DropdownItemHeading
-type MaybeDropdownItem = DropdownItem | false | undefined
-
-export type DropdownButtonType = ButtonType | 'bare'
-
-interface DropdownButtonProps {
-  testID?: string
-  type?: DropdownButtonType
-  style?: StyleProp<ViewStyle>
-  items: MaybeDropdownItem[]
-  label?: string
-  menuWidth?: number
-  children?: React.ReactNode
-  openToRight?: boolean
-  openUpwards?: boolean
-  rightOffset?: number
-  bottomOffset?: number
-  hitSlop?: Insets
-  accessibilityLabel?: string
-  accessibilityHint?: string
-}
-
-/**
- * @deprecated use Menu from `#/components/Menu.tsx` instead
- */
-export function DropdownButton({
-  testID,
-  type = 'bare',
-  style,
-  items,
-  label,
-  menuWidth,
-  children,
-  openToRight = false,
-  openUpwards = false,
-  rightOffset = 0,
-  bottomOffset = 0,
-  hitSlop = HITSLOP_10,
-  accessibilityLabel,
-}: PropsWithChildren<DropdownButtonProps>) {
-  const {_} = useLingui()
-
-  const ref1 = useRef<View>(null)
-  const ref2 = useRef<View>(null)
-
-  const onPress = (e: GestureResponderEvent) => {
-    const ref = ref1.current || ref2.current
-    const {height: winHeight} = Dimensions.get('window')
-    const pressY = e.nativeEvent.pageY
-    ref?.measure(
-      (
-        _x: number,
-        _y: number,
-        width: number,
-        _height: number,
-        pageX: number,
-        pageY: number,
-      ) => {
-        if (!menuWidth) {
-          menuWidth = 200
-        }
-        let estimatedMenuHeight = 0
-        for (const item of items) {
-          if (item && isSep(item)) {
-            estimatedMenuHeight += ESTIMATED_SEP_HEIGHT
-          } else if (item && isBtn(item)) {
-            estimatedMenuHeight += ESTIMATED_BTN_HEIGHT
-          } else if (item && isHeading(item)) {
-            estimatedMenuHeight += ESTIMATED_HEADING_HEIGHT
-          }
-        }
-        const newX = openToRight
-          ? pageX + width + rightOffset
-          : pageX + width - menuWidth
-
-        // Add a bit of additional room
-        let newY = pressY + bottomOffset + 20
-        if (openUpwards || newY + estimatedMenuHeight > winHeight) {
-          newY -= estimatedMenuHeight
-        }
-        createDropdownMenu(
-          newX,
-          newY,
-          pageY,
-          menuWidth,
-          items.filter(v => !!v) as DropdownItem[],
-          openUpwards,
-        )
-      },
-    )
-  }
-
-  const numItems = useMemo(
-    () =>
-      items.filter(item => {
-        if (item === undefined || item === false) {
-          return false
-        }
-
-        return isBtn(item)
-      }).length,
-    [items],
-  )
-
-  if (type === 'bare') {
-    return (
-      <TouchableOpacity
-        testID={testID}
-        style={style}
-        onPress={onPress}
-        hitSlop={hitSlop}
-        ref={ref1}
-        accessibilityRole="button"
-        accessibilityLabel={
-          accessibilityLabel || _(msg`Opens ${numItems} options`)
-        }
-        accessibilityHint="">
-        {children}
-      </TouchableOpacity>
-    )
-  }
-  return (
-    <View ref={ref2}>
-      <Button
-        type={type}
-        testID={testID}
-        onPress={onPress}
-        style={style}
-        label={label}>
-        {children}
-      </Button>
-    </View>
-  )
-}
-
-function createDropdownMenu(
-  x: number,
-  y: number,
-  pageY: number,
-  width: number,
-  items: DropdownItem[],
-  opensUpwards = false,
-): RootSiblings {
-  const onPressItem = (index: number) => {
-    sibling.destroy()
-    const item = items[index]
-    if (isBtn(item)) {
-      item.onPress()
-    }
-  }
-  const onOuterPress = () => sibling.destroy()
-  const sibling = new RootSiblings(
-    (
-      <DropdownItems
-        onOuterPress={onOuterPress}
-        x={x}
-        y={y}
-        pageY={pageY}
-        width={width}
-        items={items}
-        onPressItem={onPressItem}
-        openUpwards={opensUpwards}
-      />
-    ),
-  )
-  return sibling
-}
-
-type DropDownItemProps = {
-  onOuterPress: () => void
-  x: number
-  y: number
-  pageY: number
-  width: number
-  items: DropdownItem[]
-  onPressItem: (index: number) => void
-  openUpwards: boolean
-}
-
-const DropdownItems = ({
-  onOuterPress,
-  x,
-  y,
-  pageY,
-  width,
-  items,
-  onPressItem,
-  openUpwards,
-}: DropDownItemProps) => {
-  const pal = usePalette('default')
-  const theme = useTheme()
-  const {_} = useLingui()
-  const {height: screenHeight} = useWindowDimensions()
-  const dropDownBackgroundColor =
-    theme.colorScheme === 'dark' ? pal.btn : pal.view
-  const separatorColor =
-    theme.colorScheme === 'dark' ? pal.borderDark : pal.border
-
-  const numItems = items.filter(isBtn).length
-
-  // TODO: Refactor dropdown components to:
-  // - (On web, if not handled by React Native) use semantic <select />
-  // and <option /> elements for keyboard navigation out of the box
-  // - (On mobile) be buttons by default, accept `label` and `nativeID`
-  // props, and always have an explicit label
-  return (
-    <FullWindowOverlay>
-      {/* This TouchableWithoutFeedback renders the background so if the user clicks outside, the dropdown closes */}
-      <TouchableWithoutFeedback
-        onPress={onOuterPress}
-        accessibilityLabel={_(msg`Toggle dropdown`)}
-        accessibilityHint="">
-        <Animated.View
-          entering={FadeIn}
-          style={[
-            styles.bg,
-            // On web we need to adjust the top and bottom relative to the scroll position
-            isWeb
-              ? {
-                  top: -pageY,
-                  bottom: pageY - screenHeight,
-                }
-              : {
-                  top: 0,
-                  bottom: 0,
-                },
-          ]}
-        />
-      </TouchableWithoutFeedback>
-      <Animated.View
-        entering={native(
-          openUpwards ? FadeInDown.springify(1000) : FadeInUp.springify(1000),
-        )}
-        style={[
-          styles.menu,
-          {left: x, top: y, width},
-          dropDownBackgroundColor,
-        ]}>
-        {items.map((item, index) => {
-          if (isBtn(item)) {
-            return (
-              <TouchableOpacity
-                testID={item.testID}
-                key={index}
-                style={[styles.menuItem]}
-                onPress={() => onPressItem(index)}
-                accessibilityRole="button"
-                accessibilityLabel={item.label}
-                accessibilityHint={_(
-                  msg`Selects option ${index + 1} of ${numItems}`,
-                )}>
-                {item.icon && (
-                  <FontAwesomeIcon
-                    style={styles.icon}
-                    icon={item.icon}
-                    color={pal.text.color as string}
-                  />
-                )}
-                <Text style={[styles.label, pal.text]}>{item.label}</Text>
-              </TouchableOpacity>
-            )
-          } else if (isSep(item)) {
-            return (
-              <View key={index} style={[styles.separator, separatorColor]} />
-            )
-          } else if (isHeading(item)) {
-            return (
-              <View style={[styles.heading, pal.border]} key={index}>
-                <Text style={[pal.text, styles.headingLabel]}>
-                  {item.label}
-                </Text>
-              </View>
-            )
-          }
-          return null
-        })}
-      </Animated.View>
-    </FullWindowOverlay>
-  )
-}
-
-function isSep(item: DropdownItem): item is DropdownItemSeparator {
-  return 'sep' in item && item.sep
-}
-function isHeading(item: DropdownItem): item is DropdownItemHeading {
-  return 'heading' in item && item.heading
-}
-function isBtn(item: DropdownItem): item is DropdownItemButton {
-  return !isSep(item) && !isHeading(item)
-}
-
-const styles = StyleSheet.create({
-  bg: {
-    position: 'absolute',
-    left: 0,
-    width: '100%',
-    backgroundColor: 'rgba(0, 0, 0, 0.1)',
-  },
-  menu: {
-    position: 'absolute',
-    backgroundColor: '#fff',
-    borderRadius: 14,
-    paddingVertical: 6,
-  },
-  menuItem: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingVertical: 10,
-    paddingLeft: 15,
-    paddingRight: 40,
-  },
-  menuItemBorder: {
-    borderTopWidth: 1,
-    borderTopColor: colors.gray1,
-    marginTop: 4,
-    paddingTop: 12,
-  },
-  icon: {
-    marginLeft: 2,
-    marginRight: 8,
-    flexShrink: 0,
-  },
-  label: {
-    fontSize: 18,
-    flexShrink: 1,
-    flexGrow: 1,
-  },
-  separator: {
-    borderTopWidth: 1,
-    marginVertical: 8,
-  },
-  heading: {
-    flexDirection: 'row',
-    justifyContent: 'center',
-    paddingVertical: 10,
-    paddingLeft: 15,
-    paddingRight: 20,
-    borderBottomWidth: 1,
-    marginBottom: 6,
-  },
-  headingLabel: {
-    fontSize: 18,
-    fontWeight: '600',
-  },
-})
diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx
index 1a236f8bc..8b81cee10 100644
--- a/src/view/screens/Debug.tsx
+++ b/src/view/screens/Debug.tsx
@@ -4,17 +4,16 @@ import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
 import {usePalette} from '#/lib/hooks/usePalette'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
+import {
+  type CommonNavigatorParams,
+  type NativeStackScreenProps,
+} from '#/lib/routes/types'
 import {s} from '#/lib/styles'
-import {PaletteColorName, ThemeProvider} from '#/lib/ThemeContext'
+import {type PaletteColorName, ThemeProvider} from '#/lib/ThemeContext'
 import {EmptyState} from '#/view/com/util/EmptyState'
 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
 import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
 import {Button} from '#/view/com/util/forms/Button'
-import {
-  DropdownButton,
-  DropdownItem,
-} from '#/view/com/util/forms/DropdownButton'
 import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
 import * as LoadingPlaceholder from '#/view/com/util/LoadingPlaceholder'
 import {Text} from '#/view/com/util/text/Text'
@@ -134,8 +133,6 @@ function ControlsView() {
     <ScrollView style={[s.pl10, s.pr10]}>
       <Heading label="Buttons" />
       <ButtonsView />
-      <Heading label="Dropdown Buttons" />
-      <DropdownButtonsView />
       <Heading label="Toggle Buttons" />
       <ToggleButtonsView />
       <View style={s.footerSpacer} />
@@ -396,44 +393,6 @@ function ButtonsView() {
   )
 }
 
-const DROPDOWN_ITEMS: DropdownItem[] = [
-  {
-    icon: ['far', 'paste'],
-    label: 'Copy post text',
-    onPress() {},
-  },
-  {
-    icon: 'share',
-    label: 'Share...',
-    onPress() {},
-  },
-  {
-    icon: 'circle-exclamation',
-    label: 'Report post',
-    onPress() {},
-  },
-]
-function DropdownButtonsView() {
-  const defaultPal = usePalette('default')
-  return (
-    <View style={[defaultPal.view]}>
-      <View style={s.mb5}>
-        <DropdownButton
-          type="primary"
-          items={DROPDOWN_ITEMS}
-          menuWidth={200}
-          label="Primary button"
-        />
-      </View>
-      <View style={s.mb5}>
-        <DropdownButton type="bare" items={DROPDOWN_ITEMS} menuWidth={200}>
-          <Text>Bare</Text>
-        </DropdownButton>
-      </View>
-    </View>
-  )
-}
-
 function ToggleButtonsView() {
   const defaultPal = usePalette('default')
   const buttonStyles = s.mb5
diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx
index 319f88e21..91fe0d970 100644
--- a/src/view/screens/Storybook/Toasts.tsx
+++ b/src/view/screens/Storybook/Toasts.tsx
@@ -4,12 +4,28 @@ import {show as deprecatedShow} from '#/view/com/util/Toast'
 import {atoms as a} from '#/alf'
 import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
 import * as Toast from '#/components/Toast'
-import {Default} from '#/components/Toast/Toast'
 import {H1} from '#/components/Typography'
 
-function ToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
+function DefaultToast({
+  content,
+  type = 'default',
+}: {
+  content: string
+  type?: Toast.ToastType
+}) {
   return (
-    <Toast.Outer type={type}>
+    <Toast.ToastConfigProvider id="default-toast" type={type}>
+      <Toast.Outer>
+        <Toast.Icon icon={GlobeIcon} />
+        <Toast.Text>{content}</Toast.Text>
+      </Toast.Outer>
+    </Toast.ToastConfigProvider>
+  )
+}
+
+function ToastWithAction() {
+  return (
+    <Toast.Outer>
       <Toast.Icon icon={GlobeIcon} />
       <Toast.Text>This toast has an action button</Toast.Text>
       <Toast.Action
@@ -21,9 +37,9 @@ function ToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
   )
 }
 
-function LongToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
+function LongToastWithAction() {
   return (
-    <Toast.Outer type={type}>
+    <Toast.Outer>
       <Toast.Icon icon={GlobeIcon} />
       <Toast.Text>
         This is a longer message to test how the toast handles multiple lines of
@@ -44,33 +60,25 @@ export function Toasts() {
       <H1>Toast Examples</H1>
 
       <View style={[a.gap_md]}>
-        <View style={[a.gap_md, {marginHorizontal: a.px_xl.paddingLeft * -1}]}>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction />)}>
-            <ToastWithAction />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<LongToastWithAction />)}>
-            <LongToastWithAction />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction type="success" />)}>
-            <ToastWithAction type="success" />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction type="error" />)}>
-            <ToastWithAction type="error" />
-          </Pressable>
-        </View>
-
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<ToastWithAction />, {type: 'success'})}>
+          <ToastWithAction />
+        </Pressable>
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<ToastWithAction />, {type: 'error'})}>
+          <ToastWithAction />
+        </Pressable>
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<LongToastWithAction />)}>
+          <LongToastWithAction />
+        </Pressable>
         <Pressable
           accessibilityRole="button"
           onPress={() => Toast.show(`Hey I'm a toast!`)}>
-          <Default content="Hey I'm a toast!" />
+          <DefaultToast content="Hey I'm a toast!" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -79,7 +87,7 @@ export function Toasts() {
               duration: 6e3,
             })
           }>
-          <Default content="This toast will disappear after 6 seconds" />
+          <DefaultToast content="This toast will disappear after 6 seconds" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -88,7 +96,7 @@ export function Toasts() {
               `This is a longer message to test how the toast handles multiple lines of text content.`,
             )
           }>
-          <Default content="This is a longer message to test how the toast handles multiple lines of text content." />
+          <DefaultToast content="This is a longer message to test how the toast handles multiple lines of text content." />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -97,7 +105,7 @@ export function Toasts() {
               type: 'success',
             })
           }>
-          <Default content="Success! Yayyyyyyy :)" type="success" />
+          <DefaultToast content="Success! Yayyyyyyy :)" type="success" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -106,7 +114,7 @@ export function Toasts() {
               type: 'info',
             })
           }>
-          <Default content="I'm providing info!" type="info" />
+          <DefaultToast content="I'm providing info!" type="info" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -115,7 +123,7 @@ export function Toasts() {
               type: 'warning',
             })
           }>
-          <Default content="This is a warning toast" type="warning" />
+          <DefaultToast content="This is a warning toast" type="warning" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -124,7 +132,7 @@ export function Toasts() {
               type: 'error',
             })
           }>
-          <Default content="This is an error toast :(" type="error" />
+          <DefaultToast content="This is an error toast :(" type="error" />
         </Pressable>
 
         <Pressable
@@ -135,7 +143,7 @@ export function Toasts() {
               'exclamation-circle',
             )
           }>
-          <Default
+          <DefaultToast
             content="This is a test of the deprecated API"
             type="warning"
           />