about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/auth/onboarding/WelcomeDesktop.tsx4
-rw-r--r--src/view/com/auth/onboarding/WelcomeMobile.tsx3
-rw-r--r--src/view/com/composer/Composer.tsx36
-rw-r--r--src/view/com/composer/Prompt.tsx5
-rw-r--r--src/view/com/composer/photos/Gallery.tsx11
-rw-r--r--src/view/com/lists/ListItems.tsx12
-rw-r--r--src/view/com/modals/AddAppPasswords.tsx4
-rw-r--r--src/view/com/modals/AltImage.tsx8
-rw-r--r--src/view/com/modals/Confirm.tsx4
-rw-r--r--src/view/com/modals/ContentFilteringSettings.tsx22
-rw-r--r--src/view/com/modals/CreateOrEditMuteList.tsx13
-rw-r--r--src/view/com/modals/DeleteAccount.tsx5
-rw-r--r--src/view/com/modals/EditImage.tsx35
-rw-r--r--src/view/com/modals/InviteCodes.tsx4
-rw-r--r--src/view/com/modals/ListAddRemoveUser.tsx4
-rw-r--r--src/view/com/modals/Modal.web.tsx5
-rw-r--r--src/view/com/modals/ModerationDetails.tsx19
-rw-r--r--src/view/com/modals/SelfLabel.tsx18
-rw-r--r--src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx15
-rw-r--r--src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx28
-rw-r--r--src/view/com/modals/lang-settings/PostLanguagesSettings.tsx28
-rw-r--r--src/view/com/modals/report/InputIssueDetails.tsx11
-rw-r--r--src/view/com/modals/report/Modal.tsx29
-rw-r--r--src/view/com/pager/FeedsTabBar.web.tsx4
-rw-r--r--src/view/com/pager/TabBar.tsx93
-rw-r--r--src/view/com/post-thread/PostThread.tsx39
-rw-r--r--src/view/com/posts/MultiFeed.tsx68
-rw-r--r--src/view/com/profile/ProfileHeader.tsx6
-rw-r--r--src/view/com/search/HeaderWithInput.tsx19
-rw-r--r--src/view/com/search/SearchResults.tsx16
-rw-r--r--src/view/com/util/ViewHeader.tsx19
-rw-r--r--src/view/com/util/Views.web.tsx11
-rw-r--r--src/view/com/util/fab/FABInner.tsx48
-rw-r--r--src/view/com/util/forms/SelectableBtn.tsx12
-rw-r--r--src/view/com/util/layouts/Breakpoints.web.tsx6
-rw-r--r--src/view/com/util/load-latest/LoadLatestBtn.web.tsx5
-rw-r--r--src/view/com/util/moderation/ContentHider.tsx5
-rw-r--r--src/view/com/util/moderation/PostHider.tsx10
-rw-r--r--src/view/com/util/moderation/ScreenHider.tsx5
-rw-r--r--src/view/com/util/post-embeds/ExternalLinkEmbed.tsx63
-rw-r--r--src/view/com/util/post-embeds/index.tsx19
41 files changed, 469 insertions, 302 deletions
diff --git a/src/view/com/auth/onboarding/WelcomeDesktop.tsx b/src/view/com/auth/onboarding/WelcomeDesktop.tsx
index e63693443..7b7555ace 100644
--- a/src/view/com/auth/onboarding/WelcomeDesktop.tsx
+++ b/src/view/com/auth/onboarding/WelcomeDesktop.tsx
@@ -16,9 +16,7 @@ type Props = {
 
 export const WelcomeDesktop = observer(({next}: Props) => {
   const pal = usePalette('default')
-  const horizontal = useMediaQuery({
-    query: '(min-width: 1230px)',
-  })
+  const horizontal = useMediaQuery({minWidth: 1300})
   const title = (
     <>
       <Text
diff --git a/src/view/com/auth/onboarding/WelcomeMobile.tsx b/src/view/com/auth/onboarding/WelcomeMobile.tsx
index eb72de836..0f627ad0b 100644
--- a/src/view/com/auth/onboarding/WelcomeMobile.tsx
+++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx
@@ -7,7 +7,6 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {Button} from 'view/com/util/forms/Button'
 import {observer} from 'mobx-react-lite'
 import {ViewHeader} from 'view/com/util/ViewHeader'
-import {isDesktopWeb} from 'platform/detection'
 
 type Props = {
   next: () => void
@@ -95,7 +94,7 @@ export const WelcomeMobile = observer(({next, skip}: Props) => {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    marginBottom: isDesktopWeb ? 30 : 60,
+    marginBottom: 60,
     marginHorizontal: 16,
     justifyContent: 'space-between',
   },
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index c801c47bf..8ed0bb378 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -37,9 +37,10 @@ import {toShortUrl} from 'lib/strings/url-helpers'
 import {SelectPhotoBtn} from './photos/SelectPhotoBtn'
 import {OpenCameraBtn} from './photos/OpenCameraBtn'
 import {usePalette} from 'lib/hooks/usePalette'
-import QuoteEmbed from '../util/post-embeds/QuoteEmbed'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useExternalLinkFetch} from './useExternalLinkFetch'
-import {isDesktopWeb, isAndroid, isIOS} from 'platform/detection'
+import {isWeb, isNative, isAndroid, isIOS} from 'platform/detection'
+import QuoteEmbed from '../util/post-embeds/QuoteEmbed'
 import {GalleryModel} from 'state/models/media/gallery'
 import {Gallery} from './photos/Gallery'
 import {MAX_GRAPHEME_LENGTH} from 'lib/constants'
@@ -61,6 +62,7 @@ export const ComposePost = observer(function ComposePost({
 }: Props) {
   const {track} = useAnalytics()
   const pal = usePalette('default')
+  const {isDesktop, isMobile} = useWebMediaQueries()
   const store = useStores()
   const textInput = useRef<TextInputRef>(null)
   const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
@@ -99,9 +101,9 @@ export const ComposePost = observer(function ComposePost({
     () => ({
       paddingBottom:
         isAndroid || (isIOS && !isKeyboardVisible) ? insets.bottom : 0,
-      paddingTop: isAndroid ? insets.top : isDesktopWeb ? 0 : 15,
+      paddingTop: isAndroid ? insets.top : isMobile ? 15 : 0,
     }),
-    [insets, isKeyboardVisible],
+    [insets, isKeyboardVisible, isMobile],
   )
 
   const onPressCancel = useCallback(() => {
@@ -143,7 +145,7 @@ export const ComposePost = observer(function ComposePost({
     [onPressCancel],
   )
   useEffect(() => {
-    if (isDesktopWeb) {
+    if (isWeb) {
       window.addEventListener('keydown', onEscape)
       return () => window.removeEventListener('keydown', onEscape)
     }
@@ -240,7 +242,7 @@ export const ComposePost = observer(function ComposePost({
       behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
       style={styles.outer}>
       <View style={[s.flex1, viewStyles]} aria-modal accessibilityViewIsModal>
-        <View style={styles.topbar}>
+        <View style={[styles.topbar, isDesktop && styles.topbarDesktop]}>
           <TouchableOpacity
             testID="composerDiscardButton"
             onPress={onPressCancel}
@@ -334,7 +336,12 @@ export const ComposePost = observer(function ComposePost({
             </View>
           ) : undefined}
 
-          <View style={[pal.border, styles.textInputLayout]}>
+          <View
+            style={[
+              pal.border,
+              styles.textInputLayout,
+              isNative && styles.textInputLayoutMobile,
+            ]}>
             <UserAvatar avatar={store.me.avatar} size={50} />
             <TextInput
               ref={textInput}
@@ -362,7 +369,7 @@ export const ComposePost = observer(function ComposePost({
             />
           )}
           {quote ? (
-            <View style={s.mt5}>
+            <View style={[s.mt5, isWeb && s.mb10]}>
               <QuoteEmbed quote={quote} />
             </View>
           ) : undefined}
@@ -395,7 +402,7 @@ export const ComposePost = observer(function ComposePost({
               <OpenCameraBtn gallery={gallery} />
             </>
           ) : null}
-          {isDesktopWeb ? <EmojiPickerButton /> : null}
+          {isDesktop ? <EmojiPickerButton /> : null}
           <View style={s.flex1} />
           <SelectLangBtn />
           <CharProgress count={graphemeLength} />
@@ -414,11 +421,14 @@ const styles = StyleSheet.create({
   topbar: {
     flexDirection: 'row',
     alignItems: 'center',
-    paddingTop: isDesktopWeb ? 10 : undefined,
-    paddingBottom: isDesktopWeb ? 10 : 4,
+    paddingBottom: 4,
     paddingHorizontal: 20,
     height: 55,
   },
+  topbarDesktop: {
+    paddingTop: 10,
+    paddingBottom: 10,
+  },
   postBtn: {
     borderRadius: 20,
     paddingHorizontal: 20,
@@ -465,11 +475,13 @@ const styles = StyleSheet.create({
     paddingHorizontal: 15,
   },
   textInputLayout: {
-    flex: isDesktopWeb ? undefined : 1,
     flexDirection: 'row',
     borderTopWidth: 1,
     paddingTop: 16,
   },
+  textInputLayoutMobile: {
+    flex: 1,
+  },
   replyToLayout: {
     flexDirection: 'row',
     borderTopWidth: 1,
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
index 98a10b0f5..01fd7d1fa 100644
--- a/src/view/com/composer/Prompt.tsx
+++ b/src/view/com/composer/Prompt.tsx
@@ -4,11 +4,12 @@ import {UserAvatar} from '../util/UserAvatar'
 import {Text} from '../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useStores} from 'state/index'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isDesktop} = useWebMediaQueries()
   return (
     <TouchableOpacity
       testID="replyPromptBtn"
@@ -22,7 +23,7 @@ export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
         type="xl"
         style={[
           pal.text,
-          isDesktopWeb ? styles.labelDesktopWeb : styles.labelMobile,
+          isDesktop ? styles.labelDesktopWeb : styles.labelMobile,
         ]}>
         Write your reply
       </Text>
diff --git a/src/view/com/composer/photos/Gallery.tsx b/src/view/com/composer/photos/Gallery.tsx
index 6dba2f011..d5465f79a 100644
--- a/src/view/com/composer/photos/Gallery.tsx
+++ b/src/view/com/composer/photos/Gallery.tsx
@@ -7,10 +7,10 @@ import {s, colors} from 'lib/styles'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
 import {Image} from 'expo-image'
 import {Text} from 'view/com/util/text/Text'
-import {isDesktopWeb} from 'platform/detection'
 import {openAltTextModal} from 'lib/media/alt-text'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 interface Props {
   gallery: GalleryModel
@@ -19,13 +19,14 @@ interface Props {
 export const Gallery = observer(function ({gallery}: Props) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
 
   let side: number
 
   if (gallery.size === 1) {
     side = 250
   } else {
-    side = (isDesktopWeb ? 560 : 350) / gallery.size
+    side = (isMobile ? 350 : 560) / gallery.size
   }
 
   const imageStyle = {
@@ -33,14 +34,14 @@ export const Gallery = observer(function ({gallery}: Props) {
     width: side,
   }
 
-  const isOverflow = !isDesktopWeb && gallery.size > 2
+  const isOverflow = isMobile && gallery.size > 2
 
   const altTextControlStyle = isOverflow
     ? {
         left: 4,
         bottom: 4,
       }
-    : isDesktopWeb && gallery.size < 3
+    : !isMobile && gallery.size < 3
     ? {
         left: 8,
         top: 8,
@@ -60,7 +61,7 @@ export const Gallery = observer(function ({gallery}: Props) {
           right: 4,
           gap: 4,
         }
-      : isDesktopWeb && gallery.size < 3
+      : !isMobile && gallery.size < 3
       ? {
           top: 8,
           right: 8,
diff --git a/src/view/com/lists/ListItems.tsx b/src/view/com/lists/ListItems.tsx
index 7f2173d78..d611bc504 100644
--- a/src/view/com/lists/ListItems.tsx
+++ b/src/view/com/lists/ListItems.tsx
@@ -22,9 +22,9 @@ import {TextLink} from '../util/Link'
 import {ListModel} from 'state/models/content/list'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useStores} from 'state/index'
 import {s} from 'lib/styles'
-import {isDesktopWeb} from 'platform/detection'
 import {ListActions} from './ListActions'
 import {makeProfileLink} from 'lib/routes/links'
 import {sanitizeHandle} from 'lib/strings/handles'
@@ -283,6 +283,7 @@ const ListHeader = observer(
   }) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isDesktop} = useWebMediaQueries()
     const descriptionRT = React.useMemo(
       () =>
         list?.description &&
@@ -318,7 +319,7 @@ const ListHeader = observer(
                 richText={descriptionRT}
               />
             )}
-            {isDesktopWeb && (
+            {isDesktop && (
               <ListActions
                 isOwner={isOwner}
                 muted={list.viewer?.muted}
@@ -334,7 +335,8 @@ const ListHeader = observer(
             <UserAvatar type="list" avatar={list.avatar} size={64} />
           </View>
         </View>
-        <View style={[styles.fakeSelector, pal.border]}>
+        <View
+          style={{flexDirection: 'row', paddingHorizontal: isDesktop ? 16 : 6}}>
           <View
             style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
             <Text type="md-medium" style={[pal.text]}>
@@ -365,10 +367,6 @@ const styles = StyleSheet.create({
     gap: 8,
     marginTop: 12,
   },
-  fakeSelector: {
-    flexDirection: 'row',
-    paddingHorizontal: isDesktopWeb ? 16 : 6,
-  },
   fakeSelectorItem: {
     paddingHorizontal: 12,
     paddingBottom: 8,
diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx
index 6117924ae..2a8672131 100644
--- a/src/view/com/modals/AddAppPasswords.tsx
+++ b/src/view/com/modals/AddAppPasswords.tsx
@@ -5,7 +5,7 @@ import {Button} from '../util/forms/Button'
 import {s} from 'lib/styles'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {isNative} from 'platform/detection'
 import {
   FontAwesomeIcon,
   FontAwesomeIconStyle,
@@ -205,7 +205,7 @@ export function Component({}: {}) {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 50,
+    paddingBottom: isNative ? 50 : 0,
     paddingHorizontal: 16,
   },
   textInputWrapper: {
diff --git a/src/view/com/modals/AltImage.tsx b/src/view/com/modals/AltImage.tsx
index e1145a0fe..c084e84a3 100644
--- a/src/view/com/modals/AltImage.tsx
+++ b/src/view/com/modals/AltImage.tsx
@@ -18,7 +18,7 @@ import {useTheme} from 'lib/ThemeContext'
 import {Text} from '../util/text/Text'
 import LinearGradient from 'react-native-linear-gradient'
 import {useStores} from 'state/index'
-import {isDesktopWeb, isAndroid} from 'platform/detection'
+import {isAndroid, isWeb} from 'platform/detection'
 import {ImageModel} from 'state/models/media/image'
 
 export const snapPoints = ['fullscreen']
@@ -35,7 +35,7 @@ export function Component({image}: Props) {
   const windim = useWindowDimensions()
 
   const imageStyles = useMemo<ImageStyle>(() => {
-    const maxWidth = isDesktopWeb ? 450 : windim.width
+    const maxWidth = isWeb ? 450 : windim.width
     if (image.height > image.width) {
       return {
         resizeMode: 'contain',
@@ -137,12 +137,12 @@ const styles = StyleSheet.create({
     flex: 1,
     height: '100%',
     width: '100%',
-    paddingVertical: isDesktopWeb ? 0 : 18,
+    paddingVertical: isWeb ? 0 : 18,
   },
   scrollContainer: {
     flex: 1,
     height: '100%',
-    paddingHorizontal: isDesktopWeb ? 0 : 12,
+    paddingHorizontal: isWeb ? 0 : 12,
   },
   scrollInner: {
     gap: 12,
diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx
index f9bc0de14..270177182 100644
--- a/src/view/com/modals/Confirm.tsx
+++ b/src/view/com/modals/Confirm.tsx
@@ -11,7 +11,7 @@ import {s, colors} from 'lib/styles'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {cleanError} from 'lib/strings/errors'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {isWeb} from 'platform/detection'
 import type {ConfirmModal} from 'state/models/ui/shell'
 
 export const snapPoints = ['50%']
@@ -96,7 +96,7 @@ const styles = StyleSheet.create({
   container: {
     flex: 1,
     padding: 10,
-    paddingBottom: isDesktopWeb ? 0 : 60,
+    paddingBottom: isWeb ? 0 : 60,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx
index f39351feb..588b21353 100644
--- a/src/view/com/modals/ContentFilteringSettings.tsx
+++ b/src/view/com/modals/ContentFilteringSettings.tsx
@@ -11,13 +11,15 @@ import {TextLink} from '../util/Link'
 import {ToggleButton} from '../util/forms/ToggleButton'
 import {usePalette} from 'lib/hooks/usePalette'
 import {CONFIGURABLE_LABEL_GROUPS} from 'lib/labeling/const'
-import {isDesktopWeb, isIOS} from 'platform/detection'
+import {isIOS} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import * as Toast from '../util/Toast'
 
 export const snapPoints = ['90%']
 
 export const Component = observer(({}: {}) => {
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
 
   React.useEffect(() => {
@@ -88,9 +90,14 @@ export const Component = observer(({}: {}) => {
         <ContentLabelPref group="hate" />
         <ContentLabelPref group="spam" />
         <ContentLabelPref group="impersonation" />
-        <View style={styles.bottomSpacer} />
+        <View style={{height: isMobile ? 60 : 0}} />
       </ScrollView>
-      <View style={[styles.btnContainer, pal.borderDark]}>
+      <View
+        style={[
+          styles.btnContainer,
+          isMobile && styles.btnContainerMobile,
+          pal.borderDark,
+        ]}>
         <Pressable
           testID="sendReportBtn"
           onPress={onPressDone}
@@ -259,14 +266,13 @@ const styles = StyleSheet.create({
     flex: 1,
     paddingHorizontal: 10,
   },
-  bottomSpacer: {
-    height: isDesktopWeb ? 0 : 60,
-  },
   btnContainer: {
     paddingTop: 10,
     paddingHorizontal: 10,
-    paddingBottom: isDesktopWeb ? 0 : 40,
-    borderTopWidth: isDesktopWeb ? 0 : 1,
+  },
+  btnContainerMobile: {
+    paddingBottom: 40,
+    borderTopWidth: 1,
   },
 
   contentLabelPref: {
diff --git a/src/view/com/modals/CreateOrEditMuteList.tsx b/src/view/com/modals/CreateOrEditMuteList.tsx
index 09048b5db..3f3cfc5f0 100644
--- a/src/view/com/modals/CreateOrEditMuteList.tsx
+++ b/src/view/com/modals/CreateOrEditMuteList.tsx
@@ -22,8 +22,8 @@ import {UserAvatar} from '../util/UserAvatar'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useTheme} from 'lib/ThemeContext'
 import {useAnalytics} from 'lib/analytics/analytics'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {cleanError, isNetworkError} from 'lib/strings/errors'
-import {isDesktopWeb} from 'platform/detection'
 
 const MAX_NAME = 64 // todo
 const MAX_DESCRIPTION = 300 // todo
@@ -38,6 +38,7 @@ export function Component({
   list?: ListModel
 }) {
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
   const [error, setError] = useState<string>('')
   const pal = usePalette('default')
   const theme = useTheme()
@@ -130,7 +131,12 @@ export function Component({
   return (
     <KeyboardAvoidingView behavior="height">
       <ScrollView
-        style={[pal.view, styles.container]}
+        style={[
+          pal.view,
+          {
+            paddingHorizontal: isMobile ? 16 : 0,
+          },
+        ]}
         testID="createOrEditMuteListModal">
         <Text style={[styles.title, pal.text]}>
           {list ? 'Edit Mute List' : 'New Mute List'}
@@ -226,9 +232,6 @@ export function Component({
 }
 
 const styles = StyleSheet.create({
-  container: {
-    paddingHorizontal: isDesktopWeb ? 0 : 16,
-  },
   title: {
     textAlign: 'center',
     fontWeight: 'bold',
diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx
index b4933a1f2..98482457c 100644
--- a/src/view/com/modals/DeleteAccount.tsx
+++ b/src/view/com/modals/DeleteAccount.tsx
@@ -13,10 +13,10 @@ import {useStores} from 'state/index'
 import {s, colors, gradients} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useTheme} from 'lib/ThemeContext'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {cleanError} from 'lib/strings/errors'
 import {resetToTab} from '../../../Navigation'
-import {isDesktopWeb} from 'platform/detection'
 
 export const snapPoints = ['60%']
 
@@ -24,6 +24,7 @@ export function Component({}: {}) {
   const pal = usePalette('default')
   const theme = useTheme()
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
   const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false)
   const [confirmCode, setConfirmCode] = React.useState<string>('')
   const [password, setPassword] = React.useState<string>('')
@@ -78,7 +79,7 @@ export function Component({}: {}) {
               type="title-xl"
               numberOfLines={1}
               style={[
-                isDesktopWeb ? styles.titleDesktop : styles.titleMobile,
+                isMobile ? styles.titleMobile : styles.titleDesktop,
                 pal.text,
                 s.bold,
               ]}>
diff --git a/src/view/com/modals/EditImage.tsx b/src/view/com/modals/EditImage.tsx
index a4e06b955..e4cfbac35 100644
--- a/src/view/com/modals/EditImage.tsx
+++ b/src/view/com/modals/EditImage.tsx
@@ -7,6 +7,7 @@ import {useTheme} from 'lib/ThemeContext'
 import {Text} from '../util/text/Text'
 import LinearGradient from 'react-native-linear-gradient'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import ImageEditor, {Position} from 'react-avatar-editor'
 import {TextInput} from './util'
 import {enforceLen} from 'lib/strings/helpers'
@@ -18,7 +19,6 @@ import {Slider} from '@miblanchard/react-native-slider'
 import {MaterialIcons} from '@expo/vector-icons'
 import {observer} from 'mobx-react-lite'
 import {getKeys} from 'lib/type-assertions'
-import {isDesktopWeb} from 'platform/detection'
 
 export const snapPoints = ['80%']
 
@@ -51,6 +51,7 @@ export const Component = observer(function ({image, gallery}: Props) {
   const theme = useTheme()
   const store = useStores()
   const windowDimensions = useWindowDimensions()
+  const {isMobile} = useWebMediaQueries()
 
   const {
     aspectRatio,
@@ -174,19 +175,28 @@ export const Component = observer(function ({image, gallery}: Props) {
 
   const computedWidth =
     windowDimensions.width > 500 ? 410 : windowDimensions.width - 80
-  const sideLength = isDesktopWeb ? 300 : computedWidth
+  const sideLength = isMobile ? computedWidth : 300
 
   const dimensions = image.getResizedDimensions(aspectRatio, sideLength)
   const imgContainerStyles = {width: sideLength, height: sideLength}
 
   const imgControlStyles = {
     alignItems: 'center' as const,
-    flexDirection: isDesktopWeb ? ('row' as const) : ('column' as const),
-    gap: isDesktopWeb ? 5 : 0,
+    flexDirection: isMobile ? ('column' as const) : ('row' as const),
+    gap: isMobile ? 0 : 5,
   }
 
   return (
-    <View testID="editImageModal" style={[pal.view, styles.container, s.flex1]}>
+    <View
+      testID="editImageModal"
+      style={[
+        pal.view,
+        styles.container,
+        s.flex1,
+        {
+          paddingHorizontal: isMobile ? 16 : undefined,
+        },
+      ]}>
       <Text style={[styles.title, pal.text]}>Edit image</Text>
       <View style={[styles.gap18, s.flexRow]}>
         <View>
@@ -213,7 +223,7 @@ export const Component = observer(function ({image, gallery}: Props) {
           />
         </View>
         <View>
-          {isDesktopWeb ? (
+          {!isMobile ? (
             <Text type="sm-bold" style={pal.text}>
               Ratios
             </Text>
@@ -248,7 +258,7 @@ export const Component = observer(function ({image, gallery}: Props) {
               )
             })}
           </View>
-          {isDesktopWeb ? (
+          {!isMobile ? (
             <Text type="sm-bold" style={[pal.text, styles.subsection]}>
               Transformations
             </Text>
@@ -282,7 +292,14 @@ export const Component = observer(function ({image, gallery}: Props) {
         </Text>
         <TextInput
           testID="altTextImageInput"
-          style={[styles.textArea, pal.border, pal.text]}
+          style={[
+            styles.textArea,
+            pal.border,
+            pal.text,
+            {
+              maxHeight: isMobile ? 50 : undefined,
+            },
+          ]}
           keyboardAppearance={theme.colorScheme}
           multiline
           value={altText}
@@ -317,7 +334,6 @@ export const Component = observer(function ({image, gallery}: Props) {
 const styles = StyleSheet.create({
   container: {
     gap: 18,
-    paddingHorizontal: isDesktopWeb ? undefined : 16,
     height: '100%',
     width: '100%',
   },
@@ -369,7 +385,6 @@ const styles = StyleSheet.create({
     fontSize: 16,
     height: 100,
     textAlignVertical: 'top',
-    maxHeight: isDesktopWeb ? undefined : 50,
   },
   bottomSection: {
     borderTopWidth: 1,
diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx
index d46579f09..ba3cc382b 100644
--- a/src/view/com/modals/InviteCodes.tsx
+++ b/src/view/com/modals/InviteCodes.tsx
@@ -12,7 +12,7 @@ import * as Toast from '../util/Toast'
 import {useStores} from 'state/index'
 import {ScrollView} from './util'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {isWeb} from 'platform/detection'
 
 export const snapPoints = ['70%']
 
@@ -127,7 +127,7 @@ const InviteCode = observer(
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 50,
+    paddingBottom: isWeb ? 0 : 50,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/com/modals/ListAddRemoveUser.tsx b/src/view/com/modals/ListAddRemoveUser.tsx
index bfb7e4dc0..e00509285 100644
--- a/src/view/com/modals/ListAddRemoveUser.tsx
+++ b/src/view/com/modals/ListAddRemoveUser.tsx
@@ -19,7 +19,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {sanitizeHandle} from 'lib/strings/handles'
 import {s} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb, isAndroid} from 'platform/detection'
+import {isWeb, isAndroid} from 'platform/detection'
 import isEqual from 'lodash.isequal'
 
 export const snapPoints = ['fullscreen']
@@ -231,7 +231,7 @@ export const Component = observer(
 
 const styles = StyleSheet.create({
   container: {
-    paddingHorizontal: isDesktopWeb ? 0 : 16,
+    paddingHorizontal: isWeb ? 0 : 16,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 5cfdd6bb3..b3a79221d 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -3,8 +3,8 @@ import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import type {Modal as ModalIface} from 'state/models/ui/shell'
-import {isMobileWeb} from 'platform/detection'
 
 import * as ConfirmModal from './Confirm'
 import * as EditProfileModal from './EditProfile'
@@ -47,6 +47,7 @@ export const ModalsContainer = observer(function ModalsContainer() {
 function Modal({modal}: {modal: ModalIface}) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
 
   if (!store.shell.isModalActive) {
     return null
@@ -119,7 +120,7 @@ function Modal({modal}: {modal: ModalIface}) {
           <View
             style={[
               styles.container,
-              isMobileWeb && styles.containerMobile,
+              isMobile && styles.containerMobile,
               pal.view,
               pal.border,
             ]}>
diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx
index b0e68e61b..bd51845c6 100644
--- a/src/view/com/modals/ModerationDetails.tsx
+++ b/src/view/com/modals/ModerationDetails.tsx
@@ -2,11 +2,12 @@ import React from 'react'
 import {StyleSheet, View} from 'react-native'
 import {ModerationUI} from '@atproto/api'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s} from 'lib/styles'
 import {Text} from '../util/text/Text'
 import {TextLink} from '../util/Link'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {isWeb} from 'platform/detection'
 import {listUriToHref} from 'lib/strings/url-helpers'
 import {Button} from '../util/forms/Button'
 
@@ -20,6 +21,7 @@ export function Component({
   moderation: ModerationUI
 }) {
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
 
   let name
@@ -64,7 +66,15 @@ export function Component({
   }
 
   return (
-    <View testID="moderationDetailsModal" style={[styles.container, pal.view]}>
+    <View
+      testID="moderationDetailsModal"
+      style={[
+        styles.container,
+        {
+          paddingHorizontal: isMobile ? 14 : 0,
+        },
+        pal.view,
+      ]}>
       <Text type="title-xl" style={[pal.text, styles.title]}>
         {name}
       </Text>
@@ -87,7 +97,6 @@ export function Component({
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingHorizontal: isDesktopWeb ? 0 : 14,
   },
   title: {
     textAlign: 'center',
@@ -99,7 +108,7 @@ const styles = StyleSheet.create({
   },
   btn: {
     paddingVertical: 14,
-    marginTop: isDesktopWeb ? 40 : 0,
-    marginBottom: isDesktopWeb ? 0 : 40,
+    marginTop: isWeb ? 40 : 0,
+    marginBottom: isWeb ? 0 : 40,
   },
 })
diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx
index 42863fd33..820f2895b 100644
--- a/src/view/com/modals/SelfLabel.tsx
+++ b/src/view/com/modals/SelfLabel.tsx
@@ -5,7 +5,8 @@ import {Text} from '../util/text/Text'
 import {useStores} from 'state/index'
 import {s, colors} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {isWeb} from 'platform/detection'
 import {Button} from '../util/forms/Button'
 import {SelectableBtn} from '../util/forms/SelectableBtn'
 import {ScrollView} from 'view/com/modals/util'
@@ -25,6 +26,7 @@ export const Component = observer(function Component({
 }) {
   const pal = usePalette('default')
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
   const [selected, setSelected] = useState(labels)
 
   const toggleAdultLabel = (label: string) => {
@@ -54,7 +56,12 @@ export const Component = observer(function Component({
       </View>
 
       <ScrollView>
-        <View style={[styles.section, pal.border, {borderBottomWidth: 1}]}>
+        <View
+          style={[
+            styles.section,
+            pal.border,
+            {borderBottomWidth: 1, paddingHorizontal: isMobile ? 20 : 0},
+          ]}>
           <View
             style={{
               flexDirection: 'row',
@@ -152,11 +159,11 @@ export const Component = observer(function Component({
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 40,
+    paddingBottom: isWeb ? 0 : 40,
   },
   titleSection: {
-    paddingTop: isDesktopWeb ? 0 : 4,
-    paddingBottom: isDesktopWeb ? 14 : 10,
+    paddingTop: isWeb ? 0 : 4,
+    paddingBottom: isWeb ? 14 : 10,
   },
   title: {
     textAlign: 'center',
@@ -170,7 +177,6 @@ const styles = StyleSheet.create({
   section: {
     borderTopWidth: 1,
     paddingVertical: 20,
-    paddingHorizontal: isDesktopWeb ? 0 : 20,
   },
   adultExplainer: {
     paddingLeft: 5,
diff --git a/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx b/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx
index e1ecce589..c2d0c222a 100644
--- a/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx
+++ b/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx
@@ -2,8 +2,8 @@ import React from 'react'
 import {StyleSheet, Text, View, Pressable} from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
 import {s, colors, gradients} from 'lib/styles'
-import {isDesktopWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 export const ConfirmLanguagesButton = ({
   onPress,
@@ -13,8 +13,17 @@ export const ConfirmLanguagesButton = ({
   extraText?: string
 }) => {
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   return (
-    <View style={[styles.btnContainer, pal.borderDark]}>
+    <View
+      style={[
+        styles.btnContainer,
+        pal.borderDark,
+        isMobile && {
+          paddingBottom: 40,
+          borderTopWidth: 1,
+        },
+      ]}>
       <Pressable
         testID="confirmContentLanguagesBtn"
         onPress={onPress}
@@ -37,8 +46,6 @@ const styles = StyleSheet.create({
   btnContainer: {
     paddingTop: 10,
     paddingHorizontal: 10,
-    paddingBottom: isDesktopWeb ? 0 : 40,
-    borderTopWidth: isDesktopWeb ? 0 : 1,
   },
   btn: {
     flexDirection: 'row',
diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
index 4f7bbc9c7..e577991c5 100644
--- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
+++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
@@ -4,7 +4,8 @@ import {ScrollView} from '../util'
 import {useStores} from 'state/index'
 import {Text} from '../../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb, deviceLocales} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {deviceLocales} from 'platform/detection'
 import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
 import {LanguageToggle} from './LanguageToggle'
 import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
@@ -14,6 +15,7 @@ export const snapPoints = ['100%']
 export function Component({}: {}) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   const onPressDone = React.useCallback(() => {
     store.shell.closeModal()
   }, [store])
@@ -47,7 +49,19 @@ export function Component({}: {}) {
   )
 
   return (
-    <View testID="contentLanguagesModal" style={[pal.view, styles.container]}>
+    <View
+      testID="contentLanguagesModal"
+      style={[
+        pal.view,
+        styles.container,
+        isMobile
+          ? {
+              paddingTop: 20,
+            }
+          : {
+              maxHeight: '90vh',
+            },
+      ]}>
       <Text style={[pal.text, styles.title]}>Content Languages</Text>
       <Text style={[pal.text, styles.description]}>
         Which languages would you like to see in your algorithmic feeds?
@@ -67,7 +81,11 @@ export function Component({}: {}) {
             }}
           />
         ))}
-        <View style={styles.bottomSpacer} />
+        <View
+          style={{
+            height: isMobile ? 60 : 0,
+          }}
+        />
       </ScrollView>
       <ConfirmLanguagesButton onPress={onPressDone} />
     </View>
@@ -77,7 +95,6 @@ export function Component({}: {}) {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingTop: 20,
   },
   title: {
     textAlign: 'center',
@@ -94,7 +111,4 @@ const styles = StyleSheet.create({
     flex: 1,
     paddingHorizontal: 10,
   },
-  bottomSpacer: {
-    height: isDesktopWeb ? 0 : 60,
-  },
 })
diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
index 0f336e7bc..c80f8731c 100644
--- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
+++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
@@ -5,7 +5,8 @@ import {ScrollView} from '../util'
 import {useStores} from 'state/index'
 import {Text} from '../../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb, deviceLocales} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {deviceLocales} from 'platform/detection'
 import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
 import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
 import {ToggleButton} from 'view/com/util/forms/ToggleButton'
@@ -15,6 +16,7 @@ export const snapPoints = ['100%']
 export const Component = observer(() => {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   const onPressDone = React.useCallback(() => {
     store.shell.closeModal()
   }, [store])
@@ -48,7 +50,19 @@ export const Component = observer(() => {
   )
 
   return (
-    <View testID="postLanguagesModal" style={[pal.view, styles.container]}>
+    <View
+      testID="postLanguagesModal"
+      style={[
+        pal.view,
+        styles.container,
+        isMobile
+          ? {
+              paddingTop: 20,
+            }
+          : {
+              maxHeight: '90vh',
+            },
+      ]}>
       <Text style={[pal.text, styles.title]}>Post Languages</Text>
       <Text style={[pal.text, styles.description]}>
         Which languages are used in this post?
@@ -80,7 +94,11 @@ export const Component = observer(() => {
             />
           )
         })}
-        <View style={styles.bottomSpacer} />
+        <View
+          style={{
+            height: isMobile ? 60 : 0,
+          }}
+        />
       </ScrollView>
       <ConfirmLanguagesButton onPress={onPressDone} />
     </View>
@@ -90,7 +108,6 @@ export const Component = observer(() => {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingTop: 20,
   },
   title: {
     textAlign: 'center',
@@ -107,9 +124,6 @@ const styles = StyleSheet.create({
     flex: 1,
     paddingHorizontal: 10,
   },
-  bottomSpacer: {
-    height: isDesktopWeb ? 0 : 60,
-  },
   languageToggle: {
     borderTopWidth: 1,
     borderRadius: 0,
diff --git a/src/view/com/modals/report/InputIssueDetails.tsx b/src/view/com/modals/report/InputIssueDetails.tsx
index a2e5069a8..70a8f7b24 100644
--- a/src/view/com/modals/report/InputIssueDetails.tsx
+++ b/src/view/com/modals/report/InputIssueDetails.tsx
@@ -5,9 +5,9 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {CharProgress} from '../../composer/char-progress/CharProgress'
 import {Text} from '../../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s} from 'lib/styles'
 import {SendReportButton} from './SendReportButton'
-import {isDesktopWeb} from 'platform/detection'
 
 export function InputIssueDetails({
   details,
@@ -23,9 +23,13 @@ export function InputIssueDetails({
   isProcessing: boolean
 }) {
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
 
   return (
-    <View style={[styles.detailsContainer]}>
+    <View
+      style={{
+        marginTop: isMobile ? 12 : 0,
+      }}>
       <TouchableOpacity
         testID="addDetailsBtn"
         style={[s.mb10, styles.backBtn]}
@@ -63,9 +67,6 @@ export function InputIssueDetails({
 }
 
 const styles = StyleSheet.create({
-  detailsContainer: {
-    marginTop: isDesktopWeb ? 0 : 12,
-  },
   backBtn: {
     flexDirection: 'row',
     alignItems: 'center',
diff --git a/src/view/com/modals/report/Modal.tsx b/src/view/com/modals/report/Modal.tsx
index f386b110d..8aabe0871 100644
--- a/src/view/com/modals/report/Modal.tsx
+++ b/src/view/com/modals/report/Modal.tsx
@@ -3,6 +3,7 @@ import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native'
 import {ScrollView} from 'react-native-gesture-handler'
 import {AtUri} from '@atproto/api'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s} from 'lib/styles'
 import {Text} from '../../util/text/Text'
 import * as Toast from '../../util/Toast'
@@ -37,6 +38,7 @@ type ReportComponentProps =
 export function Component(content: ReportComponentProps) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   const [isProcessing, setIsProcessing] = useState(false)
   const [showDetailsInput, setShowDetailsInput] = useState(false)
   const [error, setError] = useState<string>()
@@ -87,7 +89,13 @@ export function Component(content: ReportComponentProps) {
 
   return (
     <ScrollView testID="reportModal" style={[s.flex1, pal.view]}>
-      <View style={styles.container}>
+      <View
+        style={[
+          styles.container,
+          isMobile && {
+            paddingBottom: 40,
+          },
+        ]}>
         {showDetailsInput ? (
           <InputIssueDetails
             details={details}
@@ -153,16 +161,14 @@ const SelectIssue = ({
       <Text style={[pal.textLight, styles.description]}>
         What is the issue with this {collectionName}?
       </Text>
-      <ReportReasonOptions
-        atUri={atUri}
-        selectedIssue={issue}
-        onSelectIssue={onSelectIssue}
-      />
-      {error ? (
-        <View style={s.mt10}>
-          <ErrorMessage message={error} />
-        </View>
-      ) : undefined}
+      <View style={{marginBottom: 10}}>
+        <ReportReasonOptions
+          atUri={atUri}
+          selectedIssue={issue}
+          onSelectIssue={onSelectIssue}
+        />
+      </View>
+      {error ? <ErrorMessage message={error} /> : undefined}
       {/* If no atUri is present, the report would be for account in which case, we allow sending without specifying a reason */}
       {issue || !atUri ? (
         <>
@@ -188,7 +194,6 @@ const SelectIssue = ({
 const styles = StyleSheet.create({
   container: {
     paddingHorizontal: 10,
-    paddingBottom: 40,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx
index 0df915950..6e94ab60e 100644
--- a/src/view/com/pager/FeedsTabBar.web.tsx
+++ b/src/view/com/pager/FeedsTabBar.web.tsx
@@ -13,8 +13,8 @@ export const FeedsTabBar = observer(
   (
     props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
   ) => {
-    const {isDesktop} = useWebMediaQueries()
-    if (!isDesktop) {
+    const {isMobile} = useWebMediaQueries()
+    if (isMobile) {
       return <FeedsTabBarMobile {...props} />
     } else {
       return <FeedsTabBarDesktop {...props} />
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index d454e89f1..319d28f95 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -3,7 +3,8 @@ import {StyleSheet, View, ScrollView, LayoutChangeEvent} from 'react-native'
 import {Text} from '../util/text/Text'
 import {PressableWithHover} from '../util/PressableWithHover'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb, isMobileWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {isWeb} from 'platform/detection'
 import {DraggableScrollView} from './DraggableScrollView'
 
 export interface TabBarProps {
@@ -30,6 +31,7 @@ export function TabBar({
     () => ({borderBottomColor: indicatorColor || pal.colors.link}),
     [indicatorColor, pal],
   )
+  const {isDesktop, isTablet} = useWebMediaQueries()
 
   // scrolls to the selected item when the page changes
   useEffect(() => {
@@ -61,6 +63,7 @@ export function TabBar({
     [],
   )
 
+  const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
   return (
     <View testID={testID} style={[pal.view, styles.outer]}>
       <DraggableScrollView
@@ -78,7 +81,7 @@ export function TabBar({
               hoverStyle={pal.viewLight}
               onPress={() => onPressItem(i)}>
               <Text
-                type={isDesktopWeb ? 'xl-bold' : 'lg-bold'}
+                type={isDesktop || isTablet ? 'xl-bold' : 'lg-bold'}
                 testID={testID ? `${testID}-${item}` : undefined}
                 style={selected ? pal.text : pal.textLight}>
                 {item}
@@ -91,46 +94,46 @@ export function TabBar({
   )
 }
 
-const styles = isDesktopWeb
-  ? StyleSheet.create({
-      outer: {
-        flexDirection: 'row',
-        width: 598,
-      },
-      contentContainer: {
-        columnGap: 8,
-        marginLeft: 14,
-        paddingRight: 14,
-        backgroundColor: 'transparent',
-      },
-      item: {
-        paddingTop: 14,
-        paddingBottom: 12,
-        paddingHorizontal: 10,
-        borderBottomWidth: 3,
-        borderBottomColor: 'transparent',
-        justifyContent: 'center',
-      },
-    })
-  : StyleSheet.create({
-      outer: {
-        flex: 1,
-        flexDirection: 'row',
-        backgroundColor: 'transparent',
-        maxWidth: '100%',
-      },
-      contentContainer: {
-        columnGap: isMobileWeb ? 0 : 20,
-        marginLeft: isMobileWeb ? 0 : 18,
-        paddingRight: isMobileWeb ? 0 : 36,
-        backgroundColor: 'transparent',
-      },
-      item: {
-        paddingTop: 10,
-        paddingBottom: 10,
-        paddingHorizontal: isMobileWeb ? 8 : 0,
-        borderBottomWidth: 3,
-        borderBottomColor: 'transparent',
-        justifyContent: 'center',
-      },
-    })
+const desktopStyles = StyleSheet.create({
+  outer: {
+    flexDirection: 'row',
+    width: 598,
+  },
+  contentContainer: {
+    columnGap: 8,
+    marginLeft: 14,
+    paddingRight: 14,
+    backgroundColor: 'transparent',
+  },
+  item: {
+    paddingTop: 14,
+    paddingBottom: 12,
+    paddingHorizontal: 10,
+    borderBottomWidth: 3,
+    borderBottomColor: 'transparent',
+    justifyContent: 'center',
+  },
+})
+
+const mobileStyles = StyleSheet.create({
+  outer: {
+    flex: 1,
+    flexDirection: 'row',
+    backgroundColor: 'transparent',
+    maxWidth: '100%',
+  },
+  contentContainer: {
+    columnGap: isWeb ? 0 : 20,
+    marginLeft: isWeb ? 0 : 18,
+    paddingRight: isWeb ? 0 : 36,
+    backgroundColor: 'transparent',
+  },
+  item: {
+    paddingTop: 10,
+    paddingBottom: 10,
+    paddingHorizontal: isWeb ? 8 : 0,
+    borderBottomWidth: 3,
+    borderBottomColor: 'transparent',
+    justifyContent: 'center',
+  },
+})
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 3e951dbf0..f7766dfb7 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -18,18 +18,24 @@ import {
 } from '@fortawesome/react-native-fontawesome'
 import {PostThreadItem} from './PostThreadItem'
 import {ComposePrompt} from '../composer/Prompt'
+import {ViewHeader} from '../util/ViewHeader'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {Text} from '../util/text/Text'
 import {s} from 'lib/styles'
-import {isIOS, isDesktopWeb, isMobileWeb} from 'platform/detection'
+import {isIOS, isDesktopWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useSetTitle} from 'lib/hooks/useSetTitle'
 import {useNavigation} from '@react-navigation/native'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {NavigationProp} from 'lib/routes/types'
 import {sanitizeDisplayName} from 'lib/strings/display-names'
 
 const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 0}
 
+const TOP_COMPONENT = {
+  _reactKey: '__top_component__',
+  _isHighlightedPost: false,
+}
 const PARENT_SPINNER = {
   _reactKey: '__parent_spinner__',
   _isHighlightedPost: false,
@@ -47,6 +53,7 @@ const BOTTOM_COMPONENT = {
 }
 type YieldedItem =
   | PostThreadItemModel
+  | typeof TOP_COMPONENT
   | typeof PARENT_SPINNER
   | typeof REPLY_PROMPT
   | typeof DELETED
@@ -63,13 +70,14 @@ export const PostThread = observer(function PostThread({
   onPressReply: () => void
 }) {
   const pal = usePalette('default')
+  const {isTablet} = useWebMediaQueries()
   const ref = useRef<FlatList>(null)
   const hasScrolledIntoView = useRef<boolean>(false)
   const [isRefreshing, setIsRefreshing] = React.useState(false)
   const navigation = useNavigation<NavigationProp>()
   const posts = React.useMemo(() => {
     if (view.thread) {
-      const arr = Array.from(flattenThread(view.thread))
+      const arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread)))
       if (view.isLoadingFromCache) {
         if (view.thread?.postRecord?.reply) {
           arr.unshift(PARENT_SPINNER)
@@ -158,7 +166,9 @@ export const PostThread = observer(function PostThread({
 
   const renderItem = React.useCallback(
     ({item, index}: {item: YieldedItem; index: number}) => {
-      if (item === PARENT_SPINNER) {
+      if (item === TOP_COMPONENT) {
+        return isTablet ? <ViewHeader title="Post" /> : null
+      } else if (item === PARENT_SPINNER) {
         return (
           <View style={styles.parentSpinner}>
             <ActivityIndicator />
@@ -186,19 +196,8 @@ export const PostThread = observer(function PostThread({
         // HACK
         // due to some complexities with how flatlist works, this is the easiest way
         // I could find to get a border positioned directly under the last item
-        // -
-        // addendum -- it's also the best way to get mobile web to add padding
-        // at the bottom of the thread since paddingbottom is ignored. yikes.
         // -prf
-        return (
-          <View
-            style={[
-              styles.bottomBorder,
-              pal.border,
-              isMobileWeb && styles.bottomSpacer,
-            ]}
-          />
-        )
+        return <View style={[pal.border, styles.bottomSpacer]} />
       } else if (item === CHILD_SPINNER) {
         return (
           <View style={styles.childSpinner}>
@@ -219,7 +218,7 @@ export const PostThread = observer(function PostThread({
       }
       return <></>
     },
-    [onRefresh, onPressReply, pal, posts],
+    [onRefresh, onPressReply, pal, posts, isTablet],
   )
 
   // loading
@@ -331,7 +330,6 @@ export const PostThread = observer(function PostThread({
       }
       onScrollToIndexFailed={onScrollToIndexFailed}
       style={s.hContentRegion}
-      contentContainerStyle={styles.contentContainerExtra}
     />
   )
 })
@@ -384,13 +382,8 @@ const styles = StyleSheet.create({
     paddingVertical: 10,
   },
   childSpinner: {},
-  bottomBorder: {
-    borderBottomWidth: 1,
-  },
   bottomSpacer: {
     height: 400,
-  },
-  contentContainerExtra: {
-    paddingBottom: 500,
+    borderTopWidth: 1,
   },
 })
diff --git a/src/view/com/posts/MultiFeed.tsx b/src/view/com/posts/MultiFeed.tsx
index 97899e554..9c8f4f246 100644
--- a/src/view/com/posts/MultiFeed.tsx
+++ b/src/view/com/posts/MultiFeed.tsx
@@ -22,7 +22,7 @@ import {s} from 'lib/styles'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useTheme} from 'lib/ThemeContext'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {CogIcon} from 'lib/icons'
 
 export const MultiFeed = observer(function Feed({
@@ -48,6 +48,7 @@ export const MultiFeed = observer(function Feed({
 }) {
   const pal = usePalette('default')
   const theme = useTheme()
+  const {isMobile} = useWebMediaQueries()
   const {track} = useAnalytics()
   const [isRefreshing, setIsRefreshing] = React.useState(false)
 
@@ -80,19 +81,27 @@ export const MultiFeed = observer(function Feed({
   const renderItem = React.useCallback(
     ({item}: {item: MultiFeedItem}) => {
       if (item.type === 'header') {
-        if (isDesktopWeb) {
+        if (!isMobile) {
           return (
-            <View style={[pal.view, pal.border, styles.headerDesktop]}>
-              <Text type="2xl-bold" style={pal.text}>
-                My Feeds
-              </Text>
-              <Link href="/settings/saved-feeds">
-                <CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
-              </Link>
-            </View>
+            <>
+              <View style={[pal.view, pal.border, styles.headerDesktop]}>
+                <Text type="2xl-bold" style={pal.text}>
+                  My Feeds
+                </Text>
+                <Link href="/settings/saved-feeds">
+                  <CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
+                </Link>
+              </View>
+              <DiscoverLink />
+            </>
           )
         }
-        return <View style={[styles.header, pal.border]} />
+        return (
+          <>
+            <View style={[styles.header, pal.border]} />
+            <DiscoverLink />
+          </>
+        )
       } else if (item.type === 'feed-header') {
         return (
           <View style={styles.feedHeader}>
@@ -124,18 +133,11 @@ export const MultiFeed = observer(function Feed({
           </Link>
         )
       } else if (item.type === 'footer') {
-        return (
-          <Link style={[styles.footerLink, pal.viewLight]} href="/search/feeds">
-            <FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
-            <Text type="xl-medium" style={pal.text}>
-              Discover new feeds
-            </Text>
-          </Link>
-        )
+        return <DiscoverLink />
       }
       return null
     },
-    [pal],
+    [pal, isMobile],
   )
 
   const ListFooter = React.useCallback(
@@ -150,17 +152,6 @@ export const MultiFeed = observer(function Feed({
     [multifeed.isLoading, isRefreshing, pal],
   )
 
-  const ListHeader = React.useCallback(() => {
-    return (
-      <Link style={[styles.footerLink, pal.viewLight]} href="/search/feeds">
-        <FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
-        <Text type="xl-medium" style={pal.text}>
-          Discover new feeds
-        </Text>
-      </Link>
-    )
-  }, [pal])
-
   return (
     <View testID={testID} style={style}>
       {multifeed.items.length > 0 && (
@@ -171,7 +162,6 @@ export const MultiFeed = observer(function Feed({
           keyExtractor={item => item._reactKey}
           renderItem={renderItem}
           ListFooterComponent={ListFooter}
-          ListHeaderComponent={ListHeader}
           refreshControl={
             <RefreshControl
               refreshing={isRefreshing}
@@ -199,6 +189,18 @@ export const MultiFeed = observer(function Feed({
   )
 })
 
+function DiscoverLink() {
+  const pal = usePalette('default')
+  return (
+    <Link style={[styles.discoverLink, pal.viewLight]} href="/search/feeds">
+      <FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
+      <Text type="xl-medium" style={pal.text}>
+        Discover new feeds
+      </Text>
+    </Link>
+  )
+}
+
 const styles = StyleSheet.create({
   container: {
     height: '100%',
@@ -237,7 +239,7 @@ const styles = StyleSheet.create({
     borderTopWidth: 1,
     borderBottomWidth: 1,
   },
-  footerLink: {
+  discoverLink: {
     flexDirection: 'row',
     alignItems: 'center',
     justifyContent: 'center',
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index dd3fb530e..8786fd0b9 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -27,8 +27,9 @@ import {UserBanner} from '../util/UserBanner'
 import {ProfileHeaderAlerts} from '../util/moderation/ProfileHeaderAlerts'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useAnalytics} from 'lib/analytics/analytics'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {NavigationProp} from 'lib/routes/types'
-import {isDesktopWeb, isNative} from 'platform/detection'
+import {isNative} from 'platform/detection'
 import {FollowState} from 'state/models/cache/my-follows'
 import {shareUrl} from 'lib/sharing'
 import {formatCount} from '../util/numeric/format'
@@ -108,6 +109,7 @@ const ProfileHeaderLoaded = observer(
     const navigation = useNavigation<NavigationProp>()
     const {track} = useAnalytics()
     const invalidHandle = isInvalidHandle(view.handle)
+    const {isDesktop} = useWebMediaQueries()
 
     const onPressBack = React.useCallback(() => {
       navigation.goBack()
@@ -510,7 +512,7 @@ const ProfileHeaderLoaded = observer(
           )}
           <ProfileHeaderAlerts moderation={view.moderation} />
         </View>
-        {!isDesktopWeb && !hideBackButton && (
+        {!isDesktop && !hideBackButton && (
           <TouchableWithoutFeedback
             onPress={onPressBack}
             hitSlop={BACK_HITSLOP}
diff --git a/src/view/com/search/HeaderWithInput.tsx b/src/view/com/search/HeaderWithInput.tsx
index f825c578e..7a8676602 100644
--- a/src/view/com/search/HeaderWithInput.tsx
+++ b/src/view/com/search/HeaderWithInput.tsx
@@ -10,6 +10,7 @@ import {useTheme} from 'lib/ThemeContext'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useStores} from 'state/index'
 import {useAnalytics} from 'lib/analytics/analytics'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {HITSLOP_10} from 'lib/constants'
 
 interface Props {
@@ -37,6 +38,7 @@ export function HeaderWithInput({
   const pal = usePalette('default')
   const {track} = useAnalytics()
   const textInput = React.useRef<TextInput>(null)
+  const {isMobile} = useWebMediaQueries()
 
   const onPressMenu = React.useCallback(() => {
     track('ViewHeader:MenuButtonClicked')
@@ -49,8 +51,14 @@ export function HeaderWithInput({
   }, [onPressCancelSearch, textInput])
 
   return (
-    <View style={[pal.view, pal.border, styles.header]}>
-      {showMenu ? (
+    <View
+      style={[
+        pal.view,
+        pal.border,
+        styles.header,
+        !isMobile && styles.headerDesktop,
+      ]}>
+      {showMenu && isMobile ? (
         <TouchableOpacity
           testID="viewHeaderBackOrMenuBtn"
           onPress={onPressMenu}
@@ -85,7 +93,7 @@ export function HeaderWithInput({
           onBlur={() => setIsInputFocused(false)}
           onChangeText={onChangeQuery}
           onSubmitEditing={onSubmitQuery}
-          autoFocus={true}
+          autoFocus={isMobile}
           accessibilityRole="search"
           accessibilityLabel="Search"
           accessibilityHint=""
@@ -127,6 +135,11 @@ const styles = StyleSheet.create({
     paddingHorizontal: 12,
     paddingVertical: 4,
   },
+  headerDesktop: {
+    borderWidth: 1,
+    borderTopWidth: 0,
+    paddingVertical: 10,
+  },
   headerMenuBtn: {
     width: 30,
     height: 30,
diff --git a/src/view/com/search/SearchResults.tsx b/src/view/com/search/SearchResults.tsx
index 984277705..e74a8cfe4 100644
--- a/src/view/com/search/SearchResults.tsx
+++ b/src/view/com/search/SearchResults.tsx
@@ -13,13 +13,14 @@ import {
 } from 'view/com/util/LoadingPlaceholder'
 import {Text} from 'view/com/util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s} from 'lib/styles'
-import {isDesktopWeb} from 'platform/detection'
 
 const SECTIONS = ['Posts', 'Users']
 
 export const SearchResults = observer(({model}: {model: SearchUIModel}) => {
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
 
   const renderTabBar = React.useCallback(
     (props: RenderTabBarFnProps) => {
@@ -39,10 +40,16 @@ export const SearchResults = observer(({model}: {model: SearchUIModel}) => {
 
   return (
     <Pager renderTabBar={renderTabBar} tabBarPosition="top" initialPage={0}>
-      <View style={[styles.results]}>
+      <View
+        style={{
+          paddingTop: isMobile ? 42 : 50,
+        }}>
         <PostResults key="0" model={model} />
       </View>
-      <View style={[styles.results]}>
+      <View
+        style={{
+          paddingTop: isMobile ? 42 : 50,
+        }}>
         <Profiles key="1" model={model} />
       </View>
     </Pager>
@@ -128,7 +135,4 @@ const styles = StyleSheet.create({
     paddingHorizontal: 14,
     paddingVertical: 16,
   },
-  results: {
-    paddingTop: isDesktopWeb ? 50 : 42,
-  },
 })
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index 7482db8eb..91cdb08c7 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -8,9 +8,9 @@ import {Text} from './text/Text'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {NavigationProp} from 'lib/routes/types'
-import {isDesktopWeb} from 'platform/detection'
 
 const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
 
@@ -35,6 +35,7 @@ export const ViewHeader = observer(function ({
   const store = useStores()
   const navigation = useNavigation<NavigationProp>()
   const {track} = useAnalytics()
+  const {isDesktop, isTablet} = useWebMediaQueries()
 
   const onPressBack = React.useCallback(() => {
     if (navigation.canGoBack()) {
@@ -49,7 +50,7 @@ export const ViewHeader = observer(function ({
     store.shell.openDrawer()
   }, [track, store])
 
-  if (isDesktopWeb) {
+  if (isDesktop) {
     if (showOnDesktop) {
       return (
         <DesktopWebHeader
@@ -84,13 +85,13 @@ export const ViewHeader = observer(function ({
                 icon="angle-left"
                 style={[styles.backIcon, pal.text]}
               />
-            ) : (
+            ) : !isTablet ? (
               <FontAwesomeIcon
                 size={18}
                 icon="bars"
                 style={[styles.backIcon, pal.textLight]}
               />
-            )}
+            ) : null}
           </TouchableOpacity>
         ) : null}
         <View style={styles.titleContainer} pointerEvents="none">
@@ -122,6 +123,7 @@ function DesktopWebHeader({
     <CenteredView
       style={[
         styles.header,
+        styles.headerFixed,
         styles.desktopHeader,
         pal.border,
         {
@@ -178,6 +180,7 @@ const Container = observer(
         <View
           style={[
             styles.header,
+            styles.headerFixed,
             pal.view,
             pal.border,
             showBorder && styles.border,
@@ -190,9 +193,9 @@ const Container = observer(
       <Animated.View
         style={[
           styles.header,
+          styles.headerFloating,
           pal.view,
           pal.border,
-          styles.headerFloating,
           transform,
           showBorder && styles.border,
         ]}>
@@ -208,6 +211,12 @@ const styles = StyleSheet.create({
     alignItems: 'center',
     paddingHorizontal: 12,
     paddingVertical: 6,
+    width: '100%',
+  },
+  headerFixed: {
+    maxWidth: 600,
+    marginLeft: 'auto',
+    marginRight: 'auto',
   },
   headerFloating: {
     position: 'absolute',
diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx
index 3313492e1..58a367f20 100644
--- a/src/view/com/util/Views.web.tsx
+++ b/src/view/com/util/Views.web.tsx
@@ -24,6 +24,7 @@ import {
 } from 'react-native'
 import {addStyle} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 interface AddedProps {
   desktopFixedHeight?: boolean
@@ -48,6 +49,7 @@ export const FlatList = React.forwardRef(function <ItemT>(
   ref: React.Ref<RNFlatList>,
 ) {
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   contentContainerStyle = addStyle(
     contentContainerStyle,
     styles.containerScroll,
@@ -67,6 +69,12 @@ export const FlatList = React.forwardRef(function <ItemT>(
   }
   if (desktopFixedHeight) {
     style = addStyle(style, styles.fixedHeight)
+    if (!isMobile) {
+      contentContainerStyle = addStyle(
+        contentContainerStyle,
+        styles.stableGutters,
+      )
+    }
   }
   return (
     <RNFlatList
@@ -126,6 +134,9 @@ const styles = StyleSheet.create({
   },
   fixedHeight: {
     height: '100vh',
+  },
+  stableGutters: {
+    // @ts-ignore web only -prf
     scrollbarGutter: 'stable both-edges',
   },
 })
diff --git a/src/view/com/util/fab/FABInner.tsx b/src/view/com/util/fab/FABInner.tsx
index 76824e575..afd172c82 100644
--- a/src/view/com/util/fab/FABInner.tsx
+++ b/src/view/com/util/fab/FABInner.tsx
@@ -5,7 +5,8 @@ import LinearGradient from 'react-native-linear-gradient'
 import {gradients} from 'lib/styles'
 import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
 import {useStores} from 'state/index'
-import {isMobileWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {isWeb} from 'platform/detection'
 
 export interface FABProps
   extends ComponentProps<typeof TouchableWithoutFeedback> {
@@ -14,6 +15,7 @@ export interface FABProps
 }
 
 export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
+  const {isTablet} = useWebMediaQueries()
   const store = useStores()
   const interp = useAnimatedValue(0)
   React.useEffect(() => {
@@ -24,18 +26,33 @@ export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
       isInteraction: false,
     }).start()
   }, [interp, store.shell.minimalShellMode])
-  const transform = {
-    transform: [{translateY: Animated.multiply(interp, 60)}],
-  }
+  const transform = isTablet
+    ? undefined
+    : {
+        transform: [{translateY: Animated.multiply(interp, 60)}],
+      }
+  const size = isTablet ? styles.sizeLarge : styles.sizeRegular
   return (
     <TouchableWithoutFeedback testID={testID} {...props}>
       <Animated.View
-        style={[styles.outer, isMobileWeb && styles.mobileWebOuter, transform]}>
+        style={[
+          styles.outer,
+          size,
+          isWeb && isTablet
+            ? {
+                right: 50,
+                bottom: 50,
+              }
+            : {
+                bottom: 114,
+              },
+          transform,
+        ]}>
         <LinearGradient
           colors={[gradients.blueLight.start, gradients.blueLight.end]}
           start={{x: 0, y: 0}}
           end={{x: 1, y: 1}}
-          style={styles.inner}>
+          style={[styles.inner, size]}>
           {icon}
         </LinearGradient>
       </Animated.View>
@@ -44,22 +61,23 @@ export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
 })
 
 const styles = StyleSheet.create({
+  sizeRegular: {
+    width: 60,
+    height: 60,
+    borderRadius: 30,
+  },
+  sizeLarge: {
+    width: 70,
+    height: 70,
+    borderRadius: 35,
+  },
   outer: {
     position: 'absolute',
     zIndex: 1,
     right: 24,
     bottom: 94,
-    width: 60,
-    height: 60,
-    borderRadius: 30,
-  },
-  mobileWebOuter: {
-    bottom: 114,
   },
   inner: {
-    width: 60,
-    height: 60,
-    borderRadius: 30,
     justifyContent: 'center',
     alignItems: 'center',
   },
diff --git a/src/view/com/util/forms/SelectableBtn.tsx b/src/view/com/util/forms/SelectableBtn.tsx
index 4b494264e..f09d063a1 100644
--- a/src/view/com/util/forms/SelectableBtn.tsx
+++ b/src/view/com/util/forms/SelectableBtn.tsx
@@ -2,7 +2,7 @@ import React from 'react'
 import {Pressable, ViewStyle, StyleProp, StyleSheet} from 'react-native'
 import {Text} from '../text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 interface SelectableBtnProps {
   testID?: string
@@ -28,12 +28,16 @@ export function SelectableBtn({
   const pal = usePalette('default')
   const palPrimary = usePalette('inverted')
   const needsWidthStyles = !style || !('width' in style || 'flex' in style)
+  const {isMobile} = useWebMediaQueries()
   return (
     <Pressable
       testID={testID}
       style={[
         styles.btn,
-        needsWidthStyles && styles.btnWidth,
+        needsWidthStyles && {
+          flex: isMobile ? 1 : undefined,
+          width: !isMobile ? 100 : undefined,
+        },
         left && styles.btnLeft,
         right && styles.btnRight,
         pal.border,
@@ -58,10 +62,6 @@ const styles = StyleSheet.create({
     paddingHorizontal: 10,
     paddingVertical: 10,
   },
-  btnWidth: {
-    flex: isDesktopWeb ? undefined : 1,
-    width: isDesktopWeb ? 100 : undefined,
-  },
   btnLeft: {
     borderTopLeftRadius: 8,
     borderBottomLeftRadius: 8,
diff --git a/src/view/com/util/layouts/Breakpoints.web.tsx b/src/view/com/util/layouts/Breakpoints.web.tsx
index 7031a1735..5cf73df0c 100644
--- a/src/view/com/util/layouts/Breakpoints.web.tsx
+++ b/src/view/com/util/layouts/Breakpoints.web.tsx
@@ -2,18 +2,18 @@ import React from 'react'
 import MediaQuery from 'react-responsive'
 
 export const Desktop = ({children}: React.PropsWithChildren<{}>) => (
-  <MediaQuery minWidth={1224}>{children}</MediaQuery>
+  <MediaQuery minWidth={1300}>{children}</MediaQuery>
 )
 export const TabletOrDesktop = ({children}: React.PropsWithChildren<{}>) => (
   <MediaQuery minWidth={800}>{children}</MediaQuery>
 )
 export const Tablet = ({children}: React.PropsWithChildren<{}>) => (
-  <MediaQuery minWidth={800} maxWidth={1224}>
+  <MediaQuery minWidth={800} maxWidth={1300}>
     {children}
   </MediaQuery>
 )
 export const TabletOrMobile = ({children}: React.PropsWithChildren<{}>) => (
-  <MediaQuery maxWidth={1224}>{children}</MediaQuery>
+  <MediaQuery maxWidth={1300}>{children}</MediaQuery>
 )
 export const Mobile = ({children}: React.PropsWithChildren<{}>) => (
   <MediaQuery maxWidth={800}>{children}</MediaQuery>
diff --git a/src/view/com/util/load-latest/LoadLatestBtn.web.tsx b/src/view/com/util/load-latest/LoadLatestBtn.web.tsx
index c90e5dfb1..c9576e56b 100644
--- a/src/view/com/util/load-latest/LoadLatestBtn.web.tsx
+++ b/src/view/com/util/load-latest/LoadLatestBtn.web.tsx
@@ -3,8 +3,8 @@ import {StyleSheet, TouchableOpacity} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {Text} from '../text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {LoadLatestBtn as LoadLatestBtnMobile} from './LoadLatestBtnMobile'
-import {isMobileWeb} from 'platform/detection'
 import {HITSLOP_20} from 'lib/constants'
 
 export const LoadLatestBtn = ({
@@ -19,7 +19,8 @@ export const LoadLatestBtn = ({
   minimalShellMode?: boolean
 }) => {
   const pal = usePalette('default')
-  if (isMobileWeb) {
+  const {isMobile} = useWebMediaQueries()
+  if (isMobile) {
     return (
       <LoadLatestBtnMobile
         onPress={onPress}
diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx
index 853f7840c..6cf1cefd0 100644
--- a/src/view/com/util/moderation/ContentHider.tsx
+++ b/src/view/com/util/moderation/ContentHider.tsx
@@ -1,12 +1,12 @@
 import React from 'react'
 import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {ModerationUI} from '@atproto/api'
 import {Text} from '../text/Text'
 import {ShieldExclamation} from 'lib/icons'
 import {describeModerationCause} from 'lib/moderation'
 import {useStores} from 'state/index'
-import {isDesktopWeb} from 'platform/detection'
 
 export function ContentHider({
   testID,
@@ -24,6 +24,7 @@ export function ContentHider({
 }>) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   const [override, setOverride] = React.useState(false)
 
   if (!moderation.blur || (ignoreMute && moderation.cause?.type === 'muted')) {
@@ -54,6 +55,7 @@ export function ContentHider({
         accessibilityLabel=""
         style={[
           styles.cover,
+          {paddingRight: isMobile ? 22 : 18},
           moderation.noOverride
             ? {borderWidth: 1, borderColor: pal.colors.borderDark}
             : pal.viewLight,
@@ -96,7 +98,6 @@ const styles = StyleSheet.create({
     marginTop: 4,
     paddingVertical: 14,
     paddingLeft: 14,
-    paddingRight: isDesktopWeb ? 18 : 22,
   },
   showBtn: {
     marginLeft: 'auto',
diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx
index 2a52561d4..443885dfa 100644
--- a/src/view/com/util/moderation/PostHider.tsx
+++ b/src/view/com/util/moderation/PostHider.tsx
@@ -2,13 +2,13 @@ import React, {ComponentProps} from 'react'
 import {StyleSheet, Pressable, View} from 'react-native'
 import {ModerationUI} from '@atproto/api'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {Link} from '../Link'
 import {Text} from '../text/Text'
 import {addStyle} from 'lib/styles'
 import {describeModerationCause} from 'lib/moderation'
 import {ShieldExclamation} from 'lib/icons'
 import {useStores} from 'state/index'
-import {isDesktopWeb} from 'platform/detection'
 
 interface Props extends ComponentProps<typeof Link> {
   // testID?: string
@@ -27,6 +27,7 @@ export function PostHider({
 }: Props) {
   const store = useStores()
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   const [override, setOverride] = React.useState(false)
 
   if (!moderation.blur) {
@@ -55,7 +56,11 @@ export function PostHider({
         accessibilityRole="button"
         accessibilityHint={override ? 'Hide the content' : 'Show the content'}
         accessibilityLabel=""
-        style={[styles.description, pal.viewLight]}>
+        style={[
+          styles.description,
+          {paddingRight: isMobile ? 22 : 18},
+          pal.viewLight,
+        ]}>
         <Pressable
           onPress={() => {
             store.shell.openModal({
@@ -100,7 +105,6 @@ const styles = StyleSheet.create({
     gap: 4,
     paddingVertical: 14,
     paddingLeft: 18,
-    paddingRight: isDesktopWeb ? 18 : 22,
     marginTop: 1,
   },
   showBtn: {
diff --git a/src/view/com/util/moderation/ScreenHider.tsx b/src/view/com/util/moderation/ScreenHider.tsx
index b76b1101c..0224b9fee 100644
--- a/src/view/com/util/moderation/ScreenHider.tsx
+++ b/src/view/com/util/moderation/ScreenHider.tsx
@@ -13,10 +13,10 @@ import {
 import {useNavigation} from '@react-navigation/native'
 import {ModerationUI} from '@atproto/api'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {NavigationProp} from 'lib/routes/types'
 import {Text} from '../text/Text'
 import {Button} from '../forms/Button'
-import {isDesktopWeb} from 'platform/detection'
 import {describeModerationCause} from 'lib/moderation'
 import {useStores} from 'state/index'
 
@@ -39,6 +39,7 @@ export function ScreenHider({
   const palInverted = usePalette('inverted')
   const [override, setOverride] = React.useState(false)
   const navigation = useNavigation<NavigationProp>()
+  const {isMobile} = useWebMediaQueries()
 
   if (!moderation.blur || override) {
     return (
@@ -85,7 +86,7 @@ export function ScreenHider({
           </Text>
         </TouchableWithoutFeedback>
       </Text>
-      {!isDesktopWeb && <View style={styles.spacer} />}
+      {isMobile && <View style={styles.spacer} />}
       <View style={styles.btnContainer}>
         <Button
           type="inverted"
diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
index 81f1ca560..d5bb38fb2 100644
--- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
+++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
@@ -3,8 +3,8 @@ import {Image} from 'expo-image'
 import {Text} from '../text/Text'
 import {StyleSheet, View} from 'react-native'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {AppBskyEmbedExternal} from '@atproto/api'
-import {isDesktopWeb} from 'platform/detection'
 import {toNiceDomain} from 'lib/strings/url-helpers'
 
 export const ExternalLinkEmbed = ({
@@ -15,10 +15,31 @@ export const ExternalLinkEmbed = ({
   imageChild?: React.ReactNode
 }) => {
   const pal = usePalette('default')
+  const {isMobile} = useWebMediaQueries()
   return (
-    <View style={styles.extContainer}>
+    <View
+      style={{
+        flexDirection: isMobile ? 'column' : 'row',
+      }}>
       {link.thumb ? (
-        <View style={styles.extImageContainer}>
+        <View
+          style={
+            !isMobile
+              ? {
+                  borderTopLeftRadius: 6,
+                  borderBottomLeftRadius: 6,
+                  width: 120,
+                  aspectRatio: 1,
+                  overflow: 'hidden',
+                }
+              : {
+                  borderTopLeftRadius: 6,
+                  borderTopRightRadius: 6,
+                  width: '100%',
+                  height: 200,
+                  overflow: 'hidden',
+                }
+          }>
           <Image
             style={styles.extImage}
             source={{uri: link.thumb}}
@@ -27,7 +48,13 @@ export const ExternalLinkEmbed = ({
           {imageChild}
         </View>
       ) : undefined}
-      <View style={styles.extInner}>
+      <View
+        style={{
+          paddingHorizontal: isMobile ? 10 : 14,
+          paddingTop: 8,
+          paddingBottom: 10,
+          flex: !isMobile ? 1 : undefined,
+        }}>
         <Text
           type="sm"
           numberOfLines={1}
@@ -36,14 +63,14 @@ export const ExternalLinkEmbed = ({
         </Text>
         <Text
           type="lg-bold"
-          numberOfLines={isDesktopWeb ? 2 : 4}
+          numberOfLines={isMobile ? 4 : 2}
           style={[pal.text]}>
           {link.title || link.uri}
         </Text>
         {link.description ? (
           <Text
             type="md"
-            numberOfLines={isDesktopWeb ? 2 : 4}
+            numberOfLines={isMobile ? 4 : 2}
             style={[pal.text, styles.extDescription]}>
             {link.description}
           </Text>
@@ -54,30 +81,6 @@ export const ExternalLinkEmbed = ({
 }
 
 const styles = StyleSheet.create({
-  extContainer: {
-    flexDirection: isDesktopWeb ? 'row' : 'column',
-  },
-  extInner: {
-    paddingHorizontal: isDesktopWeb ? 14 : 10,
-    paddingTop: 8,
-    paddingBottom: 10,
-    flex: isDesktopWeb ? 1 : undefined,
-  },
-  extImageContainer: isDesktopWeb
-    ? {
-        borderTopLeftRadius: 6,
-        borderBottomLeftRadius: 6,
-        width: 120,
-        aspectRatio: 1,
-        overflow: 'hidden',
-      }
-    : {
-        borderTopLeftRadius: 6,
-        borderTopRightRadius: 6,
-        width: '100%',
-        height: 200,
-        overflow: 'hidden',
-      },
   extImage: {
     width: '100%',
     height: 200,
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index bf2365f18..ce6da4a1b 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -22,6 +22,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
 import {ImagesLightbox} from 'state/models/ui/shell'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {YoutubeEmbed} from './YoutubeEmbed'
 import {ExternalLinkEmbed} from './ExternalLinkEmbed'
 import {getYoutubeVideoId} from 'lib/strings/url-helpers'
@@ -29,7 +30,6 @@ import {MaybeQuoteEmbed} from './QuoteEmbed'
 import {AutoSizedImage} from '../images/AutoSizedImage'
 import {CustomFeedEmbed} from './CustomFeedEmbed'
 import {ListEmbed} from './ListEmbed'
-import {isDesktopWeb} from 'platform/detection'
 import {isCauseALabelOnUri} from 'lib/moderation'
 
 type Embed =
@@ -50,6 +50,7 @@ export function PostEmbeds({
 }) {
   const pal = usePalette('default')
   const store = useStores()
+  const {isMobile} = useWebMediaQueries()
 
   // quote post with media
   // =
@@ -111,7 +112,10 @@ export function PostEmbeds({
               uri={thumb}
               onPress={() => openLightbox(0)}
               onPressIn={() => onPressIn(0)}
-              style={styles.singleImage}>
+              style={[
+                styles.singleImage,
+                isMobile && styles.singleImageMobile,
+              ]}>
               {alt === '' ? null : (
                 <View style={styles.altContainer}>
                   <Text style={styles.alt} accessible={false}>
@@ -130,7 +134,11 @@ export function PostEmbeds({
             images={embed.images}
             onPress={openLightbox}
             onPressIn={onPressIn}
-            style={embed.images.length === 1 ? styles.singleImage : undefined}
+            style={
+              embed.images.length === 1
+                ? [styles.singleImage, isMobile && styles.singleImageMobile]
+                : undefined
+            }
           />
         </View>
       )
@@ -169,7 +177,10 @@ const styles = StyleSheet.create({
   },
   singleImage: {
     borderRadius: 8,
-    maxHeight: isDesktopWeb ? 1000 : 500,
+    maxHeight: 1000,
+  },
+  singleImageMobile: {
+    maxHeight: 500,
   },
   extOuter: {
     borderWidth: 1,