// app.jsx — Main app, routing, tweaks, render.
// Pages: 'home' | 'instructors' | 'instructor-profile' | 'become-instructor' | 'dashboard' | 'how-it-works'

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "colorScheme": "navy-gold",
  "showBadges": true,
  "defaultView": "grid"
}/*EDITMODE-END*/;

const SCHEMES = {
  'navy-gold':    { primary: 'oklch(22% 0.06 265)', accent: 'oklch(72% 0.17 80)',  accentHover: 'oklch(68% 0.18 80)' },
  'forest-cream': { primary: 'oklch(26% 0.09 152)', accent: 'oklch(70% 0.14 95)',  accentHover: 'oklch(66% 0.15 95)' },
  'slate-rose':   { primary: 'oklch(28% 0.06 280)', accent: 'oklch(64% 0.18 12)',  accentHover: 'oklch(60% 0.19 12)' },
};

// Clean, shareable public URLs. The catch-all Vercel rewrite (vercel.json)
// already serves index.html at any path, so these resolve client-side — this
// is purely the client router learning to read/write the path. Only the public
// marketing surface is mapped; every auth/app route (dashboard, admin,
// messages, lesson, betas, …) keeps its existing query-param mechanics
// untouched, and existing ?page= deep links keep working.
const PAGE_TO_PATH = {
  home: '/',
  'how-it-works': '/how-it-works',
  'become-instructor': '/for-instructors',
  'student-portal': '/student-login',
};
// pathname → page for the mapped public set. Returns null for anything else
// (including bare '/', which must fall through to the cached-session check).
// NOTE: only single-segment paths — index.html loads each .jsx via a RELATIVE
// `src="src/..."`, so a multi-segment path (e.g. /for-instructors/login) would
// resolve those against /for-instructors/ and 404 every script. Hence the
// instructor login is /instructor-login, not /for-instructors/login.
const pageFromCleanPath = (pathname) => {
  const p = (pathname || '').replace(/\/+$/, '') || '/';
  if (p === '/instructor-login') { try { window.__BIV2_INITIAL_VIEW = 'login'; } catch (_) {} return 'become-instructor'; }
  if (p === '/for-instructors')  return 'become-instructor';
  if (p === '/how-it-works')     return 'how-it-works';
  if (p === '/student-login')    return 'student-portal';
  return null;
};

