diff --git a/app/src/components/index.ts b/app/src/components/index.ts
new file mode 100644
index 0000000000..97d134a163
--- /dev/null
+++ b/app/src/components/index.ts
@@ -0,0 +1,7 @@
+export * from 'src/components/CodeHighlighter';
+export * from 'src/components/ErrorBoundary';
+export * from 'src/components/FeedbackWidget';
+export * from 'src/components/LoaderSpinner';
+export * from 'src/components/RouteErrorBoundary';
+export * from 'src/components/SectionHeader';
+export * from 'src/components/ThemeToggle';
diff --git a/app/src/hooks/index.ts b/app/src/hooks/index.ts
index acf0704c85..693fb8ca55 100644
--- a/app/src/hooks/index.ts
+++ b/app/src/hooks/index.ts
@@ -15,3 +15,6 @@ export type {
} from 'src/hooks/useLayoutContext';
export { useThemeMode } from 'src/hooks/useThemeMode';
export { useLatestRelease } from 'src/hooks/useLatestRelease';
+export * from 'src/hooks/useFeaturedSpecs';
+export * from 'src/hooks/usePlotOfTheDay';
+export * from 'src/hooks/useTypewriter';
diff --git a/app/src/components/BareLayout.tsx b/app/src/layouts/BareLayout.tsx
similarity index 100%
rename from app/src/components/BareLayout.tsx
rename to app/src/layouts/BareLayout.tsx
diff --git a/app/src/components/Footer.test.tsx b/app/src/layouts/Footer.test.tsx
similarity index 98%
rename from app/src/components/Footer.test.tsx
rename to app/src/layouts/Footer.test.tsx
index cd770a432a..9bd55cd5cd 100644
--- a/app/src/components/Footer.test.tsx
+++ b/app/src/layouts/Footer.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
-import { Footer } from 'src/components/Footer';
+import { Footer } from 'src/layouts/Footer';
import { render, screen, userEvent } from 'src/test-utils';
describe('Footer', () => {
diff --git a/app/src/components/Footer.tsx b/app/src/layouts/Footer.tsx
similarity index 100%
rename from app/src/components/Footer.tsx
rename to app/src/layouts/Footer.tsx
diff --git a/app/src/components/Layout.test.tsx b/app/src/layouts/Layout.test.tsx
similarity index 99%
rename from app/src/components/Layout.test.tsx
rename to app/src/layouts/Layout.test.tsx
index 03519562fe..81d6b659c5 100644
--- a/app/src/components/Layout.test.tsx
+++ b/app/src/layouts/Layout.test.tsx
@@ -1,7 +1,7 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
-import { AppDataProvider } from 'src/components/Layout';
import { useAppData } from 'src/hooks/useLayoutContext';
+import { AppDataProvider } from 'src/layouts/Layout';
import { render, screen, waitFor } from 'src/test-utils';
// Helper component that reads the context and renders the four counts
diff --git a/app/src/components/Layout.tsx b/app/src/layouts/Layout.tsx
similarity index 100%
rename from app/src/components/Layout.tsx
rename to app/src/layouts/Layout.tsx
diff --git a/app/src/components/MastheadRule.test.tsx b/app/src/layouts/MastheadRule.test.tsx
similarity index 98%
rename from app/src/components/MastheadRule.test.tsx
rename to app/src/layouts/MastheadRule.test.tsx
index 07bfc02d31..996290569e 100644
--- a/app/src/components/MastheadRule.test.tsx
+++ b/app/src/layouts/MastheadRule.test.tsx
@@ -22,7 +22,7 @@ vi.mock('src/hooks', async () => {
};
});
-import { MastheadRule } from 'src/components/MastheadRule';
+import { MastheadRule } from 'src/layouts/MastheadRule';
function renderAt(initialEntry: string, ui: ReactElement) {
const theme = createTheme();
diff --git a/app/src/components/MastheadRule.tsx b/app/src/layouts/MastheadRule.tsx
similarity index 100%
rename from app/src/components/MastheadRule.tsx
rename to app/src/layouts/MastheadRule.tsx
diff --git a/app/src/components/NavBar.test.tsx b/app/src/layouts/NavBar.test.tsx
similarity index 97%
rename from app/src/components/NavBar.test.tsx
rename to app/src/layouts/NavBar.test.tsx
index 1696288949..c9f70d45ea 100644
--- a/app/src/components/NavBar.test.tsx
+++ b/app/src/layouts/NavBar.test.tsx
@@ -21,7 +21,7 @@ vi.mock('react-router-dom', async () => {
};
});
-import { NavBar } from 'src/components/NavBar';
+import { NavBar } from 'src/layouts/NavBar';
describe('NavBar', () => {
beforeEach(() => {
diff --git a/app/src/components/NavBar.tsx b/app/src/layouts/NavBar.tsx
similarity index 100%
rename from app/src/components/NavBar.tsx
rename to app/src/layouts/NavBar.tsx
diff --git a/app/src/components/RootLayout.test.tsx b/app/src/layouts/RootLayout.test.tsx
similarity index 91%
rename from app/src/components/RootLayout.test.tsx
rename to app/src/layouts/RootLayout.test.tsx
index e657292edb..1ecb91c960 100644
--- a/app/src/components/RootLayout.test.tsx
+++ b/app/src/layouts/RootLayout.test.tsx
@@ -38,13 +38,13 @@ vi.mock('src/hooks/useLayoutContext', async () => {
};
});
-vi.mock('src/components/MastheadRule', () => ({
+vi.mock('src/layouts/MastheadRule', () => ({
MastheadRule: () =>
,
}));
-vi.mock('src/components/NavBar', () => ({ NavBar: () => }));
-vi.mock('src/components/Footer', () => ({ Footer: () => }));
+vi.mock('src/layouts/NavBar', () => ({ NavBar: () => }));
+vi.mock('src/layouts/Footer', () => ({ Footer: () => }));
-import { RootLayout } from 'src/components/RootLayout';
+import { RootLayout } from 'src/layouts/RootLayout';
const theme = createTheme();
diff --git a/app/src/components/RootLayout.tsx b/app/src/layouts/RootLayout.tsx
similarity index 95%
rename from app/src/components/RootLayout.tsx
rename to app/src/layouts/RootLayout.tsx
index 7ed1c85f99..6a6550defb 100644
--- a/app/src/components/RootLayout.tsx
+++ b/app/src/layouts/RootLayout.tsx
@@ -6,12 +6,12 @@ import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
import { FeedbackWidget } from 'src/components/FeedbackWidget';
-import { Footer } from 'src/components/Footer';
-import { MastheadRule } from 'src/components/MastheadRule';
-import { NavBar } from 'src/components/NavBar';
import { useAnalytics } from 'src/hooks';
import { setAnalyticsAmbientProps } from 'src/hooks/useAnalytics';
import { useTheme } from 'src/hooks/useLayoutContext';
+import { Footer } from 'src/layouts/Footer';
+import { MastheadRule } from 'src/layouts/MastheadRule';
+import { NavBar } from 'src/layouts/NavBar';
import { paths } from 'src/routes/paths';
const containerSx = {
diff --git a/app/src/layouts/index.ts b/app/src/layouts/index.ts
new file mode 100644
index 0000000000..79d77bb75d
--- /dev/null
+++ b/app/src/layouts/index.ts
@@ -0,0 +1,6 @@
+export * from 'src/layouts/BareLayout';
+export * from 'src/layouts/Footer';
+export * from 'src/layouts/Layout';
+export * from 'src/layouts/MastheadRule';
+export * from 'src/layouts/NavBar';
+export * from 'src/layouts/RootLayout';
diff --git a/app/src/pages/LandingPage.test.tsx b/app/src/pages/LandingPage.test.tsx
index 087a320b81..90d0a4561d 100644
--- a/app/src/pages/LandingPage.test.tsx
+++ b/app/src/pages/LandingPage.test.tsx
@@ -49,11 +49,11 @@ vi.mock('react-router-dom', async () => {
return { ...actual, useNavigate: () => navigate };
});
-vi.mock('src/components/HeroSection', () => ({
+vi.mock('src/sections/landing/HeroSection', () => ({
HeroSection: () => ,
}));
-vi.mock('src/components/NumbersStrip', () => ({
+vi.mock('src/sections/landing/NumbersStrip', () => ({
NumbersStrip: () => ,
}));
diff --git a/app/src/pages/LandingPage.tsx b/app/src/pages/LandingPage.tsx
index 76ff184706..704aacad4b 100644
--- a/app/src/pages/LandingPage.tsx
+++ b/app/src/pages/LandingPage.tsx
@@ -5,9 +5,6 @@ import { Link as RouterLink, useNavigate } from 'react-router-dom';
import Box from '@mui/material/Box';
-import { HeroSection } from 'src/components/HeroSection';
-import { LibrariesSection } from 'src/components/LibrariesSection';
-import { NumbersStrip } from 'src/components/NumbersStrip';
import { SectionHeader } from 'src/components/SectionHeader';
import { GITHUB_URL } from 'src/constants';
import { useAnalytics, useAppData } from 'src/hooks';
@@ -15,6 +12,9 @@ import { type FeaturedImpl, useFeaturedSpecs } from 'src/hooks/useFeaturedSpecs'
import { useTheme } from 'src/hooks/useLayoutContext';
import { usePlotOfTheDay } from 'src/hooks/usePlotOfTheDay';
import { paths, specPath } from 'src/routes/paths';
+import { HeroSection } from 'src/sections/landing/HeroSection';
+import { LibrariesSection } from 'src/sections/landing/LibrariesSection';
+import { NumbersStrip } from 'src/sections/landing/NumbersStrip';
import { colors, semanticColors, typography } from 'src/theme';
import { buildSrcSet, getFallbackSrc } from 'src/utils/responsiveImage';
import { selectPreviewUrl } from 'src/utils/themedPreview';
diff --git a/app/src/pages/LibrariesPage.tsx b/app/src/pages/LibrariesPage.tsx
index f7fdd091ce..ce6e7784d0 100644
--- a/app/src/pages/LibrariesPage.tsx
+++ b/app/src/pages/LibrariesPage.tsx
@@ -6,11 +6,11 @@ import { useNavigate } from 'react-router-dom';
import Box from '@mui/material/Box';
import Link from '@mui/material/Link';
-import { LibraryCard } from 'src/components/LibraryCard';
import { SectionHeader } from 'src/components/SectionHeader';
import { LIB_TO_FRAMEWORK, LIBRARIES } from 'src/constants';
import { useAnalytics, useAppData } from 'src/hooks';
import { paths } from 'src/routes/paths';
+import { LibraryCard } from 'src/sections/libraries/LibraryCard';
import { colors, textStyle, typography } from 'src/theme';
// Framework filter (per library-expansion.md ยง6: "all JavaScript libs" vs
diff --git a/app/src/pages/PlotsPage.test.tsx b/app/src/pages/PlotsPage.test.tsx
index 84ad15ab3e..1b184d854d 100644
--- a/app/src/pages/PlotsPage.test.tsx
+++ b/app/src/pages/PlotsPage.test.tsx
@@ -42,15 +42,15 @@ vi.mock('react-helmet-async', () => ({
),
}));
-vi.mock('src/components/FilterBar', () => ({
+vi.mock('src/sections/plots-gallery/FilterBar', () => ({
FilterBar: () => FilterBar
,
}));
-vi.mock('src/components/ImagesGrid', () => ({
+vi.mock('src/sections/plots-gallery/ImagesGrid', () => ({
ImagesGrid: () => ImagesGrid
,
}));
-vi.mock('src/components/Footer', () => ({
+vi.mock('src/layouts/Footer', () => ({
Footer: () => Footer
,
}));
diff --git a/app/src/pages/PlotsPage.tsx b/app/src/pages/PlotsPage.tsx
index c08620b636..fe0aea498c 100644
--- a/app/src/pages/PlotsPage.tsx
+++ b/app/src/pages/PlotsPage.tsx
@@ -8,12 +8,12 @@ import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Fab from '@mui/material/Fab';
-import { FilterBar } from 'src/components/FilterBar';
-import { ImagesGrid } from 'src/components/ImagesGrid';
import type { ImageSize } from 'src/constants';
import { isFiltersEmpty, useAnalytics, useFilterState, useInfiniteScroll } from 'src/hooks';
import { useAppData, useHomeState } from 'src/hooks';
import { specPath } from 'src/routes/paths';
+import { FilterBar } from 'src/sections/plots-gallery/FilterBar';
+import { ImagesGrid } from 'src/sections/plots-gallery/ImagesGrid';
import { colors } from 'src/theme';
import type { PlotImage } from 'src/types';
diff --git a/app/src/pages/SpecPage.test.tsx b/app/src/pages/SpecPage.test.tsx
index e981ced09a..da02b03bbe 100644
--- a/app/src/pages/SpecPage.test.tsx
+++ b/app/src/pages/SpecPage.test.tsx
@@ -41,15 +41,15 @@ vi.mock('src/hooks', () => ({
}));
// Mock lazy-loaded components as simple divs
-vi.mock('src/components/SpecTabs', () => ({
+vi.mock('src/sections/spec-detail/SpecTabs', () => ({
SpecTabs: () => SpecTabs
,
}));
-vi.mock('src/components/SpecOverview', () => ({
+vi.mock('src/sections/spec-detail/SpecOverview', () => ({
SpecOverview: () => SpecOverview
,
}));
-vi.mock('src/components/SpecDetailView', () => ({
+vi.mock('src/sections/spec-detail/SpecDetailView', () => ({
SpecDetailView: () => SpecDetailView
,
}));
diff --git a/app/src/pages/SpecPage.tsx b/app/src/pages/SpecPage.tsx
index 80e79406fb..fcef4f67f6 100644
--- a/app/src/pages/SpecPage.tsx
+++ b/app/src/pages/SpecPage.tsx
@@ -9,22 +9,24 @@ import Button from '@mui/material/Button';
import Skeleton from '@mui/material/Skeleton';
import Typography from '@mui/material/Typography';
-import { LibraryPills } from 'src/components/LibraryPills';
-import { RelatedSpecs } from 'src/components/RelatedSpecs';
import { GITHUB_URL, LANG_DISPLAY } from 'src/constants';
import { useAnalytics, useCodeFetch } from 'src/hooks';
import { useAppData } from 'src/hooks';
import { ApiError, apiGet, apiUrl, endpoints } from 'src/lib/api';
import { NotFoundPage } from 'src/pages/NotFoundPage';
import { paths, specPath } from 'src/routes/paths';
+import { LibraryPills } from 'src/sections/spec-detail/LibraryPills';
+import { RelatedSpecs } from 'src/sections/spec-detail/RelatedSpecs';
import { colors, fontSize, semanticColors, typography } from 'src/theme';
-const SpecTabs = lazy(() => import('src/components/SpecTabs').then(m => ({ default: m.SpecTabs })));
+const SpecTabs = lazy(() =>
+ import('src/sections/spec-detail/SpecTabs').then(m => ({ default: m.SpecTabs }))
+);
const SpecOverview = lazy(() =>
- import('src/components/SpecOverview').then(m => ({ default: m.SpecOverview }))
+ import('src/sections/spec-detail/SpecOverview').then(m => ({ default: m.SpecOverview }))
);
const SpecDetailView = lazy(() =>
- import('src/components/SpecDetailView').then(m => ({ default: m.SpecDetailView }))
+ import('src/sections/spec-detail/SpecDetailView').then(m => ({ default: m.SpecDetailView }))
);
import type { Implementation } from 'src/types';
diff --git a/app/src/routes/index.tsx b/app/src/routes/index.tsx
index bebce66934..b0e33c37e3 100644
--- a/app/src/routes/index.tsx
+++ b/app/src/routes/index.tsx
@@ -5,9 +5,9 @@ import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import { ErrorBoundary } from 'src/components/ErrorBoundary';
-import { AppDataProvider } from 'src/components/Layout';
-import { RootLayout } from 'src/components/RootLayout';
import { RouteErrorBoundary } from 'src/components/RouteErrorBoundary';
+import { AppDataProvider } from 'src/layouts/Layout';
+import { RootLayout } from 'src/layouts/RootLayout';
import { NotFoundPage } from 'src/pages/NotFoundPage';
const LazyFallback = () => (
diff --git a/app/src/components/HeroSection.test.tsx b/app/src/sections/landing/HeroSection.test.tsx
similarity index 87%
rename from app/src/components/HeroSection.test.tsx
rename to app/src/sections/landing/HeroSection.test.tsx
index 2abb70c980..fb9f858fed 100644
--- a/app/src/components/HeroSection.test.tsx
+++ b/app/src/sections/landing/HeroSection.test.tsx
@@ -12,15 +12,15 @@ vi.mock('src/hooks', async () => {
};
});
-vi.mock('src/components/PlotOfTheDayTerminal', () => ({
+vi.mock('src/sections/landing/PlotOfTheDayTerminal', () => ({
PlotOfTheDayTerminal: () => ,
}));
-vi.mock('src/components/TypewriterText', () => ({
+vi.mock('src/sections/landing/TypewriterText', () => ({
TypewriterText: () => ,
}));
-import { HeroSection } from 'src/components/HeroSection';
+import { HeroSection } from 'src/sections/landing/HeroSection';
describe('HeroSection', () => {
beforeEach(() => {
diff --git a/app/src/components/HeroSection.tsx b/app/src/sections/landing/HeroSection.tsx
similarity index 98%
rename from app/src/components/HeroSection.tsx
rename to app/src/sections/landing/HeroSection.tsx
index c3a185de08..a9a019c39c 100644
--- a/app/src/components/HeroSection.tsx
+++ b/app/src/sections/landing/HeroSection.tsx
@@ -2,11 +2,11 @@ import { Link as RouterLink } from 'react-router-dom';
import Box from '@mui/material/Box';
-import { PlotOfTheDayTerminal } from 'src/components/PlotOfTheDayTerminal';
-import { TypewriterText } from 'src/components/TypewriterText';
import { useAnalytics } from 'src/hooks';
import type { PlotOfTheDayData } from 'src/hooks/usePlotOfTheDay';
import { paths } from 'src/routes/paths';
+import { PlotOfTheDayTerminal } from 'src/sections/landing/PlotOfTheDayTerminal';
+import { TypewriterText } from 'src/sections/landing/TypewriterText';
import { colors, typography } from 'src/theme';
interface HeroSectionProps {
diff --git a/app/src/components/LibrariesSection.tsx b/app/src/sections/landing/LibrariesSection.tsx
similarity index 96%
rename from app/src/components/LibrariesSection.tsx
rename to app/src/sections/landing/LibrariesSection.tsx
index 211e607c50..ed45374c68 100644
--- a/app/src/components/LibrariesSection.tsx
+++ b/app/src/sections/landing/LibrariesSection.tsx
@@ -1,8 +1,8 @@
import Box from '@mui/material/Box';
-import { LibraryCard } from 'src/components/LibraryCard';
import { SectionHeader } from 'src/components/SectionHeader';
import { LIBRARIES } from 'src/constants';
+import { LibraryCard } from 'src/sections/libraries/LibraryCard';
import type { LibraryInfo } from 'src/types';
interface LibrariesSectionProps {
diff --git a/app/src/components/NumbersStrip.tsx b/app/src/sections/landing/NumbersStrip.tsx
similarity index 100%
rename from app/src/components/NumbersStrip.tsx
rename to app/src/sections/landing/NumbersStrip.tsx
diff --git a/app/src/components/PaletteStrip.tsx b/app/src/sections/landing/PaletteStrip.tsx
similarity index 100%
rename from app/src/components/PaletteStrip.tsx
rename to app/src/sections/landing/PaletteStrip.tsx
diff --git a/app/src/components/PlotOfTheDay.test.tsx b/app/src/sections/landing/PlotOfTheDay.test.tsx
similarity index 99%
rename from app/src/components/PlotOfTheDay.test.tsx
rename to app/src/sections/landing/PlotOfTheDay.test.tsx
index 4115a77b52..277dbc4720 100644
--- a/app/src/components/PlotOfTheDay.test.tsx
+++ b/app/src/sections/landing/PlotOfTheDay.test.tsx
@@ -12,7 +12,7 @@ vi.mock('src/hooks', async () => {
};
});
-import { PlotOfTheDay } from 'src/components/PlotOfTheDay';
+import { PlotOfTheDay } from 'src/sections/landing/PlotOfTheDay';
// Mock sessionStorage
const sessionStorageMock: Record = {};
diff --git a/app/src/components/PlotOfTheDay.tsx b/app/src/sections/landing/PlotOfTheDay.tsx
similarity index 100%
rename from app/src/components/PlotOfTheDay.tsx
rename to app/src/sections/landing/PlotOfTheDay.tsx
diff --git a/app/src/components/PlotOfTheDayTerminal.test.tsx b/app/src/sections/landing/PlotOfTheDayTerminal.test.tsx
similarity index 96%
rename from app/src/components/PlotOfTheDayTerminal.test.tsx
rename to app/src/sections/landing/PlotOfTheDayTerminal.test.tsx
index fa1cb1ce5d..fe4383a916 100644
--- a/app/src/components/PlotOfTheDayTerminal.test.tsx
+++ b/app/src/sections/landing/PlotOfTheDayTerminal.test.tsx
@@ -19,7 +19,7 @@ vi.mock('src/hooks/useLayoutContext', async () => {
return { ...actual, useTheme: () => ({ isDark: false, toggle: vi.fn() }) };
});
-import { PlotOfTheDayTerminal } from 'src/components/PlotOfTheDayTerminal';
+import { PlotOfTheDayTerminal } from 'src/sections/landing/PlotOfTheDayTerminal';
const potd = {
spec_id: 'scatter-basic',
diff --git a/app/src/components/PlotOfTheDayTerminal.tsx b/app/src/sections/landing/PlotOfTheDayTerminal.tsx
similarity index 100%
rename from app/src/components/PlotOfTheDayTerminal.tsx
rename to app/src/sections/landing/PlotOfTheDayTerminal.tsx
diff --git a/app/src/components/ScienceNote.tsx b/app/src/sections/landing/ScienceNote.tsx
similarity index 97%
rename from app/src/components/ScienceNote.tsx
rename to app/src/sections/landing/ScienceNote.tsx
index 6b0c03a5fa..515ba7cfdd 100644
--- a/app/src/components/ScienceNote.tsx
+++ b/app/src/sections/landing/ScienceNote.tsx
@@ -2,8 +2,8 @@ import { Link as RouterLink } from 'react-router-dom';
import Box from '@mui/material/Box';
-import { PaletteStrip } from 'src/components/PaletteStrip';
import { paths } from 'src/routes/paths';
+import { PaletteStrip } from 'src/sections/landing/PaletteStrip';
import { colors, typography } from 'src/theme';
export function ScienceNote() {
diff --git a/app/src/components/TypewriterText.tsx b/app/src/sections/landing/TypewriterText.tsx
similarity index 100%
rename from app/src/components/TypewriterText.tsx
rename to app/src/sections/landing/TypewriterText.tsx
diff --git a/app/src/sections/landing/index.ts b/app/src/sections/landing/index.ts
new file mode 100644
index 0000000000..396b7c3aab
--- /dev/null
+++ b/app/src/sections/landing/index.ts
@@ -0,0 +1,8 @@
+export * from 'src/sections/landing/HeroSection';
+export * from 'src/sections/landing/LibrariesSection';
+export * from 'src/sections/landing/NumbersStrip';
+export * from 'src/sections/landing/PaletteStrip';
+export * from 'src/sections/landing/PlotOfTheDay';
+export * from 'src/sections/landing/PlotOfTheDayTerminal';
+export * from 'src/sections/landing/ScienceNote';
+export * from 'src/sections/landing/TypewriterText';
diff --git a/app/src/components/LibraryCard.test.tsx b/app/src/sections/libraries/LibraryCard.test.tsx
similarity index 96%
rename from app/src/components/LibraryCard.test.tsx
rename to app/src/sections/libraries/LibraryCard.test.tsx
index 133c492941..4c69870ec5 100644
--- a/app/src/components/LibraryCard.test.tsx
+++ b/app/src/sections/libraries/LibraryCard.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
-import { LibraryCard } from 'src/components/LibraryCard';
+import { LibraryCard } from 'src/sections/libraries/LibraryCard';
import { render, screen, userEvent } from 'src/test-utils';
describe('LibraryCard', () => {
diff --git a/app/src/components/LibraryCard.tsx b/app/src/sections/libraries/LibraryCard.tsx
similarity index 100%
rename from app/src/components/LibraryCard.tsx
rename to app/src/sections/libraries/LibraryCard.tsx
diff --git a/app/src/sections/libraries/index.ts b/app/src/sections/libraries/index.ts
new file mode 100644
index 0000000000..91a3b6078d
--- /dev/null
+++ b/app/src/sections/libraries/index.ts
@@ -0,0 +1 @@
+export * from 'src/sections/libraries/LibraryCard';
diff --git a/app/src/components/FilterBar.test.tsx b/app/src/sections/plots-gallery/FilterBar.test.tsx
similarity index 97%
rename from app/src/components/FilterBar.test.tsx
rename to app/src/sections/plots-gallery/FilterBar.test.tsx
index e989a7de66..783192225e 100644
--- a/app/src/components/FilterBar.test.tsx
+++ b/app/src/sections/plots-gallery/FilterBar.test.tsx
@@ -12,7 +12,7 @@ vi.mock('src/utils', () => ({
getSearchResults: vi.fn(() => []),
}));
-import { FilterBar } from 'src/components/FilterBar';
+import { FilterBar } from 'src/sections/plots-gallery/FilterBar';
// ResizeObserver polyfill
class MockResizeObserver {
diff --git a/app/src/components/FilterBar.tsx b/app/src/sections/plots-gallery/FilterBar.tsx
similarity index 99%
rename from app/src/components/FilterBar.tsx
rename to app/src/sections/plots-gallery/FilterBar.tsx
index 7ee1e96951..c3efcb32d9 100644
--- a/app/src/components/FilterBar.tsx
+++ b/app/src/sections/plots-gallery/FilterBar.tsx
@@ -15,8 +15,8 @@ import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import useMediaQuery from '@mui/material/useMediaQuery';
-import { ToolbarActions } from 'src/components/ToolbarActions';
import type { ImageSize } from 'src/constants';
+import { ToolbarActions } from 'src/sections/plots-gallery/ToolbarActions';
import { colors, fontSize, semanticColors, typography } from 'src/theme';
import type { ActiveFilters, FilterCategory, FilterCounts } from 'src/types';
import { FILTER_CATEGORIES, FILTER_LABELS, FILTER_TOOLTIPS } from 'src/types';
diff --git a/app/src/components/ImageCard.test.tsx b/app/src/sections/plots-gallery/ImageCard.test.tsx
similarity index 98%
rename from app/src/components/ImageCard.test.tsx
rename to app/src/sections/plots-gallery/ImageCard.test.tsx
index 7ae1774279..fff8f12c5c 100644
--- a/app/src/components/ImageCard.test.tsx
+++ b/app/src/sections/plots-gallery/ImageCard.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
-import { ImageCard } from 'src/components/ImageCard';
+import { ImageCard } from 'src/sections/plots-gallery/ImageCard';
import { render, screen } from 'src/test-utils';
import type { PlotImage } from 'src/types';
diff --git a/app/src/components/ImageCard.tsx b/app/src/sections/plots-gallery/ImageCard.tsx
similarity index 100%
rename from app/src/components/ImageCard.tsx
rename to app/src/sections/plots-gallery/ImageCard.tsx
diff --git a/app/src/components/ImagesGrid.test.tsx b/app/src/sections/plots-gallery/ImagesGrid.test.tsx
similarity index 97%
rename from app/src/components/ImagesGrid.test.tsx
rename to app/src/sections/plots-gallery/ImagesGrid.test.tsx
index 4eedcfcd52..065fdd2552 100644
--- a/app/src/components/ImagesGrid.test.tsx
+++ b/app/src/sections/plots-gallery/ImagesGrid.test.tsx
@@ -2,13 +2,13 @@ import { createRef } from 'react';
import { describe, expect, it, type Mock, vi } from 'vitest';
-import { ImagesGrid } from 'src/components/ImagesGrid';
import type { ImageSize } from 'src/constants';
+import { ImagesGrid } from 'src/sections/plots-gallery/ImagesGrid';
import { render, screen } from 'src/test-utils';
import type { LibraryInfo, PlotImage, SpecInfo } from 'src/types';
// Mock child components to isolate ImagesGrid
-vi.mock('src/components/ImageCard', () => ({
+vi.mock('src/sections/plots-gallery/ImageCard', () => ({
ImageCard: ({ image, index }: { image: PlotImage; index: number }) => (
{image.library}
),
diff --git a/app/src/components/ImagesGrid.tsx b/app/src/sections/plots-gallery/ImagesGrid.tsx
similarity index 98%
rename from app/src/components/ImagesGrid.tsx
rename to app/src/sections/plots-gallery/ImagesGrid.tsx
index 89bd93edb8..77297b9c0e 100644
--- a/app/src/components/ImagesGrid.tsx
+++ b/app/src/sections/plots-gallery/ImagesGrid.tsx
@@ -4,9 +4,9 @@ import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
-import { ImageCard } from 'src/components/ImageCard';
import { LoaderSpinner } from 'src/components/LoaderSpinner';
import type { ImageSize } from 'src/constants';
+import { ImageCard } from 'src/sections/plots-gallery/ImageCard';
import type { LanguageInfo, LibraryInfo, PlotImage, SpecInfo } from 'src/types';
interface ImagesGridProps {
diff --git a/app/src/components/ToolbarActions.test.tsx b/app/src/sections/plots-gallery/ToolbarActions.test.tsx
similarity index 96%
rename from app/src/components/ToolbarActions.test.tsx
rename to app/src/sections/plots-gallery/ToolbarActions.test.tsx
index 0820bae7e1..036dc771dd 100644
--- a/app/src/components/ToolbarActions.test.tsx
+++ b/app/src/sections/plots-gallery/ToolbarActions.test.tsx
@@ -1,6 +1,10 @@
import { describe, expect, it, vi } from 'vitest';
-import { GridSizeToggle, PlotsLink, ToolbarActions } from 'src/components/ToolbarActions';
+import {
+ GridSizeToggle,
+ PlotsLink,
+ ToolbarActions,
+} from 'src/sections/plots-gallery/ToolbarActions';
import { render, screen, userEvent } from 'src/test-utils';
describe('PlotsLink', () => {
diff --git a/app/src/components/ToolbarActions.tsx b/app/src/sections/plots-gallery/ToolbarActions.tsx
similarity index 100%
rename from app/src/components/ToolbarActions.tsx
rename to app/src/sections/plots-gallery/ToolbarActions.tsx
diff --git a/app/src/sections/plots-gallery/index.ts b/app/src/sections/plots-gallery/index.ts
new file mode 100644
index 0000000000..74e95a8d04
--- /dev/null
+++ b/app/src/sections/plots-gallery/index.ts
@@ -0,0 +1,4 @@
+export * from 'src/sections/plots-gallery/FilterBar';
+export * from 'src/sections/plots-gallery/ImageCard';
+export * from 'src/sections/plots-gallery/ImagesGrid';
+export * from 'src/sections/plots-gallery/ToolbarActions';
diff --git a/app/src/components/CodeShowcase.tsx b/app/src/sections/spec-detail/CodeShowcase.tsx
similarity index 100%
rename from app/src/components/CodeShowcase.tsx
rename to app/src/sections/spec-detail/CodeShowcase.tsx
diff --git a/app/src/components/LibraryPills.test.tsx b/app/src/sections/spec-detail/LibraryPills.test.tsx
similarity index 97%
rename from app/src/components/LibraryPills.test.tsx
rename to app/src/sections/spec-detail/LibraryPills.test.tsx
index 8e36db6dc0..6feafca447 100644
--- a/app/src/components/LibraryPills.test.tsx
+++ b/app/src/sections/spec-detail/LibraryPills.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
-import { LibraryPills } from 'src/components/LibraryPills';
+import { LibraryPills } from 'src/sections/spec-detail/LibraryPills';
import { render, screen, userEvent } from 'src/test-utils';
const mockImplementations = [
diff --git a/app/src/components/LibraryPills.tsx b/app/src/sections/spec-detail/LibraryPills.tsx
similarity index 100%
rename from app/src/components/LibraryPills.tsx
rename to app/src/sections/spec-detail/LibraryPills.tsx
diff --git a/app/src/components/RelatedSpecs.test.tsx b/app/src/sections/spec-detail/RelatedSpecs.test.tsx
similarity index 98%
rename from app/src/components/RelatedSpecs.test.tsx
rename to app/src/sections/spec-detail/RelatedSpecs.test.tsx
index c909408d35..550d47454c 100644
--- a/app/src/components/RelatedSpecs.test.tsx
+++ b/app/src/sections/spec-detail/RelatedSpecs.test.tsx
@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
-import { RelatedSpecs } from 'src/components/RelatedSpecs';
+import { RelatedSpecs } from 'src/sections/spec-detail/RelatedSpecs';
import { render, screen, waitFor } from 'src/test-utils';
describe('RelatedSpecs', () => {
diff --git a/app/src/components/RelatedSpecs.tsx b/app/src/sections/spec-detail/RelatedSpecs.tsx
similarity index 100%
rename from app/src/components/RelatedSpecs.tsx
rename to app/src/sections/spec-detail/RelatedSpecs.tsx
diff --git a/app/src/components/SpecDetailView.test.tsx b/app/src/sections/spec-detail/SpecDetailView.test.tsx
similarity index 98%
rename from app/src/components/SpecDetailView.test.tsx
rename to app/src/sections/spec-detail/SpecDetailView.test.tsx
index 8edfc32370..569534c4a8 100644
--- a/app/src/components/SpecDetailView.test.tsx
+++ b/app/src/sections/spec-detail/SpecDetailView.test.tsx
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest';
-import { SpecDetailView } from 'src/components/SpecDetailView';
import { ThemeContext, type ThemeContextValue } from 'src/hooks/useLayoutContext';
+import { SpecDetailView } from 'src/sections/spec-detail/SpecDetailView';
import { render, screen, userEvent } from 'src/test-utils';
import type { Implementation } from 'src/types';
diff --git a/app/src/components/SpecDetailView.tsx b/app/src/sections/spec-detail/SpecDetailView.tsx
similarity index 100%
rename from app/src/components/SpecDetailView.tsx
rename to app/src/sections/spec-detail/SpecDetailView.tsx
diff --git a/app/src/components/SpecOverview.test.tsx b/app/src/sections/spec-detail/SpecOverview.test.tsx
similarity index 98%
rename from app/src/components/SpecOverview.test.tsx
rename to app/src/sections/spec-detail/SpecOverview.test.tsx
index b013e19f98..3295511a1a 100644
--- a/app/src/components/SpecOverview.test.tsx
+++ b/app/src/sections/spec-detail/SpecOverview.test.tsx
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
-import { SpecOverview } from 'src/components/SpecOverview';
+import { SpecOverview } from 'src/sections/spec-detail/SpecOverview';
import { render, screen, userEvent } from 'src/test-utils';
import type { Implementation } from 'src/types';
diff --git a/app/src/components/SpecOverview.tsx b/app/src/sections/spec-detail/SpecOverview.tsx
similarity index 100%
rename from app/src/components/SpecOverview.tsx
rename to app/src/sections/spec-detail/SpecOverview.tsx
diff --git a/app/src/components/SpecTabs.test.tsx b/app/src/sections/spec-detail/SpecTabs.test.tsx
similarity index 99%
rename from app/src/components/SpecTabs.test.tsx
rename to app/src/sections/spec-detail/SpecTabs.test.tsx
index 5c8009188d..20e3d6af9f 100644
--- a/app/src/components/SpecTabs.test.tsx
+++ b/app/src/sections/spec-detail/SpecTabs.test.tsx
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
-import { SpecTabs } from 'src/components/SpecTabs';
+import { SpecTabs } from 'src/sections/spec-detail/SpecTabs';
import { render, screen, userEvent, waitFor } from 'src/test-utils';
// Mock the lazy-loaded CodeHighlighter
diff --git a/app/src/components/SpecTabs.tsx b/app/src/sections/spec-detail/SpecTabs.tsx
similarity index 100%
rename from app/src/components/SpecTabs.tsx
rename to app/src/sections/spec-detail/SpecTabs.tsx
diff --git a/app/src/sections/spec-detail/index.ts b/app/src/sections/spec-detail/index.ts
new file mode 100644
index 0000000000..3b2f699ffa
--- /dev/null
+++ b/app/src/sections/spec-detail/index.ts
@@ -0,0 +1,6 @@
+export * from 'src/sections/spec-detail/CodeShowcase';
+export * from 'src/sections/spec-detail/LibraryPills';
+export * from 'src/sections/spec-detail/RelatedSpecs';
+export * from 'src/sections/spec-detail/SpecDetailView';
+export * from 'src/sections/spec-detail/SpecOverview';
+export * from 'src/sections/spec-detail/SpecTabs';
diff --git a/app/src/utils/index.ts b/app/src/utils/index.ts
index 4f559b6ea7..7b1013aa4b 100644
--- a/app/src/utils/index.ts
+++ b/app/src/utils/index.ts
@@ -5,3 +5,7 @@
export * from 'src/utils/tooltip';
export * from 'src/utils/filters';
export * from 'src/utils/fuzzySearch';
+export * from 'src/utils/claudePrompt';
+export * from 'src/utils/responsiveImage';
+export * from 'src/utils/shuffle';
+export * from 'src/utils/themedPreview';
diff --git a/app/vitest.config.ts b/app/vitest.config.ts
index b4abd2db55..eddaccbabf 100644
--- a/app/vitest.config.ts
+++ b/app/vitest.config.ts
@@ -28,6 +28,8 @@ export default defineConfig({
'src/utils/**/*.ts',
'src/hooks/**/*.ts',
'src/components/**/*.tsx',
+ 'src/layouts/**/*.tsx',
+ 'src/sections/**/*.tsx',
'src/pages/**/*.tsx',
'src/constants/**/*.ts',
'src/routes/**/*.ts',