diff --git a/packages/shared/src/components/MainFeedLayout.tsx b/packages/shared/src/components/MainFeedLayout.tsx
index 6b863d8fc04..f1132426f89 100644
--- a/packages/shared/src/components/MainFeedLayout.tsx
+++ b/packages/shared/src/components/MainFeedLayout.tsx
@@ -17,7 +17,7 @@ import classNames from 'classnames';
import { useRouter } from 'next/router';
import type { FeedProps } from './Feed';
import Feed from './Feed';
-import { FeedPageLayoutMobile } from './utilities/common';
+import { FeedPageLayoutMobile, feedGutter } from './utilities/common';
import { ExploreChipsBar } from './feeds/ExploreChipsBar';
import { buildPersonalizedCategories } from './feeds/exploreCategories';
import { useFeeds } from '../hooks/feed/useFeeds';
@@ -671,7 +671,14 @@ export default function MainFeedLayout({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sortingEnabled, selectedAlgo, loadedSettings, loadedAlgo]);
- const disableTopPadding = isFinder || shouldUseListFeedLayout;
+ // Explore keeps the page's top padding in both layouts. It renders a
+ // breadcrumb and tab header above the feed, and zeroing the padding
+ // leaves that header jammed under the site header — while
+ // `shouldUseListFeedLayout` flips between first paint and mount
+ // (see `enableSsrSafeLayout`), so keying the spacing to it made the
+ // gap change size on navigation and settle differently on reload.
+ const disableTopPadding =
+ isFinder || (shouldUseListFeedLayout && !isAnyExplore);
const onTabChange = useCallback(
(clickedTab: ExploreTabs) => {
if (clickedTab === ExploreTabs.BestOf && isExtension) {
@@ -694,7 +701,13 @@ export default function MainFeedLayout({
);
}
@@ -705,8 +718,10 @@ export default function MainFeedLayout({
setTab={onTabChange}
showBreadcrumbs={false}
className={{
- container:
+ container: classNames(
'sticky top-[4.5rem] z-header w-full border-b border-border-subtlest-tertiary bg-background-default',
+ feedGutter,
+ ),
tabBarHeader: 'no-scrollbar overflow-x-auto',
tabBarContainer: 'min-w-0 flex-1',
}}
@@ -835,9 +850,7 @@ export default function MainFeedLayout({
) : undefined
}
- className={classNames(
- shouldUseListFeedLayout && !isFinder && 'laptop:px-6',
- )}
+ className={classNames(!isFinder && feedGutter)}
/>
)
)}
diff --git a/packages/shared/src/components/utilities/common.tsx b/packages/shared/src/components/utilities/common.tsx
index c10e822865d..04bccb732f2 100644
--- a/packages/shared/src/components/utilities/common.tsx
+++ b/packages/shared/src/components/utilities/common.tsx
@@ -4,8 +4,6 @@ import classNames from 'classnames';
import classed from '../../lib/classed';
import styles from './utilities.module.css';
import { ArrowIcon } from '../icons';
-import { pageMainClassNames } from '../layout/PageWrapperLayout';
-import { useLayoutVariant } from '../../hooks/layout/useLayoutVariant';
import { SourceMemberRole } from '../../graphql/sources';
import type { OrganizationMemberRole } from '../../features/organizations/types';
@@ -99,23 +97,37 @@ export const BaseFeedPage = classed(
styles.feedPage,
);
-// v2 (dual-sidebar layout) ships the feed inside the floating-card chrome,
-// which provides its own outer inset. The legacy `pageMainClassNames`
-// (`laptop:p-10`) adds another 40px on top, which reads as way too much
-// side spacing inside the card. Drop that padding under v2; control keeps
-// the existing behavior unchanged.
+/**
+ * The feed's horizontal inset — the single source of it.
+ *
+ * It lives on FeedContainer rather than on a page container because
+ * the feed renders through two different ones depending on layout and
+ * route: FeedPage, which carries `pageMainClassNames`, and
+ * FeedPageLayoutList, which forces `!px-0`. FeedContainer is the only
+ * element common to both, so it is the only place an inset applies
+ * everywhere and can never stack with another.
+ *
+ * Chrome outside the container — the breadcrumbs and the tab strip —
+ * uses the same constant to line up with the cards.
+ */
+export const feedGutter = 'px-4 tablet:px-6 laptop:px-10';
+
+// Vertical padding only. The horizontal inset moved to FeedContainer
+// (see `feedGutter`) because this component is not in the tree on
+// every feed route — FeedPageLayoutList is used instead on some — and
+// an inset here would both miss those routes and stack with the one
+// that covers them.
+const feedPageVerticalPadding = 'tablet:py-4 laptop:py-10';
+
export const FeedPage = ({
className,
...props
-}: HTMLAttributes): ReactElement => {
- const { isV2 } = useLayoutVariant();
- return (
-
- );
-};
+}: HTMLAttributes): ReactElement => (
+
+);
export const FeedPageLayoutList = classed(
BasePageContainer,
pageContainerClassNames,