const App = () => {
  // Start on 'dashboard' synchronously when the URL is a magic-link landing.
  // This is what kills the homepage-flash you used to see (page=home → useEffect
  // fires after auth resolves → setPage('dashboard'). With the initial state
  // already set to 'dashboard', the dashboard's "Loading…" is what shows
  // during the auth handshake, and the homepage never paints.
  // Initial page: magic-link landing → 'dashboard'; #admin in URL → 'admin'
  // (replaces the public footer Admin button — admins reach the panel via
  // bookmark or by typing #admin); legal-page hashes → that page; else home.
  // Admin "view as" tabs: if either query param is set, we render the
  // read-only viewer regardless of cached session / homepage default.
  const viewAsParams = (() => {
    const sp = new URLSearchParams(location.search);
    const s = sp.get('admin_view_student');
    const i = sp.get('admin_view_instructor');
    if (s) return { kind:'student', userId:s };
    if (i) return { kind:'instructor', userId:i };
    return null;
  })();

  // ?action=confirm-assignment&id=<uuid> — teacher arriving from the
  // "new student assigned" email. Render the standalone confirmation page
  // before any other routing logic so the teacher never sees the dashboard
  // first. Captured synchronously here so the URL takes precedence over
  // cached-session auto-routes.
  const confirmAssignmentId = (() => {
    const sp = new URLSearchParams(location.search);
    if (sp.get('action') === 'confirm-assignment') {
      const id = sp.get('id') || '';
      if (/^[0-9a-f-]{36}$/i.test(id)) return id;
    }
    return null;
  })();

  const initialPage = (() => {
    if (confirmAssignmentId) return 'confirm-assignment';
    if (viewAsParams) return 'admin-view-as';
    // ?page=verify (email deep-link from admin_request_verification). Land
    // straight on the verification page so the tutor doesn't first see the
    // homepage or dashboard. Works whether or not they have a cached session
    // — the page itself bounces non-instructors to home.
    const sp = new URLSearchParams(location.search);
    if (sp.get('page') === 'verify') return 'verify';
    // The Wyzant-style signup wizard. Honoring this BEFORE the cached-session
    // check is important — otherwise an admin (or any returning user) visiting
    // ?page=become-instructor gets bounced to their dashboard instead of the
    // wizard. Same rationale as the ?page=verify branch above.
    if (sp.get('page') === 'become-instructor')        return 'become-instructor';
    if (sp.get('page') === 'become-instructor-legacy') return 'become-instructor-legacy';
    if (sp.get('page') === 'messages')                 return 'messages';
    // Wizard-exit → ?page=instructor-portal puts the user on the pending-
    // application placeholder. Honor it on refresh so the URL isn't a lie —
    // without this the URL stays "instructor-portal" but app.jsx falls
    // through to the cached-session branch and renders the dashboard loader.
    if (sp.get('page') === 'instructor-portal')        return 'instructor-portal';
    if (sp.get('page') === 'student-portal')           return 'student-portal';
    // The "Finish your application" banner on the student dashboard sends
    // the user here with location.assign — and the homepage's Get Started
    // button now also accepts a deep link. Honor BEFORE the cached-session
    // check so a half-finished student is taken to the wizard, not their
    // dashboard, when they click the banner's Continue button.
    if (sp.get('page') === 'student-onboarding')       return 'student-onboarding';
    // ?page=lesson opens the embedded Daily call in a popup window (the new
    // path for joining lessons — replaces the bare-Daily popup so we can
    // capture both audio sides via daily-js callObject). Admin notes banner
    // is overlaid inside this same page (see lesson-room.jsx).
    if (sp.get('page') === 'lesson')                   return 'lesson';
    // /drums-beta — public Drums Lab beta page. The explicit
    // `/drums-beta → /` Vercel rewrite in vercel.json keeps the
    // browser URL as `/drums-beta` while the server returns the same
    // bytes as `/` (i.e. index.html). No sign-in required:
    // drums_attempts + drums_feedback accept rows with user_id = NULL
    // after v107.
    if (location.pathname === '/drums-beta')           return 'drums-beta';
    if (sp.get('page') === 'drums-beta')               return 'drums-beta';
    // /guitar-beta — public Guitar Lab beta page. Same shape as drums-beta:
    // explicit `/guitar-beta → /` Vercel rewrite keeps the browser URL
    // intact while the server returns index.html. v112 opens
    // guitar_attempts + guitar_feedback to anon writes.
    if (location.pathname === '/guitar-beta')          return 'guitar-beta';
    if (sp.get('page') === 'guitar-beta')              return 'guitar-beta';
    // /violin-beta — public Violin Lab beta page. The explicit
    // `/violin-beta → /` Vercel rewrite in vercel.json keeps the
    // browser URL as `/violin-beta` while the server returns the same
    // bytes as `/` (i.e. index.html). No sign-in required:
    // violin_attempts + violin_feedback accept rows with user_id = NULL
    // after v111.
    if (location.pathname === '/violin-beta')          return 'violin-beta';
    if (sp.get('page') === 'violin-beta')              return 'violin-beta';
    // /musictheory-beta — public Practice (music-theory) Lab beta page.
    // Same shape: explicit `/musictheory-beta → /` rewrite in
    // vercel.json keeps the browser URL while the server returns
    // index.html. v113 opens practice_attempts + practice_feedback to
    // anonymous writes (user_id = NULL allowed).
    if (location.pathname === '/musictheory-beta')     return 'musictheory-beta';
    if (sp.get('page') === 'musictheory-beta')         return 'musictheory-beta';
    // /piano-beta — same shape as /drums-beta but for the Piano Lab.
    // piano_attempts + piano_feedback accept rows with user_id = NULL
    // after v114.
    if (location.pathname === '/piano-beta')           return 'piano-beta';
    if (sp.get('page') === 'piano-beta')               return 'piano-beta';
    // Clean public URLs (/for-instructors, /instructor-login, /how-it-works,
    // /student-login). Honored BEFORE the cached-session check — same rationale
    // as ?page=become-instructor above: a shared link should show what it says
    // regardless of whether the visitor happens to have a cached session.
    const cleanPg = pageFromCleanPath(location.pathname);
    if (cleanPg) return cleanPg;
    if (window.__MASTERY_MAGIC_LINK_LANDING) return 'dashboard';
    // Synchronous check for a cached session (see supabase-client.js). When
    // a returning user opens the bare URL we send them straight to their
    // dashboard so they don't see the homepage flash for a beat first.
    if (window.__MASTERY_HAS_CACHED_SESSION) return 'dashboard';
    const h = (location.hash || '').replace(/^#/, '');
    if (h === 'admin')   return 'admin';
    if (h === 'privacy') return 'privacy';
    if (h === 'terms')   return 'terms';
    if (h === 'cookies') return 'cookies';
    return 'home';
  })();
  const [page, setPage] = React.useState(initialPage);
  const [selectedInstructorId, setSelectedInstructorId] = React.useState(null);
  const [searchQuery, setSearchQuery] = React.useState({ topic: '', location: '' });
  const [scrolled, setScrolled] = React.useState(false);
  const [tweaks, setTweaks] = React.useState(TWEAK_DEFAULTS);
  const [tweaksVisible, setTweaksVisible] = React.useState(false);
  const [authMode, setAuthMode] = React.useState(null); // null | 'login' | 'signup'
  const auth = window.useAuth();

  // Initial Supabase data fetch
  React.useEffect(() => {
    if (window.SUPABASE_CONFIG && window.SUPABASE_CONFIG.url && !window.SUPABASE_CONFIG.url.includes('YOUR_PROJECT')) {
      window.SITE_DATA.refresh();
    } else {
      console.warn('[mastery] Supabase config not set — instructors will be empty. Edit src/supabase-client.js with your project URL + anon key.');
    }
  }, []);

  // Re-fetch on auth changes (so dashboards reflect new state)
  React.useEffect(() => {
    if (auth.user) window.SITE_DATA.refresh();
  }, [auth.user?.id]);

  // Auto-route logged-in users from the homepage to their dashboard.
  // Fires whenever auth.user transitions from null → set (magic link landing
  // when not pre-routed, persistent session restore on page load, modal
  // sign-in). The initial-state hack above handles the magic-link case
  // synchronously; this effect is the fallback for everything else.
  //
  // We route as soon as the user is known (auth.user set + auth.loading false),
  // not waiting on auth.profile. Admins don't have a profile row, and the
  // /dashboard route handles all three cases (admin / instructor / student).
  const prevUserIdRef = React.useRef(null);
  React.useEffect(() => {
    const wasLoggedOut = prevUserIdRef.current == null;
    const isNowLoggedIn = !!auth.user?.id;
    prevUserIdRef.current = auth.user?.id || null;
    if (auth.loading) return;
    if (wasLoggedOut && isNowLoggedIn && page === 'home') {
      setPage('dashboard');
      window.scrollTo(0, 0);
    }
  }, [auth.user?.id, auth.loading]);

  // Scroll detection for nav
  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 60);
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  // Back/forward across the clean public URLs. Acts ONLY on mapped public
  // paths (and bare '/', → home) so it can never disturb the auth/app routes,
  // which manage their own history via replaceState as before.
  React.useEffect(() => {
    const onPop = () => {
      const pg = pageFromCleanPath(location.pathname);
      if (pg) { setPage(pg); window.scrollTo(0, 0); }
      else if (((location.pathname || '').replace(/\/+$/, '') || '/') === '/') { setPage('home'); window.scrollTo(0, 0); }
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  // Expose the client-side router so cross-file buttons can navigate without a
  // full page reload — the Messages nav button uses this to open Messages
  // instantly instead of reloading the whole CDN-Babel app. The ref keeps the
  // exposed handle stable while always calling the latest navigate closure.
  const navRef = React.useRef(null);
  React.useEffect(() => {
    window.MASTERY = window.MASTERY || {};
    window.MASTERY.navigate = (p) => { const fn = navRef.current; if (fn) fn(p); };
    return () => { if (window.MASTERY) delete window.MASTERY.navigate; };
  }, []);

  // Tweaks panel protocol
  React.useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode')   setTweaksVisible(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksVisible(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  const setTweak = (key, value) => {
    const next = typeof key === 'object' ? { ...tweaks, ...key } : { ...tweaks, [key]: value };
    setTweaks(next);
    window.parent.postMessage({ type: '__edit_mode_set_keys', edits: next }, '*');
  };

  // Apply color scheme to CSS vars
  const scheme = SCHEMES[tweaks.colorScheme] || SCHEMES['navy-gold'];
  React.useEffect(() => {
    document.documentElement.style.setProperty('--primary', scheme.primary);
    document.documentElement.style.setProperty('--accent', scheme.accent);
    document.documentElement.style.setProperty('--accent-hover', scheme.accentHover);
  }, [tweaks.colorScheme]);

  const goToInstructors = (query) => {
    setSearchQuery(query);
    setPage('instructors');
    window.scrollTo(0, 0);
  };

  const goToInstructor = (id) => {
    setSelectedInstructorId(id);
    setPage('instructor-profile');
    window.scrollTo(0, 0);
  };

  const navigate = (p) => {
    setPage(p);
    window.scrollTo(0, 0);
    // Reflect mapped public pages in the address bar so the URL is shareable
    // (e.g. clicking "For instructors" → /for-instructors). Every other page
    // keeps its current URL exactly as before — this only touches the public
    // marketing surface, never the auth/app routes.
    try {
      const path = PAGE_TO_PATH[p];
      if (path && location.pathname !== path) window.history.pushState({}, '', path);
    } catch (_) {}
  };
  navRef.current = navigate;

  const openAuth = (mode = 'login') => setAuthMode(mode);
  const closeAuth = () => setAuthMode(null);
  const openBecomeInstructor = () => navigate('become-instructor');

  // Admin "view as" — render the REAL StudentPortal / InstructorPortal
  // with the dashboard data layer impersonating the chosen user (v38
  // RPCs). This replaces the old snapshot-based viewer so the admin
  // sees every feature the user sees, automatically, forever.
  if (page === 'admin-view-as' && viewAsParams) {
    // Set the impersonation marker BEFORE we render, so the first
    // DASHBOARD_DATA.refresh() in the mounted portal reads the right
    // user. app.jsx's auth-changed effect also fires SITE_DATA.refresh,
    // which is fine — SITE_DATA is the public listings (no impersonation).
    if (window.MASTERY) {
      window.MASTERY.viewAs = { kind: viewAsParams.kind, userId: viewAsParams.userId };
    }
    const closeView = () => {
      if (window.MASTERY) window.MASTERY.viewAs = null;
      try { history.replaceState({}, '', location.origin + location.pathname + '#admin'); } catch(e) {}
      try { window.DASHBOARD_DATA && window.DASHBOARD_DATA.refresh(); } catch(e) {}
      // Hard navigate so the URL drops the query param and any stale
      // dashboard hook state is cleaned out.
      try { location.href = location.origin + location.pathname + '#admin'; } catch(e) {}
      navigate('admin');
    };
    const portal = viewAsParams.kind === 'student'
      ? <window.StudentPortal onBack={closeView} />
      : <window.InstructorPortal onBack={closeView} />;
    return (
      <div style={{ minHeight:'100vh', display:'flex', flexDirection:'column' }}>
        {/* Pinned admin banner so the admin never loses context that this
            is a view-as tab. Click Exit to return to the admin dashboard. */}
        <div style={{
          flex:'0 0 auto', background:'oklch(20% 0.07 265)', color:'#fff',
          padding:'10px 22px', display:'flex', alignItems:'center', gap:14,
          fontFamily:"'Plus Jakarta Sans', sans-serif", fontSize:13,
          boxShadow:'0 2px 8px rgba(0,0,0,0.18)', zIndex:100,
        }}>
          <span style={{ fontSize:11, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', background:'oklch(72% 0.17 80)', color:'oklch(18% 0.06 265)', padding:'3px 9px', borderRadius:14 }}>
            Admin · View as
          </span>
          <span style={{ opacity:0.85 }}>
            You're seeing this {viewAsParams.kind === 'student' ? 'student' : 'teacher'}'s live dashboard. Updates appear as they happen.
          </span>
          <div style={{ flex:1 }} />
          <button onClick={closeView} style={{
            background:'rgba(255,255,255,0.12)', border:'1px solid rgba(255,255,255,0.22)',
            color:'#fff', borderRadius:8, padding:'7px 14px', fontSize:12,
            fontWeight:600, cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif",
          }}>
            Exit View as
          </button>
        </div>
        <div style={{ flex:1, minHeight:0 }}>{portal}</div>
      </div>
    );
  }

  // Teacher confirmation deep-link. The page itself handles "not signed in"
  // by routing through the AuthModal; after a successful confirm it sends
  // the user to their dashboard.
  if (page === 'confirm-assignment' && confirmAssignmentId) {
    const finish = () => {
      try {
        const sp = new URLSearchParams(location.search);
        sp.delete('action'); sp.delete('id');
        const q = sp.toString();
        history.replaceState({}, '', location.pathname + (q ? '?' + q : '') + location.hash);
      } catch(e) {}
      navigate('dashboard');
      try { window.SITE_DATA && window.SITE_DATA.refresh(); } catch(e) {}
    };
    return <window.ConfirmAssignmentPage
      assignmentId={confirmAssignmentId}
      onDone={finish}
      openAuth={openAuth}
    />;
  }

  // Admin is a full-screen standalone surface — no NavBar/Footer.
  if (page === 'admin') {
    return <window.AdminDashboard onBack={() => navigate('home')} />;
  }

  // Messages page — full-screen 1-on-1 chat between assigned student/teacher.
  // Anyone signed in can hit ?page=messages; the page itself shows "sign in"
  // if there's no user and an empty state if they have no conversations.
  //
  // When the user clicks "back" we strip the ?page=messages query so a refresh
  // doesn't re-route them straight back to the inbox. Same pattern as the
  // ?page=verify branch below.
  if (page === 'messages') {
    const leaveMessages = (target = 'dashboard') => {
      try {
        const sp = new URLSearchParams(location.search);
        if (sp.get('page') === 'messages') {
          sp.delete('page');
          const q = sp.toString();
          history.replaceState({}, '', location.pathname + (q ? '?' + q : '') + location.hash);
        }
      } catch(e) {}
      navigate(target);
    };
    return <window.MessagesPage onBack={() => leaveMessages('dashboard')} />;
  }

  // Lesson page — embedded Daily.co call inside a popup window. Renders
  // window.LessonRoom which hosts a daily-js callObject (not the prebuilt
  // iframe) so the recorder can subscribe to every participant's audio
  // track and mix both sides into one .webm. Also renders the admin-notes
  // banner overlay (the in-meeting note delivery for live sessions).
  if (page === 'lesson') {
    const sp = new URLSearchParams(location.search);
    const bookingId = sp.get('bookingId') || '';
    const LR = window.LessonRoom;
    if (!LR) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Lesson room failed to load.</div>;
    }
    return <LR bookingId={bookingId} />;
  }

  if (page === 'drums-beta') {
    // Public Drums Lab beta — full-screen treatment, no NavBar / Footer,
    // anonymous-friendly. The DrumsBetaPage wrapper supplies its own
    // header + intro band.
    const DBP = window.DrumsBetaPage || (window.DrumsLab && window.DrumsLab.ui && window.DrumsLab.ui.DrumsBetaPage);
    if (!DBP) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Drums Lab failed to load.</div>;
    }
    return <DBP navigate={navigate} />;
  }

  if (page === 'guitar-beta') {
    // Public Guitar Lab beta — full-screen treatment, no NavBar / Footer,
    // anonymous-friendly. The GuitarBetaPage wrapper supplies its own
    // header + intro band.
    const GBP = window.GuitarBetaPage || (window.GuitarLab && window.GuitarLab.ui && window.GuitarLab.ui.GuitarBetaPage);
    if (!GBP) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Guitar Lab failed to load.</div>;
    }
    return <GBP navigate={navigate} />;
  }

  if (page === 'violin-beta') {
    // Public Violin Lab beta — full-screen treatment, no NavBar / Footer,
    // anonymous-friendly. The ViolinBetaPage wrapper supplies its own
    // header + intro band.
    const VBP = window.ViolinBetaPage || (window.ViolinLab && window.ViolinLab.ui && window.ViolinLab.ui.ViolinBetaPage);
    if (!VBP) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Violin Lab failed to load.</div>;
    }
    return <VBP navigate={navigate} />;
  }

  if (page === 'musictheory-beta') {
    // Public Music Theory Lab beta — full-screen treatment, no NavBar /
    // Footer, anonymous-friendly. The MusicTheoryBetaPage wrapper
    // supplies its own header + intro band.
    const MTP = window.MusicTheoryBetaPage || (window.PracticeLab && window.PracticeLab.ui && window.PracticeLab.ui.MusicTheoryBetaPage);
    if (!MTP) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Music Theory Lab failed to load.</div>;
    }
    return <MTP navigate={navigate} />;
  }

  if (page === 'piano-beta') {
    // Public Piano Lab beta — full-screen treatment, no NavBar / Footer,
    // anonymous-friendly. The PianoBetaPage wrapper supplies its own
    // header + intro band.
    const PBP = window.PianoBetaPage || (window.PianoLab && window.PianoLab.ui && window.PianoLab.ui.PianoBetaPage);
    if (!PBP) {
      return <div style={{ padding: 24, fontFamily: 'sans-serif' }}>Piano Lab failed to load.</div>;
    }
    return <PBP navigate={navigate} />;
  }

  if (page === 'verify') {
    // Strip the ?page=verify query from the URL after first load so a refresh
    // doesn't trap the user here.
    try {
      const sp = new URLSearchParams(location.search);
      if (sp.get('page') === 'verify') {
        sp.delete('page');
        const q = sp.toString();
        history.replaceState({}, '', location.pathname + (q ? '?' + q : '') + location.hash);
      }
    } catch(e) {}
    return <window.InstructorVerifyPage setPage={navigate} />;
  }

  // V2 instructor signup wizard — same full-screen treatment as ?page=verify.
  // Putting it inside the regular layout leaked the site NavBar / Footer on
  // top of the Wyzant-style funnel, which broke the commitment flow visually
  // and was the #1 ugly bug in the self-test.
  if (page === 'become-instructor') {
    return <window.BecomeInstructorV2 setPage={navigate} />;
  }
  if (page === 'become-instructor-legacy') {
    return <window.BecomeInstructorPage setPage={navigate} />;
  }

  // Dashboard is also full-screen standalone — each portal owns its own
  // auth flow (phone-based for students, email/password for instructors).
  // Admin gets routed to the admin panel — they don't have a profile row,
  // so the student/instructor portals would just bounce them to login.
  if (page === 'dashboard') {
    // FLASH FIX: bootstrap in logic.js sets auth.loading=false as soon as the
    // CACHED session resolves, but auth.profile / auth.isAdmin are loaded a
    // moment later. If we speculatively render StudentPortal during that
    // window the student login UI flashes for ~100ms before the right portal
    // takes over. Hold on a neutral loading screen until we actually know the
    // role.
    //
    // "Profile ready" = either no user (logged out, definitely show student
    // login), OR we've confirmed a role (profile row OR admin_users row).
    const profileReady = !auth.user || !!auth.profile || auth.isAdmin;
    if (auth.loading || !profileReady) {
      return (
        <div style={{ minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'oklch(98.5% 0.007 60)', color:'oklch(55% 0.03 265)', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
          <div style={{ textAlign:'center' }}>
            <div style={{ fontFamily:"'Cormorant Garamond', serif", fontSize:24, fontWeight:700, letterSpacing:'0.14em', color:'oklch(22% 0.06 265)', marginBottom:18 }}>COACHING</div>
            <div style={{ fontSize:13 }}>Loading your dashboard…</div>
          </div>
        </div>
      );
    }
    if (auth.isAdmin) {
      return <window.AdminDashboard onBack={() => navigate('home')} />;
    }
    if (auth.profile?.role === 'instructor') {
      return <window.InstructorPortal onBack={() => navigate('home')} setPage={navigate} />;
    }
    return <window.StudentPortal onBack={() => navigate('home')} />;
  }
  if (page === 'student-portal') {
    return <window.StudentPortal onBack={() => navigate('home')} />;
  }
  if (page === 'instructor-portal') {
    return <window.InstructorPortal onBack={() => navigate('home')} setPage={navigate} />;
  }
  // Get-Started landing: unknown visitor → step-by-step intake wizard.
  // After they complete it they're auto-signed-in and routed to their
  // student dashboard (StudentOnboarding's onComplete navigates there).
  if (page === 'student-onboarding') {
    return <window.StudentOnboarding
      onComplete={() => navigate('dashboard')}
      onBack={() => navigate('home')}
    />;
  }

  // Public-instructors flag: when off, /instructors and individual profile
  // pages route silently to the homepage (rather than showing a broken state).
  // The page components themselves stay in the bundle for re-launch.
  const publicOk = !!window.FEATURES?.publicInstructors;

  let body;
  if (page === 'home') {
    body = <window.HomePage onSearch={goToInstructors} setPage={navigate}
              onSelectInstructor={goToInstructor} openBecomeInstructor={openBecomeInstructor} />;
  } else if (page === 'instructors' && publicOk) {
    body = <window.InstructorsPage initialSearch={searchQuery} setPage={navigate} onSelectInstructor={goToInstructor} />;
  } else if (page === 'instructor-profile' && publicOk) {
    body = <window.InstructorProfilePage instructorId={selectedInstructorId} setPage={navigate} openAuth={openAuth} />;
  } else if (page === 'how-it-works') {
    body = <HowItWorksPage setPage={navigate} openBecomeInstructor={openBecomeInstructor} />;
  } else if (page === 'privacy') {
    body = <window.PrivacyPage setPage={navigate} />;
  } else if (page === 'terms') {
    body = <window.TermsPage setPage={navigate} />;
  } else if (page === 'cookies') {
    body = <window.CookiesPage setPage={navigate} />;
  } else if ((page === 'instructors' || page === 'instructor-profile') && !publicOk) {
    // Soft-redirect to home when the flag is off
    body = <window.HomePage onSearch={goToInstructors} setPage={navigate}
              onSelectInstructor={goToInstructor} openBecomeInstructor={openBecomeInstructor} />;
  } else {
    body = <CenteredPad>Page not found.</CenteredPad>;
  }

  return (
    <div style={{ fontFamily: "'Plus Jakarta Sans', sans-serif" }}>
      <window.NavBar
        page={page} setPage={navigate} scrolled={scrolled}
        openAuth={openAuth} openBecomeInstructor={openBecomeInstructor}
      />

      {body}

      <window.Footer setPage={navigate} openBecomeInstructor={openBecomeInstructor} />

      {authMode && (
        <window.AuthModal
          mode={authMode}
          onClose={closeAuth}
          onSuccess={() => setAuthMode(null)}
          openBecomeInstructor={openBecomeInstructor}
        />
      )}

      {/* Tweaks Panel */}
      {tweaksVisible && (
        <TweaksPanel onClose={() => {
          setTweaksVisible(false);
          window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*');
        }}>
          <TweakSection title="Color Scheme">
            <TweakRadio
              id="colorScheme"
              value={tweaks.colorScheme}
              options={[
                { value: 'navy-gold',    label: 'Navy & Gold' },
                { value: 'forest-cream', label: 'Forest' },
                { value: 'slate-rose',   label: 'Slate & Rose' },
              ]}
              onChange={v => setTweak('colorScheme', v)}
            />
          </TweakSection>
          <TweakSection title="Instructor Cards">
            <TweakToggle
              id="showBadges"
              label="Show instructor badges"
              value={tweaks.showBadges}
              onChange={v => setTweak('showBadges', v)}
            />
            <TweakRadio
              id="defaultView"
              label="Default view"
              value={tweaks.defaultView}
              options={[
                { value: 'grid', label: 'Grid' },
                { value: 'list', label: 'List' },
              ]}
              onChange={v => setTweak('defaultView', v)}
            />
          </TweakSection>
        </TweaksPanel>
      )}
    </div>
  );
};

const HowItWorksPage = ({ setPage, openBecomeInstructor }) => {
  const { howItWorks } = window.useSiteData();
  return (
    <div style={{ background: 'oklch(98% 0.008 60)', minHeight: '100vh', paddingTop: 140, paddingBottom: 80 }}>
      <section style={{ maxWidth: 920, margin: '0 auto', padding: '0 80px' }}>
        <p style={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.14em', color: 'oklch(72% 0.17 80)', textTransform: 'uppercase', marginBottom: 12, textAlign: 'center' }}>How it works</p>
        <h1 style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 'clamp(36px, 4vw, 52px)', fontWeight: 600, color: 'oklch(22% 0.06 265)', textAlign: 'center', lineHeight: 1.15, marginBottom: 56 }}>
          Find your instructor in four steps
        </h1>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 24 }}>
          {howItWorks.map(s => (
            <div key={s.step} style={{ background: '#fff', borderRadius: 16, padding: 28, border: '1px solid oklch(92% 0.01 265)' }}>
              <div style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 30, fontWeight: 700, color: 'oklch(72% 0.17 80)', marginBottom: 8 }}>{s.step}</div>
              <h3 style={{ fontWeight: 700, color: 'oklch(22% 0.06 265)', fontSize: 17, marginBottom: 6 }}>{s.title}</h3>
              <p style={{ color: 'oklch(45% 0.03 265)', fontSize: 14, lineHeight: 1.65 }}>{s.desc}</p>
            </div>
          ))}
        </div>
        <div style={{ display: 'flex', gap: 12, justifyContent: 'center', marginTop: 40 }}>
          <button onClick={() => setPage('instructors')} style={primaryBtn}>Browse instructors</button>
          <button onClick={openBecomeInstructor} style={secondaryBtn}>Become an instructor</button>
        </div>
      </section>
    </div>
  );
};

const CenteredPad = ({ children }) => (
  <div style={{ paddingTop: 200, paddingBottom: 200, textAlign: 'center', minHeight: '60vh' }}>{children}</div>
);
const primaryBtn = {
  background: 'oklch(22% 0.06 265)', color: '#fff', border: 'none', borderRadius: 10,
  padding: '12px 26px', fontWeight: 600, fontSize: 14, cursor: 'pointer',
  fontFamily: "'Plus Jakarta Sans', sans-serif",
};
const secondaryBtn = {
  background: 'transparent', color: 'oklch(22% 0.06 265)',
  border: '1.5px solid oklch(82% 0.04 265)', borderRadius: 10,
  padding: '11px 26px', fontWeight: 600, fontSize: 14, cursor: 'pointer',
  fontFamily: "'Plus Jakarta Sans', sans-serif",
};

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
