var { useState, useEffect, useCallback, useMemo, useRef } = React;

// ─── Firebase ───────────────────────────────────────────
firebase.initializeApp({
  apiKey:"AIzaSyC8ECLUReNM4JSkhRRuwTELmGTLWNVSrIE",
  authDomain:"lineconic-live.firebaseapp.com",
  databaseURL:"https://lineconic-live-default-rtdb.europe-west1.firebasedatabase.app",
  projectId:"lineconic-live",
  storageBucket:"lineconic-live.firebasestorage.app",
  messagingSenderId:"890189018310",
  appId:"1:890189018310:web:7cc55ce3f3833b14c6d3c7"
});
var db = firebase.database();
var auth = firebase.auth();
var FOUNDER_EMAILS = ['petereureka@gmail.com','peterjroch@gmail.com','hi@lineconic.com'];
var MEDIA_TYPES = (window.BrandData && window.BrandData.content && window.BrandData.content.media_types && window.BrandData.content.media_types.drops) || ['movie','music','tv','internet','ad','meme','cliche'];
var SCORE_FIELDS = ['iconic_status','quotability','emotional_impact','performance_potential','visual_cue_power'];

// ─── Shared Utilities ───────────────────────────────────
function generateCode(answer) {
  if (!answer) return '';
  return answer.trim().split(/\s+/).map(function(w){return w[0].toUpperCase()}).join('.');
}
function calcLineconicScore(scores) {
  if (!scores) return 0;
  var vals = SCORE_FIELDS.map(function(k){return Number(scores[k]) || 0});
  var avg = vals.reduce(function(a,b){return a+b}, 0) / vals.length;
  return Math.round(avg * 2 * 10) / 10;
}
function generateId(answer) {
  if (!answer) return '';
  return answer.toLowerCase().replace(/[^a-z0-9\s]/g,'').trim().replace(/\s+/g,'-');
}

// ─── Crowd Scores ───────────────────────────────────────
var crowdScores = {};
function computeCrowdScores(cardStats) {
  crowdScores = {};
  if (!cardStats) return;
  var now = Date.now();
  Object.keys(cardStats).forEach(function(cardId) {
    var shows = cardStats[cardId].shows;
    if (!shows) return;
    var entries = Object.values(shows);
    if (entries.length === 0) return;
    entries.sort(function(a,b){return (b.date||'').localeCompare(a.date||'')});
    var weightSum=0, valSum=0, lastPlayed=entries[0].date||null;
    entries.forEach(function(e) {
      var daysSince = lastPlayed ? Math.max(0,(now-new Date(e.date).getTime())/86400000) : 0;
      var recencyWeight = Math.pow(0.85, daysSince/7);
      var w = recencyWeight * e.total;
      valSum += (e.knewPct||0) * w;
      weightSum += w;
    });
    var avgPct = weightSum > 0 ? valSum/weightSum : 50;
    crowdScores[cardId] = {
      crowd_score: Math.round(avgPct/10*10)/10,
      showCount: entries.length,
      lastPlayed: lastPlayed
    };
  });
}

// ─── One-time migration: slips schema ────────────────────
function migrateSlipsSchema() {
  db.ref('slips').once('value').then(function(snap) {
    var data = snap.val();
    if (!data) return;
    var updates = {};
    Object.keys(data).forEach(function(id) {
      var slip = data[id];
      if (slip.status === undefined) updates['slips/' + id + '/status'] = 'published';
      if (slip.scheduled_date === undefined) updates['slips/' + id + '/scheduled_date'] = null;
      if (slip.performance === undefined) updates['slips/' + id + '/performance'] = null;
      if (slip.rated_at === undefined) updates['slips/' + id + '/rated_at'] = null;
    });
    if (Object.keys(updates).length > 0) {
      return db.ref().update(updates).then(function() {
        console.log('[migration] slips schema: updated ' + Object.keys(updates).length + ' fields');
      });
    } else {
      console.log('[migration] slips schema: no records to migrate');
    }
  }).catch(function(err) {
    console.error('[migration] slips schema failed:', err);
  });
}

