diff --git a/website/app/globals.css b/website/app/globals.css index 4e81fee..79c5bdc 100644 --- a/website/app/globals.css +++ b/website/app/globals.css @@ -331,9 +331,9 @@ a { color: inherit; text-decoration: none; } .button { background: var(--blue); border: 0; border-radius: 6px; color: white; cursor: pointer; display: inline-flex; font-size: 15px; font-weight: 700; justify-content: center; padding: 13px 18px; } .button:hover { filter: brightness(1.12); } .button:disabled { cursor: wait; opacity: .6; } -.button-small { font-size: 13px; padding: 9px 13px; } -main { margin: 0 auto; max-width: 1240px; padding: 6rem 28px 100px; } -main:has(.flagship-landing), main:has(.flagship-page), main:has(.ops-shell-root), main:has(.ops-error-root) { max-width: 100%; padding: 0; margin: 0; } +.site-page-frame { margin: 0 auto; max-width: 1240px; padding: 6rem 28px 100px; } +.site-page-frame:has(.flagship-landing), .site-page-frame:has(.flagship-page), .site-page-frame:has(.ops-shell-root), .site-page-frame:has(.ops-error-root), .site-page-frame:has(.founder-portal-root), +main:has(.flagship-landing), main:has(.flagship-page), main:has(.ops-shell-root), main:has(.ops-error-root), main:has(.founder-portal-root) { max-width: 100%; padding: 0; margin: 0; } .ops-shell-root, .ops-shell-root main { max-width: 100% !important; margin: 0 !important; } .ops-shell-root h1 { max-width: none !important; } .flagship-landing, @@ -445,7 +445,7 @@ input:focus { border-color: var(--blue); outline: 2px solid color-mix(in srgb, v .session-heading h2 { margin: 0; } .session-row { align-items: center; border-top: 1px solid var(--line); display: flex; justify-content: space-between; margin-top: 16px; padding-top: 16px; } .session-row p { font-size: 13px; margin: 5px 0 0; } -@media (max-width: 760px) { .site-header { flex-wrap: wrap; padding: 16px 18px; } nav { order: 3; width: 100%; } main { padding: 48px 18px 72px; } .section-grid, .section-grid-two, .account-grid, .auth-page, .admin-kpis { grid-template-columns: 1fr; margin-top: 56px; } .admin-title-row { align-items: flex-start; flex-direction: column; } .admin-toolbar { align-items: flex-start; flex-direction: column; } .admin-tabs { width: 100%; } .admin-tab { flex: 1; justify-content: center; } h1 { font-size: 48px; } .site-footer { padding-left: 18px; padding-right: 18px; } } +@media (max-width: 760px) { .site-header { flex-wrap: wrap; padding: 16px 18px; } nav { order: 3; width: 100%; } .site-page-frame, main { padding: 48px 18px 72px; } .section-grid, .section-grid-two, .account-grid, .auth-page, .admin-kpis { grid-template-columns: 1fr; margin-top: 56px; } .admin-title-row { align-items: flex-start; flex-direction: column; } .admin-toolbar { align-items: flex-start; flex-direction: column; } .admin-tabs { width: 100%; } .admin-tab { flex: 1; justify-content: center; } h1 { font-size: 48px; } .site-footer { padding-left: 18px; padding-right: 18px; } } @media (max-width: 760px) { .flagship-hero, .ride-hero-panel, .public-split { grid-template-columns: 1fr; padding: 28px; }.flagship-hero { min-height: 0; padding: 36px 24px; }.metric-ribbon { grid-template-columns: repeat(2, 1fr); gap: 22px; margin-bottom: 56px; }.metric-ribbon div:nth-child(3) { border-left: 0; }.feature-grid, .club-pillars, .architecture-grid { grid-template-columns: 1fr; }.conversion-band { align-items: flex-start; flex-direction: column; gap: 20px; }.radar { max-width: 270px; }.public-intro h1 { font-size: 48px; } } .flagship-section-heading { margin-top: 90px; } .flagship-feature-grid { grid-template-columns: repeat(2, 1fr); } diff --git a/website/app/layout.tsx b/website/app/layout.tsx index 13d4085..f555057 100644 --- a/website/app/layout.tsx +++ b/website/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata, Viewport } from 'next'; import './globals.css'; import { SiteHeader } from '../components/site-header'; import { SiteFooter } from '../components/site-footer'; +import { SitePageFrame } from '../components/site-page-frame'; export const viewport: Viewport = { width: 'device-width', @@ -161,7 +162,7 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac -
{children}
+ {children} diff --git a/website/components/founder-portal/founder-portal-shell.tsx b/website/components/founder-portal/founder-portal-shell.tsx index 6877e43..43c49c8 100644 --- a/website/components/founder-portal/founder-portal-shell.tsx +++ b/website/components/founder-portal/founder-portal-shell.tsx @@ -35,7 +35,7 @@ export function FounderPortalShell({ const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); return ( -
+
{/* Sidebar (Desktop persistent + Mobile off-canvas drawer) */} {/* Content Body Container */} -
+
{children}
diff --git a/website/components/founder-portal/founder-top-bar.tsx b/website/components/founder-portal/founder-top-bar.tsx index 78add09..171efba 100644 --- a/website/components/founder-portal/founder-top-bar.tsx +++ b/website/components/founder-portal/founder-top-bar.tsx @@ -51,7 +51,7 @@ export function FounderTopBar({ return (
-
+
{/* Left: Mobile hamburger + Breadcrumbs + Switch Club */}
{/* Mobile Hamburger Toggle */} diff --git a/website/components/site-page-frame.tsx b/website/components/site-page-frame.tsx new file mode 100644 index 0000000..7cde9e2 --- /dev/null +++ b/website/components/site-page-frame.tsx @@ -0,0 +1,22 @@ +'use client'; + +import React from 'react'; +import { usePathname } from 'next/navigation'; + +/** + * SitePageFrame wraps page content. + * For portal and operations routes that manage their own internal
landmark, + * it renders a non-semantic
to avoid invalid nested
elements. + * For standard public and content routes, it renders a semantic
landmark + * to ensure assistive technologies can identify the primary content. + */ +export function SitePageFrame({ children }: { children: React.ReactNode }) { + const pathname = usePathname(); + const isPortalRoute = pathname?.includes('/manage') || pathname?.startsWith('/admin'); + + if (isPortalRoute) { + return
{children}
; + } + + return
{children}
; +} diff --git a/website/tests/founder-portal.test.cjs b/website/tests/founder-portal.test.cjs index 0e72a39..5caea7e 100644 --- a/website/tests/founder-portal.test.cjs +++ b/website/tests/founder-portal.test.cjs @@ -263,9 +263,11 @@ async function runAllTests() { const shellSrc = fs.readFileSync(path.resolve(__dirname, '../components/founder-portal/founder-portal-shell.tsx'), 'utf8'); const sidebarSrc = fs.readFileSync(path.resolve(__dirname, '../components/founder-portal/founder-sidebar.tsx'), 'utf8'); - // Desktop persistent sidebar: lg:pl-72, lg:translate-x-0, max-w-[1440px] + // Desktop persistent sidebar: lg:pl-72, lg:translate-x-0, max-w-[1536px] assert(shellSrc.includes('lg:pl-72'), 'Missing lg:pl-72 desktop sidebar offset'); - assert(shellSrc.includes('max-w-[1440px]'), 'Missing max-w-[1440px] desktop canvas container'); + assert(shellSrc.includes('max-w-[1536px]'), 'FounderPortalShell must use max-w-[1536px] desktop canvas container'); + assert(!shellSrc.includes('max-w-[1440px]'), 'FounderPortalShell must NOT retain old max-w-[1440px] cap'); + assert(shellSrc.includes('founder-portal-root'), 'Missing founder-portal-root class on shell'); assert(sidebarSrc.includes('w-72'), 'Missing w-72 persistent sidebar width'); // Mobile drawer: translate-x-full lg:translate-x-0, touch targets