about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-09-05 10:42:19 -0700
committerGitHub <noreply@github.com>2023-09-05 10:42:19 -0700
commit764c7cd5694a41c98d8543b68d7791fa90db4291 (patch)
tree8a11af0aa0e898cf7fb57ab0354f9fb5d28f004e /src
parentbe8084ae103064d5680485f25e202c763957f2b4 (diff)
downloadvoidsky-764c7cd5694a41c98d8543b68d7791fa90db4291.tar.zst
Updates to use dynamic/responsive styles on web (#1351)
* Move most responsive queries to the hook

* Fix invalid CSS value

* Fixes to tablet render of post thread

* Fix overflow issues on web

* Fix search header on tablet

* Fix QP margin in web composer

* Fix: only apply double gutter once to flatlist (close #1368)

* Fix styles on discover feeds header

* Fix double discover links in multifeed
Diffstat (limited to 'src')
-rw-r--r--src/lib/hooks/useWebMediaQueries.tsx20
-rw-r--r--src/platform/detection.ts2
-rw-r--r--src/state/models/feeds/multi-feed.ts3
-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
-rw-r--r--src/view/screens/AppPasswords.tsx23
-rw-r--r--src/view/screens/CustomFeed.tsx21
-rw-r--r--src/view/screens/DiscoverFeeds.tsx32
-rw-r--r--src/view/screens/Feeds.tsx21
-rw-r--r--src/view/screens/Home.tsx30
-rw-r--r--src/view/screens/Moderation.tsx5
-rw-r--r--src/view/screens/ModerationBlockedAccounts.tsx14
-rw-r--r--src/view/screens/ModerationMuteLists.tsx10
-rw-r--r--src/view/screens/ModerationMutedAccounts.tsx14
-rw-r--r--src/view/screens/PostThread.tsx9
-rw-r--r--src/view/screens/PreferencesHomeFeed.tsx23
-rw-r--r--src/view/screens/ProfileList.tsx8
-rw-r--r--src/view/screens/SavedFeeds.tsx18
-rw-r--r--src/view/screens/Search.web.tsx5
-rw-r--r--src/view/screens/Settings.tsx7
-rw-r--r--src/view/shell/Composer.web.tsx24
-rw-r--r--src/view/shell/desktop/LeftNav.tsx147
-rw-r--r--src/view/shell/desktop/RightNav.tsx6
-rw-r--r--src/view/shell/index.web.tsx10
63 files changed, 762 insertions, 461 deletions
diff --git a/src/lib/hooks/useWebMediaQueries.tsx b/src/lib/hooks/useWebMediaQueries.tsx
index fd7e383f0..3f43a0aaf 100644
--- a/src/lib/hooks/useWebMediaQueries.tsx
+++ b/src/lib/hooks/useWebMediaQueries.tsx
@@ -2,13 +2,19 @@ import {useMediaQuery} from 'react-responsive'
 import {isNative} from 'platform/detection'
 
 export function useWebMediaQueries() {
-  const isDesktop = useMediaQuery({
-    query: '(min-width: 1224px)',
-  })
-  const isTabletOrMobile = useMediaQuery({query: '(max-width: 1224px)'})
-  const isMobile = useMediaQuery({query: '(max-width: 800px)'})
+  const isDesktop = useMediaQuery({minWidth: 1300})
+  const isTablet = useMediaQuery({minWidth: 800, maxWidth: 1300})
+  const isMobile = useMediaQuery({maxWidth: 800})
+  const isTabletOrMobile = isMobile || isTablet
+  const isTabletOrDesktop = isDesktop || isTablet
   if (isNative) {
-    return {isMobile: true, isTabletOrMobile: true, isDesktop: false}
+    return {
+      isMobile: true,
+      isTablet: false,
+      isTabletOrMobile: true,
+      isTabletOrDesktop: false,
+      isDesktop: false,
+    }
   }
-  return {isMobile, isTabletOrMobile, isDesktop}
+  return {isMobile, isTablet, isTabletOrMobile, isTabletOrDesktop, isDesktop}
 }
diff --git a/src/platform/detection.ts b/src/platform/detection.ts
index 41ca20e5d..d414b008c 100644
--- a/src/platform/detection.ts
+++ b/src/platform/detection.ts
@@ -7,7 +7,7 @@ export const isAndroid = Platform.OS === 'android'
 export const isNative = isIOS || isAndroid
 export const devicePlatform = isIOS ? 'ios' : isAndroid ? 'android' : 'web'
 export const isWeb = !isNative
-export const isMobileWebMediaQuery = 'only screen and (max-width: 1230px)'
+export const isMobileWebMediaQuery = 'only screen and (max-width: 1300px)'
 export const isMobileWeb =
   isWeb &&
   // @ts-ignore we know window exists -prf
diff --git a/src/state/models/feeds/multi-feed.ts b/src/state/models/feeds/multi-feed.ts
index fdcd208cd..95574fb56 100644
--- a/src/state/models/feeds/multi-feed.ts
+++ b/src/state/models/feeds/multi-feed.ts
@@ -111,7 +111,8 @@ export class PostsMultiFeedModel {
         uri: makeProfileLink(feedInfo.data.creator, 'feed', urip.rkey),
       })
     }