// ─── One-time migration: film → movie ───────────────────
function migrateFilmToMovie() {
  var updates = {};
  db.ref('cards/cards').orderByChild('media_type').equalTo('film').once('value').then(function(snap) {
    var data = snap.val();
    if (data) {
      Object.keys(data).forEach(function(id) {
        updates['cards/cards/' + id + '/media_type'] = 'movie';
      });
    }
    return db.ref('drops').orderByChild('medium').equalTo('film').once('value');
  }).then(function(snap) {
    var data = snap.val();
    if (data) {
      Object.keys(data).forEach(function(id) {
        updates['drops/' + id + '/medium'] = 'movie';
      });
    }
    if (Object.keys(updates).length > 0) {
      return db.ref().update(updates).then(function() {
        console.log('[migration] film→movie: updated ' + Object.keys(updates).length + ' fields');
      });
    } else {
      console.log('[migration] film→movie: no records to migrate');
    }
  }).catch(function(err) {
    console.error('[migration] film→movie failed:', err);
  });
}

// ─── Expired Media Cleanup ──────────────────────────────
function cleanupExpiredMedia() {
  var SIX_HOURS = 6 * 60 * 60 * 1000;
  var cutoff = Date.now() - SIX_HOURS;

  db.ref('drops').once('value').then(function(snap) {
    var allDrops = snap.val() || {};
    var activeDropIds = {};
    Object.keys(allDrops).forEach(function(id) {
      if (allDrops[id].clip_url) activeDropIds[id] = true;
    });

    return firebase.storage().ref('media').listAll().then(function(result) {
      result.prefixes.forEach(function(folderRef) {
        var dropId = folderRef.name;
        if (activeDropIds[dropId]) return;

        folderRef.listAll().then(function(files) {
          files.items.forEach(function(fileRef) {
            fileRef.getMetadata().then(function(meta) {
              if (new Date(meta.timeCreated).getTime() < cutoff) {
                fileRef.delete().then(function() {
                  console.log('[cleanup] deleted expired: ' + fileRef.fullPath);
                });
              }
            });
          });
        });
      });
    });
  }).catch(function(err) {
    console.error('[cleanup] media sweep failed:', err);
  });
}

// ─── Seed Founder User ──────────────────────────────────
function seedFounderUser(user) {
  if (FOUNDER_EMAILS.indexOf(user.email) === -1) return Promise.resolve();
  var ref = db.ref('users/' + user.uid);
  return ref.once('value').then(function(snap) {
    if (snap.exists()) return;
    return ref.set({
      email: user.email,
      role: 'founder',
      display_name: user.displayName || user.email.split('@')[0],
      city: null,
      created_at: new Date().toISOString(),
      created_by: 'self'
    }).then(function() {
      console.log('[seed] founder user created for ' + user.email);
    });
  });
}

// ─── Tab Access Map ─────────────────────────────────────
var TAB_ACCESS = {
  cards:     ['founder', 'captain'],
  builder:   ['founder', 'captain'],
  analytics: ['founder', 'captain'],
  ai:        ['founder', 'captain', 'admin'],
  creators:  ['founder'],
  create:    ['founder', 'captain', 'admin'],
  calendar:  ['founder', 'captain', 'admin'],
  insights:  ['founder', 'captain', 'admin', 'viewer'],
  hotseat:   ['founder', 'captain'],
  settings:  ['founder', 'captain'],
  chloe:     ['founder', 'captain', 'admin']
};

// ─── AI Fetch Wrapper ───────────────────────────────────
function aiFetch(url, options, timeoutMs) {
  timeoutMs = timeoutMs || 30000;
  var controller = new AbortController();
  var timer = setTimeout(function(){ controller.abort(); }, timeoutMs);
  var opts = Object.assign({}, options, { signal: controller.signal });
  return fetch(url, opts).then(function(res) {
    clearTimeout(timer);
    if (res.ok) return res;
    if (res.status === 401 || res.status === 403) throw new Error('AUTH_EXPIRED');
    if (res.status === 429) throw new Error('RATE_LIMITED');
    if (res.status >= 500) throw new Error('SERVER_ERROR');
    throw new Error('HTTP_' + res.status);
  }).catch(function(err) {
    clearTimeout(timer);
    if (err.name === 'AbortError') throw new Error('TIMEOUT');
    throw err;
  });
}

