# Nested Layout Skeleton

Visual map of how pages nest inside each other in the Next.js App Router.
Each level persists across navigation — children swap, parents stay.

## Mental model

```
┌─────────────────────────────────────────────────────────────────┐
│ app/layout.tsx              (root)                              │
│   html / body / fonts / Providers / Toast / CookieBanner        │
│   ─────────────────────────────────────────────────────────     │
│   No global header. Each route group renders its own chrome.    │
└─────────────────────────────────────────────────────────────────┘
                                  │
        ┌─────────────────────────┼─────────────────────────────┐
        │                         │                             │
        ▼                         ▼                             ▼
   Public routes            Storefronts                   Admin
   (/, /pricing,            (/tuxedo/*,                   (/admin/*)
    /contact, /login)        /indian-river-direct/*)
```

## Full tree

```
src/app/
├── layout.tsx ────────────────────────────────────────────────── [ROOT]
│   • <html>, <body>
│   • next/font: Fraunces (display), Manrope (sans), Fragment_Mono
│   • <Providers> (theme, posthog, sentry, etc.)
│   • <ToastNotificationContainer />
│   • <CookieConsentBanner />
│   ─── pages render INSIDE ───
│   │
│   ├── error.tsx              [ROOT-LEVEL] Atelier error page
│   ├── loading.tsx            [ROOT-LEVEL] "Preparing your harvest"
│   ├── not-found.tsx          [ROOT-LEVEL] "Off the beaten path"
│   │
│   ├── page.tsx               /                  LandingPageClient
│   │   └── renders its own SiteHeader + Hero + SiteFooter
│   │
│   ├── login/
│   │   ├── page.tsx           /login             LoginClient (standalone)
│   │   └── loading.tsx        [isolated]
│   │
│   ├── cart/
│   │   ├── page.tsx           /cart              CartClient (standalone)
│   │   └── loading.tsx
│   │
│   ├── checkout/
│   │   ├── page.tsx           /checkout          CheckoutClient (standalone)
│   │   ├── loading.tsx
│   │   └── success/page.tsx   /checkout/success
│   │
│   ├── change-password/page.tsx
│   ├── pricing/page.tsx       + loading.tsx
│   ├── contact/page.tsx       + loading.tsx
│   ├── blog/page.tsx
│   ├── changelog/page.tsx
│   ├── roadmap/page.tsx
│   ├── waitlist/page.tsx
│   ├── security/page.tsx
│   ├── privacy-policy/page.tsx
│   ├── terms-and-conditions/page.tsx
│   ├── maintenance/page.tsx
│   │
│   ├── ─── STOREFRONTS ─────────────────────────────────────────
│   │
│   ├── tuxedo/
│   │   ├── layout.tsx ─────────────────────── [TUXEDO CHROME]
│   │   │   • Dark emerald gradient backdrop
│   │   │   • Ambient emerald orb (top-right blur)
│   │   │   • <StorefrontHeader> + <StorefrontFooter> per page
│   │   │   • BreadcrumbList + LocalBusiness JSON-LD in metadata
│   │   │   ─── INSIDE ───
│   │   │   ├── error.tsx
│   │   │   ├── loading.tsx
│   │   │   ├── page.tsx                   /tuxedo
│   │   │   ├── stops/
│   │   │   │   ├── page.tsx               /tuxedo/stops
│   │   │   │   ├── loading.tsx
│   │   │   │   └── [slug]/
│   │   │   │       ├── page.tsx           /tuxedo/stops/:slug
│   │   │   │       ├── error.tsx
│   │   │   │       └── loading.tsx
│   │   │   ├── about/
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.tsx               /tuxedo/about
│   │   │   │   ├── error.tsx
│   │   │   │   └── loading.tsx
│   │   │   ├── faq/
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.tsx               /tuxedo/faq
│   │   │   │   ├── error.tsx
│   │   │   │   └── loading.tsx
│   │   │   ├── contact/
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.tsx               /tuxedo/contact
│   │   │   │   ├── error.tsx
│   │   │   │   └── loading.tsx
│   │   │   ├── products/
│   │   │   │   └── [slug]/page.tsx        /tuxedo/products/:slug
│   │   │   └── time-clock/page.tsx        /tuxedo/time-clock
│   │
│   ├── indian-river-direct/
│   │   ├── layout.tsx ─────────────────── [IRD CHROME]
│   │   │   • Light blue/white glass gradient backdrop
│   │   │   • Three decorative blue orbs
│   │   │   • <StorefrontHeader> + <StorefrontFooter> per page
│   │   │   • LocalBusiness (FL, family-owned 1985) JSON-LD
│   │   │   ─── INSIDE ───
│   │   │   ├── error.tsx
│   │   │   ├── loading.tsx
│   │   │   ├── page.tsx                   /indian-river-direct
│   │   │   ├── stops/
│   │   │   │   ├── page.tsx
│   │   │   │   └── [slug]/
│   │   │   │       ├── page.tsx
│   │   │   │       ├── error.tsx
│   │   │   │       └── loading.tsx
│   │   │   ├── about/   (layout + page + error + loading)
│   │   │   ├── faq/     (layout + page + error + loading)
│   │   │   └── contact/ (layout + page + error + loading)
│   │
│   ├── ─── ADMIN ──────────────────────────────────────────────
│   │
│   └── admin/
│       ├── layout.tsx ───────────────────── [ADMIN SHELL]
│       │   • dynamic = "force-dynamic"  (reads cookies)
│       │   • getAdminUser() → AdminSidebar + content area
│       │   • ToastProvider + ToastContainer
│       │   • Sidebar persists across all /admin/* routes
│       │   • Parchment background via .admin-section
│       │   ─── INSIDE ───
│       │   ├── error.tsx                  Admin error page
│       │   ├── loading.tsx                Skeleton: header + stats + table
│       │   ├── page.tsx                   /admin  (Dashboard)
│       │   │
│       │   ├── orders/
│       │   │   ├── page.tsx               /admin/orders
│       │   │   ├── [id]/page.tsx          /admin/orders/:id
│       │   │   └── new/page.tsx           /admin/orders/new
│       │   │
│       │   ├── products/
│       │   │   ├── page.tsx               /admin/products
│       │   │   ├── [id]/page.tsx
│       │   │   ├── new/page.tsx
│       │   │   └── import/page.tsx
│       │   │
│       │   ├── stops/
│       │   │   ├── page.tsx               /admin/stops
│       │   │   ├── [id]/page.tsx
│       │   │   └── new/page.tsx
│       │   │
│       │   ├── communications/
│       │   │   ├── loading.tsx
│       │   │   ├── page.tsx               /admin/communications
│       │   │   ├── compose/page.tsx
│       │   │   ├── campaigns/[id]/page.tsx
│       │   │   ├── contacts/page.tsx
│       │   │   ├── logs/page.tsx
│       │   │   ├── segments/page.tsx
│       │   │   ├── settings/page.tsx
│       │   │   ├── templates/page.tsx
│       │   │   ├── templates/[id]/page.tsx
│       │   │   ├── analytics/page.tsx
│       │   │   ├── abandoned-carts/page.tsx
│       │   │   └── welcome-sequence/page.tsx
│       │   │
│       │   ├── settings/  (sub-tree of 13 pages: billing, brand,
│       │   │                payments, shipping, ai, apps,
│       │   │                integrations, square-sync, ...)
│       │   │
│       │   ├── route-trace/  (lots, lookup, settings)
│       │   ├── me/
│       │   ├── pickup/                  Store-employee landing
│       │   ├── sales/import/
│       │   ├── import/
│       │   ├── analytics/
│       │   ├── command-center/
│       │   ├── advanced/
│       │   ├── reports/
│       │   ├── shipping/
│       │   ├── taxes/
│       │   ├── time-tracking/
│       │   ├── water-log/  (sub-tree)
│       │   ├── wholesale/
│       │   └── launch-checklist/
│       │
│       ├── wholesale/         (separate sub-app, not under admin/layout)
│       │   ├── login/page.tsx
│       │   ├── portal/page.tsx
│       │   ├── register/page.tsx
│       │   ├── employee/page.tsx
│       │   └── payment/{success,cancel}/page.tsx
│       │
│       ├── water/             (separate sub-app, not under admin/layout)
│       │   ├── page.tsx
│       │   ├── loading.tsx
│       │   └── admin/  (login + page)
│       │
│       ├── ird/time-clock/    (time-clock for IRD employees)
│       ├── trace/[lotNumber]/page.tsx     (public route-trace lookup)
│       └── protected-example/page.tsx     (smoke test for middleware)
```