-    if (!this.hasMore) {
+    if (!this.hasMore && this.hasContent) {
+      // only show if hasContent to avoid double discover-feed links
       items.push({_reactKey: '__footer__', type: 'footer'})
     }
     return items
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,
diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx
index 582bc0f9b..8fac86d34 100644
--- a/src/view/screens/AppPasswords.tsx
+++ b/src/view/screens/AppPasswords.tsx
@@ -7,7 +7,7 @@ import {Button} from '../com/util/forms/Button'
 import * as Toast from '../com/util/Toast'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {observer} from 'mobx-react-lite'
 import {NativeStackScreenProps} from '@react-navigation/native-stack'
@@ -23,6 +23,7 @@ export const AppPasswords = withAuthRequired(
     const pal = usePalette('default')
     const store = useStores()
     const {screen} = useAnalytics()
+    const {isTabletOrDesktop} = useWebMediaQueries()
 
     useFocusEffect(
       React.useCallback(() => {
@@ -41,7 +42,7 @@ export const AppPasswords = withAuthRequired(
         <CenteredView
           style={[
             styles.container,
-            isDesktopWeb && styles.containerDesktop,
+            isTabletOrDesktop && styles.containerDesktop,
             pal.view,
             pal.border,
           ]}
@@ -53,11 +54,11 @@ export const AppPasswords = withAuthRequired(
               pressing the button below.
             </Text>
           </View>
-          {!isDesktopWeb && <View style={styles.flex1} />}
+          {!isTabletOrDesktop && <View style={styles.flex1} />}
           <View
             style={[
               styles.btnContainer,
-              isDesktopWeb && styles.btnContainerDesktop,
+              isTabletOrDesktop && styles.btnContainerDesktop,
             ]}>
             <Button
               testID="appPasswordBtn"
@@ -77,7 +78,7 @@ export const AppPasswords = withAuthRequired(
       <CenteredView
         style={[
           styles.container,
-          isDesktopWeb && styles.containerDesktop,
+          isTabletOrDesktop && styles.containerDesktop,
           pal.view,
           pal.border,
         ]}
@@ -87,7 +88,7 @@ export const AppPasswords = withAuthRequired(
           style={[
             styles.scrollContainer,
             pal.border,
-            !isDesktopWeb && styles.flex1,
+            !isTabletOrDesktop && styles.flex1,
           ]}>
           {store.me.appPasswords.map((password, i) => (
             <AppPassword
@@ -97,7 +98,7 @@ export const AppPasswords = withAuthRequired(
               createdAt={password.createdAt}
             />
           ))}
-          {isDesktopWeb && (
+          {isTabletOrDesktop && (
             <View style={[styles.btnContainer, styles.btnContainerDesktop]}>
               <Button
                 testID="appPasswordBtn"
@@ -110,7 +111,7 @@ export const AppPasswords = withAuthRequired(
             </View>
           )}
         </ScrollView>
-        {!isDesktopWeb && (
+        {!isTabletOrDesktop && (
           <View style={styles.btnContainer}>
             <Button
               testID="appPasswordBtn"
@@ -128,6 +129,7 @@ export const AppPasswords = withAuthRequired(
 )
 
 function AppPasswordsHeader() {
+  const {isTabletOrDesktop} = useWebMediaQueries()
   const pal = usePalette('default')
   return (
     <>
@@ -137,7 +139,7 @@ function AppPasswordsHeader() {
         style={[
           styles.description,
           pal.text,
-          isDesktopWeb && styles.descriptionDesktop,
+          isTabletOrDesktop && styles.descriptionDesktop,
         ]}>
         Use app passwords to login to other Bluesky clients without giving full
         access to your account or password.
@@ -207,11 +209,12 @@ function AppPassword({
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 100,
+    paddingBottom: 100,
   },
   containerDesktop: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 0,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/screens/CustomFeed.tsx b/src/view/screens/CustomFeed.tsx
index 01d499dad..f4e1b0eb7 100644
--- a/src/view/screens/CustomFeed.tsx
+++ b/src/view/screens/CustomFeed.tsx
@@ -22,7 +22,7 @@ import {ViewHeader} from 'view/com/util/ViewHeader'
 import {Button} from 'view/com/util/forms/Button'
 import {Text} from 'view/com/util/text/Text'
 import * as Toast from 'view/com/util/Toast'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useSetTitle} from 'lib/hooks/useSetTitle'
 import {shareUrl} from 'lib/sharing'
 import {toShareUrl} from 'lib/strings/url-helpers'
@@ -122,6 +122,7 @@ export const CustomFeedScreenInner = observer(
   ({route, feedOwnerDid}: Props & {feedOwnerDid: string}) => {
     const store = useStores()
     const pal = usePalette('default')
+    const {isTabletOrDesktop} = useWebMediaQueries()
     const {track} = useAnalytics()
     const {rkey, name: handleOrDid} = route.params
     const uri = useMemo(
@@ -357,7 +358,7 @@ export const CustomFeedScreenInner = observer(
                   )}
                 </Text>
               )}
-              {isDesktopWeb && (
+              {isTabletOrDesktop && (
                 <View style={[styles.headerBtns, styles.headerBtnsDesktop]}>
                   <Button
                     type={currentFeed?.isSaved ? 'default' : 'inverted'}
@@ -452,7 +453,14 @@ export const CustomFeedScreenInner = observer(
               ) : null}
             </View>
           </View>
-          <View style={[styles.fakeSelector, pal.border]}>
+          <View
+            style={[
+              styles.fakeSelector,
+              {
+                paddingHorizontal: isTabletOrDesktop ? 16 : 6,
+              },
+              pal.border,
+            ]}>
             <View
               style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
               <Text type="md-medium" style={[pal.text]}>
@@ -474,6 +482,7 @@ export const CustomFeedScreenInner = observer(
       rkey,
       isPinned,
       onTogglePinned,
+      isTabletOrDesktop,
     ])
 
     const renderEmptyState = React.useCallback(() => {
@@ -486,7 +495,9 @@ export const CustomFeedScreenInner = observer(
 
     return (
       <View style={s.hContentRegion}>
-        <ViewHeader title="" renderButton={currentFeed && renderHeaderBtns} />
+        {!isTabletOrDesktop && (
+          <ViewHeader title="" renderButton={currentFeed && renderHeaderBtns} />
+        )}
         <Feed
           scrollElRef={scrollElRef}
           feed={algoFeed}
@@ -495,6 +506,7 @@ export const CustomFeedScreenInner = observer(
           ListHeaderComponent={renderListHeaderComponent}
           renderEmptyState={renderEmptyState}
           extraData={[uri, isPinned]}
+          style={!isTabletOrDesktop ? {flex: 1} : undefined}
         />
         {isScrolledDown ? (
           <LoadLatestBtn
@@ -550,7 +562,6 @@ const styles = StyleSheet.create({
   },
   fakeSelector: {
     flexDirection: 'row',
-    paddingHorizontal: isDesktopWeb ? 16 : 6,
   },
   fakeSelectorItem: {
     paddingHorizontal: 12,
diff --git a/src/view/screens/DiscoverFeeds.tsx b/src/view/screens/DiscoverFeeds.tsx
index d4d4e5e6e..11f38c26a 100644
--- a/src/view/screens/DiscoverFeeds.tsx
+++ b/src/view/screens/DiscoverFeeds.tsx
@@ -10,8 +10,8 @@ import {FeedsDiscoveryModel} from 'state/models/discovery/feeds'
 import {CenteredView, FlatList} from 'view/com/util/Views'
 import {CustomFeed} from 'view/com/feeds/CustomFeed'
 import {Text} from 'view/com/util/text/Text'
-import {isDesktopWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s} from 'lib/styles'
 import {CustomFeedModel} from 'state/models/feeds/custom-feed'
 import {HeaderWithInput} from 'view/com/search/HeaderWithInput'
@@ -23,6 +23,7 @@ export const DiscoverFeedsScreen = withAuthRequired(
     const store = useStores()
     const pal = usePalette('default')
     const feeds = React.useMemo(() => new FeedsDiscoveryModel(store), [store])
+    const {isTabletOrDesktop} = useWebMediaQueries()
 
     // search stuff
     const [isInputFocused, setIsInputFocused] = React.useState<boolean>(false)
@@ -74,7 +75,7 @@ export const DiscoverFeedsScreen = withAuthRequired(
         <View style={styles.empty}>
           <Text type="lg" style={pal.textLight}>
             {feeds.isLoading
-              ? isDesktopWeb
+              ? isTabletOrDesktop
                 ? 'Loading...'
                 : ''
               : query
@@ -100,23 +101,22 @@ export const DiscoverFeedsScreen = withAuthRequired(
 
     return (
       <CenteredView style={[styles.container, pal.view]}>
-        <View style={[isDesktopWeb && styles.containerDesktop, pal.border]}>
+        <View
+          style={[isTabletOrDesktop && styles.containerDesktop, pal.border]}>
           <ViewHeader title="Discover Feeds" showOnDesktop />
-          <View style={{marginTop: isDesktopWeb ? 5 : 0, marginBottom: 4}}>
-            <HeaderWithInput
-              isInputFocused={isInputFocused}
-              query={query}
-              setIsInputFocused={setIsInputFocused}
-              onChangeQuery={onChangeQuery}
-              onPressClearQuery={onPressClearQuery}
-              onPressCancelSearch={onPressCancelSearch}
-              onSubmitQuery={onSubmitQuery}
-              showMenu={false}
-            />
-          </View>
         </View>
+        <HeaderWithInput
+          isInputFocused={isInputFocused}
+          query={query}
+          setIsInputFocused={setIsInputFocused}
+          onChangeQuery={onChangeQuery}
+          onPressClearQuery={onPressClearQuery}
+          onPressCancelSearch={onPressCancelSearch}
+          onSubmitQuery={onSubmitQuery}
+          showMenu={false}
+        />
         <FlatList
-          style={[!isDesktopWeb && s.flex1]}
+          style={[!isTabletOrDesktop && s.flex1]}
           data={feeds.feeds}
           keyExtractor={item => item.data.uri}
           contentContainerStyle={styles.contentContainer}
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx
index 7d45ce4c1..6e0706737 100644
--- a/src/view/screens/Feeds.tsx
+++ b/src/view/screens/Feeds.tsx
@@ -12,22 +12,23 @@ import {NativeStackScreenProps, FeedsTabNavigatorParams} from 'lib/routes/types'
 import {observer} from 'mobx-react-lite'
 import {PostsMultiFeedModel} from 'state/models/feeds/multi-feed'
 import {MultiFeed} from 'view/com/posts/MultiFeed'
-import {isDesktopWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useTimer} from 'lib/hooks/useTimer'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
 import {ComposeIcon2, CogIcon} from 'lib/icons'
 import {s} from 'lib/styles'
 
 const LOAD_NEW_PROMPT_TIME = 60e3 // 60 seconds
-const HEADER_OFFSET = isDesktopWeb ? 0 : 40
+const MOBILE_HEADER_OFFSET = 40
 
 type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
 export const FeedsScreen = withAuthRequired(
   observer<Props>(({}: Props) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isMobile} = useWebMediaQueries()
     const flatListRef = React.useRef<FlatList>(null)
     const multifeed = React.useMemo<PostsMultiFeedModel>(
       () => new PostsMultiFeedModel(store),
@@ -105,14 +106,16 @@ export const FeedsScreen = withAuthRequired(
           multifeed={multifeed}
           onScroll={onMainScroll}
           scrollEventThrottle={100}
-          headerOffset={HEADER_OFFSET}
-        />
-        <ViewHeader
-          title="My Feeds"
-          canGoBack={false}
-          hideOnScroll
-          renderButton={renderHeaderBtn}
+          headerOffset={isMobile ? MOBILE_HEADER_OFFSET : undefined}
         />
+        {isMobile && (
+          <ViewHeader
+            title="My Feeds"
+            canGoBack={false}
+            hideOnScroll
+            renderButton={renderHeaderBtn}
+          />
+        )}
         {isScrolledDown || loadPromptVisible ? (
           <LoadLatestBtn
             onPress={onSoftReset}
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 4f1ebe039..795d813d1 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -19,14 +19,11 @@ import {useStores} from 'state/index'
 import {s} from 'lib/styles'
 import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
 import {useAnalytics} from 'lib/analytics/analytics'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {ComposeIcon2} from 'lib/icons'
-import {isDesktopWeb, isMobileWebMediaQuery, isWeb} from 'platform/detection'
 
 const HEADER_OFFSET_MOBILE = 78
 const HEADER_OFFSET_DESKTOP = 50
-const HEADER_OFFSET = isDesktopWeb
-  ? HEADER_OFFSET_DESKTOP
-  : HEADER_OFFSET_MOBILE
 const POLL_FREQ = 30e3 // 30sec
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
@@ -158,10 +155,13 @@ const FeedPage = observer(
     renderEmptyState?: () => JSX.Element
   }) => {
     const store = useStores()
+    const {isMobile} = useWebMediaQueries()
     const [onMainScroll, isScrolledDown, resetMainScroll] =
       useOnMainScroll(store)
     const {screen, track} = useAnalytics()
-    const [headerOffset, setHeaderOffset] = React.useState(HEADER_OFFSET)
+    const [headerOffset, setHeaderOffset] = React.useState(
+      isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP,
+    )
     const scrollElRef = React.useRef<FlatList>(null)
     const {appState} = useAppState({
       onForeground: () => doPoll(true),
@@ -206,15 +206,9 @@ const FeedPage = observer(
     }, [isPageFocused, scrollToTop, feed])
 
     // listens for resize events
-    const listenForResize = React.useCallback(() => {
-      // @ts-ignore we know window exists -prf
-      const isMobileWeb = global.window.matchMedia(
-        isMobileWebMediaQuery,
-      )?.matches
-      setHeaderOffset(
-        isMobileWeb ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP,
-      )
-    }, [])
+    React.useEffect(() => {
+      setHeaderOffset(isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP)
+    }, [isMobile])
 
     // fires when page within screen is activated/deactivated
     // - check for latest
@@ -234,17 +228,10 @@ const FeedPage = observer(
         feed.update()
       }
 
-      if (isWeb) {
-        window.addEventListener('resize', listenForResize)
-      }
-
       return () => {
         clearInterval(pollInterval)
         softResetSub.remove()
         feedCleanup()
-        if (isWeb) {
-          isWeb && window.removeEventListener('resize', listenForResize)
-        }
       }
     }, [
       store,
@@ -254,7 +241,6 @@ const FeedPage = observer(
       feed,
       isPageFocused,
       isScreenFocused,
-      listenForResize,
     ])
 
     const onPressCompose = React.useCallback(() => {
diff --git a/src/view/screens/Moderation.tsx b/src/view/screens/Moderation.tsx
index 41df1244e..23a808feb 100644
--- a/src/view/screens/Moderation.tsx
+++ b/src/view/screens/Moderation.tsx
@@ -16,7 +16,7 @@ import {Link} from '../com/util/Link'
 import {Text} from '../com/util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useAnalytics} from 'lib/analytics/analytics'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Moderation'>
 export const ModerationScreen = withAuthRequired(
@@ -24,6 +24,7 @@ export const ModerationScreen = withAuthRequired(
     const pal = usePalette('default')
     const store = useStores()
     const {screen, track} = useAnalytics()
+    const {isTabletOrDesktop} = useWebMediaQueries()
 
     useFocusEffect(
       React.useCallback(() => {
@@ -42,7 +43,7 @@ export const ModerationScreen = withAuthRequired(
         style={[
           s.hContentRegion,
           pal.border,
-          isDesktopWeb ? styles.desktopContainer : pal.viewLight,
+          isTabletOrDesktop ? styles.desktopContainer : pal.viewLight,
         ]}
         testID="moderationScreen">
         <ViewHeader title="Moderation" showOnDesktop />
diff --git a/src/view/screens/ModerationBlockedAccounts.tsx b/src/view/screens/ModerationBlockedAccounts.tsx
index 959c6d9ca..10fa87080 100644
--- a/src/view/screens/ModerationBlockedAccounts.tsx
+++ b/src/view/screens/ModerationBlockedAccounts.tsx
@@ -10,7 +10,7 @@ import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
 import {Text} from '../com/util/text/Text'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {observer} from 'mobx-react-lite'
 import {NativeStackScreenProps} from '@react-navigation/native-stack'
@@ -30,6 +30,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
   observer(({}: Props) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isTabletOrDesktop} = useWebMediaQueries()
     const {screen} = useAnalytics()
     const blockedAccounts = useMemo(
       () => new BlockedAccountsModel(store),
@@ -72,7 +73,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
       <CenteredView
         style={[
           styles.container,
-          isDesktopWeb && styles.containerDesktop,
+          isTabletOrDesktop && styles.containerDesktop,
           pal.view,
           pal.border,
         ]}
@@ -83,14 +84,14 @@ export const ModerationBlockedAccounts = withAuthRequired(
           style={[
             styles.description,
             pal.text,
-            isDesktopWeb && styles.descriptionDesktop,
+            isTabletOrDesktop && styles.descriptionDesktop,
           ]}>
           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.
         </Text>
         {!blockedAccounts.hasContent ? (
-          <View style={[pal.border, !isDesktopWeb && styles.flex1]}>
+          <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
             <View style={[styles.empty, pal.viewLight]}>
               <Text type="lg" style={[pal.text, styles.emptyText]}>
                 You have not blocked any accounts yet. To block an account, go
@@ -101,7 +102,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
           </View>
         ) : (
           <FlatList
-            style={[!isDesktopWeb && styles.flex1]}
+            style={[!isTabletOrDesktop && styles.flex1]}
             data={blockedAccounts.blocks}
             keyExtractor={(item: ActorDefs.ProfileView) => item.did}
             refreshControl={
@@ -133,11 +134,12 @@ export const ModerationBlockedAccounts = withAuthRequired(
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 100,
+    paddingBottom: 100,
   },
   containerDesktop: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 0,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/screens/ModerationMuteLists.tsx b/src/view/screens/ModerationMuteLists.tsx
index c2771290f..bc933c24e 100644
--- a/src/view/screens/ModerationMuteLists.tsx
+++ b/src/view/screens/ModerationMuteLists.tsx
@@ -15,9 +15,9 @@ import {ListsList} from 'view/com/lists/ListsList'
 import {Button} from 'view/com/util/forms/Button'
 import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {CenteredView} from 'view/com/util/Views'
 import {ViewHeader} from 'view/com/util/ViewHeader'
-import {isDesktopWeb} from 'platform/detection'
 
 type Props = NativeStackScreenProps<
   CommonNavigatorParams,
@@ -26,6 +26,7 @@ type Props = NativeStackScreenProps<
 export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
   const pal = usePalette('default')
   const store = useStores()
+  const {isTabletOrDesktop} = useWebMediaQueries()
   const navigation = useNavigation<NavigationProp>()
 
   const mutelists: ListsListModel = React.useMemo(
@@ -89,7 +90,7 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
         styles.container,
         pal.view,
         pal.border,
-        isDesktopWeb && styles.containerDesktop,
+        isTabletOrDesktop && styles.containerDesktop,
       ]}
       testID="moderationMutelistsScreen">
       <ViewHeader
@@ -99,7 +100,7 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
       />
       <ListsList
         listsList={mutelists}
-        showAddBtns={isDesktopWeb}
+        showAddBtns={isTabletOrDesktop}
         renderEmptyState={renderEmptyState}
         onPressCreateNew={onPressNewMuteList}
       />
@@ -110,11 +111,12 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 100,
+    paddingBottom: 100,
   },
   containerDesktop: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 0,
   },
   createBtn: {
     width: 40,
diff --git a/src/view/screens/ModerationMutedAccounts.tsx b/src/view/screens/ModerationMutedAccounts.tsx
index c638a55d7..eb822270a 100644
--- a/src/view/screens/ModerationMutedAccounts.tsx
+++ b/src/view/screens/ModerationMutedAccounts.tsx
@@ -10,7 +10,7 @@ import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
 import {Text} from '../com/util/text/Text'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {observer} from 'mobx-react-lite'
 import {NativeStackScreenProps} from '@react-navigation/native-stack'
@@ -30,6 +30,7 @@ export const ModerationMutedAccounts = withAuthRequired(
   observer(({}: Props) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isTabletOrDesktop} = useWebMediaQueries()
     const {screen} = useAnalytics()
     const mutedAccounts = useMemo(() => new MutedAccountsModel(store), [store])
 
@@ -69,7 +70,7 @@ export const ModerationMutedAccounts = withAuthRequired(
       <CenteredView
         style={[
           styles.container,
-          isDesktopWeb && styles.containerDesktop,
+          isTabletOrDesktop && styles.containerDesktop,
           pal.view,
           pal.border,
         ]}
@@ -80,13 +81,13 @@ export const ModerationMutedAccounts = withAuthRequired(
           style={[
             styles.description,
             pal.text,
-            isDesktopWeb && styles.descriptionDesktop,
+            isTabletOrDesktop && styles.descriptionDesktop,
           ]}>
           Muted accounts have their posts removed from your feed and from your
           notifications. Mutes are completely private.
         </Text>
         {!mutedAccounts.hasContent ? (
-          <View style={[pal.border, !isDesktopWeb && styles.flex1]}>
+          <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
             <View style={[styles.empty, pal.viewLight]}>
               <Text type="lg" style={[pal.text, styles.emptyText]}>
                 You have not muted any accounts yet. To mute an account, go to
@@ -97,7 +98,7 @@ export const ModerationMutedAccounts = withAuthRequired(
           </View>
         ) : (
           <FlatList
-            style={[!isDesktopWeb && styles.flex1]}
+            style={[!isTabletOrDesktop && styles.flex1]}
             data={mutedAccounts.mutes}
             keyExtractor={item => item.did}
             refreshControl={
@@ -129,11 +130,12 @@ export const ModerationMutedAccounts = withAuthRequired(
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 100,
+    paddingBottom: 100,
   },
   containerDesktop: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 0,
   },
   title: {
     textAlign: 'center',
diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx
index 86b2d3027..a6aafa530 100644
--- a/src/view/screens/PostThread.tsx
+++ b/src/view/screens/PostThread.tsx
@@ -12,7 +12,7 @@ import {useStores} from 'state/index'
 import {s} from 'lib/styles'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {clamp} from 'lodash'
-import {isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 const SHELL_FOOTER_HEIGHT = 44
 
@@ -26,6 +26,7 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
     () => new PostThreadModel(store, {uri}),
     [store, uri],
   )
+  const {isMobile} = useWebMediaQueries()
 
   useFocusEffect(
     React.useCallback(() => {
@@ -67,15 +68,15 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
 
   return (
     <View style={s.hContentRegion}>
-      <ViewHeader title="Post" />
-      <View style={s.hContentRegion}>
+      {isMobile && <ViewHeader title="Post" />}
+      <View style={s.flex1}>
         <PostThreadComponent
           uri={uri}
           view={view}
           onPressReply={onPressReply}
         />
       </View>
-      {!isDesktopWeb && (
+      {isMobile && (
         <View
           style={[
             styles.prompt,
diff --git a/src/view/screens/PreferencesHomeFeed.tsx b/src/view/screens/PreferencesHomeFeed.tsx
index b04f274f7..bd6dd8b39 100644
--- a/src/view/screens/PreferencesHomeFeed.tsx
+++ b/src/view/screens/PreferencesHomeFeed.tsx
@@ -6,7 +6,8 @@ import {Text} from '../com/util/text/Text'
 import {useStores} from 'state/index'
 import {s, colors} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isWeb, isDesktopWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {isWeb} from 'platform/detection'
 import {ToggleButton} from 'view/com/util/forms/ToggleButton'
 import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
 import {ViewHeader} from 'view/com/util/ViewHeader'
@@ -50,6 +51,7 @@ type Props = NativeStackScreenProps<
 export const PreferencesHomeFeed = observer(({navigation}: Props) => {
   const pal = usePalette('default')
   const store = useStores()
+  const {isTabletOrDesktop} = useWebMediaQueries()
 
   return (
     <CenteredView
@@ -58,10 +60,11 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
         pal.view,
         pal.border,
         styles.container,
-        isDesktopWeb && styles.desktopContainer,
+        isTabletOrDesktop && styles.desktopContainer,
       ]}>
       <ViewHeader title="Home Feed Preferences" showOnDesktop />
-      <View style={styles.titleSection}>
+      <View
+        style={[styles.titleSection, isTabletOrDesktop && {paddingTop: 20}]}>
         <Text type="xl" style={[pal.textLight, styles.description]}>
           Fine-tune the content you see on your home screen.
         </Text>
@@ -122,7 +125,12 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
         </View>
       </ScrollView>
 
-      <View style={[styles.btnContainer, pal.borderDark]}>
+      <View
+        style={[
+          styles.btnContainer,
+          !isTabletOrDesktop && {borderTopWidth: 1, paddingHorizontal: 20},
+          pal.borderDark,
+        ]}>
         <TouchableOpacity
           testID="confirmBtn"
           onPress={() => {
@@ -130,7 +138,7 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
               ? navigation.goBack()
               : navigation.navigate('Settings')
           }}
-          style={[styles.btn, isDesktopWeb && styles.btnDesktop]}
+          style={[styles.btn, isTabletOrDesktop && styles.btnDesktop]}
           accessibilityRole="button"
           accessibilityLabel="Confirm"
           accessibilityHint="">
@@ -144,15 +152,15 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 40 : 90,
+    paddingBottom: 90,
   },
   desktopContainer: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 40,
   },
   titleSection: {
     paddingBottom: 30,
-    paddingTop: isDesktopWeb ? 20 : 0,
   },
   title: {
     textAlign: 'center',
@@ -184,7 +192,6 @@ const styles = StyleSheet.create({
   },
   btnContainer: {
     paddingTop: 20,
-    borderTopWidth: isDesktopWeb ? 0 : 1,
   },
   dimmed: {
     opacity: 0.3,
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index 3c50fdde0..e86a457b6 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -14,8 +14,8 @@ import {ListModel} from 'state/models/content/list'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useSetTitle} from 'lib/hooks/useSetTitle'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {NavigationProp} from 'lib/routes/types'
-import {isDesktopWeb} from 'platform/detection'
 import {toShareUrl} from 'lib/strings/url-helpers'
 import {shareUrl} from 'lib/sharing'
 import {ListActions} from 'view/com/lists/ListActions'
@@ -26,6 +26,7 @@ export const ProfileListScreen = withAuthRequired(
   observer(({route}: Props) => {
     const store = useStores()
     const navigation = useNavigation<NavigationProp>()
+    const {isTabletOrDesktop} = useWebMediaQueries()
     const pal = usePalette('default')
     const {name, rkey} = route.params
 
@@ -131,7 +132,7 @@ export const ProfileListScreen = withAuthRequired(
       <CenteredView
         style={[
           styles.container,
-          isDesktopWeb && styles.containerDesktop,
+          isTabletOrDesktop && styles.containerDesktop,
           pal.view,
           pal.border,
         ]}
@@ -155,10 +156,11 @@ export const ProfileListScreen = withAuthRequired(
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    paddingBottom: isDesktopWeb ? 0 : 100,
+    paddingBottom: 100,
   },
   containerDesktop: {
     borderLeftWidth: 1,
     borderRightWidth: 1,
+    paddingBottom: 0,
   },
 })
diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx
index aba61e7d9..5055ee76f 100644
--- a/src/view/screens/SavedFeeds.tsx
+++ b/src/view/screens/SavedFeeds.tsx
@@ -14,11 +14,12 @@ import {usePalette} from 'lib/hooks/usePalette'
 import {CommonNavigatorParams} from 'lib/routes/types'
 import {observer} from 'mobx-react-lite'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {ViewHeader} from 'view/com/util/ViewHeader'
 import {CenteredView} from 'view/com/util/Views'
 import {Text} from 'view/com/util/text/Text'
-import {isDesktopWeb, isWeb} from 'platform/detection'
+import {isWeb} from 'platform/detection'
 import {s, colors} from 'lib/styles'
 import DraggableFlatList, {
   ShadowDecorator,
@@ -37,6 +38,7 @@ export const SavedFeeds = withAuthRequired(
   observer(({}: Props) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
     const {screen} = useAnalytics()
 
     const savedFeeds = useMemo(() => store.me.savedFeeds, [store])
@@ -53,7 +55,7 @@ export const SavedFeeds = withAuthRequired(
         <View
           style={[
             pal.border,
-            !isDesktopWeb && s.flex1,
+            isMobile && s.flex1,
             pal.viewLight,
             styles.empty,
           ]}>
@@ -62,7 +64,7 @@ export const SavedFeeds = withAuthRequired(
           </Text>
         </View>
       )
-    }, [pal])
+    }, [pal, isMobile])
 
     const renderListFooterComponent = useCallback(() => {
       return (
@@ -116,15 +118,11 @@ export const SavedFeeds = withAuthRequired(
         style={[
           s.hContentRegion,
           pal.border,
-          isDesktopWeb && styles.desktopContainer,
+          isTabletOrDesktop && styles.desktopContainer,
         ]}>
-        <ViewHeader
-          title="Edit My Feeds"
-          showOnDesktop
-          showBorder={!isDesktopWeb}
-        />
+        <ViewHeader title="Edit My Feeds" showOnDesktop showBorder />
         <DraggableFlatList
-          containerStyle={[isDesktopWeb ? s.hContentRegion : s.flex1]}
+          containerStyle={[isTabletOrDesktop ? s.hContentRegion : s.flex1]}
           data={savedFeeds.all}
           keyExtractor={item => item.data.uri}
           refreshing={savedFeeds.isRefreshing}
diff --git a/src/view/screens/Search.web.tsx b/src/view/screens/Search.web.tsx
index 3218b4579..f325b1233 100644
--- a/src/view/screens/Search.web.tsx
+++ b/src/view/screens/Search.web.tsx
@@ -12,6 +12,7 @@ import {
   SearchTabNavigatorParams,
 } from 'lib/routes/types'
 import {useStores} from 'state/index'
+import {CenteredView} from 'view/com/util/Views'
 import * as Mobile from './SearchMobile'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
@@ -57,9 +58,9 @@ export const SearchScreen = withAuthRequired(
 
     if (!isDesktop) {
       return (
-        <View style={styles.scrollContainer}>
+        <CenteredView style={styles.scrollContainer}>
           <Mobile.SearchScreen navigation={navigation} route={route} />
-        </View>
+        </CenteredView>
       )
     }
 
diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx
index 481d77086..a416bad45 100644
--- a/src/view/screens/Settings.tsx
+++ b/src/view/screens/Settings.tsx
@@ -35,10 +35,10 @@ import {ToggleButton} from 'view/com/util/forms/ToggleButton'
 import {SelectableBtn} from 'view/com/util/forms/SelectableBtn'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useCustomPalette} from 'lib/hooks/useCustomPalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {AccountData} from 'state/models/session'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {NavigationProp} from 'lib/routes/types'
-import {isDesktopWeb} from 'platform/detection'
 import {pluralize} from 'lib/strings/helpers'
 import {formatCount} from 'view/com/util/numeric/format'
 import Clipboard from '@react-native-clipboard/clipboard'
@@ -58,6 +58,7 @@ export const SettingsScreen = withAuthRequired(
     const pal = usePalette('default')
     const store = useStores()
     const navigation = useNavigation<NavigationProp>()
+    const {isMobile} = useWebMediaQueries()
     const {screen, track} = useAnalytics()
     const [isSwitching, setIsSwitching] = React.useState(false)
     const [debugHeaderEnabled, toggleDebugHeader] = useDebugHeaderSetting(
@@ -203,7 +204,7 @@ export const SettingsScreen = withAuthRequired(
         <ViewHeader title="Settings" />
         <ScrollView
           style={[s.hContentRegion]}
-          contentContainerStyle={!isDesktopWeb && pal.viewLight}
+          contentContainerStyle={isMobile && pal.viewLight}
           scrollIndicatorInsets={{right: 1}}>
           <View style={styles.spacer20} />
           {store.session.currentSession !== undefined ? (
@@ -508,7 +509,7 @@ export const SettingsScreen = withAuthRequired(
               System log
             </Text>
           </TouchableOpacity>
-          {isDesktopWeb || __DEV__ ? (
+          {__DEV__ ? (
             <ToggleButton
               type="default-light"
               label="Experiment: Use AppView Proxy"
diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx
index c0da27da6..e8f7908c2 100644
--- a/src/view/shell/Composer.web.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -4,7 +4,7 @@ import {StyleSheet, View} from 'react-native'
 import {ComposePost} from '../com/composer/Composer'
 import {ComposerOpts} from 'state/models/ui/shell'
 import {usePalette} from 'lib/hooks/usePalette'
-import {isMobileWeb} from 'platform/detection'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 const BOTTOM_BAR_HEIGHT = 61
 
@@ -26,6 +26,7 @@ export const Composer = observer(
     mention?: ComposerOpts['mention']
   }) => {
     const pal = usePalette('default')
+    const {isMobile} = useWebMediaQueries()
 
     // rendering
     // =
@@ -36,7 +37,13 @@ export const Composer = observer(
 
     return (
       <View style={styles.mask} aria-modal accessibilityViewIsModal>
-        <View style={[styles.container, pal.view, pal.border]}>
+        <View
+          style={[
+            styles.container,
+            isMobile && styles.containerMobile,
+            pal.view,
+            pal.border,
+          ]}>
           <ComposePost
             replyTo={replyTo}
             quote={quote}
@@ -66,11 +73,14 @@ const styles = StyleSheet.create({
     width: '100%',
     paddingVertical: 0,
     paddingHorizontal: 2,
-    borderRadius: isMobileWeb ? 0 : 8,
-    marginBottom: isMobileWeb ? BOTTOM_BAR_HEIGHT : 0,
+    borderRadius: 8,
+    marginBottom: 0,
     borderWidth: 1,
-    maxHeight: isMobileWeb
-      ? `calc(100% - ${BOTTOM_BAR_HEIGHT}px)`
-      : 'calc(100% - (40px * 2))',
+    maxHeight: 'calc(100% - (40px * 2))',
+  },
+  containerMobile: {
+    borderRadius: 0,
+    marginBottom: BOTTOM_BAR_HEIGHT,
+    maxHeight: `calc(100% - ${BOTTOM_BAR_HEIGHT}px)`,
   },
 })
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 50d482fda..087455d3f 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -17,6 +17,7 @@ import {Link} from 'view/com/util/Link'
 import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {s, colors} from 'lib/styles'
 import {
   HomeIcon,
@@ -41,18 +42,28 @@ import {makeProfileLink} from 'lib/routes/links'
 
 const ProfileCard = observer(() => {
   const store = useStores()
+  const {isDesktop} = useWebMediaQueries()
+  const size = isDesktop ? 64 : 48
   return store.me.handle ? (
-    <Link href={makeProfileLink(store.me)} style={styles.profileCard} asAnchor>
-      <UserAvatar avatar={store.me.avatar} size={64} />
+    <Link
+      href={makeProfileLink(store.me)}
+      style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}
+      asAnchor>
+      <UserAvatar avatar={store.me.avatar} size={size} />
     </Link>
   ) : (
-    <View style={styles.profileCard}>
-      <LoadingPlaceholder width={64} height={64} style={{borderRadius: 64}} />
+    <View style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}>
+      <LoadingPlaceholder
+        width={size}
+        height={size}
+        style={{borderRadius: size}}
+      />
     </View>
   )
 })
 
 function BackBtn() {
+  const {isTablet} = useWebMediaQueries()
   const pal = usePalette('default')
   const navigation = useNavigation<NavigationProp>()
   const shouldShow = useNavigationState(state => !isStateAtTabRoot(state))
@@ -65,7 +76,7 @@ function BackBtn() {
     }
   }, [navigation])
 
-  if (!shouldShow) {
+  if (!shouldShow || isTablet) {
     return <></>
   }
   return (
@@ -96,6 +107,7 @@ const NavItem = observer(
   ({count, href, icon, iconFilled, label}: NavItemProps) => {
     const pal = usePalette('default')
     const store = useStores()
+    const {isDesktop, isTablet} = useWebMediaQueries()
     const [pathName] = React.useMemo(() => router.matchPath(href), [href])
     const currentRouteInfo = useNavigationState(state => {
       if (!state) {
@@ -137,17 +149,28 @@ const NavItem = observer(
         accessibilityRole="tab"
         accessibilityLabel={label}
         accessibilityHint="">
-        <View style={[styles.navItemIconWrapper]}>
+        <View
+          style={[
+            styles.navItemIconWrapper,
+            isTablet && styles.navItemIconWrapperTablet,
+          ]}>
           {isCurrent ? iconFilled : icon}
           {typeof count === 'string' && count ? (
-            <Text type="button" style={styles.navItemCount}>
+            <Text
+              type="button"
+              style={[
+                styles.navItemCount,
+                isTablet && styles.navItemCountTablet,
+              ]}>
               {count}
             </Text>
           ) : null}
         </View>
-        <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
-          {label}
-        </Text>
+        {isDesktop && (
+          <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
+            {label}
+          </Text>
+        )}
       </PressableWithHover>
     )
   },
@@ -156,6 +179,7 @@ const NavItem = observer(
 function ComposeBtn() {
   const store = useStores()
   const {getState} = useNavigation()
+  const {isTablet} = useWebMediaQueries()
 
   const getProfileHandle = () => {
     const {routes} = getState()
@@ -172,6 +196,9 @@ function ComposeBtn() {
   const onPressCompose = () =>
     store.shell.openComposer({mention: getProfileHandle()})
 
+  if (isTablet) {
+    return null
+  }
   return (
     <TouchableOpacity
       style={[styles.newPostBtn]}
@@ -196,28 +223,43 @@ function ComposeBtn() {
 export const DesktopLeftNav = observer(function DesktopLeftNav() {
   const store = useStores()
   const pal = usePalette('default')
+  const {isDesktop, isTablet} = useWebMediaQueries()
 
   return (
-    <View style={[styles.leftNav, pal.view]}>
+    <View
+      style={[
+        styles.leftNav,
+        isTablet && styles.leftNavTablet,
+        pal.view,
+        pal.border,
+      ]}>
       {store.session.hasSession && <ProfileCard />}
       <BackBtn />
       <NavItem
         href="/"
-        icon={<HomeIcon size={24} style={pal.text} />}
+        icon={<HomeIcon size={isDesktop ? 24 : 28} style={pal.text} />}
         iconFilled={
-          <HomeIconSolid strokeWidth={4} size={24} style={pal.text} />
+          <HomeIconSolid
+            strokeWidth={4}
+            size={isDesktop ? 24 : 28}
+            style={pal.text}
+          />
         }
         label="Home"
       />
       <NavItem
         href="/search"
         icon={
-          <MagnifyingGlassIcon2 strokeWidth={2} size={24} style={pal.text} />
+          <MagnifyingGlassIcon2
+            strokeWidth={2}
+            size={isDesktop ? 24 : 26}
+            style={pal.text}
+          />
         }
         iconFilled={
           <MagnifyingGlassIcon2Solid
             strokeWidth={2}
-            size={24}
+            size={isDesktop ? 24 : 26}
             style={pal.text}
           />
         }
@@ -229,14 +271,14 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
           <SatelliteDishIcon
             strokeWidth={1.75}
             style={pal.text as FontAwesomeIconStyle}
-            size={24}
+            size={isDesktop ? 24 : 28}
           />
         }
         iconFilled={
           <SatelliteDishIconSolid
             strokeWidth={1.75}
             style={pal.text as FontAwesomeIconStyle}
-            size={24}
+            size={isDesktop ? 24 : 28}
           />
         }
         label="My Feeds"
@@ -244,9 +286,19 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
       <NavItem
         href="/notifications"
         count={store.me.notifications.unreadCountLabel}
-        icon={<BellIcon strokeWidth={2} size={24} style={pal.text} />}
+        icon={
+          <BellIcon
+            strokeWidth={2}
+            size={isDesktop ? 24 : 26}
+            style={pal.text}
+          />
+        }
         iconFilled={
-          <BellIconSolid strokeWidth={1.5} size={24} style={pal.text} />
+          <BellIconSolid
+            strokeWidth={1.5}
+            size={isDesktop ? 24 : 26}
+            style={pal.text}
+          />
         }
         label="Notifications"
       />
@@ -256,14 +308,14 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
           <HandIcon
             strokeWidth={5.5}
             style={pal.text as FontAwesomeIconStyle}
-            size={24}
+            size={isDesktop ? 24 : 27}
           />
         }
         iconFilled={
           <FontAwesomeIcon
             icon="hand"
             style={pal.text as FontAwesomeIconStyle}
-            size={20}
+            size={isDesktop ? 20 : 26}
           />
         }
         label="Moderation"
@@ -271,18 +323,38 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
       {store.session.hasSession && (
         <NavItem
           href={makeProfileLink(store.me)}
-          icon={<UserIcon strokeWidth={1.75} size={28} style={pal.text} />}
+          icon={
+            <UserIcon
+              strokeWidth={1.75}
+              size={isDesktop ? 28 : 30}
+              style={pal.text}
+            />
+          }
           iconFilled={
-            <UserIconSolid strokeWidth={1.75} size={28} style={pal.text} />
+            <UserIconSolid
+              strokeWidth={1.75}
+              size={isDesktop ? 28 : 30}
+              style={pal.text}
+            />
           }
           label="Profile"
         />
       )}
       <NavItem
         href="/settings"
-        icon={<CogIcon strokeWidth={1.75} size={28} style={pal.text} />}
+        icon={
+          <CogIcon
+            strokeWidth={1.75}
+            size={isDesktop ? 28 : 32}
+            style={pal.text}
+          />
+        }
         iconFilled={
-          <CogIconSolid strokeWidth={1.5} size={28} style={pal.text} />
+          <CogIconSolid
+            strokeWidth={1.5}
+            size={isDesktop ? 28 : 32}
+            style={pal.text}
+          />
         }
         label="Settings"
       />
@@ -300,12 +372,24 @@ const styles = StyleSheet.create({
     maxHeight: 'calc(100vh - 10px)',
     overflowY: 'auto',
   },
+  leftNavTablet: {
+    top: 0,
+    left: 0,
+    right: 'auto',
+    borderRightWidth: 1,
+    height: '100%',
+    width: 76,
+    alignItems: 'center',
+  },
 
   profileCard: {
     marginVertical: 10,
     width: 90,
     paddingLeft: 12,
   },
+  profileCardTablet: {
+    width: 70,
+  },
 
   backBtn: {
     position: 'absolute',
@@ -330,6 +414,10 @@ const styles = StyleSheet.create({
     height: 28,
     marginTop: 2,
   },
+  navItemIconWrapperTablet: {
+    width: 40,
+    height: 40,
+  },
   navItemCount: {
     position: 'absolute',
     top: 0,
@@ -341,6 +429,10 @@ const styles = StyleSheet.create({
     paddingHorizontal: 4,
     borderRadius: 6,
   },
+  navItemCountTablet: {
+    left: 18,
+    fontSize: 14,
+  },
 
   newPostBtn: {
     flexDirection: 'row',
@@ -354,10 +446,9 @@ const styles = StyleSheet.create({
     marginLeft: 12,
     marginTop: 20,
     marginBottom: 10,
+    gap: 8,
   },
-  newPostBtnIconWrapper: {
-    marginRight: 8,
-  },
+  newPostBtnIconWrapper: {},
   newPostBtnLabel: {
     color: colors.white,
     fontSize: 16,
diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx
index 6fbd777fb..746bbcf59 100644
--- a/src/view/shell/desktop/RightNav.tsx
+++ b/src/view/shell/desktop/RightNav.tsx
@@ -9,6 +9,7 @@ import {TextLink} from 'view/com/util/Link'
 import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
 import {s} from 'lib/styles'
 import {useStores} from 'state/index'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {pluralize} from 'lib/strings/helpers'
 import {formatCount} from 'view/com/util/numeric/format'
 
@@ -17,6 +18,11 @@ export const DesktopRightNav = observer(function DesktopRightNav() {
   const pal = usePalette('default')
   const palError = usePalette('error')
 
+  const {isTablet} = useWebMediaQueries()
+  if (isTablet) {
+    return null
+  }
+
   return (
     <View style={[styles.rightNav, pal.view]}>
       {store.session.hasSession && <DesktopSearch />}
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index e36439c82..6182f1ba4 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -19,7 +19,7 @@ import {NavigationProp} from 'lib/routes/types'
 
 const ShellInner = observer(() => {
   const store = useStores()
-  const {isDesktop} = useWebMediaQueries()
+  const {isDesktop, isMobile} = useWebMediaQueries()
   const navigator = useNavigation<NavigationProp>()
 
   useEffect(() => {
@@ -28,11 +28,11 @@ const ShellInner = observer(() => {
     })
   }, [navigator, store.shell])
 
-  const showBottomBar = !isDesktop && !store.onboarding.isActive
+  const showBottomBar = isMobile && !store.onboarding.isActive
   const showSideNavs =
-    isDesktop && store.session.hasSession && !store.onboarding.isActive
+    !isMobile && store.session.hasSession && !store.onboarding.isActive
   return (
-    <>
+    <View style={[s.hContentRegion, {overflow: 'hidden'}]}>
       <View style={s.hContentRegion}>
         <ErrorBoundary>
           <FlatNavigator />
@@ -67,7 +67,7 @@ const ShellInner = observer(() => {
           </View>
         </TouchableOpacity>
       )}
-    </>
+    </View>
   )
 })