function formatAiError(err) {
  var msg = err.message || String(err);
  switch(msg) {
    case 'TIMEOUT': return 'AI request timed out. Check your connection and try again.';
    case 'AUTH_EXPIRED': return 'Session expired. Sign out and back in.';
    case 'RATE_LIMITED': return 'Too many requests. Wait a moment and retry.';
    case 'SERVER_ERROR': return 'AI service is temporarily unavailable. Everything else still works — try again shortly.';
    case 'Failed to fetch': return 'Network error. Check your connection.';
    default: return msg.startsWith('HTTP_') ? 'Request failed (' + msg + '). Try again.' : msg;
  }
}

// ─── Toast Hook ─────────────────────────────────────────
function useToast() {
  var ref = useState(null);
  var toast = ref[0], setToast = ref[1];
  function show(msg) { setToast(msg); setTimeout(function(){setToast(null)}, 2500); }
  return [toast, show];
}

// ─── Auth Components ────────────────────────────────────
function LoginScreen() {
  var [email, setEmail] = useState('');
  var [password, setPassword] = useState('');
  var [error, setError] = useState(null);
  var [loading, setLoading] = useState(false);

  function handleSubmit(e) {
    e.preventDefault();
    if (loading) return;
    setError(null); setLoading(true);
    auth.signInWithEmailAndPassword(email, password)
      .then(function(){})
      .catch(function(err) {
        setLoading(false);
        switch(err.code) {
          case 'auth/invalid-email': setError('INVALID EMAIL FORMAT'); break;
          case 'auth/user-not-found': case 'auth/wrong-password': case 'auth/invalid-credential': setError('INVALID CREDENTIALS'); break;
          case 'auth/too-many-requests': setError('TOO MANY ATTEMPTS. TRY LATER.'); break;
          default: setError('AUTH FAILED: ' + err.code);
        }
      });
  }

  return (
    <div className="A-auth">
      <div className="A-auth-title">L</div>
      <div className="A-auth-sub">ADMIN PORTAL — SIGN IN</div>
      <form onSubmit={handleSubmit} style={{display:'flex',flexDirection:'column',gap:12,width:'100%',maxWidth:280,padding:'0 16px'}}>
        <input className="A-input" type="email" placeholder="EMAIL" value={email} onChange={function(e){setEmail(e.target.value)}} style={{textTransform:'uppercase',letterSpacing:1}} autoFocus />
        <input className="A-input" type="password" placeholder="PASSWORD" value={password} onChange={function(e){setPassword(e.target.value)}} style={{letterSpacing:1}} />
        {error && <div style={{fontSize:10,color:'var(--signal)',letterSpacing:1}}>{error}</div>}
        <button type="submit" className="A-btn signal" disabled={loading} style={{padding:'10px 14px'}}>
          {loading ? 'SIGNING IN...' : 'SIGN IN'}
        </button>
      </form>
    </div>
  );
}