## Key nesting rules

1. **The root `app/layout.tsx` is the only one that renders `<html>` and `<body>`**. Every other layout is a child of it.
2. **A `layout.tsx` in a folder wraps every `page.tsx` in that folder and all subfolders**. Children swap; layout state persists.
3. **`loading.tsx` and `error.tsx` are per-folder** — Next.js shows them when navigating to a sibling `page.tsx`. They re-render as you move between sections.
4. **Storefronts are fully isolated**: each `tuxedo/layout.tsx` and `indian-river-direct/layout.tsx` provides its own backdrop and lets individual pages render their own `StorefrontHeader` / `StorefrontFooter`.
5. **Admin is a single SPA-feeling shell**: navigating between `/admin/orders` and `/admin/products` keeps the `AdminSidebar` mounted, only the content area swaps.

## Things that DO NOT yet nest (gaps)

| Page | Issue | Fix |
|---|---|---|
| `/cart` | No shared layout with `/checkout` | Add `app/(shop)/layout.tsx` route group to wrap both |
| `/wholesale/*` | Wholesale pages have no shared layout | Add `app/wholesale/layout.tsx` with auth gate + nav |
| `/water/*` | Water pages have no shared layout | Add `app/water/layout.tsx` |
| `/admin/communications/*` | 13 pages share no sub-layout | Could add `app/admin/communications/layout.tsx` with section tabs |
| `/admin/settings/*` | 13 settings pages share no sub-layout | Add `app/admin/settings/layout.tsx` with settings sidebar |

## How to add a nested layout

```bash
# Example: add a settings sub-layout
mkdir -p src/app/admin/settings
# Create src/app/admin/settings/layout.tsx
# It will wrap every page under /admin/settings/* automatically.
```

```tsx
// src/app/admin/settings/layout.tsx
export default function SettingsLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="grid grid-cols-1 lg:grid-cols-[14rem_1fr] gap-6">
      <SettingsNav />     {/* sticks while content swaps */}
      <section>{children}</section>
    </div>
  );
}
```

## How to add parallel routes (modals as overlays)

```bash
mkdir -p 'src/app/@modal'
mkdir -p 'src/app/admin/products/(.)new'   # intercepts /admin/products/new
# Layout returns <>{children}{modal}</>
```

This makes `/admin/products/new` open as a modal over `/admin/products` instead of a hard navigation.