function AuthGate(props) {
  var [user, setUser] = useState(undefined);
  var [userRecord, setUserRecord] = useState(undefined);
  var [denied, setDenied] = useState(false);

  useEffect(function() {
    var userRecordRef = null;

    var unsub = auth.onAuthStateChanged(function(u) {
      // Cleanup previous listener
      if (userRecordRef) { userRecordRef.off(); userRecordRef = null; }
      setUserRecord(undefined);

      if (!u) { setUser(null); setDenied(false); return; }

      setUser(u);

      // Seed founder if applicable, then listen for user record
      seedFounderUser(u).then(function() {
        userRecordRef = db.ref('users/' + u.uid);
        userRecordRef.on('value', function(snap) {
          var record = snap.val();
          if (record && record.role) {
            setUserRecord(record);
            setDenied(false);
            migrateFilmToMovie();
            migrateSlipsSchema();
          } else {
            // Check pending_users for invite
            var emailKey = u.email.replace(/\./g, ',');
            db.ref('pending_users/' + emailKey).once('value').then(function(pendingSnap) {
              var pending = pendingSnap.val();
              if (pending) {
                // Atomic: create user record + delete pending invite
                var newRecord = {
                  email: u.email,
                  role: pending.role,
                  display_name: pending.display_name || u.displayName || u.email.split('@')[0],
                  city: null,
                  created_at: new Date().toISOString(),
                  created_by: pending.invited_by || 'unknown'
                };
                var updates = {};
                updates['users/' + u.uid] = newRecord;
                updates['pending_users/' + emailKey] = null;
                db.ref().update(updates).then(function() {
                  console.log('[auth] pending invite resolved for ' + u.email);
                  // .on('value') listener will fire and set userRecord
                }).catch(function(err) {
                  console.error('[auth] failed to resolve pending invite:', err);
                  setDenied(true);
                });
              } else {
                setDenied(true);
              }
            });
          }
        });
      }).catch(function(err) {
        console.error('[auth] seed failed:', err);
        setDenied(true);
      });
    });

    return function() {
      unsub();
      if (userRecordRef) userRecordRef.off();
    };
  }, []);

  if (user === undefined) return <div className="A-auth"><div style={{color:'var(--text-dim)',fontSize:14,letterSpacing:2,textTransform:'uppercase'}}>LOADING...</div></div>;
  if (denied) return <div className="A-auth"><div style={{fontSize:14,letterSpacing:2,textTransform:'uppercase'}}>ACCESS DENIED</div><div className="A-auth-sub">Your account is not authorized.</div><button className="A-btn" onClick={function(){auth.signOut()}}>SIGN OUT</button></div>;
  if (!user) return <LoginScreen />;
  if (userRecord === undefined) return <div className="A-auth"><div style={{color:'var(--text-dim)',fontSize:14,letterSpacing:2,textTransform:'uppercase'}}>LOADING...</div></div>;
  return props.children(user, userRecord);
}

// ─── Tab definitions ────────────────────────────────────
var TABS = [
  {id:'cards', label:'CARDS', group:'content'},
  {id:'ai', label:'AI LAB', group:'content'},
  {id:'creators', label:'CREATORS', group:'content'},
  {id:'builder', label:'BUILDER', group:'shows'},
  {id:'hotseat', label:'HOT SEAT', group:'shows'},
  {id:'calendar', label:'CALENDAR', group:'shows'},
  {id:'analytics', label:'ANALYTICS', group:'ops'},
  {id:'insights', label:'INSIGHTS', group:'ops'},
  {id:'create', label:'CREATE', group:'ops'},
  {id:'settings', label:'SETTINGS', group:'settings'},
  {id:'chloe', label:'CHLOE', group:'chloe'}
];

// ─── Publish All Button ─────────────────────────────────
var PUBLISH_COLLECTIONS = ['shows','templates','drops','slips','hotseat-cards','creators','card-stats','show-index'];

function PublishAllButton(props) {
  var user = props.user, showToast = props.showToast, isMobile = props.isMobile;
  var [publishing, setPublishing] = useState(false);
  var [progress, setProgress] = useState('');

  function handlePublishAll() {
    if (publishing) return;
    setPublishing(true);
    setProgress('Starting...');

    user.getIdToken().then(function(token) {
      return fetch('/api/publish-data', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token },
        body: JSON.stringify({ collections: PUBLISH_COLLECTIONS })
      });
    }).then(function(res) { return res.json(); }).then(function(data) {
      setPublishing(false);
      setProgress('');
      if (data.ok) {
        var total = Object.values(data.results).reduce(function(sum, r) { return sum + (r.records || 0); }, 0);
        showToast('PUBLISHED ALL — ' + total + ' RECORDS');
      } else {
        var failed = data.errors ? Object.keys(data.errors).join(', ') : 'unknown';
        showToast('PARTIAL PUBLISH — FAILED: ' + failed);
      }
    }).catch(function(err) {
      setPublishing(false);
      setProgress('');
      showToast('PUBLISH FAILED: ' + err.message);
    });
  }

  return React.createElement('button', {
    className: 'A-btn cyan',
    style: { fontSize: 9, padding: '4px 10px', minHeight: 'unset', marginRight: 8, opacity: publishing ? 0.6 : 1 },
    onClick: handlePublishAll,
    disabled: publishing,
    title: 'Publish all Firebase data to GitHub backup'
  }, publishing ? (progress || 'PUBLISHING...') : (isMobile ? 'BACKUP' : 'PUBLISH ALL'));
}

// ─── Portal Shell ───────────────────────────────────────
function AdminPortal(props) {
  var user = props.user;
  var userRecord = props.userRecord;
  var role = userRecord.role;

  var visibleTabs = useMemo(function() {
    return TABS.filter(function(t) { return TAB_ACCESS[t.id] && TAB_ACCESS[t.id].indexOf(role) !== -1; });
  }, [role]);

  var [isMobile, setIsMobile] = useState(window.innerWidth < 768);
  useEffect(function(){
    function onResize(){setIsMobile(window.innerWidth < 768)}
    window.addEventListener('resize', onResize);
    return function(){window.removeEventListener('resize', onResize)};
  },[]);
  var [drawerOpen, setDrawerOpen] = useState(false);

  var [tab, setTab] = useState(function() {
    return window.location.hash.replace('#','') || 'cards';
  });
  var [toast, showToast] = useToast();

  // Shared data state
  var [cards, setCards] = useState(null);
  var [meta, setMeta] = useState(null);
  var [cardStats, setCardStats] = useState(null);
  var [showIndex, setShowIndex] = useState(null);
  var [activeShow, setActiveShow] = useState(null);
  var [drops, setDrops] = useState(null);
  var [templates, setTemplates] = useState(null);
  var [tasteProfile, setTasteProfile] = useState(null);
  var [brandSettings, setBrandSettings] = useState(null);
  var [slips, setSlips] = useState(null);
  var [hotseatCards, setHotseatCards] = useState(null);
  var [hotseatEditions, setHotseatEditions] = useState(null);
  var [creators, setCreators] = useState(null);
  var [culturalPulse, setCulturalPulse] = useState(null);

  // Hash routing
  useEffect(function() {
    function onHash() { setTab(window.location.hash.replace('#','') || 'cards'); }
    window.addEventListener('hashchange', onHash);
    return function() { window.removeEventListener('hashchange', onHash); };
  }, []);

  // Redirect if current tab not visible for this role
  useEffect(function() {
    var visibleIds = visibleTabs.map(function(t) { return t.id; });
    if (visibleIds.indexOf(tab) === -1 && visibleTabs.length > 0) {
      switchTab(visibleTabs[0].id);
    }
  }, [tab, visibleTabs]);

  function switchTab(id) {
    window.location.hash = id;
    setTab(id);
    setDrawerOpen(false);
  }

  // Brand data state (canon-compiled JSON)
  var [brandBuildInfo, setBrandBuildInfo] = useState('');

  // Load brand data from core/brand/ JSON files
  useEffect(function() {
    if (window.loadBrandData) {
      window.loadBrandData().then(function() {
        setBrandBuildInfo(window.getBrandBuildInfo ? window.getBrandBuildInfo() : '');
      });
    }
  }, []);

  // Load Firebase data once
  useEffect(function() {
    var cardsRef = db.ref('cards/cards');
    var metaRef = db.ref('cards/meta');
    cardsRef.on('value', function(snap) { setCards(snap.val() || {}); });
    metaRef.on('value', function(snap) { setMeta(snap.val() || {}); });
    var statsRef = db.ref('card_stats');
    var indexRef = db.ref('show_index');
    statsRef.on('value', function(snap) {
      var data = snap.val();
      setCardStats(data);
      computeCrowdScores(data);
    });
    indexRef.on('value', function(snap) { setShowIndex(snap.val() || {}); });
    var activeRef = db.ref('active_show');
    activeRef.on('value', function(snap) { setActiveShow(snap.val() || null); });
    var dropsRef = db.ref('drops');
    dropsRef.on('value', function(snap) { setDrops(snap.val() || {}); }, function(err) { console.error('drops listener error:', err); setDrops({}); });
    var templatesRef = db.ref('templates');
    templatesRef.on('value', function(snap) { setTemplates(snap.val() || {}); }, function(err) { console.error('templates listener error:', err); setTemplates({}); });
    var tasteRef = db.ref('taste_profile');
    tasteRef.on('value', function(snap) { setTasteProfile(snap.val() || null); }, function(err) { console.error('taste_profile listener error:', err); setTasteProfile(null); });
    var brandRef = db.ref('brand_settings');
    brandRef.on('value', function(snap) { setBrandSettings(snap.val() || null); }, function(err) { console.error('brand_settings listener error:', err); setBrandSettings(null); });
    var slipsRef = db.ref('slips');
    slipsRef.on('value', function(snap) { setSlips(snap.val() || {}); }, function(err) { console.error('slips listener error:', err); setSlips({}); });
    var hotseatRef = db.ref('hotseat_cards');
    hotseatRef.on('value', function(snap) { setHotseatCards(snap.val() || {}); }, function(err) { console.error('hotseat_cards listener error:', err); setHotseatCards({}); });
    var editionsRef = db.ref('hotseat_editions');
    editionsRef.on('value', function(snap) { setHotseatEditions(snap.val() || {}); }, function(err) { console.error('hotseat_editions listener error:', err); setHotseatEditions({}); });
    var creatorsRef = db.ref('creators');
    creatorsRef.on('value', function(snap) { setCreators(snap.val() || {}); }, function(err) { console.error('creators listener error:', err); setCreators({}); });
    var pulseRef = db.ref('cultural_pulse');
    pulseRef.on('value', function(snap) { setCulturalPulse(snap.val() || null); }, function(err) { console.error('cultural_pulse listener error:', err); setCulturalPulse(null); });
    return function() { cardsRef.off(); metaRef.off(); statsRef.off(); indexRef.off(); activeRef.off(); dropsRef.off(); templatesRef.off(); tasteRef.off(); brandRef.off(); slipsRef.off(); hotseatRef.off(); editionsRef.off(); creatorsRef.off(); pulseRef.off(); };
  }, []);

  // Derive library array from Firebase cards object (replaces static card-library.json fetch)
  var library = useMemo(function() {
    if (!cards) return null;
    return Object.values(cards);
  }, [cards]);

  var sharedProps = {
    user: user, userRecord: userRecord, role: role, db: db, auth: auth, cards: cards, setCards: setCards, meta: meta, setMeta: setMeta,
    library: library, cardStats: cardStats, showIndex: showIndex, activeShow: activeShow, drops: drops, templates: templates, tasteProfile: tasteProfile, brandSettings: brandSettings, slips: slips, hotseatCards: hotseatCards, hotseatEditions: hotseatEditions, creators: creators, culturalPulse: culturalPulse, showToast: showToast,
    crowdScores: crowdScores, MEDIA_TYPES: MEDIA_TYPES, SCORE_FIELDS: SCORE_FIELDS,
    generateCode: generateCode, calcLineconicScore: calcLineconicScore, generateId: generateId,
    computeCrowdScores: computeCrowdScores, switchTab: switchTab
  };

  // Compute insights badge count for reuse in tabs and drawer
  var insightsBadgeCount = useMemo(function() {
    var unratedDrops = drops ? Object.values(drops).filter(function(d) { return d.status === 'published' && !d.performance; }).length : 0;
    var unratedSlips = slips ? Object.values(slips).filter(function(s) { return s.status === 'published' && !s.performance; }).length : 0;
    return unratedDrops + unratedSlips;
  }, [drops, slips]);

  return (
    <div className="A-shell">
      <div className="A-head">
        <div style={{display:'flex',alignItems:'center',gap:8}}>
          {isMobile && <button className="A-btn" style={{fontSize:16,padding:'4px 8px',minHeight:'unset',border:'none',color:'var(--text)'}} onClick={function(){setDrawerOpen(true)}}>☰</button>}
          <span className="A-brand">L</span>
          <span className="A-brand-sub">ADMIN</span>
        </div>
        <div className="A-user">
          {!isMobile && brandBuildInfo && <span style={{fontSize:8,color:'var(--text-dim)',letterSpacing:'.06em',marginRight:12}} title="Canon brand data build">CANON: {brandBuildInfo}</span>}
          {(role === 'founder' || role === 'captain') && <PublishAllButton user={user} showToast={showToast} isMobile={isMobile} />}
          <span style={{fontSize:9,padding:'2px 8px',border:'1px solid var(--signal)',color:'var(--signal)',letterSpacing:'.08em',textTransform:'uppercase'}}>{role}</span>
          <span className="A-user-email">{user.email}</span>
          <button className="A-btn" style={{fontSize:10,padding:'4px 10px',minHeight:'unset'}} onClick={function(){auth.signOut()}}>OUT</button>
        </div>
      </div>
      {!isMobile && <div className="A-tabs">
        {visibleTabs.map(function(t, i) {
          var badge = null;
          if (t.id === 'insights' && insightsBadgeCount > 0) {
            badge = React.createElement('span', {style:{marginLeft:6,background:'var(--signal)',color:'#000',fontSize:8,fontWeight:700,padding:'1px 5px',verticalAlign:'top'}}, insightsBadgeCount);
          }
          var showDivider = i > 0 && visibleTabs[i-1].group !== t.group;
          return React.createElement(React.Fragment, {key: t.id},
            showDivider && <div className="A-tab-divider"></div>,
            <div className={'A-tab' + (tab === t.id ? ' on' : '') + (t.id === 'chloe' ? ' chloe' : '')} onClick={function(){switchTab(t.id)}}>{t.label}{badge}</div>
          );
        })}
      </div>}
      {isMobile && <div className={'A-drawer' + (drawerOpen ? ' open' : '')}>
        <div className="A-drawer-backdrop" onClick={function(){setDrawerOpen(false)}}></div>
        <div className="A-drawer-panel">
          <div style={{padding:'20px',borderBottom:'1px solid var(--border)'}}>
            <span className="A-brand" style={{fontSize:'1.2rem'}}>L</span>
            <span className="A-brand-sub" style={{fontSize:'1.2rem'}}>ADMIN</span>
          </div>
          <div style={{flex:1,overflow:'auto',padding:'8px 0'}}>
            {visibleTabs.map(function(t, i) {
              var badge = null;
              if (t.id === 'insights' && insightsBadgeCount > 0) {
                badge = React.createElement('span', {style:{marginLeft:8,background:'var(--signal)',color:'#000',fontSize:9,fontWeight:700,padding:'1px 6px'}}, insightsBadgeCount);
              }
              var showDivider = i > 0 && visibleTabs[i-1].group !== t.group;
              return React.createElement(React.Fragment, {key: t.id},
                showDivider && <div className="A-drawer-divider"></div>,
                <div className={'A-drawer-tab' + (tab === t.id ? ' on' : '') + (t.id === 'chloe' ? ' chloe' : '')} onClick={function(){switchTab(t.id)}}>{t.label}{badge}</div>
              );
            })}
          </div>
          <div style={{padding:'16px 20px',borderTop:'1px solid var(--border)',fontSize:10,color:'var(--text-dim)',letterSpacing:'.06em'}}>
            <div style={{marginBottom:8}}>{user.email}</div>
            <div style={{display:'flex',alignItems:'center',gap:8}}>
              <span style={{fontSize:9,padding:'2px 6px',border:'1px solid var(--signal)',color:'var(--signal)',letterSpacing:'.08em',textTransform:'uppercase'}}>{role}</span>
              <button className="A-btn" style={{fontSize:9,padding:'4px 10px',minHeight:'unset'}} onClick={function(){auth.signOut()}}>SIGN OUT</button>
            </div>
          </div>
        </div>
      </div>}
      <div className="A-body">
        {tab === 'cards' && <CardsModule {...sharedProps} />}
        {tab === 'builder' && <BuilderModule {...sharedProps} />}
        {tab === 'analytics' && <AnalyticsModule {...sharedProps} />}
        {tab === 'ai' && <AILabModule {...sharedProps} />}
        {tab === 'creators' && <CreatorsModule {...sharedProps} />}
        {tab === 'create' && <CreateModule {...sharedProps} />}
        {tab === 'calendar' && <CalendarModule {...sharedProps} />}
        {tab === 'insights' && <InsightsModule {...sharedProps} />}
        {tab === 'hotseat' && <HotSeatModule {...sharedProps} />}
        {tab === 'settings' && <SettingsModule {...sharedProps} />}
        {tab === 'chloe' && <ChloeModule {...sharedProps} />}
      </div>
      {toast && <div className="A-toast" key={toast+Date.now()}>{toast}</div>}
    </div>
  );
}

// ─── Module placeholders (will be defined in separate files) ──
// They're loaded via additional script tags below

function App() {
  return (
    <AuthGate>
      {function(user, userRecord) { return <AdminPortal user={user} userRecord={userRecord} />; }}
    </AuthGate>
  );
}

// App is rendered from admin.html after all modules load
